From cd3cfe4e64a30301bb434ac415c0c06936bb4c91 Mon Sep 17 00:00:00 2001 From: liukai Date: Wed, 3 Sep 2025 18:02:40 +0800 Subject: [PATCH] == --- pom.xml | 14 ++- src/main/java/com/ai/app/config/AIConfig.java | 35 ++++++-- .../com/ai/app/controller/ChatController.java | 55 ------------ .../app/controller/DashScopeController.java | 85 +++++++++++++++++++ .../ai/app/service/ChatHistoryService.java | 15 ++++ .../service/impl/ChatHistoryServiceImpl.java | 67 +++++++++++++++ src/main/resources/application.yml | 13 ++- 7 files changed, 219 insertions(+), 65 deletions(-) delete mode 100644 src/main/java/com/ai/app/controller/ChatController.java create mode 100644 src/main/java/com/ai/app/controller/DashScopeController.java create mode 100644 src/main/java/com/ai/app/service/ChatHistoryService.java create mode 100644 src/main/java/com/ai/app/service/impl/ChatHistoryServiceImpl.java diff --git a/pom.xml b/pom.xml index 8104e76..38ddfbe 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,11 @@ org.springframework.ai spring-ai-starter-model-deepseek - + + + com.alibaba.cloud.ai + spring-ai-alibaba-starter-dashscope + org.springframework.boot spring-boot-starter-data-redis @@ -89,6 +93,14 @@ pom import + + + com.alibaba.cloud.ai + spring-ai-alibaba-bom + 1.0.0.2 + pom + import + diff --git a/src/main/java/com/ai/app/config/AIConfig.java b/src/main/java/com/ai/app/config/AIConfig.java index d76ea84..cedcd20 100644 --- a/src/main/java/com/ai/app/config/AIConfig.java +++ b/src/main/java/com/ai/app/config/AIConfig.java @@ -1,5 +1,6 @@ package com.ai.app.config; +import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor; import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor; @@ -54,9 +55,9 @@ public class AIConfig { } /** - * 配置AI对话客户端 + * dashScopeChatClient对话客户端 * - * @param deepSeekChatModel deepseek大模型 + * @param dashScopeChatModel 千问max大模型 * @param simpleLoggerAdvisor 日志Advisor * @param messageChatMemoryAdvisor 会话记忆Advisor * @return: org.springframework.ai.chat.client.ChatClient @@ -64,9 +65,33 @@ public class AIConfig { * @date: 2025/8/29 9:06 */ @Bean - public ChatClient chatClient(DeepSeekChatModel deepSeekChatModel, - SimpleLoggerAdvisor simpleLoggerAdvisor, - MessageChatMemoryAdvisor messageChatMemoryAdvisor) { + public ChatClient dashScopeChatClient(DashScopeChatModel dashScopeChatModel, + SimpleLoggerAdvisor simpleLoggerAdvisor, + MessageChatMemoryAdvisor messageChatMemoryAdvisor) { + return ChatClient + //模型 + .builder(dashScopeChatModel) + //系统角色 + .defaultSystem("你是一个小团团") + //环绕增强 + .defaultAdvisors(simpleLoggerAdvisor, messageChatMemoryAdvisor) + .build(); + } + + /** + * deepseek 对话客户端 + * + * @param deepSeekChatModel deepseek大模型 + * @param simpleLoggerAdvisor 日志增强 + * @param messageChatMemoryAdvisor 会话记忆增强 + * @return: org.springframework.ai.chat.client.ChatClient + * @author kai.liu + * @date: 2025/9/3 16:45 + */ + @Bean + public ChatClient deepSeekChatClient(DeepSeekChatModel deepSeekChatModel, + SimpleLoggerAdvisor simpleLoggerAdvisor, + MessageChatMemoryAdvisor messageChatMemoryAdvisor) { return ChatClient //模型 .builder(deepSeekChatModel) diff --git a/src/main/java/com/ai/app/controller/ChatController.java b/src/main/java/com/ai/app/controller/ChatController.java deleted file mode 100644 index 7840b0a..0000000 --- a/src/main/java/com/ai/app/controller/ChatController.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.ai.app.controller; - -import com.ai.app.dto.MessageDTO; -import com.ai.app.service.AIChatMessageService; -import org.springframework.ai.chat.client.ChatClient; -import org.springframework.ai.chat.memory.ChatMemory; -import org.springframework.ai.chat.memory.InMemoryChatMemoryRepository; -import org.springframework.ai.chat.messages.Message; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import reactor.core.publisher.Flux; - -import java.util.List; -import java.util.stream.Collectors; - -/** - * @describe AI对话控制器 - * @Author kai.liu - * @Date 2025/8/28 10:06 - */ - -@RestController -@RequestMapping("/ai") -public class ChatController { - - @Autowired - private ChatClient chatClient; - - @Autowired - private InMemoryChatMemoryRepository inMemoryChatMemoryRepository; - - @RequestMapping(value = "/chat", produces = "text/stream;charset=UTF-8") - public Flux chat(String prompt, String chatId) { - return chatClient - .prompt() - .user(prompt) - .advisors(a -> a.param(ChatMemory.CONVERSATION_ID, chatId)) - .stream().content(); - } - - @RequestMapping("/history/chat") - public List history() { - return inMemoryChatMemoryRepository.findConversationIds(); - } - - @RequestMapping("/history/chat/{chatId}") - public List history(@PathVariable("chatId") String chatId) { - List messages = inMemoryChatMemoryRepository.findByConversationId(chatId); - return messages.stream().map(e -> { - return new MessageDTO(e.getMessageType().getValue(), e.getText()); - }).collect(Collectors.toList()); - } -} diff --git a/src/main/java/com/ai/app/controller/DashScopeController.java b/src/main/java/com/ai/app/controller/DashScopeController.java new file mode 100644 index 0000000..7bbf347 --- /dev/null +++ b/src/main/java/com/ai/app/controller/DashScopeController.java @@ -0,0 +1,85 @@ +package com.ai.app.controller; + +import com.ai.app.dto.MessageDTO; +import com.ai.app.service.ChatHistoryService; +import org.springframework.ai.chat.client.ChatClient; +import org.springframework.ai.chat.memory.ChatMemory; +import org.springframework.ai.chat.memory.InMemoryChatMemoryRepository; +import org.springframework.ai.chat.messages.Message; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Flux; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * @describe AI对话控制器 + * @Author kai.liu + * @Date 2025/8/28 10:06 + */ + +@RestController +@RequestMapping("/dashscope") +public class DashScopeController { + + @Autowired + @Qualifier("dashScopeChatClient") + private ChatClient dashScopeChatClient; + + @Autowired + private ChatHistoryService chatHistoryService; + + @Autowired + private InMemoryChatMemoryRepository inMemoryChatMemoryRepository; + + /** + * 对话聊天 + * + * @param prompt 用户提示词 + * @param chatId 对话ID + * @return: reactor.core.publisher.Flux + * @author kai.liu + * @date: 2025/9/3 17:30 + */ + @RequestMapping(value = "/chat", produces = "text/stream;charset=UTF-8") + public Flux chat(String prompt, String chatId) { + return dashScopeChatClient + .prompt() + .user(prompt) + .advisors(a -> a.param(ChatMemory.CONVERSATION_ID, chatId)) + .stream().content(); + } + + /** + * 会话ID列表 + * + * @param type 类型 + * @return: java.util.List + * @author kai.liu + * @date: 2025/9/3 17:30 + */ + @GetMapping("/getHistoryChatIdList/{type}") + public List getHistoryChatIdList(@PathVariable("type") String type) { + return chatHistoryService.getHistoryChatIds(type); + } + + /** + * 会话历史 + * + * @param chatId 会话ID + * @return: java.util.List + * @author kai.liu + * @date: 2025/9/3 17:31 + */ + @RequestMapping("/getChatHistory/{type}/{chatId}") + public List getChatHistory(@PathVariable("type") String type, @PathVariable("chatId") String chatId) { + chatHistoryService.saveHistoryChatId(type, chatId); + List messages = inMemoryChatMemoryRepository.findByConversationId(chatId); + return messages.stream().map(e -> new MessageDTO(e.getMessageType().getValue(), e.getText())).collect(Collectors.toList()); + } +} diff --git a/src/main/java/com/ai/app/service/ChatHistoryService.java b/src/main/java/com/ai/app/service/ChatHistoryService.java new file mode 100644 index 0000000..b0eac8e --- /dev/null +++ b/src/main/java/com/ai/app/service/ChatHistoryService.java @@ -0,0 +1,15 @@ +package com.ai.app.service; + +import java.util.List; + +/** + * @describe 对话历史接口定义 + * @Author kai.liu + * @Date 2025/9/3 17:05 + */ +public interface ChatHistoryService { + + void saveHistoryChatId(String type, String chatId); + + List getHistoryChatIds(String type); +} diff --git a/src/main/java/com/ai/app/service/impl/ChatHistoryServiceImpl.java b/src/main/java/com/ai/app/service/impl/ChatHistoryServiceImpl.java new file mode 100644 index 0000000..973e6b5 --- /dev/null +++ b/src/main/java/com/ai/app/service/impl/ChatHistoryServiceImpl.java @@ -0,0 +1,67 @@ +package com.ai.app.service.impl; + +import com.ai.app.service.ChatHistoryService; +import com.ai.app.service.RedisTemplateService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +/** + * @describe + * @Author kai.liu + * @Date 2025/9/3 17:05 + */ +@Slf4j +@Service +public class ChatHistoryServiceImpl implements ChatHistoryService { + + @Autowired + private RedisTemplateService redisTemplateService; + + public static final String CHAT_TYPE_KEY = "ai:history:type:"; + + /** + * 保存会话ID + * + * @param type 类型 + * @param chatId 会话ID + * @return: void + * @author kai.liu + * @date: 2025/9/3 17:14 + */ + @Override + public void saveHistoryChatId(String type, String chatId) { + String key = CHAT_TYPE_KEY + type; + List chatIds; + if (redisTemplateService.hasKey(key)) { + chatIds = (List) redisTemplateService.get(key); + } else { + chatIds = new ArrayList<>(); + } + if (chatIds.contains(chatId)) { + return; + } + chatIds.add(chatId); + redisTemplateService.set(key, chatIds); + } + + /** + * 获取历史会话id列表 + * + * @param type 类型 + * @return: java.util.List + * @author kai.liu + * @date: 2025/9/3 17:08 + */ + @Override + public List getHistoryChatIds(String type) { + String key = CHAT_TYPE_KEY + type; + if (redisTemplateService.hasKey(key)) { + return (List) redisTemplateService.get(key); + } + return List.of(); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index f101b36..30be96d 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,7 +1,7 @@ server: port: 8080 - # servlet: - # context-path: /ai + servlet: + context-path: /ai tomcat: # 等待队列长度 (所有线程忙碌时,排队等待的连接数, 默认: 100) accept-count: 1000 @@ -40,10 +40,15 @@ spring: max-request-size: 100MB ai: deepseek: - api-key: sk-f970111b34c84a8c812919fb4fad8b65 + api-key: ${DEEPSEEK_API_KEY} chat: options: - model: deepseek-reasoner + model: deepseek-r1 + dashscope: + api-key: ${DASHSCOPE_API_KEY} + chat: + options: + model: qwen-max data: redis: host: 180.76.119.46