diff --git a/pom.xml b/pom.xml index ca6086c..1d22c4c 100644 --- a/pom.xml +++ b/pom.xml @@ -35,6 +35,23 @@ org.springframework.ai spring-ai-starter-model-deepseek + + + org.springframework.ai + spring-ai-starter-model-ollama + + + + org.springframework.ai + spring-ai-starter-model-zhipuai + + + + org.springframework.ai + spring-ai-starter-model-openai + + + org.springframework.boot diff --git a/src/main/java/com/hanserwei/airobot/config/ChatClientConfig.java b/src/main/java/com/hanserwei/airobot/config/ChatClientConfig.java index 5c10c5c..b72373b 100644 --- a/src/main/java/com/hanserwei/airobot/config/ChatClientConfig.java +++ b/src/main/java/com/hanserwei/airobot/config/ChatClientConfig.java @@ -1,14 +1,19 @@ package com.hanserwei.airobot.config; import com.hanserwei.airobot.advisor.MyLoggerAdvisor; +import jakarta.annotation.Resource; import org.springframework.ai.chat.client.ChatClient; +import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor; import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor; +import org.springframework.ai.chat.memory.ChatMemory; import org.springframework.ai.deepseek.DeepSeekChatModel; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class ChatClientConfig { + @Resource + private ChatMemory chatMemory; /** * 初始化 ChatClient 客户端 diff --git a/src/main/java/com/hanserwei/airobot/config/ChatMemoryConfig.java b/src/main/java/com/hanserwei/airobot/config/ChatMemoryConfig.java new file mode 100644 index 0000000..d4f00a5 --- /dev/null +++ b/src/main/java/com/hanserwei/airobot/config/ChatMemoryConfig.java @@ -0,0 +1,30 @@ +package com.hanserwei.airobot.config; + +import jakarta.annotation.Resource; +import org.springframework.ai.chat.memory.ChatMemory; +import org.springframework.ai.chat.memory.ChatMemoryRepository; +import org.springframework.ai.chat.memory.MessageWindowChatMemory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ChatMemoryConfig { + + /** + * 记忆存储 + */ + @Resource + private ChatMemoryRepository chatMemoryRepository; + + /** + * 初始化一个 ChatMemory 实例,并注入到 Spring 容器中 + * @return ChatMemory + */ + @Bean + public ChatMemory chatMemory() { + return MessageWindowChatMemory.builder() + .maxMessages(50) // 最大消息窗口为 50,默认值为 20 + .chatMemoryRepository(chatMemoryRepository) // 记忆存储 + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/com/hanserwei/airobot/controller/ChatClientController.java b/src/main/java/com/hanserwei/airobot/controller/ChatClientController.java index 602d7b7..f240484 100644 --- a/src/main/java/com/hanserwei/airobot/controller/ChatClientController.java +++ b/src/main/java/com/hanserwei/airobot/controller/ChatClientController.java @@ -2,6 +2,7 @@ package com.hanserwei.airobot.controller; import jakarta.annotation.Resource; import org.springframework.ai.chat.client.ChatClient; +import org.springframework.ai.chat.memory.ChatMemory; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -36,9 +37,11 @@ public class ChatClientController { * @return 对话结果 */ @GetMapping(value = "/generateStream", produces = "text/html;charset=utf-8") - public Flux generateStream(@RequestParam(value = "message", defaultValue = "你是谁?") String message) { + public Flux generateStream(@RequestParam(value = "message", defaultValue = "你是谁?") String message, + @RequestParam(value = "chatId") String chatId) { return chatClient.prompt() .user(message) // 提示词 + .advisors(a -> a.param(ChatMemory.CONVERSATION_ID, chatId)) .stream() // 流式输出 .content(); diff --git a/src/main/java/com/hanserwei/airobot/controller/OllamaController.java b/src/main/java/com/hanserwei/airobot/controller/OllamaController.java new file mode 100644 index 0000000..0334e66 --- /dev/null +++ b/src/main/java/com/hanserwei/airobot/controller/OllamaController.java @@ -0,0 +1,33 @@ +package com.hanserwei.airobot.controller; + +import jakarta.annotation.Resource; +import org.springframework.ai.chat.model.ChatResponse; +import org.springframework.ai.chat.prompt.Prompt; +import org.springframework.ai.ollama.OllamaChatModel; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/v3/ai") +public class OllamaController { + + @Resource + private OllamaChatModel chatModel; + + /** + * 普通对话 + * @param message 对话输入内容 + * @return 对话结果 + */ + @GetMapping("/generate") + public String generate(@RequestParam(value = "message", defaultValue = "你是谁?") String message) { + // 构建提示词,调用大模型 + ChatResponse chatResponse = chatModel.call(new Prompt(message)); + + // 响应回答内容 + return chatResponse.getResult().getOutput().getText(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/hanserwei/airobot/controller/OpenAIController.java b/src/main/java/com/hanserwei/airobot/controller/OpenAIController.java new file mode 100644 index 0000000..19157ff --- /dev/null +++ b/src/main/java/com/hanserwei/airobot/controller/OpenAIController.java @@ -0,0 +1,53 @@ +package com.hanserwei.airobot.controller; + +import jakarta.annotation.Resource; +import org.springframework.ai.chat.messages.UserMessage; +import org.springframework.ai.chat.model.Generation; +import org.springframework.ai.chat.prompt.Prompt; +import org.springframework.ai.openai.OpenAiChatModel; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Flux; + +import java.util.Objects; + +@RestController +@RequestMapping("/v5/ai") +public class OpenAIController { + + @Resource + private OpenAiChatModel chatModel; + + /** + * 普通对话 + * @param message 对话输入内容 + * @return 对话结果 + */ + @GetMapping("/generate") + public String generate(@RequestParam(value = "message", defaultValue = "你是谁?") String message) { + // 一次性返回结果 + return chatModel.call(message); + } + + /** + * 流式对话 + * @param message 对话输入内容 + * @return 对话结果 + */ + @GetMapping(value = "/generateStream", produces = "text/html;charset=utf-8") + public Flux generateStream(@RequestParam(value = "message", defaultValue = "你是谁?") String message) { + // 构建提示词 + Prompt prompt = new Prompt(new UserMessage(message)); + + // 流式输出 + return chatModel.stream(prompt) + .mapNotNull(chatResponse -> { + Generation generation = chatResponse.getResult(); + return generation.getOutput().getText(); + }); + + } + +} \ No newline at end of file diff --git a/src/main/java/com/hanserwei/airobot/controller/ZhiPuController.java b/src/main/java/com/hanserwei/airobot/controller/ZhiPuController.java new file mode 100644 index 0000000..3a420f2 --- /dev/null +++ b/src/main/java/com/hanserwei/airobot/controller/ZhiPuController.java @@ -0,0 +1,47 @@ +package com.hanserwei.airobot.controller; + +import jakarta.annotation.Resource; +import org.springframework.ai.chat.messages.UserMessage; +import org.springframework.ai.chat.prompt.Prompt; +import org.springframework.ai.zhipuai.ZhiPuAiChatModel; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Flux; + +@RestController +@RequestMapping("/v4/ai") +public class ZhiPuController { + + @Resource + private ZhiPuAiChatModel chatModel; + + /** + * 普通对话 + * @param message 对话输入内容 + * @return 对话结果 + */ + @GetMapping("/generate") + public String generate(@RequestParam(value = "message", defaultValue = "你是谁?") String message) { + // 一次性返回结果 + return chatModel.call(message); + } + + /** + * 流式对话 + * @param message 对话输入内容 + * @return 对话结果 + */ + @GetMapping(value = "/generateStream", produces = "text/html;charset=utf-8") + public Flux generateStream(@RequestParam(value = "message", defaultValue = "你是谁?") String message) { + // 构建提示词 + Prompt prompt = new Prompt(new UserMessage(message)); + + // 流式输出 + return chatModel.stream(prompt) + .mapNotNull(chatResponse -> chatResponse.getResult().getOutput().getText()); + + } + +} \ No newline at end of file diff --git a/src/main/java/com/hanserwei/airobot/utils/EncryptorUtil.java b/src/main/java/com/hanserwei/airobot/utils/EncryptorUtil.java index 7bf6b8d..e3909c3 100644 --- a/src/main/java/com/hanserwei/airobot/utils/EncryptorUtil.java +++ b/src/main/java/com/hanserwei/airobot/utils/EncryptorUtil.java @@ -5,7 +5,7 @@ import org.jasypt.util.text.AES256TextEncryptor; public class EncryptorUtil { public static void main(String[] args) { AES256TextEncryptor textEncryptor = new AES256TextEncryptor(); - textEncryptor.setPassword("password"); - System.out.println(textEncryptor.encrypt("sk-xxxxxxxxxxxxxx")); + textEncryptor.setPassword("hanserwei"); + System.out.println(textEncryptor.encrypt("sk-QXBlsyIonybNTcG5tt5GvmMpg2WpdMLPTvU55TXrt9urWpL8")); } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index c3f06da..235ec2e 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -10,6 +10,27 @@ spring: options: model: deepseek-chat # 使用哪个模型 temperature: 0.8 # 温度值 + ollama: + base-url: http://localhost:11434 # Ollama 服务的访问地址, 11434 端口是 Ollama 默认的启动端口 + chat: + options: # 模型参数 + model: qwen3:14b # 指定 Ollama 使用的大模型名称,根据你实际安装的来,我运行的是 14b + temperature: 0.7 # 温度值 + zhipuai: + base-url: https://open.bigmodel.cn/api/paas # 智谱 AI 的请求 URL, 可不填,默认值为 open.bigmodel.cn/api/paas + api-key: ENC(Rz1O0AygSzG3q4UrIpIPHRwFoTQXCUZkWZ54vNzl1kgdBkQECzCYa3LoOADM9NlGLlAwCKTMtkj0nd6cP98T59DohcKtzc3iYyiAoNRfH0rsiu483CpaCciyMwxCUi5O) # 填写智谱 AI 的 API Key, 该成你自己的 + chat: + options: # 模型参数 + model: GLM-4.6 # 模型名称,使用智谱 AI 哪个模型 + temperature: 0.7 # 温度值 + openai: + base-url: https://api.master-jsx.top # OpenAI 服务的访问地址,这里使用的第三方代理商:智增增 + api-key: ENC(D6ETp0VBeDYXvM612dcoGkyHaGUcPuwOVuSLtL92TOCxydyMKXL7/VBndWjFkxAQP/AS7TeQeegla+Ny6TrLStwdJtd28mVhoyf2YsKuXIdRnKF/mv8/uZ0MpzMdv9YR) # 填写智增增的 API Key, 该成你自己的 + chat: + options: + model: gpt-4o # 模型名称 + temperature: 0.7 # 温度值 + jasypt: encryptor: password: ${jasypt.encryptor.password}