浏览代码

fix model dynamic config

gbhblt 1 年之前
父节点
当前提交
45c927a26a

+ 50 - 227
langchat-core/src/main/java/cn/tycoding/langchat/core/provider/ProviderInitialize.java

@@ -16,6 +16,8 @@
 
 package cn.tycoding.langchat.core.provider;
 
+import cn.hutool.core.lang.Pair;
+import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.tycoding.langchat.biz.component.ModelTypeEnum;
 import cn.tycoding.langchat.biz.component.ProviderEnum;
@@ -23,12 +25,16 @@ import cn.tycoding.langchat.biz.entity.AigcModel;
 import cn.tycoding.langchat.biz.service.AigcModelService;
 import cn.tycoding.langchat.common.component.SpringContextHolder;
 import cn.tycoding.langchat.core.consts.EmbedConst;
+import cn.tycoding.langchat.core.provider.model.config.strategy.ModelConfigHandler;
 import dev.langchain4j.model.anthropic.AnthropicStreamingChatModel;
 import dev.langchain4j.model.azure.AzureOpenAiEmbeddingModel;
 import dev.langchain4j.model.azure.AzureOpenAiImageModel;
 import dev.langchain4j.model.azure.AzureOpenAiStreamingChatModel;
+import dev.langchain4j.model.chat.StreamingChatLanguageModel;
 import dev.langchain4j.model.dashscope.QwenEmbeddingModel;
 import dev.langchain4j.model.dashscope.QwenStreamingChatModel;
+import dev.langchain4j.model.embedding.DimensionAwareEmbeddingModel;
+import dev.langchain4j.model.image.ImageModel;
 import dev.langchain4j.model.ollama.OllamaEmbeddingModel;
 import dev.langchain4j.model.ollama.OllamaStreamingChatModel;
 import dev.langchain4j.model.openai.OpenAiEmbeddingModel;
@@ -41,6 +47,7 @@ import dev.langchain4j.model.zhipu.ZhipuAiEmbeddingModel;
 import dev.langchain4j.model.zhipu.ZhipuAiImageModel;
 import dev.langchain4j.model.zhipu.ZhipuAiStreamingChatModel;
 import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.BeansException;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
@@ -55,8 +62,9 @@ import java.util.Objects;
  */
 @Configuration
 @AllArgsConstructor
