diff --git a/core-java-modules/core-java-string-algorithms-5/src/main/java/com/baeldung/uniqueint/StringToUniqueInt.java b/core-java-modules/core-java-string-algorithms-5/src/main/java/com/baeldung/uniqueint/StringToUniqueInt.java index 5128714be205..2eb104f05018 100644 --- a/core-java-modules/core-java-string-algorithms-5/src/main/java/com/baeldung/uniqueint/StringToUniqueInt.java +++ b/core-java-modules/core-java-string-algorithms-5/src/main/java/com/baeldung/uniqueint/StringToUniqueInt.java @@ -38,12 +38,12 @@ public static int toIntByMD5(String value) { } public static int toIntByLookup(String value) { - var found = lookupMap.get(value); + Integer found = lookupMap.get(value); if (found != null) { return found; } - var intValue = counter.incrementAndGet(); + Integer intValue = counter.incrementAndGet(); lookupMap.put(value, intValue); return intValue; } diff --git a/pom.xml b/pom.xml index d3db76e746de..cc376aacd99d 100644 --- a/pom.xml +++ b/pom.xml @@ -764,6 +764,7 @@ spring-ai spring-ai-2 spring-ai-3 + spring-ai-4 spring-ai-modules spring-aop spring-aop-2 @@ -1196,6 +1197,7 @@ spring-ai spring-ai-2 spring-ai-3 + spring-ai-4 spring-ai-modules spring-aop spring-aop-2 diff --git a/spring-ai-4/pom.xml b/spring-ai-4/pom.xml new file mode 100644 index 000000000000..ac2466af39f8 --- /dev/null +++ b/spring-ai-4/pom.xml @@ -0,0 +1,119 @@ + + + 4.0.0 + spring-ai-4 + 0.0.1 + jar + spring-ai-4 + + + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../parent-boot-3 + + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + true + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + true + + + false + + + + + + + + org.springframework.ai + spring-ai-bom + ${spring-ai.version} + pom + import + + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.ai + spring-ai-starter-model-openai + + + org.springframework.ai + spring-ai-model-chat-memory-repository-jdbc + + + org.hsqldb + hsqldb + runtime + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + chat-memory + + true + + + com.baeldung.springai.memory.Application + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + ${spring.boot.mainclass} + + + + org.apache.maven.plugins + maven-compiler-plugin + + 21 + + + + + + + 5.9.0 + 3.5.0 + 1.0.0 + + + diff --git a/spring-ai-4/src/main/java/com/baeldung/springai/memory/Application.java b/spring-ai-4/src/main/java/com/baeldung/springai/memory/Application.java new file mode 100644 index 000000000000..5cdaa360c6bc --- /dev/null +++ b/spring-ai-4/src/main/java/com/baeldung/springai/memory/Application.java @@ -0,0 +1,15 @@ +package com.baeldung.springai.memory; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication app = new SpringApplication(Application.class); + app.setAdditionalProfiles("memory"); + app.run(args); + } + +} diff --git a/spring-ai-4/src/main/java/com/baeldung/springai/memory/ChatConfig.java b/spring-ai-4/src/main/java/com/baeldung/springai/memory/ChatConfig.java new file mode 100644 index 000000000000..a44f8f7d0739 --- /dev/null +++ b/spring-ai-4/src/main/java/com/baeldung/springai/memory/ChatConfig.java @@ -0,0 +1,21 @@ +package com.baeldung.springai.memory; + +import org.springframework.ai.chat.memory.ChatMemoryRepository; +import org.springframework.ai.chat.memory.repository.jdbc.HsqldbChatMemoryRepositoryDialect; +import org.springframework.ai.chat.memory.repository.jdbc.JdbcChatMemoryRepository; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.core.JdbcTemplate; + +@Configuration +public class ChatConfig { + + @Bean + public ChatMemoryRepository getChatMemoryRepository(JdbcTemplate jdbcTemplate) { + return JdbcChatMemoryRepository.builder() + .jdbcTemplate(jdbcTemplate) + .dialect(new HsqldbChatMemoryRepositoryDialect()) + .build(); + } + +} diff --git a/spring-ai-4/src/main/java/com/baeldung/springai/memory/ChatController.java b/spring-ai-4/src/main/java/com/baeldung/springai/memory/ChatController.java new file mode 100644 index 000000000000..f860eea77ca0 --- /dev/null +++ b/spring-ai-4/src/main/java/com/baeldung/springai/memory/ChatController.java @@ -0,0 +1,25 @@ +package com.baeldung.springai.memory; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; + +@RestController +public class ChatController { + + private final ChatService chatService; + + public ChatController(ChatService chatService) { + this.chatService = chatService; + } + + @PostMapping("/chat") + public ResponseEntity chat(@RequestBody @Valid ChatRequest request) { + String response = chatService.chat(request.getPrompt()); + return ResponseEntity.ok(response); + } + +} diff --git a/spring-ai-4/src/main/java/com/baeldung/springai/memory/ChatRequest.java b/spring-ai-4/src/main/java/com/baeldung/springai/memory/ChatRequest.java new file mode 100644 index 000000000000..cedefe07fa35 --- /dev/null +++ b/spring-ai-4/src/main/java/com/baeldung/springai/memory/ChatRequest.java @@ -0,0 +1,18 @@ +package com.baeldung.springai.memory; + +import javax.validation.constraints.NotNull; + +public class ChatRequest { + + @NotNull + private String prompt; + + public String getPrompt() { + return prompt; + } + + public void setPrompt(String prompt) { + this.prompt = prompt; + } + +} diff --git a/spring-ai-4/src/main/java/com/baeldung/springai/memory/ChatService.java b/spring-ai-4/src/main/java/com/baeldung/springai/memory/ChatService.java new file mode 100644 index 000000000000..64fc63acca79 --- /dev/null +++ b/spring-ai-4/src/main/java/com/baeldung/springai/memory/ChatService.java @@ -0,0 +1,38 @@ +package com.baeldung.springai.memory; + +import org.springframework.ai.chat.client.ChatClient; +import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor; +import org.springframework.ai.chat.memory.ChatMemory; +import org.springframework.ai.chat.model.ChatModel; +import org.springframework.stereotype.Component; +import org.springframework.web.context.annotation.SessionScope; + +import java.util.UUID; + +@Component +@SessionScope +public class ChatService { + + private final ChatClient chatClient; + private final String conversationId; + + public ChatService(ChatModel chatModel, ChatMemory chatMemory) { + this.chatClient = ChatClient.builder(chatModel) + .defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build()) + .build(); + this.conversationId = UUID.randomUUID().toString(); + } + + public String getConversationId() { + return conversationId; + } + + public String chat(String prompt) { + return chatClient.prompt() + .user(userMessage -> userMessage.text(prompt)) + .advisors(a -> a.param(ChatMemory.CONVERSATION_ID, conversationId)) + .call() + .content(); + } + +} diff --git a/spring-ai-4/src/main/resources/application-memory.yml b/spring-ai-4/src/main/resources/application-memory.yml new file mode 100644 index 000000000000..a0531b4eab58 --- /dev/null +++ b/spring-ai-4/src/main/resources/application-memory.yml @@ -0,0 +1,15 @@ +spring: + ai: + openai: + api-key: "" + + datasource: + url: jdbc:hsqldb:mem:chatdb + driver-class-name: org.hsqldb.jdbc.JDBCDriver + username: sa + password: + + sql: + init: + mode: always + schema-locations: classpath:org/springframework/ai/chat/memory/repository/jdbc/schema-hsqldb.sql diff --git a/spring-ai-4/src/main/resources/logback.xml b/spring-ai-4/src/main/resources/logback.xml new file mode 100644 index 000000000000..449efbdaebb0 --- /dev/null +++ b/spring-ai-4/src/main/resources/logback.xml @@ -0,0 +1,15 @@ + + + + [%d{yyyy-MM-dd HH:mm:ss}] [%p] [%c{1}] - %m%n + + + + + + + + + + + \ No newline at end of file diff --git a/spring-ai-4/src/test/java/com/baeldung/springai/memory/ChatServiceLiveTest.java b/spring-ai-4/src/test/java/com/baeldung/springai/memory/ChatServiceLiveTest.java new file mode 100644 index 000000000000..c96024846a92 --- /dev/null +++ b/spring-ai-4/src/test/java/com/baeldung/springai/memory/ChatServiceLiveTest.java @@ -0,0 +1,39 @@ +package com.baeldung.springai.memory; + +import org.junit.jupiter.api.Test; +import org.springframework.ai.chat.memory.ChatMemory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest +@ActiveProfiles("memory") +class ChatServiceLiveTest { + + private static final String PROMPT_1ST = "Tell me a joke"; + private static final String PROMPT_2ND = "Tell me another one"; + + @Autowired + private ChatMemory chatMemory; + + @Autowired + private ChatService chatService; + + @Test + void whenChatServiceIsCalledTwice_thenChatMemoryHasCorrectNumberOfEntries() { + String conversationId = chatService.getConversationId(); + + // 1st request + String response1 = chatService.chat(PROMPT_1ST); + assertThat(response1).isNotEmpty(); + assertThat(chatMemory.get(conversationId)).hasSize(2); + + // 2nd request + String response2 = chatService.chat(PROMPT_2ND); + assertThat(response2).isNotEmpty(); + assertThat(chatMemory.get(conversationId)).hasSize(4); + } + +} \ No newline at end of file