[Spring Boot] How to use OpenAI ChatGPT APIs in a Spring Boot Application

Jay Kim
3 min readAug 9, 2023

--

Chat Completions API is described as follows (link):

Chat models take a list of messages as input and return a model-generated message as output. Although the chat format is designed to make multi-turn conversations easy, it’s just as useful for single-turn tasks without any conversation.

There are libraries available to integrate with ChatGPT but this article shows how to use ChatGPT APIs without any external dependencies.

Implementation

WebClient is used to call the ChatGPT APIs, that’s why spring-boot-starter-webflux dependency is added to build.gradle.kts.

plugins {
java
id("org.springframework.boot") version "3.1.2"
id("io.spring.dependency-management") version "1.1.2"
}

group = "io.jay"
version = "0.0.1-SNAPSHOT"

java {
sourceCompatibility = JavaVersion.VERSION_17
}

repositories {
mavenCentral()
}

dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-webflux")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}

tasks.withType<Test> {
useJUnitPlatform()
}

Place your API key in the application.yml like below. The API key will be sent as Authorization HTTP header in the request. API keys can be created from https://platform.openai.com/account/api-keys.

chatgpt:
api-key: your-api-key

In order to keep things simple, the controller endpoint receives a question or a prompt in the request body and sends to ChatGPT directly. You could do more robust things to come up with a prompt.

Note that you could change and play around with the gpt model and temperature in the ChatRequest constructor. Also, you could use different role for Message.

package io.jay.service;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.support.WebClientAdapter;
import org.springframework.web.service.annotation.PostExchange;
import org.springframework.web.service.invoker.HttpServiceProxyFactory;
import reactor.netty.http.client.HttpClient;

import java.time.Duration;
import java.util.List;
import java.util.stream.Collectors;

interface GptClient {
@PostExchange("/v1/chat/completions")
ChatResponse chat(@RequestBody ChatRequest request);
}

@SpringBootApplication
public class MainApplication {

@Value("${chatgpt.api-key}")
private String apiKey;

public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}

@Bean
GptClient client(WebClient.Builder builder) {
var httpClient = HttpClient.newConnection()
.responseTimeout(Duration.ofSeconds(60))
.keepAlive(false);

var wc = builder.baseUrl("https://api.openai.com")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer " + apiKey)
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();

var wca = WebClientAdapter.forClient(wc);
return HttpServiceProxyFactory.builder()
.blockTimeout(Duration.ofSeconds(60))
.clientAdapter(wca)
.build()
.createClient(GptClient.class);
}
}

class ChatRequest {
private String model;
private List<Message> messages;
private double temperature;

public ChatRequest() {

}

public ChatRequest(String prompt) {
this.model = "gpt-3.5-turbo";
this.messages = List.of(new Message("user", prompt));
this.temperature = 0.0;
}

public String getModel() {
return model;
}

public void setModel(String model) {
this.model = model;
}

public List<Message> getMessages() {
return messages;
}

public void setMessages(List<Message> messages) {
this.messages = messages;
}

public double getTemperature() {
return temperature;
}

public void setTemperature(double temperature) {
this.temperature = temperature;
}
}

record Message(String role, String content) {
}

record Choice(int index, Message message) {
}

record ChatResponse(List<Choice> choices) {
}

@Controller
@ResponseBody
@RequestMapping("/api")
class ChatController {

private final GptClient gpt;

public ChatController(GptClient gpt) {
this.gpt = gpt;
}

@PostMapping("/chat")
public String chat(@RequestBody String prompt) {
var response = gpt.chat(new ChatRequest(prompt));
System.out.println(response);

return response.choices().stream()
.map(c -> c.message().content())
.collect(Collectors.joining("\n"));
}
}

Testing

Response from OpenAI ChatGPT

--

--