In the fast-paced world of technology, integrating artificial intelligence (AI) into applications has become essential for driving innovation and improving efficiency. The Spring AI Project is a powerful extension of the Spring framework, designed to make it easier to incorporate AI capabilities into Spring-based applications. Let us delve into understanding Spring AI and Spring AI Structured Outputs.
1. What is Spring AI?
The Spring AI Project extends the widely adopted Spring framework, providing a suite of tools and libraries that simplify the integration of AI functionalities into Spring applications. It bridges the gap between AI models and business applications, offering seamless integration, enhanced configurability, and strong support for various AI services and frameworks. Whether you’re working with machine learning models, natural language processing, or computer vision, Spring AI equips you with the components needed to effortlessly embed AI capabilities into your application. Spring AI offers three built-in classes—MapOutputConverter
, ListOutputConverter
, and BeanOutputConverter
—that facilitate handling the most common response structures typically encountered in APIs. At a broad level, these converters serve two primary functions:
- They guide the prompt to generate responses in a specified format (such as XML or JSON) and structure, ensuring consistent and precise output.
- After receiving the response, they parse it into Java development services classes, including POJOs, Lists, or Maps, facilitating seamless integration with Java-based applications.
2. How to generate an OpenAI API key?
We’ll use an OpenAI model to generate a chat completion bot, so let’s first understand how to obtain an OpenAI key.
- Create an Account or Sign In: Go to the OpenAI website and either sign up for a new account or log in to your existing one.
- Access API Keys: After logging in, head to the API Keys section within your account dashboard.
- Generate a New API Key: Select the option to create a new API key. Assign a name or description to the key for easy reference.
- Generate and Save the Key: Click the Generate Key button. Make sure to copy the newly created API key and store it in a safe place, as you will need it to access OpenAI’s services.
3. Code example
3.1 Dependencies
Add the following dependencies to your 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.3</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>springai-structuredoutput</name> <description>springai-structuredoutput</description> <url/> <licenses> <license/> </licenses> <developers> <developer/> </developers> <scm> <connection/> <developerConnection/> <tag/> <url/> </scm> <properties> <java.version>17</java.version> <spring-ai.version>1.0.0-M2</spring-ai.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</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> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-bom</artifactId> <version>${spring-ai.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <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> </repositories> </project>
3.2 Update the application properties
Add the following properties to the application.properties
file. Remember to replace the OpenAI key.
# Application properties spring.application.name=springai-structuredoutput spring.main.banner-mode=off server.port=9090 # OpenAI API key spring.ai.openai.api-key=your-openai-api-key
3.3 Create a Model DTO
Create a Model DTO as it will be used for the BeanOutputConverter
endpoint in the controller.
package com.demo.model; public class Movie { private String category; private String book; private String year; private String review; private String author; private String summary; public Movie() { } public Movie(String category, String book, String year, String review, String author, String summary) { this.category = category; this.book = book; this.year = year; this.review = review; this.author = author; this.summary = summary; } // getter method }
3.4 Creating the Controller
The ChatController
class is a REST controller in a Spring Boot application, responsible for handling the HTTP requests related to Structured Ouput in Spring AI.
package com.demo.controller; import com.demo.model.Movie; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.converter.ListOutputConverter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.List; import java.util.Map; @RestController @RequestMapping("/chat") public class ChatController { private final ChatClient client; @Autowired public ChatController(ChatClient.Builder builder) { this.client = builder.build(); } /** * Handles GET requests to /chat/response. * * @param category the category of the movie * @param year the year of the movie * @return a JSON string containing the movie details */ // curl -X GET "http://localhost:9090/chat/response?category=action&year=2022" @GetMapping("/response") public String getResponse(@RequestParam String category, @RequestParam String year) { System.out.println("category: " + category); System.out.println("year: " + year); System.out.println("String response"); return client.prompt() .user(user -> user.text("Please provide the movie detail for the given {category} and {year} in the JSON format.") .param("category", category) .param("year", year)) .call() .content(); } /** * Handles GET requests to /chat/beanResponse. * * @param category the category of the movie * @param year the year of the movie * @return a Movie object containing the movie details */ // curl -X GET "http://localhost:9090/chat/beanResponse?category=action&year=2022" @GetMapping("/beanResponse") public Movie getBeanResponse(@RequestParam String category, @RequestParam String year) { System.out.println("category: " + category); System.out.println("year: " + year); System.out.println("Bean response"); return client.prompt() .user(user -> user.text("Please provide the movie detail for the given {category} and {year}.") .param("category", category) .param("year", year)) .call() .entity(Movie.class); } /** * Handles GET requests to /chat/listResponse. * * @param category the category of the movie * @param year the year of the movie * @return a list of strings containing the names of the best movies */ // curl -X GET "http://localhost:9090/chat/listResponse?category=action&year=2022" @GetMapping("/listResponse") public List<String> getListResponse(@RequestParam String category, @RequestParam String year) { System.out.println("category: " + category); System.out.println("year: " + year); System.out.println("List response"); return client.prompt() .user(user -> user.text("Please provide the names of 5 best movies for the given {category} and {year}.") .param("category", category) .param("year", year)) .call() .entity(new ListOutputConverter(new DefaultConversionService())); } /** * Handles GET requests to /chat/mapResponse. * * @param category the category of the movie * @param year the year of the movie * @return a map containing the movie details */ // curl -X GET "http://localhost:9090/chat/mapResponse?category=action&year=2022" @GetMapping("/mapResponse") public Map<String, Object> getMapResponse(@RequestParam String category, @RequestParam String year) { System.out.println("category: " + category); System.out.println("year: " + year); System.out.println("Map response"); return client.prompt() .user(u -> u.text(""" Please provide me best movie for the given {category} and the {year}. Please do provide a summary of the movie as well, the information should be\s limited and not much in depth. The response should be in the JSON format\s containing this information: category, movie, year, review, author, summary Please remove ```json from the final output """) .param("category", category) .param("year", year)) .call() .entity(new ParameterizedTypeReference<>() { }); } }
3.5 Create the Main file
Create a Spring Boot application to initialize the application.
package com.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SpringaiStructuredoutputApplication { public static void main(String[] args) { SpringApplication.run(SpringaiStructuredoutputApplication.class, args); System.out.println("Application started successfully."); } }
3.6 Run the application and Demo
Now start the application and open the Postman tool to hit the api endpoint. Import the below curl GET requests in the Postman tool. You’re free to change the prompt with a valid instruction.
// Handles GET requests to /chat/response. curl -X GET "http://localhost:9090/chat/response?category=action&year=2022" // Handles GET requests to /chat/beanResponse. http://localhost:9090/chat/beanResponse?category=action&year=2022 // Handles GET requests to /chat/listResponse. http://localhost:9090/chat/listResponse?category=action&year=2022 // Handles GET requests to /chat/mapResponse. http://localhost:9090/chat/mapResponse?category=action&year=2022
If everything goes well api responses in different formats will be returned and shown to the user.
4. Conclusion
In conclusion, as Generative AI Development Services continues to reshape the technological landscape, tools like Spring AI are essential for seamlessly integrating AI into applications. By leveraging Spring AI, developers can easily add advanced AI capabilities to their Spring-based projects, enabling innovative solutions like generating images from user prompts, chat completion bots, etc.