Commit 9d149f414747278cab75b3e12038bafb7dab3d58
1 parent
96a74315
feat:【ai 大模型】增加 gemini 接入
Showing
10 changed files
with
211 additions
and
14 deletions
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiPlatformEnum.java
| @@ -34,6 +34,7 @@ public enum AiPlatformEnum implements ArrayValuable<String> { | @@ -34,6 +34,7 @@ public enum AiPlatformEnum implements ArrayValuable<String> { | ||
| 34 | OPENAI("OpenAI", "OpenAI"), // OpenAI 官方 | 34 | OPENAI("OpenAI", "OpenAI"), // OpenAI 官方 |
| 35 | AZURE_OPENAI("AzureOpenAI", "AzureOpenAI"), // OpenAI 微软 | 35 | AZURE_OPENAI("AzureOpenAI", "AzureOpenAI"), // OpenAI 微软 |
| 36 | ANTHROPIC("Anthropic", "Anthropic"), // Anthropic Claude | 36 | ANTHROPIC("Anthropic", "Anthropic"), // Anthropic Claude |
| 37 | + GEMINI("Gemini", "Gemini"), // 谷歌 Gemini | ||
| 37 | OLLAMA("Ollama", "Ollama"), | 38 | OLLAMA("Ollama", "Ollama"), |
| 38 | 39 | ||
| 39 | STABLE_DIFFUSION("StableDiffusion", "StableDiffusion"), // Stability AI | 40 | STABLE_DIFFUSION("StableDiffusion", "StableDiffusion"), // Stability AI |
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java
| @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.ai.framework.ai.core.AiModelFactory; | @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.ai.framework.ai.core.AiModelFactory; | ||
| 6 | import cn.iocoder.yudao.module.ai.framework.ai.core.AiModelFactoryImpl; | 6 | import cn.iocoder.yudao.module.ai.framework.ai.core.AiModelFactoryImpl; |
| 7 | import cn.iocoder.yudao.module.ai.framework.ai.core.model.baichuan.BaiChuanChatModel; | 7 | import cn.iocoder.yudao.module.ai.framework.ai.core.model.baichuan.BaiChuanChatModel; |
| 8 | import cn.iocoder.yudao.module.ai.framework.ai.core.model.doubao.DouBaoChatModel; | 8 | import cn.iocoder.yudao.module.ai.framework.ai.core.model.doubao.DouBaoChatModel; |
| 9 | +import cn.iocoder.yudao.module.ai.framework.ai.core.model.gemini.GeminiChatModel; | ||
| 9 | import cn.iocoder.yudao.module.ai.framework.ai.core.model.hunyuan.HunYuanChatModel; | 10 | import cn.iocoder.yudao.module.ai.framework.ai.core.model.hunyuan.HunYuanChatModel; |
| 10 | import cn.iocoder.yudao.module.ai.framework.ai.core.model.midjourney.api.MidjourneyApi; | 11 | import cn.iocoder.yudao.module.ai.framework.ai.core.model.midjourney.api.MidjourneyApi; |
| 11 | import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowApiConstants; | 12 | import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowApiConstants; |
| @@ -52,6 +53,34 @@ public class AiAutoConfiguration { | @@ -52,6 +53,34 @@ public class AiAutoConfiguration { | ||
| 52 | // ========== 各种 AI Client 创建 ========== | 53 | // ========== 各种 AI Client 创建 ========== |
| 53 | 54 | ||
| 54 | @Bean | 55 | @Bean |
| 56 | + @ConditionalOnProperty(value = "yudao.ai.gemini.enable", havingValue = "true") | ||
| 57 | + public GeminiChatModel geminiChatModel(YudaoAiProperties yudaoAiProperties) { | ||
| 58 | + YudaoAiProperties.GeminiProperties properties = yudaoAiProperties.getGemini(); | ||
| 59 | + return buildGeminiChatClient(properties); | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + public GeminiChatModel buildGeminiChatClient(YudaoAiProperties.GeminiProperties properties) { | ||
| 63 | + if (StrUtil.isEmpty(properties.getModel())) { | ||
| 64 | + properties.setModel(GeminiChatModel.MODEL_DEFAULT); | ||
| 65 | + } | ||
| 66 | + OpenAiChatModel openAiChatModel = OpenAiChatModel.builder() | ||
| 67 | + .openAiApi(OpenAiApi.builder() | ||
| 68 | + .baseUrl(GeminiChatModel.BASE_URL) | ||
| 69 | + .completionsPath(GeminiChatModel.COMPLETE_PATH) | ||
| 70 | + .apiKey(properties.getApiKey()) | ||
| 71 | + .build()) | ||
| 72 | + .defaultOptions(OpenAiChatOptions.builder() | ||
| 73 | + .model(properties.getModel()) | ||
| 74 | + .temperature(properties.getTemperature()) | ||
| 75 | + .maxTokens(properties.getMaxTokens()) | ||
| 76 | + .topP(properties.getTopP()) | ||
| 77 | + .build()) | ||
| 78 | + .toolCallingManager(getToolCallingManager()) | ||
| 79 | + .build(); | ||
| 80 | + return new GeminiChatModel(openAiChatModel); | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + @Bean | ||
| 55 | @ConditionalOnProperty(value = "yudao.ai.doubao.enable", havingValue = "true") | 84 | @ConditionalOnProperty(value = "yudao.ai.doubao.enable", havingValue = "true") |
| 56 | public DouBaoChatModel douBaoChatClient(YudaoAiProperties yudaoAiProperties) { | 85 | public DouBaoChatModel douBaoChatClient(YudaoAiProperties yudaoAiProperties) { |
| 57 | YudaoAiProperties.DouBaoProperties properties = yudaoAiProperties.getDoubao(); | 86 | YudaoAiProperties.DouBaoProperties properties = yudaoAiProperties.getDoubao(); |
| @@ -150,17 +179,22 @@ public class AiAutoConfiguration { | @@ -150,17 +179,22 @@ public class AiAutoConfiguration { | ||
| 150 | if (StrUtil.isEmpty(properties.getModel())) { | 179 | if (StrUtil.isEmpty(properties.getModel())) { |
| 151 | properties.setModel(XingHuoChatModel.MODEL_DEFAULT); | 180 | properties.setModel(XingHuoChatModel.MODEL_DEFAULT); |
| 152 | } | 181 | } |
| 182 | + OpenAiApi.Builder builder = OpenAiApi.builder() | ||
| 183 | + .baseUrl(XingHuoChatModel.BASE_URL_V1) | ||
| 184 | + .apiKey(properties.getAppKey() + ":" + properties.getSecretKey()); | ||
| 185 | + if ("x1".equals(properties.getModel())) { | ||
| 186 | + builder.baseUrl(XingHuoChatModel.BASE_URL_V2) | ||
| 187 | + .completionsPath(XingHuoChatModel.BASE_COMPLETIONS_PATH_V2); | ||
| 188 | + } | ||
| 153 | OpenAiChatModel openAiChatModel = OpenAiChatModel.builder() | 189 | OpenAiChatModel openAiChatModel = OpenAiChatModel.builder() |
| 154 | - .openAiApi(OpenAiApi.builder() | ||
| 155 | - .baseUrl(XingHuoChatModel.BASE_URL) | ||
| 156 | - .apiKey(properties.getAppKey() + ":" + properties.getSecretKey()) | ||
| 157 | - .build()) | 190 | + .openAiApi(builder.build()) |
| 158 | .defaultOptions(OpenAiChatOptions.builder() | 191 | .defaultOptions(OpenAiChatOptions.builder() |
| 159 | .model(properties.getModel()) | 192 | .model(properties.getModel()) |
| 160 | .temperature(properties.getTemperature()) | 193 | .temperature(properties.getTemperature()) |
| 161 | .maxTokens(properties.getMaxTokens()) | 194 | .maxTokens(properties.getMaxTokens()) |
| 162 | .topP(properties.getTopP()) | 195 | .topP(properties.getTopP()) |
| 163 | .build()) | 196 | .build()) |
| 197 | + // TODO @芋艿:星火的 function call 有 bug,会报 ToolResponseMessage must have an id 错误!!! | ||
| 164 | .toolCallingManager(getToolCallingManager()) | 198 | .toolCallingManager(getToolCallingManager()) |
| 165 | .build(); | 199 | .build(); |
| 166 | return new XingHuoChatModel(openAiChatModel); | 200 | return new XingHuoChatModel(openAiChatModel); |
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java
| @@ -14,6 +14,11 @@ import org.springframework.boot.context.properties.ConfigurationProperties; | @@ -14,6 +14,11 @@ import org.springframework.boot.context.properties.ConfigurationProperties; | ||
| 14 | public class YudaoAiProperties { | 14 | public class YudaoAiProperties { |
| 15 | 15 | ||
| 16 | /** | 16 | /** |
| 17 | + * 谷歌 Gemini | ||
| 18 | + */ | ||
| 19 | + private GeminiProperties gemini; | ||
| 20 | + | ||
| 21 | + /** | ||
| 17 | * 字节豆包 | 22 | * 字节豆包 |
| 18 | */ | 23 | */ |
| 19 | @SuppressWarnings("SpellCheckingInspection") | 24 | @SuppressWarnings("SpellCheckingInspection") |
| @@ -55,6 +60,19 @@ public class YudaoAiProperties { | @@ -55,6 +60,19 @@ public class YudaoAiProperties { | ||
| 55 | private SunoProperties suno; | 60 | private SunoProperties suno; |
| 56 | 61 | ||
| 57 | @Data | 62 | @Data |
| 63 | + public static class GeminiProperties { | ||
| 64 | + | ||
| 65 | + private String enable; | ||
| 66 | + private String apiKey; | ||
| 67 | + | ||
| 68 | + private String model; | ||
| 69 | + private Double temperature; | ||
| 70 | + private Integer maxTokens; | ||
| 71 | + private Double topP; | ||
| 72 | + | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + @Data | ||
| 58 | public static class DouBaoProperties { | 76 | public static class DouBaoProperties { |
| 59 | 77 | ||
| 60 | private String enable; | 78 | private String enable; |
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/AiModelFactoryImpl.java
| @@ -14,6 +14,7 @@ import cn.iocoder.yudao.module.ai.framework.ai.config.AiAutoConfiguration; | @@ -14,6 +14,7 @@ import cn.iocoder.yudao.module.ai.framework.ai.config.AiAutoConfiguration; | ||
| 14 | import cn.iocoder.yudao.module.ai.framework.ai.config.YudaoAiProperties; | 14 | import cn.iocoder.yudao.module.ai.framework.ai.config.YudaoAiProperties; |
| 15 | import cn.iocoder.yudao.module.ai.framework.ai.core.model.baichuan.BaiChuanChatModel; | 15 | import cn.iocoder.yudao.module.ai.framework.ai.core.model.baichuan.BaiChuanChatModel; |
| 16 | import cn.iocoder.yudao.module.ai.framework.ai.core.model.doubao.DouBaoChatModel; | 16 | import cn.iocoder.yudao.module.ai.framework.ai.core.model.doubao.DouBaoChatModel; |
| 17 | +import cn.iocoder.yudao.module.ai.framework.ai.core.model.gemini.GeminiChatModel; | ||
| 17 | import cn.iocoder.yudao.module.ai.framework.ai.core.model.hunyuan.HunYuanChatModel; | 18 | import cn.iocoder.yudao.module.ai.framework.ai.core.model.hunyuan.HunYuanChatModel; |
| 18 | import cn.iocoder.yudao.module.ai.framework.ai.core.model.midjourney.api.MidjourneyApi; | 19 | import cn.iocoder.yudao.module.ai.framework.ai.core.model.midjourney.api.MidjourneyApi; |
| 19 | import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowApiConstants; | 20 | import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowApiConstants; |
| @@ -173,6 +174,8 @@ public class AiModelFactoryImpl implements AiModelFactory { | @@ -173,6 +174,8 @@ public class AiModelFactoryImpl implements AiModelFactory { | ||
| 173 | return buildAzureOpenAiChatModel(apiKey, url); | 174 | return buildAzureOpenAiChatModel(apiKey, url); |
| 174 | case ANTHROPIC: | 175 | case ANTHROPIC: |
| 175 | return buildAnthropicChatModel(apiKey, url); | 176 | return buildAnthropicChatModel(apiKey, url); |
| 177 | + case GEMINI: | ||
| 178 | + return buildGeminiChatModel(apiKey); | ||
| 176 | case OLLAMA: | 179 | case OLLAMA: |
| 177 | return buildOllamaChatModel(url); | 180 | return buildOllamaChatModel(url); |
| 178 | default: | 181 | default: |
| @@ -213,6 +216,8 @@ public class AiModelFactoryImpl implements AiModelFactory { | @@ -213,6 +216,8 @@ public class AiModelFactoryImpl implements AiModelFactory { | ||
| 213 | return SpringUtil.getBean(AzureOpenAiChatModel.class); | 216 | return SpringUtil.getBean(AzureOpenAiChatModel.class); |
| 214 | case ANTHROPIC: | 217 | case ANTHROPIC: |
| 215 | return SpringUtil.getBean(AnthropicChatModel.class); | 218 | return SpringUtil.getBean(AnthropicChatModel.class); |
| 219 | + case GEMINI: | ||
| 220 | + return SpringUtil.getBean(GeminiChatModel.class); | ||
| 216 | case OLLAMA: | 221 | case OLLAMA: |
| 217 | return SpringUtil.getBean(OllamaChatModel.class); | 222 | return SpringUtil.getBean(OllamaChatModel.class); |
| 218 | default: | 223 | default: |
| @@ -535,6 +540,15 @@ public class AiModelFactoryImpl implements AiModelFactory { | @@ -535,6 +540,15 @@ public class AiModelFactoryImpl implements AiModelFactory { | ||
| 535 | } | 540 | } |
| 536 | 541 | ||
| 537 | /** | 542 | /** |
| 543 | + * 可参考 {@link AiAutoConfiguration#buildGeminiChatClient(YudaoAiProperties.GeminiProperties)} | ||
| 544 | + */ | ||
| 545 | + private static GeminiChatModel buildGeminiChatModel(String apiKey) { | ||
| 546 | + YudaoAiProperties.GeminiProperties properties = SpringUtil.getBean(YudaoAiProperties.class) | ||
| 547 | + .getGemini().setApiKey(apiKey); | ||
| 548 | + return new AiAutoConfiguration().buildGeminiChatClient(properties); | ||
| 549 | + } | ||
| 550 | + | ||
| 551 | + /** | ||
| 538 | * 可参考 {@link OpenAiImageAutoConfiguration} 的 openAiImageModel 方法 | 552 | * 可参考 {@link OpenAiImageAutoConfiguration} 的 openAiImageModel 方法 |
| 539 | */ | 553 | */ |
| 540 | private OpenAiImageModel buildOpenAiImageModel(String openAiToken, String url) { | 554 | private OpenAiImageModel buildOpenAiImageModel(String openAiToken, String url) { |
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/gemini/GeminiChatModel.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.framework.ai.core.model.gemini; | ||
| 2 | + | ||
| 3 | +import lombok.RequiredArgsConstructor; | ||
| 4 | +import lombok.extern.slf4j.Slf4j; | ||
| 5 | +import org.springframework.ai.chat.model.ChatModel; | ||
| 6 | +import org.springframework.ai.chat.model.ChatResponse; | ||
| 7 | +import org.springframework.ai.chat.prompt.ChatOptions; | ||
| 8 | +import org.springframework.ai.chat.prompt.Prompt; | ||
| 9 | +import org.springframework.ai.openai.OpenAiChatModel; | ||
| 10 | +import reactor.core.publisher.Flux; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * 谷歌 Gemini {@link ChatModel} 实现类,基于 Google AI Studio 提供的 <a href="https://ai.google.dev/gemini-api/docs/openai">OpenAI 兼容方案</a> | ||
| 14 | + * | ||
| 15 | + * @author 芋道源码 | ||
| 16 | + */ | ||
| 17 | +@Slf4j | ||
| 18 | +@RequiredArgsConstructor | ||
| 19 | +public class GeminiChatModel implements ChatModel { | ||
| 20 | + | ||
| 21 | + public static final String BASE_URL = "https://generativelanguage.googleapis.com/v1beta/openai/"; | ||
| 22 | + public static final String COMPLETE_PATH = "/chat/completions"; | ||
| 23 | + | ||
| 24 | + public static final String MODEL_DEFAULT = "gemini-2.5-flash"; | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * 兼容 OpenAI 接口,进行复用 | ||
| 28 | + */ | ||
| 29 | + private final OpenAiChatModel openAiChatModel; | ||
| 30 | + | ||
| 31 | + @Override | ||
| 32 | + public ChatResponse call(Prompt prompt) { | ||
| 33 | + return openAiChatModel.call(prompt); | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + @Override | ||
| 37 | + public Flux<ChatResponse> stream(Prompt prompt) { | ||
| 38 | + return openAiChatModel.stream(prompt); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + @Override | ||
| 42 | + public ChatOptions getDefaultOptions() { | ||
| 43 | + return openAiChatModel.getDefaultOptions(); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | +} |
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/xinghuo/XingHuoChatModel.java
| @@ -18,28 +18,34 @@ import reactor.core.publisher.Flux; | @@ -18,28 +18,34 @@ import reactor.core.publisher.Flux; | ||
| 18 | @RequiredArgsConstructor | 18 | @RequiredArgsConstructor |
| 19 | public class XingHuoChatModel implements ChatModel { | 19 | public class XingHuoChatModel implements ChatModel { |
| 20 | 20 | ||
| 21 | - public static final String BASE_URL = "https://spark-api-open.xf-yun.com"; | 21 | + public static final String BASE_URL_V1 = "https://spark-api-open.xf-yun.com"; |
| 22 | 22 | ||
| 23 | - public static final String MODEL_DEFAULT = "generalv3.5"; | 23 | + public static final String BASE_URL_V2 = "https://spark-api-open.xf-yun.com"; |
| 24 | + public static final String BASE_COMPLETIONS_PATH_V2 = "/v2/chat/completions"; | ||
| 24 | 25 | ||
| 25 | /** | 26 | /** |
| 26 | - * 兼容 OpenAI 接口,进行复用 | 27 | + * 已知模型名列表:x1、4.0Ultra、generalv3.5、max-32k、generalv3、pro-128k、lite |
| 27 | */ | 28 | */ |
| 28 | - private final OpenAiChatModel openAiChatModel; | 29 | + public static final String MODEL_DEFAULT = "4.0Ultra"; |
| 30 | + | ||
| 31 | + /** | ||
| 32 | + * v1 兼容 OpenAI 接口,进行复用 | ||
| 33 | + */ | ||
| 34 | + private final OpenAiChatModel openAiChatModelV1; | ||
| 29 | 35 | ||
| 30 | @Override | 36 | @Override |
| 31 | public ChatResponse call(Prompt prompt) { | 37 | public ChatResponse call(Prompt prompt) { |
| 32 | - return openAiChatModel.call(prompt); | 38 | + return openAiChatModelV1.call(prompt); |
| 33 | } | 39 | } |
| 34 | 40 | ||
| 35 | @Override | 41 | @Override |
| 36 | public Flux<ChatResponse> stream(Prompt prompt) { | 42 | public Flux<ChatResponse> stream(Prompt prompt) { |
| 37 | - return openAiChatModel.stream(prompt); | 43 | + return openAiChatModelV1.stream(prompt); |
| 38 | } | 44 | } |
| 39 | 45 | ||
| 40 | @Override | 46 | @Override |
| 41 | public ChatOptions getDefaultOptions() { | 47 | public ChatOptions getDefaultOptions() { |
| 42 | - return openAiChatModel.getDefaultOptions(); | 48 | + return openAiChatModelV1.getDefaultOptions(); |
| 43 | } | 49 | } |
| 44 | 50 | ||
| 45 | } | 51 | } |
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java
| @@ -12,6 +12,7 @@ import org.springframework.ai.anthropic.AnthropicChatOptions; | @@ -12,6 +12,7 @@ import org.springframework.ai.anthropic.AnthropicChatOptions; | ||
| 12 | import org.springframework.ai.azure.openai.AzureOpenAiChatOptions; | 12 | import org.springframework.ai.azure.openai.AzureOpenAiChatOptions; |
| 13 | import org.springframework.ai.chat.messages.*; | 13 | import org.springframework.ai.chat.messages.*; |
| 14 | import org.springframework.ai.chat.prompt.ChatOptions; | 14 | import org.springframework.ai.chat.prompt.ChatOptions; |
| 15 | +import org.springframework.ai.deepseek.DeepSeekChatOptions; | ||
| 15 | import org.springframework.ai.minimax.MiniMaxChatOptions; | 16 | import org.springframework.ai.minimax.MiniMaxChatOptions; |
| 16 | import org.springframework.ai.ollama.api.OllamaOptions; | 17 | import org.springframework.ai.ollama.api.OllamaOptions; |
| 17 | import org.springframework.ai.openai.OpenAiChatOptions; | 18 | import org.springframework.ai.openai.OpenAiChatOptions; |
| @@ -47,6 +48,9 @@ public class AiUtils { | @@ -47,6 +48,9 @@ public class AiUtils { | ||
| 47 | .withToolNames(toolNames).withToolContext(toolContext).build(); | 48 | .withToolNames(toolNames).withToolContext(toolContext).build(); |
| 48 | case YI_YAN: | 49 | case YI_YAN: |
| 49 | return QianFanChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens).build(); | 50 | return QianFanChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens).build(); |
| 51 | + case DEEP_SEEK: | ||
| 52 | + return DeepSeekChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens) | ||
| 53 | + .toolNames(toolNames).toolContext(toolContext).build(); | ||
| 50 | case ZHI_PU: | 54 | case ZHI_PU: |
| 51 | return ZhiPuAiChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens) | 55 | return ZhiPuAiChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens) |
| 52 | .toolNames(toolNames).toolContext(toolContext).build(); | 56 | .toolNames(toolNames).toolContext(toolContext).build(); |
| @@ -57,7 +61,7 @@ public class AiUtils { | @@ -57,7 +61,7 @@ public class AiUtils { | ||
| 57 | return MoonshotChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens) | 61 | return MoonshotChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens) |
| 58 | .toolNames(toolNames).toolContext(toolContext).build(); | 62 | .toolNames(toolNames).toolContext(toolContext).build(); |
| 59 | case OPENAI: | 63 | case OPENAI: |
| 60 | - case DEEP_SEEK: // 复用 OpenAI 客户端 | 64 | + case GEMINI: // 复用 OpenAI 客户端 |
| 61 | case DOU_BAO: // 复用 OpenAI 客户端 | 65 | case DOU_BAO: // 复用 OpenAI 客户端 |
| 62 | case HUN_YUAN: // 复用 OpenAI 客户端 | 66 | case HUN_YUAN: // 复用 OpenAI 客户端 |
| 63 | case XING_HUO: // 复用 OpenAI 客户端 | 67 | case XING_HUO: // 复用 OpenAI 客户端 |
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/GeminiChatModelTests.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.framework.ai.core.model.chat; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.ai.framework.ai.core.model.gemini.GeminiChatModel; | ||
| 4 | +import org.junit.jupiter.api.Disabled; | ||
| 5 | +import org.junit.jupiter.api.Test; | ||
| 6 | +import org.springframework.ai.chat.messages.Message; | ||
| 7 | +import org.springframework.ai.chat.messages.SystemMessage; | ||
| 8 | +import org.springframework.ai.chat.messages.UserMessage; | ||
| 9 | +import org.springframework.ai.chat.model.ChatResponse; | ||
| 10 | +import org.springframework.ai.chat.prompt.Prompt; | ||
| 11 | +import org.springframework.ai.openai.OpenAiChatModel; | ||
| 12 | +import org.springframework.ai.openai.OpenAiChatOptions; | ||
| 13 | +import org.springframework.ai.openai.api.OpenAiApi; | ||
| 14 | +import reactor.core.publisher.Flux; | ||
| 15 | + | ||
| 16 | +import java.util.ArrayList; | ||
| 17 | +import java.util.List; | ||
| 18 | + | ||
| 19 | +/** | ||
| 20 | + * {@link GeminiChatModel} 集成测试 | ||
| 21 | + * | ||
| 22 | + * @author 芋道源码 | ||
| 23 | + */ | ||
| 24 | +public class GeminiChatModelTests { | ||
| 25 | + | ||
| 26 | + private final OpenAiChatModel openAiChatModel = OpenAiChatModel.builder() | ||
| 27 | + .openAiApi(OpenAiApi.builder() | ||
| 28 | + .baseUrl(GeminiChatModel.BASE_URL) | ||
| 29 | + .completionsPath(GeminiChatModel.COMPLETE_PATH) | ||
| 30 | + .apiKey("AIzaSyAVoBxgoFvvte820vEQMma2LKBnC98bqMQ") | ||
| 31 | + .build()) | ||
| 32 | + .defaultOptions(OpenAiChatOptions.builder() | ||
| 33 | + .model(GeminiChatModel.MODEL_DEFAULT) // 模型 | ||
| 34 | + .temperature(0.7) | ||
| 35 | + .build()) | ||
| 36 | + .build(); | ||
| 37 | + | ||
| 38 | + private final GeminiChatModel chatModel = new GeminiChatModel(openAiChatModel); | ||
| 39 | + | ||
| 40 | + @Test | ||
| 41 | + @Disabled | ||
| 42 | + public void testCall() { | ||
| 43 | + // 准备参数 | ||
| 44 | + List<Message> messages = new ArrayList<>(); | ||
| 45 | + messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。")); | ||
| 46 | + messages.add(new UserMessage("1 + 1 = ?")); | ||
| 47 | + | ||
| 48 | + // 调用 | ||
| 49 | + ChatResponse response = chatModel.call(new Prompt(messages)); | ||
| 50 | + // 打印结果 | ||
| 51 | + System.out.println(response); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + @Test | ||
| 55 | + @Disabled | ||
| 56 | + public void testStream() { | ||
| 57 | + // 准备参数 | ||
| 58 | + List<Message> messages = new ArrayList<>(); | ||
| 59 | + messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。")); | ||
| 60 | + messages.add(new UserMessage("1 + 1 = ?")); | ||
| 61 | + | ||
| 62 | + // 调用 | ||
| 63 | + Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages)); | ||
| 64 | + // 打印结果 | ||
| 65 | + flux.doOnNext(System.out::println).then().block(); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | +} |
yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/XingHuoChatModelTests.java
| @@ -25,11 +25,13 @@ public class XingHuoChatModelTests { | @@ -25,11 +25,13 @@ public class XingHuoChatModelTests { | ||
| 25 | 25 | ||
| 26 | private final OpenAiChatModel openAiChatModel = OpenAiChatModel.builder() | 26 | private final OpenAiChatModel openAiChatModel = OpenAiChatModel.builder() |
| 27 | .openAiApi(OpenAiApi.builder() | 27 | .openAiApi(OpenAiApi.builder() |
| 28 | - .baseUrl(XingHuoChatModel.BASE_URL) | 28 | + .baseUrl(XingHuoChatModel.BASE_URL_V2) |
| 29 | + .completionsPath(XingHuoChatModel.BASE_COMPLETIONS_PATH_V2) | ||
| 29 | .apiKey("75b161ed2aef4719b275d6e7f2a4d4cd:YWYxYWI2MTA4ODI2NGZlYTQyNjAzZTcz") // appKey:secretKey | 30 | .apiKey("75b161ed2aef4719b275d6e7f2a4d4cd:YWYxYWI2MTA4ODI2NGZlYTQyNjAzZTcz") // appKey:secretKey |
| 30 | .build()) | 31 | .build()) |
| 31 | .defaultOptions(OpenAiChatOptions.builder() | 32 | .defaultOptions(OpenAiChatOptions.builder() |
| 32 | - .model("generalv3.5") // 模型 | 33 | +// .model("generalv3.5") // 模型 |
| 34 | + .model("x1") // 模型 | ||
| 33 | .temperature(0.7) | 35 | .temperature(0.7) |
| 34 | .build()) | 36 | .build()) |
| 35 | .build(); | 37 | .build(); |
yudao-server/src/main/resources/application.yaml
| @@ -197,6 +197,10 @@ spring: | @@ -197,6 +197,10 @@ spring: | ||
| 197 | 197 | ||
| 198 | yudao: | 198 | yudao: |
| 199 | ai: | 199 | ai: |
| 200 | + gemini: # 谷歌 Gemini | ||
| 201 | + enable: true | ||
| 202 | + api-key: AIzaSyAVoBxgoFvvte820vEQMma2LKBnC98bqMQ | ||
| 203 | + model: gemini-2.5-flash | ||
| 200 | doubao: # 字节豆包 | 204 | doubao: # 字节豆包 |
| 201 | enable: true | 205 | enable: true |
| 202 | api-key: 5c1b5747-26d2-4ebd-a4e0-dd0e8d8b4272 | 206 | api-key: 5c1b5747-26d2-4ebd-a4e0-dd0e8d8b4272 |