In this blog post, we'll explore how to leverage Spring AI to create a simple chat API using OpenAI's language model and Java. Before we go into the example, let's see why this is exciting!
Java Developers, Rejoice!
No need to learn a new language!
As a seasoned Java developer, you might think that diving into AI development requires learning a new language, such as Python. After all, Python is widely recognized for its robust AI libraries and frameworks. However, with Spring AI, Java developers can achieve AI integration without stepping outside their comfort zone.
Most corporate applications are built using Java due to its stability, scalability, and enterprise-level support. Integrating AI directly into these applications using Spring AI allows businesses to enhance their functionality and user experience without needing to overhaul their technology stack. It also ensures that developers can work within a familiar environment, improving productivity and reducing the learning curve.
Staying within the Java ecosystem means you can continue to use your existing skills and knowledge. You won't have to invest time and resources in learning a new language or adapting to different paradigms. This not only saves time but also helps maintain consistency in your codebase, making future updates and maintenance more manageable.
What is Spring AI?
Spring AI is a library that aims to make it easier for developers to create applications with artificial intelligence features. The main goal of Spring AI is to help connect your company's data and systems with AI models in a straightforward way.
Connecting your enterprise Data and APIs with the AI Models
.The library offers a set of tools and features that developers can use as building blocks for AI applications. These include support for various AI model providers like OpenAI, Microsoft, Amazon, Google, and Hugging Face. It supports different types of AI models such as chat and image generation. Spring AI is designed to be flexible, allowing developers to easily switch between different components without having to rewrite a lot of code.
Spring AI Architecture
Here is the architecture of Spring AI*( source: official documentation)*
Supported models
OpenAI, Microsoft, Amazon, Google, Amazon Bedrock, Hugging Face and more.
Some key features of Spring AI include the ability to use AI models from different providers with a consistent interface, support for turning AI outputs into Java objects, and tools for managing and processing data for AI use. It also provides ready-to-use components that work well with Spring Boot, a popular framework for building Java applications. With these features, developers can more easily create applications that do things like answer questions based on company documents or have conversations using a company's knowledge base.
Seamless Java Integration
Spring AI is designed to integrate AI capabilities into Java applications effortlessly. It provides a straightforward way to connect with language models using Java, making it an excellent choice for those who want to keep their tech stack consistent. This library allows you to leverage the power of conversational AI without needing to rewrite your existing codebase in a different language.
Imagine adding a conversational interface to your enterprise application that can handle customer inquiries, provide personalized recommendations, or automate routine tasks. With Spring AI, these features can be implemented quickly and efficiently. You can focus on developing the business logic and user experience without worrying about the intricacies of a new programming language.
Prerequisites
Before we begin, make sure you have the following:
Java Development Kit (JDK) 17 or later
Maven
An OpenAI API key
Project Setup
Let's start by setting up a new Spring Boot project with the necessary dependencies.
pom.xml
First, we'll configure our pom.xml
file:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.donvitocodes</groupId>
<artifactId>openai-java</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>OpenAI Java</name>
<description>Simple AI Application using OpenAPI Service</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.0.0-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
</project>
This configuration sets up our project with Spring Boot, Spring AI, and the necessary dependencies for working with OpenAI.
Application Structure
Now, let's create the main application class Application.Java
package com.donvitocodes;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Configuration Class
Next, we'll create a configuration class Config.java to set up our ChatClient.
package com.donvitocodes;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
class Config {
@Bean
ChatClient chatClient(ChatClient.Builder builder) {
String modelName = "gpt-4o-mini";
float temperature = 0f;
int maxTokens = 1024;
return builder
.defaultOptions(OpenAiChatOptions.builder()
.withModel(modelName)
.withTemperature(temperature)
.withMaxTokens(maxTokens)
.withStreamUsage(true)
.build())
.build();
}
}
This configuration sets up the ChatClient with custom options for the OpenAI model, including the model name, temperature, and maximum tokens.
Creating the Controller
Finally, let's create a controller:
package com.donvitocodes;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import java.util.Map;
@RestController
class AIController {
private final ChatClient chatClient;
AIController(ChatClient chatClient) {
this.chatClient = chatClient;
}
@GetMapping("/chat")
Map<String, String> completion(@RequestParam(value = "message", defaultValue = "") String message) {
return Map.of(
"completion",
chatClient.prompt()
.user(message)
.call()
.content());
}
// Streaming
@GetMapping(value = "/chat-stream", produces = "application/stream+json")
public Flux<String> streamCompletion(@RequestParam(value = "message", defaultValue = "") String message) {
return chatClient.prompt()
.user(message)
.stream()
.content();
}
}
This controller exposes a simple GET endpoint that accepts a message parameter and returns the AI-generated response. The response is not streaming in this case.
Streaming the Chat Response
If you want to stream the response, this is that part of the code
@GetMapping(value = "/chat-stream", produces = "application/stream+json")
public Flux<String> streamCompletion(@RequestParam(value = "message", defaultValue = "") String message) {
return chatClient.prompt()
.user(message)
.stream()
.content();
}
Running the Application
To run the application, make sure you've set your OpenAI API key as an environment variable:
export SPRING_AI_OPENAI_API_KEY=your_api_key_here
Then, you can start the application using Maven:
mvn spring-boot:run
Testing the API
URL:http://localhost:8080/chat
Method:GET
Query Parameter:
message
(string): The prompt or instruction to be processed by the API. For example,"create a short blog post about investing in real estate"
.
Once your application is running, you can test the API using curl or any HTTP client:
curl --location 'http://localhost:8080/chat?message=create%20a%20short%20blog%20post%20about%20investing%20in%20real%20estate'
Or use Postman
Testing with Streaming
You need to use --no-buffer or -N when doing the curl. Make sure you call the localhost:8080//chat-stream endpoint.
curl --no-buffer --location 'http://localhost:8080/chat-stream?message=create%20a%20short%20blog%20post%20about%20investing%20in%20real%20estate%20in%20the%20philippines'
The API will return the AI-generated response based on the input message.
In this blog post, we've explored how to create a chat API using Spring AI, OpenAI, and Java. This integration provides a powerful foundation for building AI-powered conversational applications within the Spring ecosystem. By leveraging Spring AI's abstraction layer, you can easily switch between different AI providers or models in the future, making your application more flexible and maintainable.
Remember to handle API rate limits, implement proper error handling, and consider adding authentication to your API before deploying it to production.
Happy coding!
If you're interested in learning more about developing apps with Generative AI, subscribe to my blog for more tutorials and sample code. You can also follow me in Twitter or connect with me in LinkedIn.