Commit 6e64ae774e28a017e41306e53637be0d29366063

Authored by YunaiV
1 parent 59c853b5

【代码新增】AI:接入智谱 GLM-4 模型

yudao-module-ai/yudao-spring-boot-starter-ai/pom.xml
... ... @@ -20,9 +20,10 @@
20 20 <dependencies>
21 21 <dependency>
22 22 <groupId>org.springframework.ai</groupId>
23   - <artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
  23 + <artifactId>spring-ai-zhipuai-spring-boot-starter</artifactId>
24 24 <version>${spring-ai.version}</version>
25 25 </dependency>
  26 +
26 27 <dependency>
27 28 <groupId>org.springframework.ai</groupId>
28 29 <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
... ... @@ -30,6 +31,11 @@
30 31 </dependency>
31 32 <dependency>
32 33 <groupId>org.springframework.ai</groupId>
  34 + <artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
  35 + <version>${spring-ai.version}</version>
  36 + </dependency>
  37 + <dependency>
  38 + <groupId>org.springframework.ai</groupId>
33 39 <artifactId>spring-ai-stability-ai-spring-boot-starter</artifactId>
34 40 <version>${spring-ai.version}</version>
35 41 </dependency>
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/enums/AiPlatformEnum.java
... ... @@ -17,6 +17,7 @@ public enum AiPlatformEnum {
17 17 TONG_YI("TongYi", "通义千问"), // 阿里
18 18 YI_YAN("YiYan", "文心一言"), // 百度
19 19 DEEP_SEEK("DeepSeek", "DeepSeek"), // DeepSeek
  20 + ZHI_PU("ZhiPu", "智谱"), // 智谱 AI
20 21 XING_HUO("XingHuo", "星火"), // 讯飞
21 22  
22 23 // ========== 国外平台 ==========
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiModelFactoryImpl.java
... ... @@ -23,8 +23,12 @@ import org.springframework.ai.autoconfigure.openai.OpenAiAutoConfiguration;
23 23 import org.springframework.ai.autoconfigure.qianfan.QianFanAutoConfiguration;
24 24 import org.springframework.ai.autoconfigure.qianfan.QianFanChatProperties;
25 25 import org.springframework.ai.autoconfigure.qianfan.QianFanConnectionProperties;
  26 +import org.springframework.ai.autoconfigure.zhipuai.ZhiPuAiAutoConfiguration;
  27 +import org.springframework.ai.autoconfigure.zhipuai.ZhiPuAiChatProperties;
  28 +import org.springframework.ai.autoconfigure.zhipuai.ZhiPuAiConnectionProperties;
26 29 import org.springframework.ai.chat.model.ChatModel;
27 30 import org.springframework.ai.image.ImageModel;
  31 +import org.springframework.ai.model.function.FunctionCallbackContext;
28 32 import org.springframework.ai.ollama.OllamaChatModel;
29 33 import org.springframework.ai.ollama.api.OllamaApi;
30 34 import org.springframework.ai.openai.OpenAiChatModel;
... ... @@ -36,6 +40,8 @@ import org.springframework.ai.qianfan.QianFanChatModel;
36 40 import org.springframework.ai.qianfan.api.QianFanApi;
37 41 import org.springframework.ai.stabilityai.StabilityAiImageModel;
38 42 import org.springframework.ai.stabilityai.api.StabilityAiApi;
  43 +import org.springframework.ai.zhipuai.ZhiPuAiChatModel;
  44 +import org.springframework.ai.zhipuai.api.ZhiPuAiApi;
39 45 import org.springframework.retry.support.RetryTemplate;
40 46 import org.springframework.web.client.ResponseErrorHandler;
41 47 import org.springframework.web.client.RestClient;
... ... @@ -61,6 +67,8 @@ public class AiModelFactoryImpl implements AiModelFactory {
61 67 return buildYiYanChatModel(apiKey);
62 68 case DEEP_SEEK:
63 69 return buildDeepSeekChatModel(apiKey);
  70 + case ZHI_PU:
  71 + return buildZhiPuChatModel(apiKey, url);
64 72 case XING_HUO:
65 73 return buildXingHuoChatModel(apiKey);
66 74 case OPENAI:
... ... @@ -81,6 +89,10 @@ public class AiModelFactoryImpl implements AiModelFactory {
81 89 return SpringUtil.getBean(TongYiChatModel.class);
82 90 case YI_YAN:
83 91 return SpringUtil.getBean(QianFanChatModel.class);
  92 + case DEEP_SEEK:
  93 + return SpringUtil.getBean(DeepSeekChatModel.class);
  94 + case ZHI_PU:
  95 + return SpringUtil.getBean(ZhiPuAiChatModel.class);
84 96 case XING_HUO:
85 97 return SpringUtil.getBean(XingHuoChatModel.class);
86 98 case OPENAI:
... ... @@ -176,6 +188,15 @@ public class AiModelFactoryImpl implements AiModelFactory {
176 188 }
177 189  
178 190 /**
  191 + * 可参考 {@link ZhiPuAiAutoConfiguration#zhiPuAiChatModel(ZhiPuAiConnectionProperties, ZhiPuAiChatProperties, RestClient.Builder, List, FunctionCallbackContext, RetryTemplate, ResponseErrorHandler)}
  192 + */
  193 + private ZhiPuAiChatModel buildZhiPuChatModel(String apiKey, String url) {
  194 + url = StrUtil.blankToDefault(url, ZhiPuAiConnectionProperties.DEFAULT_BASE_URL);
  195 + ZhiPuAiApi zhiPuAiApi = new ZhiPuAiApi(url, apiKey);
  196 + return new ZhiPuAiChatModel(zhiPuAiApi);
  197 + }
  198 +
  199 + /**
179 200 * 可参考 {@link YudaoAiAutoConfiguration#xingHuoChatClient(YudaoAiProperties)}
180 201 */
181 202 private static XingHuoChatModel buildXingHuoChatModel(String key) {
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/util/AiUtils.java
... ... @@ -10,6 +10,7 @@ import org.springframework.ai.chat.prompt.ChatOptions;
10 10 import org.springframework.ai.ollama.api.OllamaOptions;
11 11 import org.springframework.ai.openai.OpenAiChatOptions;
12 12 import org.springframework.ai.qianfan.QianFanChatOptions;
  13 +import org.springframework.ai.zhipuai.ZhiPuAiChatOptions;
13 14  
14 15 /**
15 16 * Spring AI 工具类
... ... @@ -22,18 +23,20 @@ public class AiUtils {
22 23 Float temperatureF = temperature != null ? temperature.floatValue() : null;
23 24 //noinspection EnhancedSwitchMigration
24 25 switch (platform) {
25   - case OPENAI:
26   - return OpenAiChatOptions.builder().withModel(model).withTemperature(temperatureF).withMaxTokens(maxTokens).build();
27   - case OLLAMA:
28   - return OllamaOptions.create().withModel(model).withTemperature(temperatureF).withNumPredict(maxTokens);
29   - case YI_YAN:
30   - return QianFanChatOptions.builder().withModel(model).withTemperature(temperatureF).withMaxTokens(maxTokens).build();
31   - case XING_HUO:
32   - return XingHuoChatOptions.builder().model(model).temperature(temperatureF).maxTokens(maxTokens).build();
33 26 case TONG_YI:
34 27 return TongYiChatOptions.builder().withModel(model).withTemperature(temperature).withMaxTokens(maxTokens).build();
  28 + case YI_YAN:
  29 + return QianFanChatOptions.builder().withModel(model).withTemperature(temperatureF).withMaxTokens(maxTokens).build();
35 30 case DEEP_SEEK:
36 31 return DeepSeekChatOptions.builder().model(model).temperature(temperatureF).maxTokens(maxTokens).build();
  32 + case ZHI_PU:
  33 + return ZhiPuAiChatOptions.builder().withModel(model).withTemperature(temperatureF).withMaxTokens(maxTokens).build();
  34 + case XING_HUO:
  35 + return XingHuoChatOptions.builder().model(model).temperature(temperatureF).maxTokens(maxTokens).build();
  36 + case OPENAI:
  37 + return OpenAiChatOptions.builder().withModel(model).withTemperature(temperatureF).withMaxTokens(maxTokens).build();
  38 + case OLLAMA:
  39 + return OllamaOptions.create().withModel(model).withTemperature(temperatureF).withNumPredict(maxTokens);
37 40 default:
38 41 throw new IllegalArgumentException(StrUtil.format("未知平台({})", platform));
39 42 }
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/DeepSeekChatModelTests.java
1 1 package cn.iocoder.yudao.framework.ai.chat;
2 2  
3 3 import cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatModel;
  4 +import org.junit.jupiter.api.Disabled;
4 5 import org.junit.jupiter.api.Test;
5 6 import org.springframework.ai.chat.messages.Message;
6 7 import org.springframework.ai.chat.messages.SystemMessage;
... ... @@ -22,6 +23,7 @@ public class DeepSeekChatModelTests {
22 23 private final DeepSeekChatModel chatModel = new DeepSeekChatModel("sk-e94db327cc7d457d99a8de8810fc6b12");
23 24  
24 25 @Test
  26 + @Disabled
25 27 public void testCall() {
26 28 // 准备参数
27 29 List<Message> messages = new ArrayList<>();
... ... @@ -35,6 +37,7 @@ public class DeepSeekChatModelTests {
35 37 }
36 38  
37 39 @Test
  40 + @Disabled
38 41 public void testStream() {
39 42 // 准备参数
40 43 List<Message> messages = new ArrayList<>();
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/XingHuoChatModelTests.java
1 1 package cn.iocoder.yudao.framework.ai.chat;
2 2  
3 3 import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatModel;
  4 +import org.junit.jupiter.api.Disabled;
4 5 import org.junit.jupiter.api.Test;
5 6 import org.springframework.ai.chat.messages.Message;
6 7 import org.springframework.ai.chat.messages.SystemMessage;
... ... @@ -24,6 +25,7 @@ public class XingHuoChatModelTests {
24 25 "Y2JiYTIxZjA3MDMxMjNjZjQzYzVmNzdh");
25 26  
26 27 @Test
  28 + @Disabled
27 29 public void testCall() {
28 30 // 准备参数
29 31 List<Message> messages = new ArrayList<>();
... ... @@ -37,6 +39,7 @@ public class XingHuoChatModelTests {
37 39 }
38 40  
39 41 @Test
  42 + @Disabled
40 43 public void testStream() {
41 44 // 准备参数
42 45 List<Message> messages = new ArrayList<>();
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/ZhiPuAiChatModelTests.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.ai.chat;
  2 +
  3 +import org.junit.jupiter.api.Disabled;
  4 +import org.junit.jupiter.api.Test;
  5 +import org.springframework.ai.chat.messages.Message;
  6 +import org.springframework.ai.chat.messages.SystemMessage;
  7 +import org.springframework.ai.chat.messages.UserMessage;
  8 +import org.springframework.ai.chat.model.ChatResponse;
  9 +import org.springframework.ai.chat.prompt.Prompt;
  10 +import org.springframework.ai.zhipuai.ZhiPuAiChatModel;
  11 +import org.springframework.ai.zhipuai.ZhiPuAiChatOptions;
  12 +import org.springframework.ai.zhipuai.api.ZhiPuAiApi;
  13 +import reactor.core.publisher.Flux;
  14 +
  15 +import java.util.ArrayList;
  16 +import java.util.List;
  17 +
  18 +/**
  19 + * {@link ZhiPuAiChatModel} 的集成测试
  20 + *
  21 + * @author 芋道源码
  22 + */
  23 +public class ZhiPuAiChatModelTests {
  24 +
  25 + private final ZhiPuAiApi zhiPuAiApi = new ZhiPuAiApi("32f84543e54eee31f8d56b2bd6020573.3vh9idLJZ2ZhxDEs");
  26 + private final ZhiPuAiChatModel chatModel = new ZhiPuAiChatModel(zhiPuAiApi,
  27 + ZhiPuAiChatOptions.builder().withModel(ZhiPuAiApi.ChatModel.GLM_4.getModelName()).build());
  28 +
  29 + @Test
  30 + @Disabled
  31 + public void testCall() {
  32 + // 准备参数
  33 + List<Message> messages = new ArrayList<>();
  34 + messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
  35 + messages.add(new UserMessage("1 + 1 = ?"));
  36 +
  37 + // 调用
  38 + ChatResponse response = chatModel.call(new Prompt(messages));
  39 + // 打印结果
  40 + System.out.println(response);
  41 + System.out.println(response.getResult().getOutput());
  42 + }
  43 +
  44 + @Test
  45 + @Disabled
  46 + public void testStream() {
  47 + // 准备参数
  48 + List<Message> messages = new ArrayList<>();
  49 + messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。"));
  50 + messages.add(new UserMessage("1 + 1 = ?"));
  51 +
  52 + // 调用
  53 + Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages));
  54 + // 打印结果
  55 + flux.doOnNext(response -> {
  56 +// System.out.println(response);
  57 + System.out.println(response.getResult().getOutput());
  58 + }).then().block();
  59 + }
  60 +
  61 +}
... ...
yudao-server/src/main/resources/application.yaml
... ... @@ -156,13 +156,15 @@ spring:
156 156 qianfan: # 文心一言
157 157 api-key: x0cuLZ7XsaTCU08vuJWO87Lg
158 158 secret-key: R9mYF9dl9KASgi5RUq0FQt3wRisSnOcK
  159 + zhipuai: # 智谱 AI
  160 + api-key: 32f84543e54eee31f8d56b2bd6020573.3vh9idLJZ2ZhxDEs
  161 + openai:
  162 + api-key: sk-yzKea6d8e8212c3bdd99f9f44ced1cae37c097e5aa3BTS7z
  163 + base-url: https://api.gptsapi.net
159 164 ollama:
160 165 base-url: http://127.0.0.1:11434
161 166 chat:
162 167 model: llama3
163   - openai:
164   - api-key: sk-yzKea6d8e8212c3bdd99f9f44ced1cae37c097e5aa3BTS7z
165   - base-url: https://api.gptsapi.net
166 168 stabilityai:
167 169 api-key: sk-e53UqbboF8QJCscYvzJscJxJXoFcFg4iJjl1oqgE7baJETmx
168 170 cloud:
... ... @@ -173,11 +175,11 @@ spring:
173 175  
174 176 yudao:
175 177 ai:
176   - deep-seek:
  178 + deep-seek: # DeepSeek
177 179 enable: true
178 180 api-key: sk-e94db327cc7d457d99a8de8810fc6b12
179 181 model: deepseek-chat
180   - xinghuo:
  182 + xinghuo: # 讯飞星火
181 183 enable: true
182 184 appId: 13c8cca6
183 185 appKey: cb6415c19d6162cda07b47316fcb0416
... ...