==
This commit is contained in:
14
pom.xml
14
pom.xml
@@ -34,7 +34,11 @@
|
|||||||
<groupId>org.springframework.ai</groupId>
|
<groupId>org.springframework.ai</groupId>
|
||||||
<artifactId>spring-ai-starter-model-deepseek</artifactId>
|
<artifactId>spring-ai-starter-model-deepseek</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- 阿里百炼大模型自动配置-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.cloud.ai</groupId>
|
||||||
|
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||||
@@ -89,6 +93,14 @@
|
|||||||
<type>pom</type>
|
<type>pom</type>
|
||||||
<scope>import</scope>
|
<scope>import</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- 阿里百炼版本管理-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.cloud.ai</groupId>
|
||||||
|
<artifactId>spring-ai-alibaba-bom</artifactId>
|
||||||
|
<version>1.0.0.2</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.ai.app.config;
|
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.ChatClient;
|
||||||
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
|
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
|
||||||
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
|
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 simpleLoggerAdvisor 日志Advisor
|
||||||
* @param messageChatMemoryAdvisor 会话记忆Advisor
|
* @param messageChatMemoryAdvisor 会话记忆Advisor
|
||||||
* @return: org.springframework.ai.chat.client.ChatClient
|
* @return: org.springframework.ai.chat.client.ChatClient
|
||||||
@@ -64,7 +65,31 @@ public class AIConfig {
|
|||||||
* @date: 2025/8/29 9:06
|
* @date: 2025/8/29 9:06
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public ChatClient chatClient(DeepSeekChatModel deepSeekChatModel,
|
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,
|
SimpleLoggerAdvisor simpleLoggerAdvisor,
|
||||||
MessageChatMemoryAdvisor messageChatMemoryAdvisor) {
|
MessageChatMemoryAdvisor messageChatMemoryAdvisor) {
|
||||||
return ChatClient
|
return ChatClient
|
||||||
|
|||||||
@@ -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<String> 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<String> history() {
|
|
||||||
return inMemoryChatMemoryRepository.findConversationIds();
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequestMapping("/history/chat/{chatId}")
|
|
||||||
public List<MessageDTO> history(@PathVariable("chatId") String chatId) {
|
|
||||||
List<Message> messages = inMemoryChatMemoryRepository.findByConversationId(chatId);
|
|
||||||
return messages.stream().map(e -> {
|
|
||||||
return new MessageDTO(e.getMessageType().getValue(), e.getText());
|
|
||||||
}).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
85
src/main/java/com/ai/app/controller/DashScopeController.java
Normal file
85
src/main/java/com/ai/app/controller/DashScopeController.java
Normal file
@@ -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<java.lang.String>
|
||||||
|
* @author kai.liu
|
||||||
|
* @date: 2025/9/3 17:30
|
||||||
|
*/
|
||||||
|
@RequestMapping(value = "/chat", produces = "text/stream;charset=UTF-8")
|
||||||
|
public Flux<String> 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<java.lang.String>
|
||||||
|
* @author kai.liu
|
||||||
|
* @date: 2025/9/3 17:30
|
||||||
|
*/
|
||||||
|
@GetMapping("/getHistoryChatIdList/{type}")
|
||||||
|
public List<String> getHistoryChatIdList(@PathVariable("type") String type) {
|
||||||
|
return chatHistoryService.getHistoryChatIds(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 会话历史
|
||||||
|
*
|
||||||
|
* @param chatId 会话ID
|
||||||
|
* @return: java.util.List<com.ai.app.dto.MessageDTO>
|
||||||
|
* @author kai.liu
|
||||||
|
* @date: 2025/9/3 17:31
|
||||||
|
*/
|
||||||
|
@RequestMapping("/getChatHistory/{type}/{chatId}")
|
||||||
|
public List<MessageDTO> getChatHistory(@PathVariable("type") String type, @PathVariable("chatId") String chatId) {
|
||||||
|
chatHistoryService.saveHistoryChatId(type, chatId);
|
||||||
|
List<Message> messages = inMemoryChatMemoryRepository.findByConversationId(chatId);
|
||||||
|
return messages.stream().map(e -> new MessageDTO(e.getMessageType().getValue(), e.getText())).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/main/java/com/ai/app/service/ChatHistoryService.java
Normal file
15
src/main/java/com/ai/app/service/ChatHistoryService.java
Normal file
@@ -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<String> getHistoryChatIds(String type);
|
||||||
|
}
|
||||||
@@ -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<String> chatIds;
|
||||||
|
if (redisTemplateService.hasKey(key)) {
|
||||||
|
chatIds = (List<String>) 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<java.lang.String>
|
||||||
|
* @author kai.liu
|
||||||
|
* @date: 2025/9/3 17:08
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<String> getHistoryChatIds(String type) {
|
||||||
|
String key = CHAT_TYPE_KEY + type;
|
||||||
|
if (redisTemplateService.hasKey(key)) {
|
||||||
|
return (List<String>) redisTemplateService.get(key);
|
||||||
|
}
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
server:
|
server:
|
||||||
port: 8080
|
port: 8080
|
||||||
# servlet:
|
servlet:
|
||||||
# context-path: /ai
|
context-path: /ai
|
||||||
tomcat:
|
tomcat:
|
||||||
# 等待队列长度 (所有线程忙碌时,排队等待的连接数, 默认: 100)
|
# 等待队列长度 (所有线程忙碌时,排队等待的连接数, 默认: 100)
|
||||||
accept-count: 1000
|
accept-count: 1000
|
||||||
@@ -40,10 +40,15 @@ spring:
|
|||||||
max-request-size: 100MB
|
max-request-size: 100MB
|
||||||
ai:
|
ai:
|
||||||
deepseek:
|
deepseek:
|
||||||
api-key: sk-f970111b34c84a8c812919fb4fad8b65
|
api-key: ${DEEPSEEK_API_KEY}
|
||||||
chat:
|
chat:
|
||||||
options:
|
options:
|
||||||
model: deepseek-reasoner
|
model: deepseek-r1
|
||||||
|
dashscope:
|
||||||
|
api-key: ${DASHSCOPE_API_KEY}
|
||||||
|
chat:
|
||||||
|
options:
|
||||||
|
model: qwen-max
|
||||||
data:
|
data:
|
||||||
redis:
|
redis:
|
||||||
host: 180.76.119.46
|
host: 180.76.119.46
|
||||||
|
|||||||
Reference in New Issue
Block a user