+@Slf4j
 public class ProviderInitialize implements ApplicationContextAware {
-
+    private List<ModelConfigHandler> modelConfigHandlers;
     private final AigcModelService aigcModelService;
     private final SpringContextHolder contextHolder;
 
@@ -89,242 +97,57 @@ public class ProviderInitialize implements ApplicationContextAware {
     }
 
     private void chatHandler(AigcModel model) {
-        String type = model.getType();
-        String provider = model.getProvider();
-
-        if (ModelTypeEnum.CHAT.name().equals(type)) {
-            if (ProviderEnum.OPENAI.name().equals(provider)) {
-                if (StrUtil.isBlank(model.getApiKey())) {
-                    return;
-                }
-                OpenAiStreamingChatModel build =  OpenAiStreamingChatModel
-                        .builder()
-                        .apiKey(model.getApiKey())
-                        .baseUrl(model.getBaseUrl())
-                        .modelName(model.getModel())
-                        .maxTokens(model.getResponseLimit())
-                        .temperature(model.getTemperature())
-                        .logRequests(true)
-                        .logResponses(true)
-                        .topP(model.getTopP())
-                        .build();
-                contextHolder.registerBean(model.getId(), build);
-            }
-            if (ProviderEnum.AZURE_OPENAI.name().equals(provider)) {
-                if (StrUtil.isBlank(model.getApiKey())) {
-                    return;
-                }
-                AzureOpenAiStreamingChatModel build =  AzureOpenAiStreamingChatModel
-                        .builder()
-                        .apiKey(model.getApiKey())
-                        .endpoint(model.getEndpoint())
-                        .deploymentName(model.getAzureDeploymentName())
-                        .maxTokens(model.getResponseLimit())
-                        .temperature(model.getTemperature())
-                        .logRequestsAndResponses(true)
-                        .topP(model.getTopP())
-                        .build();
-                contextHolder.registerBean(model.getId(), build);
-            }
-            if (ProviderEnum.GEMINI.name().equals(provider)) {
-                if (StrUtil.isBlank(model.getApiKey()) || StrUtil.isBlank(model.getSecretKey())) {
-                    return;
-                }
-                VertexAiGeminiStreamingChatModel build = VertexAiGeminiStreamingChatModel
-                        .builder()
-                        .project(model.getGeminiProject())
-                        .location(model.getGeminiLocation())
-                        .modelName(model.getModel())
-                        .temperature(Float.parseFloat(model.getTemperature().toString()))
-                        .maxOutputTokens(model.getResponseLimit())
-                        .logRequests(true)
-                        .logResponses(true)
-                        .topP(Float.parseFloat(model.getTopP().toString()))
-                        .build();
-                contextHolder.registerBean(model.getId(), build);
-            }
-            if (ProviderEnum.OLLAMA.name().equals(provider)) {
-                OllamaStreamingChatModel build = OllamaStreamingChatModel
-                        .builder()
-                        .baseUrl(model.getBaseUrl())
-                        .modelName(model.getModel())
-                        .temperature(model.getTemperature())
-                        .topP(model.getTopP())
-                        .logRequests(true)
-                        .logResponses(true)
-                        .build();
-                contextHolder.registerBean(model.getId(), build);
-            }
-            if (ProviderEnum.CLAUDE.name().equals(provider)) {
-                if (!model.getBaseUrl().endsWith("/")) {
-                    model.setBaseUrl(model.getBaseUrl() + "/");
+        try {
+            String type = model.getType();
+            if (!ModelTypeEnum.CHAT.name().equals(type)) {
+                return;
+            }
+            modelConfigHandlers.forEach(x -> {
+                StreamingChatLanguageModel streamingChatLanguageModel = x.chatConfig(model);
+                if (ObjectUtil.isNotEmpty(streamingChatLanguageModel)) {
+                    contextHolder.registerBean(model.getId(), streamingChatLanguageModel);
                 }
-                AnthropicStreamingChatModel build = AnthropicStreamingChatModel
-                        .builder()
-                        .apiKey(model.getApiKey())
-                        .baseUrl(model.getBaseUrl())
-                        .modelName(model.getModel())
-                        .temperature(model.getTemperature())
-                        .topP(model.getTopP())
-                        .logRequests(true)
-                        .logResponses(true)
-                        .build();
-                contextHolder.registerBean(model.getId(), build);
-            }
-            if (ProviderEnum.Q_FAN.name().equals(provider)) {
-                QianfanStreamingChatModel build = QianfanStreamingChatModel
-                        .builder()
-                        .apiKey(model.getApiKey())
-                        .secretKey(model.getSecretKey())
-                        .modelName(model.getModel())
-                        .baseUrl(model.getBaseUrl())
-                        .temperature(model.getTemperature())
-                        .topP(model.getTopP())
-                        .logRequests(true)
-                        .logResponses(true)
-                        .build();
-                contextHolder.registerBean(model.getId(), build);
-            }
-            if (ProviderEnum.Q_WEN.name().equals(provider)) {
-                QwenStreamingChatModel build = QwenStreamingChatModel
-                        .builder()
-                        .apiKey(model.getApiKey())
-                        .modelName(model.getModel())
-                        .baseUrl(model.getBaseUrl())
-                        .maxTokens(model.getResponseLimit())
-                        .temperature(Float.parseFloat(model.getTemperature().toString()))
-                        .topP(model.getTopP())
-                        .build();
-                contextHolder.registerBean(model.getId(), build);
-            }
-            if (ProviderEnum.ZHIPU.name().equals(provider)) {
-                ZhipuAiStreamingChatModel build = ZhipuAiStreamingChatModel
-                        .builder()
-                        .apiKey(model.getApiKey())
-                        .baseUrl(model.getBaseUrl())
-                        .model(model.getModel())
-                        .maxToken(model.getResponseLimit())
-                        .temperature(model.getTemperature())
-                        .topP(model.getTopP())
-                        .logRequests(true)
-                        .logResponses(true)
-                        .build();
-                contextHolder.registerBean(model.getId(), build);
-            }
+            });
+        } catch (Exception e) {
+            log.error("model 【id{} name{}】 chat 配置报错", model.getId(), model.getName());
         }
+
     }
 
     private void embeddingHandler(AigcModel model) {
-        String type = model.getType();
-        String provider = model.getProvider();
+        try {
+            String type = model.getType();
+            if (!ModelTypeEnum.EMBEDDING.name().equals(type)) {
+                return;
+            }
+            modelConfigHandlers.forEach(x -> {
+                Pair<String, DimensionAwareEmbeddingModel> embeddingModelPair = x.embeddingConfig(model);
+                if (ObjectUtil.isNotEmpty(embeddingModelPair)) {
+                    contextHolder.registerBean(embeddingModelPair.getKey(), embeddingModelPair.getValue());
+                }
+            });
 
-        if (ModelTypeEnum.EMBEDDING.name().equals(type)) {
-            if (ProviderEnum.OPENAI.name().equals(provider)) {
-                OpenAiEmbeddingModel build = OpenAiEmbeddingModel
-                        .builder()
-                        .apiKey(model.getApiKey())
-                        .baseUrl(model.getBaseUrl())
-                        .modelName(model.getModel())
-                        .dimensions(model.getDimensions())
-                        .logRequests(true)
-                        .logResponses(true)
-                        .build();
-                contextHolder.registerBean(EmbedConst.CLAZZ_NAME_OPENAI, build);
-            }
-            if (ProviderEnum.AZURE_OPENAI.name().equals(provider)) {
-                AzureOpenAiEmbeddingModel build = AzureOpenAiEmbeddingModel
-                        .builder()
-                        .apiKey(model.getApiKey())
-                        .deploymentName(model.getBaseUrl())
-                        .logRequestsAndResponses(true)
-                        .build();
-                contextHolder.registerBean(EmbedConst.CLAZZ_NAME_AZURE_OPENAI, build);
-            }
-            if (ProviderEnum.Q_FAN.name().equals(provider)) {
-                QianfanEmbeddingModel build = QianfanEmbeddingModel
-                        .builder()
-                        .apiKey(model.getApiKey())
-                        .modelName(model.getModel())
-                        .secretKey(model.getSecretKey())
-                        .logRequests(true)
-                        .logResponses(true)
-                        .build();
-                contextHolder.registerBean(EmbedConst.CLAZZ_NAME_QIANFAN, build);
-            }
-            if (ProviderEnum.Q_WEN.name().equals(provider)) {
-                QwenEmbeddingModel build = QwenEmbeddingModel
-                        .builder()
-                        .apiKey(model.getApiKey())
-                        .modelName(model.getModel())
-                        .build();
-                contextHolder.registerBean(EmbedConst.CLAZZ_NAME_QIANWEN, build);
-            }
-            if (ProviderEnum.ZHIPU.name().equals(provider)) {
-                ZhipuAiEmbeddingModel build = ZhipuAiEmbeddingModel
-                        .builder()
-                        .apiKey(model.getApiKey())
-                        .model(model.getModel())
-                        .baseUrl(model.getBaseUrl())
-                        .logRequests(true)
-                        .logResponses(true)
-                        .build();
-                contextHolder.registerBean(EmbedConst.CLAZZ_NAME_ZHIPU, build);
-            }
-            if (ProviderEnum.OLLAMA.name().equals(provider)) {
-                OllamaEmbeddingModel build = OllamaEmbeddingModel
-                        .builder()
-                        .baseUrl(model.getBaseUrl())
-                        .modelName(model.getModel())
-                        .logRequests(true)
-                        .logResponses(true)
-                        .build();
-                contextHolder.registerBean(EmbedConst.CLAZZ_NAME_OLLAMA, build);
-            }
+        } catch (Exception e) {
+            log.error("model 【id{} name{}】 embedding 配置报错", model.getId(), model.getName());
         }
+
     }
 
     private void imageHandler(AigcModel model) {
-        String type = model.getType();
-        String provider = model.getProvider();
-
-        if (ModelTypeEnum.TEXT_IMAGE.name().equals(type)) {
-            if (ProviderEnum.OPENAI.name().equals(provider)) {
-                OpenAiImageModel build = OpenAiImageModel
-                        .builder()
-                        .apiKey(model.getApiKey())
-                        .baseUrl(model.getBaseUrl())
-                        .modelName(model.getModel())
-                        .size(model.getImageSize())
-                        .quality(model.getImageQuality())
-                        .style(model.getImageStyle())
-                        .logRequests(true)
-                        .logResponses(true)
-                        .build();
-                contextHolder.registerBean(model.getId(), build);
-            }
-            if (ProviderEnum.AZURE_OPENAI.name().equals(provider)) {
-                AzureOpenAiImageModel build = AzureOpenAiImageModel
-                        .builder()
-                        .apiKey(model.getApiKey())
-                        .deploymentName(model.getAzureDeploymentName())
-                        .size(model.getImageSize())
-                        .quality(model.getImageQuality())
-                        .style(model.getImageStyle())
-                        .logRequestsAndResponses(true)
-                        .build();
-                contextHolder.registerBean(model.getId(), build);
-            }
-            if (ProviderEnum.ZHIPU.name().equals(provider)) {
-                ZhipuAiImageModel build = ZhipuAiImageModel
-                        .builder()
-                        .apiKey(model.getApiKey())
-                        .model(model.getModel())
-                        .baseUrl(model.getBaseUrl())
-                        .logRequests(true)
-                        .logResponses(true)
-                        .build();
-                contextHolder.registerBean(model.getId(), build);
-            }
+        try {
+            String type = model.getType();
+            if (!ModelTypeEnum.TEXT_IMAGE.name().equals(type)) {
+                return;
+            }
+            modelConfigHandlers.forEach(x -> {
+                ImageModel imageModel = x.imageConfig(model);
+                if (ObjectUtil.isNotEmpty(imageModel)) {
+                    contextHolder.registerBean(model.getId(), imageModel);
+                }
+            });
+        } catch (Exception e) {
+            log.error("model 【id{} name{}】 image 配置报错", model.getId(), model.getName());
         }
+
     }
 }

+ 109 - 0
langchat-core/src/main/java/cn/tycoding/langchat/core/provider/model/config/strategy/AzureOenAIModelConfigHandler.java

@@ -0,0 +1,109 @@
+package cn.tycoding.langchat.core.provider.model.config.strategy;
+
+import cn.hutool.core.lang.Pair;
+import cn.hutool.core.util.StrUtil;
+import cn.tycoding.langchat.biz.component.ProviderEnum;
+import cn.tycoding.langchat.biz.entity.AigcModel;
+import cn.tycoding.langchat.core.consts.EmbedConst;
+import dev.langchain4j.model.azure.AzureOpenAiEmbeddingModel;
+import dev.langchain4j.model.azure.AzureOpenAiImageModel;
+import dev.langchain4j.model.azure.AzureOpenAiStreamingChatModel;
+import dev.langchain4j.model.chat.StreamingChatLanguageModel;
+import dev.langchain4j.model.embedding.DimensionAwareEmbeddingModel;
+import dev.langchain4j.model.image.ImageModel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author GB
+ * @desc
+ * @since  2024-08-19 10:08
+ */
+@Slf4j
+@Component
+public class AzureOenAIModelConfigHandler implements ModelConfigHandler{
+    @Override
+    public boolean whetherCurrentModel(AigcModel model) {
+        return ProviderEnum.AZURE_OPENAI.name().equals(model.getProvider());
+    }
+
+    @Override
+    public boolean basicCheck(AigcModel model) {
+        return !StrUtil.isBlank(model.getApiKey());
+    }
+
+    @Override
+    public StreamingChatLanguageModel chatConfig(AigcModel model) {
+        try{
+            if(!whetherCurrentModel(model)){
+                return null;
+            }
+            if(!basicCheck(model)){
+                log.info("Azure OpenAi 配置信息有误");
+                return null;
+            }
+            return AzureOpenAiStreamingChatModel
+                    .builder()
+                    .apiKey(model.getApiKey())
+                    .endpoint(model.getEndpoint())
+                    .deploymentName(model.getAzureDeploymentName())
+                    .maxTokens(model.getResponseLimit())
+                    .temperature(model.getTemperature())
+                    .logRequestsAndResponses(true)
+                    .topP(model.getTopP())
+                    .build();
+        }catch (Exception e){
+         log.error("AzureOenAI chat 配置报错",e);
+         return null;
+        }
+    }
+
+    @Override
+    public Pair<String, DimensionAwareEmbeddingModel> embeddingConfig(AigcModel model) {
+        try{
+            if(!whetherCurrentModel(model)){
+                return null;
+            }
+            if(!basicCheck(model)){
+                log.info("Azure OpenAi 配置信息有误");
+                return null;
+            }
+            AzureOpenAiEmbeddingModel openAiEmbeddingModel = AzureOpenAiEmbeddingModel
+                    .builder()
+                    .apiKey(model.getApiKey())
+                    .deploymentName(model.getBaseUrl())
+                    .logRequestsAndResponses(true)
+                    .build();
+            return Pair.of(EmbedConst.CLAZZ_NAME_AZURE_OPENAI,openAiEmbeddingModel);
+        }catch (Exception e){
+            log.error("AzureOenAI embedding 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public ImageModel imageConfig(AigcModel model) {
+        try {
+            if(!whetherCurrentModel(model)){
+                return null;
+            }
+            if(!basicCheck(model)){
+                log.info("Azure OpenAi 配置信息有误");
+                return null;
+            }
+            return AzureOpenAiImageModel
+                    .builder()
+                    .apiKey(model.getApiKey())
+                    .deploymentName(model.getAzureDeploymentName())
+                    .size(model.getImageSize())
+                    .quality(model.getImageQuality())
+                    .style(model.getImageStyle())
+                    .logRequestsAndResponses(true)
+                    .build();
+        } catch (Exception e) {
+            log.error("AzureOenAI image 配置报错", e);
+            return null;
+        }
+
+    }
+}

+ 99 - 0
langchat-core/src/main/java/cn/tycoding/langchat/core/provider/model/config/strategy/ClaudeModelConfigHandler.java

@@ -0,0 +1,99 @@
+package cn.tycoding.langchat.core.provider.model.config.strategy;
+
+import cn.hutool.core.lang.Pair;
+import cn.tycoding.langchat.biz.component.ProviderEnum;
+import cn.tycoding.langchat.biz.entity.AigcModel;
+import dev.langchain4j.model.anthropic.AnthropicStreamingChatModel;
+import dev.langchain4j.model.chat.StreamingChatLanguageModel;
+import dev.langchain4j.model.embedding.DimensionAwareEmbeddingModel;
+import dev.langchain4j.model.image.ImageModel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author GB
+ * @desc
+ * @since  2024-08-19 10:08
+ */
+@Slf4j
+@Component
+public class ClaudeModelConfigHandler implements ModelConfigHandler{
+    @Override
+    public boolean whetherCurrentModel(AigcModel model) {
+        return ProviderEnum.CLAUDE.name().equals(model.getProvider());
+    }
+
+    @Override
+    public boolean basicCheck(AigcModel model) {
+        String baseUrl = model.getBaseUrl();
+        if (baseUrl == null) {
+            log.error("Base URL 为空");
+            return false;
+        }
+        if (!baseUrl.endsWith("/")) {
+            model.setBaseUrl(baseUrl + "/");
+        }
+        return true;
+    }
+
+    @Override
+    public StreamingChatLanguageModel chatConfig(AigcModel model) {
+        try{
+            if(!whetherCurrentModel(model)){
+                return null;
+            }
+            if(!basicCheck(model)){
+                log.error("claude 配置信息有误");
+                return null;
+            }
+            return AnthropicStreamingChatModel
+                    .builder()
+                    .apiKey(model.getApiKey())
+                    .baseUrl(model.getBaseUrl())
+                    .modelName(model.getModel())
+                    .temperature(model.getTemperature())
+                    .topP(model.getTopP())
+                    .logRequests(true)
+                    .logResponses(true)
+                    .build();
+        }catch(Exception e){
+            log.error("Claude chat 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public Pair<String, DimensionAwareEmbeddingModel> embeddingConfig(AigcModel model) {
+        try{
+            if(!whetherCurrentModel(model)){
+                return null;
+            }
+            if(!basicCheck(model)){
+                log.error("claude 配置信息有误");
+                return null;
+            }
+            return null;
+        }catch (Exception e){
+            log.error("Claude embedding 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public ImageModel imageConfig(AigcModel model) {
+        try{
+            if(!whetherCurrentModel(model)){
+                return null;
+            }
+            if(!basicCheck(model)){
+                log.error("claude 配置信息有误");
+                return null;
+            }
+            return null;
+        }catch (Exception e){
+            log.error("Claude image 配置报错", e);
+            return null;
+        }
+
+    }
+}

+ 92 - 0
langchat-core/src/main/java/cn/tycoding/langchat/core/provider/model/config/strategy/GeminiModelConfigHandler.java

@@ -0,0 +1,92 @@
+package cn.tycoding.langchat.core.provider.model.config.strategy;
+
+import cn.hutool.core.lang.Pair;
+import cn.hutool.core.util.StrUtil;
+import cn.tycoding.langchat.biz.component.ProviderEnum;
+import cn.tycoding.langchat.biz.entity.AigcModel;
+import dev.langchain4j.model.chat.StreamingChatLanguageModel;
+import dev.langchain4j.model.embedding.DimensionAwareEmbeddingModel;
+import dev.langchain4j.model.image.ImageModel;
+import dev.langchain4j.model.vertexai.VertexAiGeminiStreamingChatModel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author GB
+ * @desc
+ * @date 2024-08-19 10:08
+ */
+@Slf4j
+@Component
+public class GeminiModelConfigHandler implements ModelConfigHandler {
+    @Override
+    public boolean whetherCurrentModel(AigcModel model) {
+        return ProviderEnum.GEMINI.name().equals(model.getProvider());
+    }
+
+    @Override
+    public boolean basicCheck(AigcModel model) {
+        return !StrUtil.isBlank(model.getApiKey()) && !StrUtil.isBlank(model.getSecretKey());
+    }
+
+    @Override
+    public StreamingChatLanguageModel chatConfig(AigcModel model) {
+        try {
+            if(!whetherCurrentModel(model)){
+                return null;
+            }
+            if (!basicCheck(model)) {
+                log.info("Gemini 配置信息有误,无法加载");
+                return null;
+            }
+            return VertexAiGeminiStreamingChatModel
+                    .builder()
+                    .project(model.getGeminiProject())
+                    .location(model.getGeminiLocation())
+                    .modelName(model.getModel())
+                    .temperature(Float.parseFloat(model.getTemperature().toString()))
+                    .maxOutputTokens(model.getResponseLimit())
+                    .logRequests(true)
+                    .logResponses(true)
+                    .topP(Float.parseFloat(model.getTopP().toString()))
+                    .build();
+        } catch (Exception e) {
+            log.error("Gemini 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public Pair<String, DimensionAwareEmbeddingModel> embeddingConfig(AigcModel model) {
+        try {
+            if(!whetherCurrentModel(model)){
+                return null;
+            }
+            if (!basicCheck(model)) {
+                log.info("Gemini 配置信息有误,无法加载");
+                return null;
+            }
+            return null;
+        } catch (Exception e) {
+            return null;
+        }
+
+    }
+
+    @Override
+    public ImageModel imageConfig(AigcModel model) {
+        try {
+            if(!whetherCurrentModel(model)){
+                return null;
+            }
+            if (!basicCheck(model)) {
+                log.info("Gemini 配置信息有误,无法加载");
+                return null;
+            }
+            return null;
+        } catch (Exception e) {
+            return null;
+        }
+
+    }
+}

+ 55 - 0
langchat-core/src/main/java/cn/tycoding/langchat/core/provider/model/config/strategy/ModelConfigHandler.java

@@ -0,0 +1,55 @@
+package cn.tycoding.langchat.core.provider.model.config.strategy;
+
+import cn.hutool.core.lang.Pair;
+import cn.tycoding.langchat.biz.entity.AigcModel;
+import dev.langchain4j.model.chat.StreamingChatLanguageModel;
+import dev.langchain4j.model.embedding.DimensionAwareEmbeddingModel;
+import dev.langchain4j.model.image.ImageModel;
+
+/**
+ * @author GB
+ * @desc 模型装配策略
+ * @since 2024-08-18 09:57
+ */
+public interface ModelConfigHandler {
+    /**
+     * 判断是不是当前模型
+     * @param model
+     * @return
+     */
+    boolean whetherCurrentModel(AigcModel model);
+
+    /**
+     * 基本校验
+     * @param model
+     * @return
+     */
+    boolean basicCheck(AigcModel model);
+
+
+    /**
+     * chat config
+     *
+     * @param model
+     * @return
+     */
+    StreamingChatLanguageModel chatConfig(AigcModel model);
+
+    /**
+     * embedding config
+     *
+     * @param model
+     * @return
+     */
+    Pair<String, DimensionAwareEmbeddingModel> embeddingConfig(AigcModel model);
+
+    /**
+     * image config
+     *
+     * @param model
+     * @return
+     */
+    ImageModel imageConfig(AigcModel model);
+
+
+}

+ 120 - 0
langchat-core/src/main/java/cn/tycoding/langchat/core/provider/model/config/strategy/OenAIModelConfigHandler.java

@@ -0,0 +1,120 @@
+package cn.tycoding.langchat.core.provider.model.config.strategy;
+
+import cn.hutool.core.lang.Pair;
+import cn.hutool.core.util.StrUtil;
+import cn.tycoding.langchat.biz.component.ProviderEnum;
+import cn.tycoding.langchat.biz.entity.AigcModel;
+import cn.tycoding.langchat.core.consts.EmbedConst;
+import dev.langchain4j.model.chat.StreamingChatLanguageModel;
+import dev.langchain4j.model.embedding.DimensionAwareEmbeddingModel;
+import dev.langchain4j.model.image.ImageModel;
+import dev.langchain4j.model.openai.OpenAiEmbeddingModel;
+import dev.langchain4j.model.openai.OpenAiImageModel;
+import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @author GB
+ * @desc
+ * @since 2024-08-19 10:08
+ */
+@Slf4j
+public class OenAIModelConfigHandler implements ModelConfigHandler{
+    @Override
+    public boolean whetherCurrentModel(AigcModel model) {
+        return ProviderEnum.OPENAI.name().equals(model.getProvider());
+    }
+
+    @Override
+    public boolean basicCheck(AigcModel model) {
+        String apiKey = model.getApiKey();
+        if (StrUtil.isBlank(apiKey)) {
+            log.error("openai apikey is null");
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public StreamingChatLanguageModel chatConfig(AigcModel model) {
+        try {
+            if(!whetherCurrentModel(model)){
+                return null;
+            }
+            if (!basicCheck(model)) {
+                log.error("openai 配置信息有误");
+                return null;
+            }
+            return OpenAiStreamingChatModel
+                    .builder()
+                    .apiKey(model.getApiKey())
+                    .baseUrl(model.getBaseUrl())
+                    .modelName(model.getModel())
+                    .maxTokens(model.getResponseLimit())
+                    .temperature(model.getTemperature())
+                    .logRequests(true)
+                    .logResponses(true)
+                    .topP(model.getTopP())
+                    .build();
+        } catch (Exception e) {
+            log.error("openai chat 模型配置报错", e);
+            return null;
+        }
+
+    }
+
+    @Override
+    public Pair<String, DimensionAwareEmbeddingModel> embeddingConfig(AigcModel model) {
+        try {
+            if(!whetherCurrentModel(model)){
+                return null;
+            }
+            if (!basicCheck(model)) {
+                log.error("openai 配置信息有误");
+                return null;
+            }
+            OpenAiEmbeddingModel openAiEmbeddingModel = OpenAiEmbeddingModel
+                    .builder()
+                    .apiKey(model.getApiKey())
+                    .baseUrl(model.getBaseUrl())
+                    .modelName(model.getModel())
+                    .dimensions(model.getDimensions())
+                    .logRequests(true)
+                    .logResponses(true)
+                    .build();
+            return Pair.of(EmbedConst.CLAZZ_NAME_OPENAI,openAiEmbeddingModel);
+        } catch (Exception e) {
+            log.error("openai embedding 模型配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public ImageModel imageConfig(AigcModel model) {
+        try {
+            if(!whetherCurrentModel(model)){
+                return null;
+            }
+            if (!basicCheck(model)) {
+                log.error("openai 配置信息有误");
+                return null;
+            }
+            return OpenAiImageModel
+                    .builder()
+                    .apiKey(model.getApiKey())
+                    .baseUrl(model.getBaseUrl())
+                    .modelName(model.getModel())
+                    .size(model.getImageSize())
+                    .quality(model.getImageQuality())
+                    .style(model.getImageStyle())
+                    .logRequests(true)
+                    .logResponses(true)
+                    .build();
+        } catch (Exception e) {
+            log.error("openai image 模型配置报错", e);
+            return null;
+        }
+
+
+    }
+}

+ 98 - 0
langchat-core/src/main/java/cn/tycoding/langchat/core/provider/model/config/strategy/OllamaModelConfigHandler.java

@@ -0,0 +1,98 @@
+package cn.tycoding.langchat.core.provider.model.config.strategy;
+
+import cn.hutool.core.lang.Pair;
+import cn.tycoding.langchat.biz.component.ProviderEnum;
+import cn.tycoding.langchat.biz.entity.AigcModel;
+import cn.tycoding.langchat.core.consts.EmbedConst;
+import dev.langchain4j.model.chat.StreamingChatLanguageModel;
+import dev.langchain4j.model.embedding.DimensionAwareEmbeddingModel;
+import dev.langchain4j.model.image.ImageModel;
+import dev.langchain4j.model.ollama.OllamaEmbeddingModel;
+import dev.langchain4j.model.ollama.OllamaStreamingChatModel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author GB
+ * @desc
+ * @date 2024-08-19 10:08
+ */
+@Slf4j
+@Component
+public class OllamaModelConfigHandler implements ModelConfigHandler{
+    @Override
+    public boolean whetherCurrentModel(AigcModel model) {
+        return ProviderEnum.OLLAMA.name().equals(model.getProvider());
+    }
+
+    @Override
+    public boolean basicCheck(AigcModel model) {
+        return true;
+    }
+
+    @Override
+    public StreamingChatLanguageModel chatConfig(AigcModel model) {
+        try{
+            if(!whetherCurrentModel(model)){
+                return null;
+            }
+            if(!basicCheck(model)){
+                log.error("Ollama embedding 配置信息有误");
+                return null;
+            }
+            return OllamaStreamingChatModel
+                    .builder()
+                    .baseUrl(model.getBaseUrl())
+                    .modelName(model.getModel())
+                    .temperature(model.getTemperature())
+                    .topP(model.getTopP())
+                    .logRequests(true)
+                    .logResponses(true)
+                    .build();
+        }catch (Exception e){
+            log.error("Ollama chat 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public Pair<String, DimensionAwareEmbeddingModel> embeddingConfig(AigcModel model) {
+        try {
+            if(!whetherCurrentModel(model)){
+                return null;
+            }
+            if(!basicCheck(model)){
+                log.error("Ollama embedding 配置信息有误");
+                return null;
+            }
+            OllamaEmbeddingModel ollamaEmbeddingModel = OllamaEmbeddingModel
+                    .builder()
+                    .baseUrl(model.getBaseUrl())
+                    .modelName(model.getModel())
+                    .logRequests(true)
+                    .logResponses(true)
+                    .build();
+            return Pair.of(EmbedConst.CLAZZ_NAME_OLLAMA, ollamaEmbeddingModel);
+        } catch (Exception e) {
+            log.error("Ollama embedding 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public ImageModel imageConfig(AigcModel model) {
+        try {
+            if(!whetherCurrentModel(model)){
+                return null;
+            }
+            if(!basicCheck(model)){
+                log.error("Ollama embedding 配置信息有误");
+                return null;
+            }
+            return null;
+        } catch (Exception e) {
+            log.error("Ollama image 配置报错", e);
+            return null;
+        }
+    }
+}

+ 103 - 0
langchat-core/src/main/java/cn/tycoding/langchat/core/provider/model/config/strategy/QFanModelConfigHandler.java

@@ -0,0 +1,103 @@
+package cn.tycoding.langchat.core.provider.model.config.strategy;
+
+import cn.hutool.core.lang.Pair;
+import cn.tycoding.langchat.biz.component.ProviderEnum;
+import cn.tycoding.langchat.biz.entity.AigcModel;
+import cn.tycoding.langchat.core.consts.EmbedConst;
+import dev.langchain4j.model.chat.StreamingChatLanguageModel;
+import dev.langchain4j.model.embedding.DimensionAwareEmbeddingModel;
+import dev.langchain4j.model.image.ImageModel;
+import dev.langchain4j.model.qianfan.QianfanEmbeddingModel;
+import dev.langchain4j.model.qianfan.QianfanStreamingChatModel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author GB
+ * @desc
+ * @since 2024-08-19 10:08
+ */
+@Slf4j
+@Component
+public class QFanModelConfigHandler implements ModelConfigHandler {
+    @Override
+    public boolean whetherCurrentModel(AigcModel model) {
+        return ProviderEnum.Q_FAN.name().equals(model.getProvider());
+    }
+
+    @Override
+    public boolean basicCheck(AigcModel model) {
+        return true;
+    }
+
+    @Override
+    public StreamingChatLanguageModel chatConfig(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                log.error("qiafan  配置信息有误");
+                return null;
+            }
+            return QianfanStreamingChatModel
+                    .builder()
+                    .apiKey(model.getApiKey())
+                    .secretKey(model.getSecretKey())
+                    .modelName(model.getModel())
+                    .baseUrl(model.getBaseUrl())
+                    .temperature(model.getTemperature())
+                    .topP(model.getTopP())
+                    .logRequests(true)
+                    .logResponses(true)
+                    .build();
+
+        } catch (Exception e) {
+            log.error("Qianfan chat 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public Pair<String, DimensionAwareEmbeddingModel> embeddingConfig(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                log.error("qiafan  配置信息有误");
+                return null;
+            }
+            QianfanEmbeddingModel qianfanEmbeddingModel = QianfanEmbeddingModel
+                    .builder()
+                    .apiKey(model.getApiKey())
+                    .modelName(model.getModel())
+                    .secretKey(model.getSecretKey())
+                    .logRequests(true)
+                    .logResponses(true)
+                    .build();
+            return Pair.of(EmbedConst.CLAZZ_NAME_QIANFAN, qianfanEmbeddingModel);
+        } catch (Exception e) {
+            log.error("Qianfan embedding 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public ImageModel imageConfig(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                log.error("qiafan  配置信息有误");
+                return null;
+            }
+            return null;
+        } catch (Exception e) {
+            log.error("Qianfan image 配置报错", e);
+            return null;
+        }
+
+    }
+}

+ 97 - 0
langchat-core/src/main/java/cn/tycoding/langchat/core/provider/model/config/strategy/QWenModelConfigHandler.java

@@ -0,0 +1,97 @@
+package cn.tycoding.langchat.core.provider.model.config.strategy;
+
+import cn.hutool.core.lang.Pair;
+import cn.tycoding.langchat.biz.component.ProviderEnum;
+import cn.tycoding.langchat.biz.entity.AigcModel;
+import cn.tycoding.langchat.core.consts.EmbedConst;
+import dev.langchain4j.model.chat.StreamingChatLanguageModel;
+import dev.langchain4j.model.dashscope.QwenEmbeddingModel;
+import dev.langchain4j.model.dashscope.QwenStreamingChatModel;
+import dev.langchain4j.model.embedding.DimensionAwareEmbeddingModel;
+import dev.langchain4j.model.image.ImageModel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author GB
+ * @desc
+ * @date 2024-08-19 10:08
+ */
+@Slf4j
+@Component
+public class QWenModelConfigHandler implements ModelConfigHandler {
+    @Override
+    public boolean whetherCurrentModel(AigcModel model) {
+        return ProviderEnum.Q_WEN.name().equals(model.getProvider());
+    }
+
+    @Override
+    public boolean basicCheck(AigcModel model) {
+        return true;
+    }
+
+    @Override
+    public StreamingChatLanguageModel chatConfig(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                log.error("qianwen  配置信息有误");
+                return null;
+            }
+            return QwenStreamingChatModel
+                    .builder()
+                    .apiKey(model.getApiKey())
+                    .modelName(model.getModel())
+                    .baseUrl(model.getBaseUrl())
+                    .maxTokens(model.getResponseLimit())
+                    .temperature(Float.parseFloat(model.getTemperature().toString()))
+                    .topP(model.getTopP())
+                    .build();
+        } catch (Exception e) {
+            log.error("qian wen chat 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public Pair<String, DimensionAwareEmbeddingModel> embeddingConfig(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                log.error("qianwen  配置信息有误");
+                return null;
+            }
+            QwenEmbeddingModel qwenEmbeddingModel = QwenEmbeddingModel
+                    .builder()
+                    .apiKey(model.getApiKey())
+                    .modelName(model.getModel())
+                    .build();
+            return Pair.of(EmbedConst.CLAZZ_NAME_QIANWEN, qwenEmbeddingModel);
+        } catch (Exception e) {
+            log.error("qian wen embedding 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public ImageModel imageConfig(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                log.error("qianwen  配置信息有误");
+                return null;
+            }
+            return null;
+        } catch (Exception e) {
+            log.error("qian wen image 配置报错", e);
+            return null;
+        }
+
+    }
+}

+ 110 - 0
langchat-core/src/main/java/cn/tycoding/langchat/core/provider/model/config/strategy/ZhiPuModelConfigHandler.java

@@ -0,0 +1,110 @@
+package cn.tycoding.langchat.core.provider.model.config.strategy;
+
+import cn.hutool.core.lang.Pair;
+import cn.tycoding.langchat.biz.component.ProviderEnum;
+import cn.tycoding.langchat.biz.entity.AigcModel;
+import cn.tycoding.langchat.core.consts.EmbedConst;
+import dev.langchain4j.model.chat.StreamingChatLanguageModel;
+import dev.langchain4j.model.embedding.DimensionAwareEmbeddingModel;
+import dev.langchain4j.model.image.ImageModel;
+import dev.langchain4j.model.zhipu.ZhipuAiEmbeddingModel;
+import dev.langchain4j.model.zhipu.ZhipuAiImageModel;
+import dev.langchain4j.model.zhipu.ZhipuAiStreamingChatModel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author GB
+ * @desc
+ * @since 2024-08-19
+ */
+@Slf4j
+@Component
+public class ZhiPuModelConfigHandler implements ModelConfigHandler{
+    @Override
+    public boolean whetherCurrentModel(AigcModel model) {
+        return ProviderEnum.ZHIPU.name().equals(model.getProvider());
+    }
+
+    @Override
+    public boolean basicCheck(AigcModel model) {
+        return true;
+    }
+
+    @Override
+    public StreamingChatLanguageModel chatConfig(AigcModel model) {
+        try{
+            if(!whetherCurrentModel(model)){
+                return null;
+            }
+            if(!basicCheck(model)){
+                log.error("zhipu 配置信息有误");
+                return null;
+            }
+            return ZhipuAiStreamingChatModel
+                    .builder()
+                    .apiKey(model.getApiKey())
+                    .baseUrl(model.getBaseUrl())
+                    .model(model.getModel())
+                    .maxToken(model.getResponseLimit())
+                    .temperature(model.getTemperature())
+                    .topP(model.getTopP())
+                    .logRequests(true)
+                    .logResponses(true)
+                    .build();
+        }catch(Exception e){
+            log.error("zhipu chat 配置报错", e);
+            return null;
+        }
+
+    }
+
+    @Override
+    public Pair<String, DimensionAwareEmbeddingModel> embeddingConfig(AigcModel model) {
+        try{
+            if(!whetherCurrentModel(model)){
+                return null;
+            }
+            if(!basicCheck(model)){
+                log.error("zhipu 配置信息有误");
+                return null;
+            }
+            ZhipuAiEmbeddingModel zhipuAiEmbeddingModel = ZhipuAiEmbeddingModel
+                    .builder()
+                    .apiKey(model.getApiKey())
+                    .model(model.getModel())
+                    .baseUrl(model.getBaseUrl())
+                    .logRequests(true)
+                    .logResponses(true)
+                    .build();
+            return Pair.of(EmbedConst.CLAZZ_NAME_ZHIPU, zhipuAiEmbeddingModel);
+        }catch (Exception e){
+            log.error("zhipu embedding 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public ImageModel imageConfig(AigcModel model) {
+        try{
+            if(!whetherCurrentModel(model)){
+                return null;
+            }
+            if(!basicCheck(model)){
+                log.error("zhipu 配置信息有误");
+                return null;
+            }
+           return  ZhipuAiImageModel
+                    .builder()
+                    .apiKey(model.getApiKey())
+                    .model(model.getModel())
+                    .baseUrl(model.getBaseUrl())
+                    .logRequests(true)
+                    .logResponses(true)
+                    .build();
+        }catch (Exception e){
+            log.error("zhipu image 配置报错", e);
+            return null;
+        }
+    }
+}