diff --git a/.github/workflows/chatbot-ollama-springai.yml b/.github/workflows/chatbot-ollama-springai.yml index 5562dee..f09824a 100644 --- a/.github/workflows/chatbot-ollama-springai.yml +++ b/.github/workflows/chatbot-ollama-springai.yml @@ -3,11 +3,11 @@ name: chatbot-ollama-springai CI Build on: push: paths: - - "chatbot-ollama-springai/**" + - "chatbot/chatbot-ollama-springai/**" branches: [main] pull_request: paths: - - "chatbot-ollama-springai/**" + - "chatbot/chatbot-ollama-springai/**" types: - opened - synchronize @@ -19,10 +19,9 @@ jobs: runs-on: ubuntu-latest defaults: run: - working-directory: chatbot-ollama-springai + working-directory: chatbot/chatbot-ollama-springai strategy: matrix: - distribution: [ 'temurin' ] java: [ '21' ] steps: - uses: actions/checkout@v4 @@ -33,7 +32,7 @@ jobs: uses: actions/setup-java@v4.2.1 with: java-version: ${{ matrix.java }} - distribution: ${{ matrix.distribution }} + distribution: temurin cache: 'maven' - name: Build and analyze run: ./mvnw clean verify \ No newline at end of file diff --git a/chatbot-ollama-springai/src/main/java/com/example/chatbot/config/ChatConfig.java b/chatbot-ollama-springai/src/main/java/com/example/chatbot/config/ChatConfig.java deleted file mode 100644 index 74525be..0000000 --- a/chatbot-ollama-springai/src/main/java/com/example/chatbot/config/ChatConfig.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.example.chatbot.config; - -import java.util.List; -import java.util.Map; -import java.util.Set; -import org.springframework.ai.chat.memory.ChatMemory; -import org.springframework.ai.chat.memory.ChatMemoryChatServiceListener; -import org.springframework.ai.chat.memory.ChatMemoryRetriever; -import org.springframework.ai.chat.memory.InMemoryChatMemory; -import org.springframework.ai.chat.memory.LastMaxTokenSizeContentTransformer; -import org.springframework.ai.chat.memory.SystemPromptChatMemoryAugmentor; -import org.springframework.ai.chat.memory.VectorStoreChatMemoryChatServiceListener; -import org.springframework.ai.chat.memory.VectorStoreChatMemoryRetriever; -import org.springframework.ai.chat.model.ChatModel; -import org.springframework.ai.chat.prompt.transformer.QuestionContextAugmentor; -import org.springframework.ai.chat.prompt.transformer.TransformerContentType; -import org.springframework.ai.chat.prompt.transformer.VectorStoreRetriever; -import org.springframework.ai.chat.service.ChatService; -import org.springframework.ai.chat.service.PromptTransformingChatService; -import org.springframework.ai.tokenizer.JTokkitTokenCountEstimator; -import org.springframework.ai.tokenizer.TokenCountEstimator; -import org.springframework.ai.vectorstore.SearchRequest; -import org.springframework.ai.vectorstore.VectorStore; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration(proxyBeanMethods = false) -public class ChatConfig { - - @Bean - ChatMemory chatHistory() { - return new InMemoryChatMemory(); - } - - @Bean - TokenCountEstimator tokenCountEstimator() { - return new JTokkitTokenCountEstimator(); - } - - @Bean - ChatService chatService( - ChatModel chatModel, - ChatMemory chatMemory, - TokenCountEstimator tokenCountEstimator, - VectorStore vectorStore) { - return PromptTransformingChatService.builder(chatModel) - .withRetrievers(List.of( - new VectorStoreRetriever(vectorStore, SearchRequest.defaults()), - ChatMemoryRetriever.builder() - .withChatHistory(chatMemory) - .withMetadata(Map.of(TransformerContentType.SHORT_TERM_MEMORY, "")) - .build(), - new VectorStoreChatMemoryRetriever( - vectorStore, 10, Map.of(TransformerContentType.LONG_TERM_MEMORY, "")))) - .withContentPostProcessors(List.of( - new LastMaxTokenSizeContentTransformer( - tokenCountEstimator, 1000, Set.of(TransformerContentType.SHORT_TERM_MEMORY)), - new LastMaxTokenSizeContentTransformer( - tokenCountEstimator, 1000, Set.of(TransformerContentType.LONG_TERM_MEMORY)), - new LastMaxTokenSizeContentTransformer( - tokenCountEstimator, 2000, Set.of(TransformerContentType.EXTERNAL_KNOWLEDGE)))) - .withAugmentors(List.of( - new QuestionContextAugmentor(), - new SystemPromptChatMemoryAugmentor( - """ - Use the long term conversation history from the LONG TERM HISTORY section to provide accurate answers. - - LONG TERM HISTORY: - {history} - """, - Set.of(TransformerContentType.LONG_TERM_MEMORY)), - new SystemPromptChatMemoryAugmentor(Set.of(TransformerContentType.SHORT_TERM_MEMORY)))) - .withChatServiceListeners(List.of( - new ChatMemoryChatServiceListener(chatMemory), - new VectorStoreChatMemoryChatServiceListener( - vectorStore, Map.of(TransformerContentType.LONG_TERM_MEMORY, "")))) - .build(); - } -} diff --git a/chatbot-ollama-springai/src/main/java/com/example/chatbot/service/ChatbotService.java b/chatbot-ollama-springai/src/main/java/com/example/chatbot/service/ChatbotService.java deleted file mode 100644 index 7c828db..0000000 --- a/chatbot-ollama-springai/src/main/java/com/example/chatbot/service/ChatbotService.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.example.chatbot.service; - -import com.example.chatbot.model.request.AIChatRequest; -import com.example.chatbot.model.response.AIChatResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.ai.chat.messages.UserMessage; -import org.springframework.ai.chat.prompt.Prompt; -import org.springframework.ai.chat.prompt.transformer.ChatServiceContext; -import org.springframework.ai.chat.service.ChatService; -import org.springframework.ai.chat.service.ChatServiceResponse; -import org.springframework.stereotype.Service; - -@Service -public class ChatbotService { - - private static final Logger LOGGER = LoggerFactory.getLogger(ChatbotService.class); - - private final ChatService chatService; - - public ChatbotService(ChatService chatService) { - this.chatService = chatService; - } - - public AIChatResponse chat(AIChatRequest request) { - Prompt prompt = new Prompt(new UserMessage(request.query())); - String conversationId = request.conversationId() == null ? "default" : request.conversationId(); - ChatServiceResponse chatServiceResponse = this.chatService.call(new ChatServiceContext(prompt, conversationId)); - LOGGER.info("Response :{}", chatServiceResponse.getChatResponse().getResult()); - return new AIChatResponse( - chatServiceResponse.getChatResponse().getResult().getOutput().getContent(), - chatServiceResponse.getPromptContext().getConversationId()); - } -} diff --git a/chatbot-ollama-springai/.gitignore b/chatbot/chatbot-ollama-springai/.gitignore similarity index 100% rename from chatbot-ollama-springai/.gitignore rename to chatbot/chatbot-ollama-springai/.gitignore diff --git a/chatbot-ollama-springai/.mvn/wrapper/maven-wrapper.properties b/chatbot/chatbot-ollama-springai/.mvn/wrapper/maven-wrapper.properties similarity index 100% rename from chatbot-ollama-springai/.mvn/wrapper/maven-wrapper.properties rename to chatbot/chatbot-ollama-springai/.mvn/wrapper/maven-wrapper.properties diff --git a/chatbot-ollama-springai/ReadMe.md b/chatbot/chatbot-ollama-springai/ReadMe.md similarity index 100% rename from chatbot-ollama-springai/ReadMe.md rename to chatbot/chatbot-ollama-springai/ReadMe.md diff --git a/chatbot/chatbot-ollama-springai/docker/docker-compose.yml b/chatbot/chatbot-ollama-springai/docker/docker-compose.yml new file mode 100644 index 0000000..6ec9ab6 --- /dev/null +++ b/chatbot/chatbot-ollama-springai/docker/docker-compose.yml @@ -0,0 +1,15 @@ +version: '3.7' +services: + chroma: + container_name: chroma + image: chromadb/chroma:0.5.0 + extra_hosts: [ 'host.docker.internal:host-gateway' ] + restart: always + ports: + - "8000:8000" + healthcheck: + # Adjust below to match your container port + test: [ "CMD", "curl", "-f", "http://localhost:8000/api/v1/heartbeat" ] + interval: 30s + timeout: 10s + retries: 3 \ No newline at end of file diff --git a/chatbot-ollama-springai/mvnw b/chatbot/chatbot-ollama-springai/mvnw similarity index 100% rename from chatbot-ollama-springai/mvnw rename to chatbot/chatbot-ollama-springai/mvnw diff --git a/chatbot-ollama-springai/mvnw.cmd b/chatbot/chatbot-ollama-springai/mvnw.cmd similarity index 100% rename from chatbot-ollama-springai/mvnw.cmd rename to chatbot/chatbot-ollama-springai/mvnw.cmd diff --git a/chatbot-ollama-springai/pom.xml b/chatbot/chatbot-ollama-springai/pom.xml similarity index 70% rename from chatbot-ollama-springai/pom.xml rename to chatbot/chatbot-ollama-springai/pom.xml index 279e116..66b4f2a 100644 --- a/chatbot-ollama-springai/pom.xml +++ b/chatbot/chatbot-ollama-springai/pom.xml @@ -18,7 +18,7 @@ 21 2.43.0 - 1.0.0-SNAPSHOT + 1.0.0-M1 @@ -90,50 +90,50 @@ spring-boot-maven-plugin - com.diffplug.spotless - spotless-maven-plugin - ${spotless.version} - - - - 2.47.0 - - - - - - - - - compile - - check - - - - - + com.diffplug.spotless + spotless-maven-plugin + ${spotless.version} + + + + 2.47.0 + + + + + + + + + compile + + check + + + + + - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + false - + - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + false - + diff --git a/chatbot-ollama-springai/src/main/java/com/example/chatbot/ChatbotOllamaApplication.java b/chatbot/chatbot-ollama-springai/src/main/java/com/example/chatbot/ChatbotOllamaApplication.java similarity index 100% rename from chatbot-ollama-springai/src/main/java/com/example/chatbot/ChatbotOllamaApplication.java rename to chatbot/chatbot-ollama-springai/src/main/java/com/example/chatbot/ChatbotOllamaApplication.java diff --git a/chatbot/chatbot-ollama-springai/src/main/java/com/example/chatbot/config/ChatConfig.java b/chatbot/chatbot-ollama-springai/src/main/java/com/example/chatbot/config/ChatConfig.java new file mode 100644 index 0000000..1fbe4af --- /dev/null +++ b/chatbot/chatbot-ollama-springai/src/main/java/com/example/chatbot/config/ChatConfig.java @@ -0,0 +1,31 @@ +package com.example.chatbot.config; + +import org.springframework.ai.chat.client.ChatClient; +import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor; +import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor; +import org.springframework.ai.chat.client.advisor.VectorStoreChatMemoryAdvisor; +import org.springframework.ai.chat.memory.ChatMemory; +import org.springframework.ai.chat.memory.InMemoryChatMemory; +import org.springframework.ai.vectorstore.SearchRequest; +import org.springframework.ai.vectorstore.VectorStore; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +public class ChatConfig { + + @Bean + ChatMemory chatMemory() { + return new InMemoryChatMemory(); + } + + @Bean + ChatClient chatClient(ChatClient.Builder chatClientBuilder, ChatMemory chatMemory, VectorStore vectorStore) { + return chatClientBuilder + .defaultAdvisors( + new MessageChatMemoryAdvisor(chatMemory), + new QuestionAnswerAdvisor(vectorStore, SearchRequest.defaults()), // RAG + new VectorStoreChatMemoryAdvisor(vectorStore)) + .build(); + } +} diff --git a/chatbot-ollama-springai/src/main/java/com/example/chatbot/controller/ChatbotController.java b/chatbot/chatbot-ollama-springai/src/main/java/com/example/chatbot/controller/ChatbotController.java similarity index 100% rename from chatbot-ollama-springai/src/main/java/com/example/chatbot/controller/ChatbotController.java rename to chatbot/chatbot-ollama-springai/src/main/java/com/example/chatbot/controller/ChatbotController.java diff --git a/chatbot-ollama-springai/src/main/java/com/example/chatbot/model/request/AIChatRequest.java b/chatbot/chatbot-ollama-springai/src/main/java/com/example/chatbot/model/request/AIChatRequest.java similarity index 100% rename from chatbot-ollama-springai/src/main/java/com/example/chatbot/model/request/AIChatRequest.java rename to chatbot/chatbot-ollama-springai/src/main/java/com/example/chatbot/model/request/AIChatRequest.java diff --git a/chatbot-ollama-springai/src/main/java/com/example/chatbot/model/response/AIChatResponse.java b/chatbot/chatbot-ollama-springai/src/main/java/com/example/chatbot/model/response/AIChatResponse.java similarity index 100% rename from chatbot-ollama-springai/src/main/java/com/example/chatbot/model/response/AIChatResponse.java rename to chatbot/chatbot-ollama-springai/src/main/java/com/example/chatbot/model/response/AIChatResponse.java diff --git a/chatbot/chatbot-ollama-springai/src/main/java/com/example/chatbot/service/ChatbotService.java b/chatbot/chatbot-ollama-springai/src/main/java/com/example/chatbot/service/ChatbotService.java new file mode 100644 index 0000000..af6e8a5 --- /dev/null +++ b/chatbot/chatbot-ollama-springai/src/main/java/com/example/chatbot/service/ChatbotService.java @@ -0,0 +1,37 @@ +package com.example.chatbot.service; + +import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY; +import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY; + +import com.example.chatbot.model.request.AIChatRequest; +import com.example.chatbot.model.response.AIChatResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.ai.chat.client.ChatClient; +import org.springframework.ai.chat.model.ChatResponse; +import org.springframework.stereotype.Service; + +@Service +public class ChatbotService { + + private static final Logger LOGGER = LoggerFactory.getLogger(ChatbotService.class); + + private final ChatClient chatClient; + + public ChatbotService(ChatClient chatClient) { + this.chatClient = chatClient; + } + + public AIChatResponse chat(AIChatRequest request) { + + ChatResponse chatResponse = this.chatClient + .prompt() + .user(request.query()) + .advisors(a -> a.param(CHAT_MEMORY_CONVERSATION_ID_KEY, request.conversationId()) + .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100)) + .call() + .chatResponse(); + LOGGER.info("Response :{}", chatResponse.getResult()); + return new AIChatResponse(chatResponse.getResult().getOutput().getContent(), request.conversationId()); + } +} diff --git a/chatbot-ollama-springai/src/main/resources/application.properties b/chatbot/chatbot-ollama-springai/src/main/resources/application.properties similarity index 100% rename from chatbot-ollama-springai/src/main/resources/application.properties rename to chatbot/chatbot-ollama-springai/src/main/resources/application.properties diff --git a/chatbot-ollama-springai/src/test/java/com/example/chatbot/ChatbotOllamaApplicationTests.java b/chatbot/chatbot-ollama-springai/src/test/java/com/example/chatbot/ChatbotOllamaApplicationTests.java similarity index 86% rename from chatbot-ollama-springai/src/test/java/com/example/chatbot/ChatbotOllamaApplicationTests.java rename to chatbot/chatbot-ollama-springai/src/test/java/com/example/chatbot/ChatbotOllamaApplicationTests.java index bee559e..9de3c62 100644 --- a/chatbot-ollama-springai/src/test/java/com/example/chatbot/ChatbotOllamaApplicationTests.java +++ b/chatbot/chatbot-ollama-springai/src/test/java/com/example/chatbot/ChatbotOllamaApplicationTests.java @@ -43,7 +43,7 @@ void chat() throws StreamReadException, DatabindException, IOException { Response response = given().contentType(ContentType.JSON) .body(new AIChatRequest( "As a cricketer, how many centuries did Sachin Tendulkar scored adding up both One Day International (ODI) and Test centuries ?", - null)) + "junit1")) .when() .post("/api/ai/chat") .then() @@ -56,18 +56,15 @@ void chat() throws StreamReadException, DatabindException, IOException { .response(); AIChatResponse aiChatResponse = objectMapper.readValue(response.asByteArray(), AIChatResponse.class); - System.out.println("conversationalId :: " + aiChatResponse.conversationId()); given().contentType(ContentType.JSON) - .body(new AIChatRequest( - "How many One Day International (ODI) centuries did he scored ?", - aiChatResponse.conversationId())) + .body(new AIChatRequest("Who scored 100 centuries ?", aiChatResponse.conversationId())) .when() .post("/api/ai/chat") .then() .statusCode(HttpStatus.SC_OK) .contentType(ContentType.JSON) - .body("answer", containsString("49")) + .body("answer", containsString("Sachin")) .log() .all(true); } diff --git a/chatbot-ollama-springai/src/test/java/com/example/chatbot/TestChatbotOllamaApplication.java b/chatbot/chatbot-ollama-springai/src/test/java/com/example/chatbot/TestChatbotOllamaApplication.java similarity index 100% rename from chatbot-ollama-springai/src/test/java/com/example/chatbot/TestChatbotOllamaApplication.java rename to chatbot/chatbot-ollama-springai/src/test/java/com/example/chatbot/TestChatbotOllamaApplication.java