Skip to content

Commit 793e335

Browse files
authored
Bael 8841 (#18024)
* BAEL-8841, Implementing an AI Assistant with Spring AI * BAEL-8841, Implementing an AI Assistant with Spring AI * BAEL-8841, Implementing an AI Assistant with Spring AI * BAEL-8841, Implementing an AI Assistant with Spring AI * Update order_mgmt.sql * BAEL-8841, Implementing an AI Assistant with Spring AI * BAEL-8841, Implementing an AI Assistant with Spring AI * BAEL-8841, Implementing an AI Assistant with Spring AI * Update order_mgmt.sql
1 parent a97478b commit 793e335

15 files changed

+444
-2
lines changed

pom.xml

+4-2
Original file line numberDiff line numberDiff line change
@@ -716,7 +716,7 @@
716716
<module>jws</module>
717717
<module>ksqldb</module>
718718
<module>kubernetes-modules</module>
719-
<module>language-interop</module>
719+
<!--<module>language-interop</module>-->
720720
<module>libraries</module> <!-- very long running -->
721721
<module>libraries-2</module>
722722
<module>libraries-3</module>
@@ -789,6 +789,7 @@
789789
<module>spring-activiti</module>
790790
<module>spring-actuator</module>
791791
<module>spring-ai</module>
792+
<module>spring-ai-2</module>
792793
<module>spring-aop-2</module>
793794
<module>spring-aop</module>
794795
<module>spring-batch</module>
@@ -1102,7 +1103,7 @@
11021103
<module>jws</module>
11031104
<module>ksqldb</module>
11041105
<module>kubernetes-modules</module>
1105-
<module>language-interop</module>
1106+
<!-- <module>language-interop</module>-->
11061107
<module>libraries</module> <!-- very long running -->
11071108
<module>libraries-2</module>
11081109
<module>libraries-3</module>
@@ -1174,6 +1175,7 @@
11741175
<module>spring-activiti</module>
11751176
<module>spring-actuator</module>
11761177
<module>spring-ai</module>
1178+
<module>spring-ai-2</module>
11771179
<module>spring-aop-2</module>
11781180
<module>spring-aop</module>
11791181
<module>spring-batch</module>

spring-ai-2/pom.xml

+14
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,19 @@
5151
<groupId>org.springframework.ai</groupId>
5252
<artifactId>spring-ai-chroma-store-spring-boot-starter</artifactId>
5353
</dependency>
54+
<dependency>
55+
<groupId>org.springframework.boot</groupId>
56+
<artifactId>spring-boot-starter-data-jpa</artifactId>
57+
</dependency>
58+
<dependency>
59+
<groupId>org.springframework.ai</groupId>
60+
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
61+
</dependency>
62+
<dependency>
63+
<groupId>org.hsqldb</groupId>
64+
<artifactId>hsqldb</artifactId>
65+
<scope>runtime</scope>
66+
</dependency>
5467

5568
<!-- Test dependencies -->
5669
<dependency>
@@ -97,6 +110,7 @@
97110
<properties>
98111
<spring-boot.version>3.3.5</spring-boot.version>
99112
<spring-ai.version>1.0.0-M4</spring-ai.version>
113+
<junit-jupiter.version>5.9.0</junit-jupiter.version>
100114
</properties>
101115

102116
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.baeldung.spring.ai.om;
2+
3+
import java.util.List;
4+
import java.util.function.Function;
5+
6+
import org.springframework.context.annotation.Bean;
7+
import org.springframework.context.annotation.Configuration;
8+
import org.springframework.context.annotation.Description;
9+
import org.springframework.context.annotation.Profile;
10+
11+
@Configuration
12+
@Profile("aiassistant")
13+
public class OmAiAssistantConfiguration {
14+
@Bean
15+
@Description("Create an order. The Order ID is identified with orderID. The order quantity is identified by orderQuantity."
16+
+ "The user is identified by userID. "
17+
+ "The order quantity should be a positive whole number."
18+
+ " If any of the parameters like user id and the order quantity is missing then ask the user to provide the missing information.")
19+
public Function<CreateOrderRequest, Long> createOrderFn(OrderManagementService orderManagementService) {
20+
return createOrderRequest -> orderManagementService.createOrder(createOrderRequest.orderInfo());
21+
}
22+
@Bean
23+
@Description("get all the orders of an user. The user ID is identified with userID.")
24+
public Function<GetOrderRequest, List<OrderInfo>> getUserOrdersFn(OrderManagementService orderManagementService) {
25+
return getOrderRequest -> orderManagementService.getAllUserOrders(getOrderRequest.userID()).get();
26+
}
27+
}
28+
29+
record GetOrderRequest(String userID) {
30+
}
31+
32+
record CreateOrderRequest(OrderInfo orderInfo) {
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.baeldung.spring.ai.om;
2+
3+
import jakarta.persistence.Column;
4+
import jakarta.persistence.Entity;
5+
import jakarta.persistence.Id;
6+
7+
@Entity(name = "User_Order")
8+
public class OrderInfo {
9+
@Id
10+
@Column(name = "order_id")
11+
private Long orderID;
12+
13+
@Column(name = "user_id")
14+
private String userID;
15+
16+
@Column(name = "quantity")
17+
private Integer orderQuantity;
18+
19+
public OrderInfo() {
20+
super();
21+
}
22+
23+
public OrderInfo(Integer orderQuantity, String userID, Long orderID) {
24+
this.orderQuantity = orderQuantity;
25+
this.userID = userID;
26+
this.orderID = orderID;
27+
}
28+
29+
public Long getOrderID() {
30+
return orderID;
31+
}
32+
33+
public void setOrderID(Long orderID) {
34+
this.orderID = orderID;
35+
}
36+
37+
public String getUserID() {
38+
return userID;
39+
}
40+
41+
public void setUserID(String userID) {
42+
this.userID = userID;
43+
}
44+
45+
public Integer getOrderQuantity() {
46+
return orderQuantity;
47+
}
48+
49+
public void setOrderQuantity(Integer orderQuantity) {
50+
this.orderQuantity = orderQuantity;
51+
}
52+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.baeldung.spring.ai.om;
2+
3+
import java.util.Set;
4+
import org.springframework.ai.chat.model.ChatModel;
5+
import org.springframework.ai.chat.model.ChatResponse;
6+
import org.springframework.ai.chat.prompt.Prompt;
7+
import org.springframework.ai.openai.OpenAiChatOptions;
8+
import org.springframework.beans.factory.annotation.Autowired;
9+
import org.springframework.stereotype.Service;
10+
11+
@Service
12+
public class OrderManagementAIAssistant {
13+
@Autowired
14+
private ChatModel chatClient;
15+
16+
public ChatResponse callChatClient(Set<String> functionNames, String promptString) {
17+
Prompt prompt = new Prompt(promptString, OpenAiChatOptions
18+
.builder()
19+
.withFunctions(functionNames)
20+
.build()
21+
);
22+
return chatClient.call(prompt);
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.baeldung.spring.ai.om;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
6+
@SpringBootApplication
7+
public class OrderManagementApplication {
8+
9+
public static void main(String[] args) {
10+
SpringApplication.run(OrderManagementApplication.class, args);
11+
}
12+
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.baeldung.spring.ai.om;
2+
3+
import java.util.List;
4+
import java.util.Optional;
5+
6+
import org.springframework.beans.factory.annotation.Autowired;
7+
import org.springframework.stereotype.Service;
8+
9+
@Service
10+
public class OrderManagementService {
11+
@Autowired
12+
private OrderRepository orderRepository;
13+
14+
public Long createOrder(OrderInfo orderInfo) {
15+
return orderRepository.save(orderInfo).getOrderID();
16+
}
17+
18+
public Optional<List<OrderInfo>> getAllUserOrders(String userID) {
19+
return orderRepository.findByUserID(userID);
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.baeldung.spring.ai.om;
2+
3+
import java.util.List;
4+
import java.util.Optional;
5+
6+
import org.springframework.data.jpa.repository.JpaRepository;
7+
import org.springframework.stereotype.Repository;
8+
9+
@Repository
10+
public interface OrderRepository extends JpaRepository<OrderInfo, Long> {
11+
@Override
12+
OrderInfo save(OrderInfo entity);
13+
Optional<List<OrderInfo>> findByUserID(String userID);
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
spring.application.name=spring-ai-assistant
2+
3+
spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver
4+
spring.datasource.url=jdbc:hsqldb:mem:testdb;DB_CLOSE_DELAY=-1
5+
spring.datasource.username=sa
6+
spring.datasource.password=
7+
spring.jpa.hibernate.ddl-auto=none
8+
9+
spring.ai.openai.chat.options.model=gpt-4o-mini
10+
spring.ai.openai.api-key=xxxxxxx
11+
spring.autoconfigure.exclude=org.springframework.ai.autoconfigure.ollama.OllamaAutoConfiguration,org.springframework.ai.autoconfigure.vectorstore.chroma.ChromaVectorStoreAutoConfiguration
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<configuration>
2+
3+
<!-- Console Appender -->
4+
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
5+
<encoder>
6+
<pattern>[%d{yyyy-MM-dd HH:mm:ss}] [%p] [%c{1}] - %m%n</pattern>
7+
</encoder>
8+
</appender>
9+
10+
<!-- Root Logger: Set to INFO level -->
11+
<root level="INFO">
12+
<appender-ref ref="CONSOLE" />
13+
</root>
14+
15+
<!-- Enable DEBUG Logs for Spring AI -->
16+
<logger name="org.springframework" level="INFO" additivity="false">
17+
<appender-ref ref="CONSOLE" />
18+
</logger>
19+
20+
</configuration>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
@startuml
2+
!theme sunlust
3+
<style>
4+
sequenceDiagram {
5+
LineColor #63b175
6+
LineThickness 1.7
7+
}
8+
</style>
9+
skinparam BackgroundColor #fffce8/#f8f9fa
10+
skinparam sequenceMessageAlign direction
11+
12+
skinparam sequence {
13+
ParticipantBackgroundColor #63b175
14+
ParticipantPadding 50
15+
ParticipantFontColor #fff
16+
}
17+
autonumber
18+
actor User
19+
participant "Application" as App
20+
participant "Chat Client" as ChatClient
21+
participant "LLM Service" as LLM
22+
23+
activate User
24+
User -> ChatClient: query (e.g., "Show my orders")
25+
activate ChatClient
26+
ChatClient --> App: query
27+
activate App
28+
App -> LLM: prompt with function schema (e.g., GetOrderRequest)
29+
activate LLM
30+
LLM --> LLM: identify appropriate function
31+
LLM --> App: request to execute function
32+
deactivate LLM
33+
App --> App: executes function
34+
App -> LLM: function execution result
35+
activate LLM
36+
LLM --> App: Final response
37+
deactivate LLM
38+
App -> ChatClient: Final Response
39+
deactivate App
40+
ChatClient --> User: Final Response
41+
deactivate ChatClient
42+
43+
@enduml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
@startuml
2+
'https://plantuml.com/class-diagram
3+
hide empty attributes
4+
skinparam Handwritten false
5+
skinparam ClassBorderColor black
6+
skinparam BackgroundColor #fffce8/#f8f9fa
7+
skinparam class {
8+
ArrowColor SeaGreen
9+
BackgroundColor #fffce8
10+
}
11+
12+
class OrderManagementService {
13+
+createOrder(OrderInfo):Long
14+
+getAllUserOrders(String):String
15+
}
16+
interface JpaRepository<OrderInfo, Long> {
17+
+save(OrderInfo):OrderInfo
18+
}
19+
20+
class OrderRepository {
21+
+save():OrderInfo
22+
+findByUserID():Optional<List<OrderInfo>>
23+
}
24+
class OrderInfo {
25+
-orderID:Long
26+
-userID:String
27+
-orderQuantity:Integer
28+
}
29+
30+
OrderManagementService -right-> OrderInfo:uses
31+
OrderManagementService -up-> OrderRepository:uses
32+
OrderRepository -up-|> JpaRepository:extends
33+
OrderRepository -down-> OrderInfo:uses
34+
35+
@enduml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
@startuml
2+
'https://plantuml.com/class-diagram
3+
hide empty attributes
4+
skinparam Handwritten false
5+
skinparam ClassBorderColor black
6+
skinparam BackgroundColor #fffce8/#f8f9fa
7+
skinparam class {
8+
ArrowColor SeaGreen
9+
BackgroundColor #fffce8
10+
}
11+
12+
interface ChatModel {
13+
+call(Prompt):ChatResponse
14+
}
15+
class OpenAIChatModel {
16+
+call(Prompt):ChatResponse
17+
}
18+
class ChatResponse {
19+
}
20+
21+
class OmAiAssistantConfiguration {
22+
+createOrderFn(OrderManagementService):Function<CreateOrderRequest, Long>
23+
+getUserOrdersFn(OrderManagementService):Function<GetOrderRequest, List<OrderInfo>>
24+
}
25+
26+
class OrderManagementAIAssistant {
27+
+callChatClient(Set<String>, String):ChatResponse
28+
}
29+
30+
class OrderManagementService {
31+
+createOrderFn(OrderInfo):Long
32+
+getAllUserOrders(String):String
33+
}
34+
35+
interface Function {
36+
}
37+
38+
note left of OmAiAssistantConfiguration::createOrderFn
39+
<b>@Bean</b>
40+
end note
41+
note left of OmAiAssistantConfiguration::getUserOrdersFn
42+
<b>@Bean</b>
43+
end note
44+
45+
OmAiAssistantConfiguration --> OrderManagementService: uses
46+
OmAiAssistantConfiguration --> Function:uses
47+
OpenAIChatModel -left|> ChatModel:implements
48+
OrderManagementAIAssistant --> ChatModel:uses
49+
ChatModel -left-> ChatResponse:uses
50+
ChatModel -[hidden]-> OmAiAssistantConfiguration
51+
52+
@enduml

0 commit comments

Comments
 (0)