From a7e5aaec3bf155a8c451fc031dbdaa5ff4d283d2 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 24 Feb 2025 21:19:44 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E3=80=91AI=EF=BC=9A=E8=BD=A8=E8=BF=B9=E6=B5=81=E5=8A=A8?= =?UTF-8?q?=E7=9A=84=E6=8E=A5=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .image/common/ai-feature.png | Bin 21239 -> 21387 bytes .../ai/config/YudaoAiAutoConfiguration.java | 27 +++++++ .../ai/config/YudaoAiProperties.java | 19 +++++ .../ai/core/enums/AiPlatformEnum.java | 1 + .../ai/core/factory/AiModelFactoryImpl.java | 14 ++++ .../siliconflow/SiliconFlowChatModel.java | 47 ++++++++++++ .../yudao/framework/ai/core/util/AiUtils.java | 1 + .../ai/chat/DouBaoChatModelTests.java | 3 +- .../ai/chat/HunYuanChatModelTests.java | 3 +- .../ai/chat/SiliconFlowChatModelTests.java | 69 ++++++++++++++++++ .../src/main/resources/application.yaml | 4 + 11 files changed, 184 insertions(+), 4 deletions(-) create mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/siliconflow/SiliconFlowChatModel.java create mode 100644 yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/SiliconFlowChatModelTests.java diff --git a/.image/common/ai-feature.png b/.image/common/ai-feature.png index b4a55f547c85650d1b34e0bf0852a40634ecc99f..fadc1cc5d660ef1e3a03fcdb472cba4187ff33b3 100644 GIT binary patch literal 21387 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 z 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 mKhyoTgm1@ZDcM_`%s-~;|KNUAPI 文档 + * + * @author fansili + */ +@Slf4j +@RequiredArgsConstructor +public class SiliconFlowChatModel implements ChatModel { + + public static final String BASE_URL = "https://api.siliconflow.cn"; + + public static final String MODEL_DEFAULT = "deepseek-ai/DeepSeek-R1-Distill-Qwen-7B"; + + /** + * 兼容 OpenAI 接口,进行复用 + */ + private final OpenAiChatModel openAiChatModel; + + @Override + public ChatResponse call(Prompt prompt) { + return openAiChatModel.call(prompt); + } + + @Override + public Flux stream(Prompt prompt) { + return openAiChatModel.stream(prompt); + } + + @Override + public ChatOptions getDefaultOptions() { + return openAiChatModel.getDefaultOptions(); + } + +} diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/util/AiUtils.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/util/AiUtils.java index 51c300c27a..b1a3a3b507 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/util/AiUtils.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/util/AiUtils.java @@ -33,6 +33,7 @@ public class AiUtils { case DOU_BAO: // 复用 OpenAI 客户端 case HUN_YUAN: // 复用 OpenAI 客户端 case XING_HUO: // 复用 OpenAI 客户端 + case SILICON_FLOW: // 复用 OpenAI 客户端 return OpenAiChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens).build(); case AZURE_OPENAI: // TODO 芋艿:貌似没 model 字段???! diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/DouBaoChatModelTests.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/DouBaoChatModelTests.java index 2a6ef7fd21..fc5dc3a274 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/DouBaoChatModelTests.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/DouBaoChatModelTests.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.framework.ai.chat; -import cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatModel; import cn.iocoder.yudao.framework.ai.core.model.doubao.DouBaoChatModel; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -18,7 +17,7 @@ import java.util.ArrayList; import java.util.List; /** - * {@link DeepSeekChatModel} 集成测试 + * {@link DouBaoChatModel} 集成测试 * * @author 芋道源码 */ diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/HunYuanChatModelTests.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/HunYuanChatModelTests.java index 886c9dc1de..e083e6be2d 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/HunYuanChatModelTests.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/HunYuanChatModelTests.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.framework.ai.chat; -import cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatModel; import cn.iocoder.yudao.framework.ai.core.model.hunyuan.HunYuanChatModel; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -18,7 +17,7 @@ import java.util.ArrayList; import java.util.List; /** - * {@link DeepSeekChatModel} 集成测试 + * {@link HunYuanChatModel} 集成测试 * * @author 芋道源码 */ diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/SiliconFlowChatModelTests.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/SiliconFlowChatModelTests.java new file mode 100644 index 0000000000..880795fe96 --- /dev/null +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/chat/SiliconFlowChatModelTests.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.framework.ai.chat; + +import cn.iocoder.yudao.framework.ai.core.model.siliconflow.SiliconFlowChatModel; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.ai.chat.messages.Message; +import org.springframework.ai.chat.messages.SystemMessage; +import org.springframework.ai.chat.messages.UserMessage; +import org.springframework.ai.chat.model.ChatResponse; +import org.springframework.ai.chat.prompt.Prompt; +import org.springframework.ai.openai.OpenAiChatModel; +import org.springframework.ai.openai.OpenAiChatOptions; +import org.springframework.ai.openai.api.OpenAiApi; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.List; + +/** + * {@link SiliconFlowChatModel} 集成测试 + * + * @author 芋道源码 + */ +public class SiliconFlowChatModelTests { + + private final OpenAiChatModel openAiChatModel = OpenAiChatModel.builder() + .openAiApi(OpenAiApi.builder() + .baseUrl(SiliconFlowChatModel.BASE_URL) + .apiKey("sk-epsakfenqnyzoxhmbucsxlhkdqlcbnimslqoivkshalvdozz") // apiKey + .build()) + .defaultOptions(OpenAiChatOptions.builder() + .model(SiliconFlowChatModel.MODEL_DEFAULT) // 模型 +// .model("deepseek-ai/DeepSeek-R1") // 模型(deepseek-ai/DeepSeek-R1)可用赠费 +// .model("Pro/deepseek-ai/DeepSeek-R1") // 模型(Pro/deepseek-ai/DeepSeek-R1)需要付费 + .temperature(0.7) + .build()) + .build(); + + private final SiliconFlowChatModel chatModel = new SiliconFlowChatModel(openAiChatModel); + + @Test + @Disabled + public void testCall() { + // 准备参数 + List messages = new ArrayList<>(); + messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。")); + messages.add(new UserMessage("1 + 1 = ?")); + + // 调用 + ChatResponse response = chatModel.call(new Prompt(messages)); + // 打印结果 + System.out.println(response); + } + + @Test + @Disabled + public void testStream() { + // 准备参数 + List messages = new ArrayList<>(); + messages.add(new SystemMessage("你是一个优质的文言文作者,用文言文描述着各城市的人文风景。")); + messages.add(new UserMessage("1 + 1 = ?")); + + // 调用 + Flux flux = chatModel.stream(new Prompt(messages)); + // 打印结果 + flux.doOnNext(System.out::println).then().block(); + } + +} diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml index 2093e5b50d..b3792c4c16 100644 --- a/yudao-server/src/main/resources/application.yaml +++ b/yudao-server/src/main/resources/application.yaml @@ -192,6 +192,10 @@ yudao: enable: true api-key: sk-abc model: hunyuan-turbo + siliconflow: # 硅基流动 + enable: true + api-key: sk-epsakfenqnyzoxhmbucsxlhkdqlcbnimslqoivkshalvdozz + model: deepseek-ai/DeepSeek-R1-Distill-Qwen-7B xinghuo: # 讯飞星火 enable: true appKey: 75b161ed2aef4719b275d6e7f2a4d4cd