Browse Source

Merge pull request #5 from GBHBY/gbhblt

fix model dynamic config
TyCoding 1 year ago
parent
commit
d21ad53db5

+ 34 - 0
langchat-common/src/main/java/cn/tycoding/langchat/common/enums/ChatErrorEnum.java

@@ -0,0 +1,34 @@
+package cn.tycoding.langchat.common.enums;
+
+import lombok.AllArgsConstructor;
+
+/**
+ * @author GB
+ * @desc
+ * @since 2024-08-21
+ */
+@AllArgsConstructor
+public enum ChatErrorEnum {
+    API_KEY_IS_NULL(1000, "模型 %s %s api key 为空,请检查配置"),
+    BASE_URL_IS_NULL(1003, "模型 %s %s base url 为空,请检查配置"),
+    SECRET_KEY_IS_NULL(1005, "模型 %s %s base secret Key 为空,请检查配置"),
+    ;
+
+    /**
+     * 错误码
+     */
+    private int errorCode;
+    /**
+     * 错误描述,用于展示给用户
+     */
+    private String errorDesc;
+
+    public int getErrorCode() {
+        return this.errorCode;
+    }
+
+    public String getErrorDesc(String modelName, String type) {
+        return this.errorDesc.formatted(modelName, type);
+    }
+
+}

+ 48 - 246
langchat-core/src/main/java/cn/tycoding/langchat/core/provider/ProviderInitialize.java

@@ -16,31 +16,19 @@
 
 package cn.tycoding.langchat.core.provider;
 
-import cn.hutool.core.util.StrUtil;
+import cn.hutool.core.lang.Pair;
+import cn.hutool.core.util.ObjectUtil;
 import cn.tycoding.langchat.biz.component.ModelTypeEnum;
-import cn.tycoding.langchat.biz.component.ProviderEnum;
 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 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.dashscope.QwenEmbeddingModel;
-import dev.langchain4j.model.dashscope.QwenStreamingChatModel;
-import dev.langchain4j.model.ollama.OllamaEmbeddingModel;
-import dev.langchain4j.model.ollama.OllamaStreamingChatModel;
-import dev.langchain4j.model.openai.OpenAiEmbeddingModel;
-import dev.langchain4j.model.openai.OpenAiImageModel;
-import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
-import dev.langchain4j.model.qianfan.QianfanEmbeddingModel;
-import dev.langchain4j.model.qianfan.QianfanStreamingChatModel;
-import dev.langchain4j.model.vertexai.VertexAiGeminiStreamingChatModel;
-import dev.langchain4j.model.zhipu.ZhipuAiEmbeddingModel;
-import dev.langchain4j.model.zhipu.ZhipuAiImageModel;
-import dev.langchain4j.model.zhipu.ZhipuAiStreamingChatModel;
+import cn.tycoding.langchat.core.provider.model.config.strategy.ModelConfigHandler;
+import dev.langchain4j.model.chat.StreamingChatLanguageModel;
+import dev.langchain4j.model.embedding.DimensionAwareEmbeddingModel;
+import dev.langchain4j.model.image.ImageModel;
 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 +43,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 +78,55 @@ 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;
+        try {
+            String type = model.getType();
+            if (!ModelTypeEnum.CHAT.name().equals(type)) {
+                return;
+            }
+            modelConfigHandlers.forEach(x -> {
+                StreamingChatLanguageModel streamingChatLanguageModel = x.buildStreamingChat(model);
+                if (ObjectUtil.isNotEmpty(streamingChatLanguageModel)) {
+                    contextHolder.registerBean(model.getId(), streamingChatLanguageModel);
                 }
-                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() + "/");
-                }
-                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: {}】streaming 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.buildEmbedding(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.buildImage(model);
+                if (ObjectUtil.isNotEmpty(imageModel)) {
+                    contextHolder.registerBean(model.getId(), imageModel);
+                }
+            });
+        } catch (Exception e) {
+            log.error("model 【id{} name{}】 image 配置报错", model.getId(), model.getName());
         }
     }
 }

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

@@ -0,0 +1,147 @@
+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.common.enums.ChatErrorEnum;
+import cn.tycoding.langchat.common.exception.ServiceException;
+import cn.tycoding.langchat.core.consts.EmbedConst;
+import dev.langchain4j.model.azure.AzureOpenAiChatModel;
+import dev.langchain4j.model.azure.AzureOpenAiEmbeddingModel;
+import dev.langchain4j.model.azure.AzureOpenAiImageModel;
+import dev.langchain4j.model.azure.AzureOpenAiStreamingChatModel;
+import dev.langchain4j.model.chat.ChatLanguageModel;
+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 buildStreamingChat(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                throw new ServiceException(ChatErrorEnum.API_KEY_IS_NULL.getErrorCode(),
+                        ChatErrorEnum.API_KEY_IS_NULL.getErrorDesc(ProviderEnum.AZURE_OPENAI.name(), model.getType()));
+            }
+            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 (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("AzureOenAI chat 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public ChatLanguageModel buildChatLanguageModel(AigcModel model) {
+        if (!whetherCurrentModel(model)) {
+            return null;
+        }
+        if (!basicCheck(model)) {
+            throw new ServiceException(ChatErrorEnum.API_KEY_IS_NULL.getErrorCode(),
+                    ChatErrorEnum.API_KEY_IS_NULL.getErrorDesc(ProviderEnum.AZURE_OPENAI.name(), model.getType()));
+        }
+        try {
+            return AzureOpenAiChatModel.builder()
+                    .apiKey(model.getApiKey())
+                    .endpoint(model.getEndpoint())
+                    .deploymentName(model.getAzureDeploymentName())
+                    .maxTokens(model.getResponseLimit())
+                    .temperature(model.getTemperature())
+                    .logRequestsAndResponses(true)
+                    .topP(model.getTopP()).build();
+        } catch (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("AzureOenAI chat 配置报错", e);
+            return null;
+        }
+
+    }
+
+    @Override
+    public Pair<String, DimensionAwareEmbeddingModel> buildEmbedding(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                throw new ServiceException(ChatErrorEnum.API_KEY_IS_NULL.getErrorCode(),
+                        ChatErrorEnum.API_KEY_IS_NULL.getErrorDesc(ProviderEnum.AZURE_OPENAI.name(), model.getType()));
+            }
+            AzureOpenAiEmbeddingModel openAiEmbeddingModel = AzureOpenAiEmbeddingModel
+                    .builder()
+                    .apiKey(model.getApiKey())
+                    .deploymentName(model.getBaseUrl())
+                    .logRequestsAndResponses(true)
+                    .build();
+            return Pair.of(EmbedConst.CLAZZ_NAME_AZURE_OPENAI, openAiEmbeddingModel);
+        } catch (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("AzureOenAI embedding 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public ImageModel buildImage(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                throw new ServiceException(ChatErrorEnum.API_KEY_IS_NULL.getErrorCode(),
+                        ChatErrorEnum.API_KEY_IS_NULL.getErrorDesc(ProviderEnum.AZURE_OPENAI.name(), model.getType()));
+            }
+            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;
+        }
+
+    }
+}

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

@@ -0,0 +1,146 @@
+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.common.enums.ChatErrorEnum;
+import cn.tycoding.langchat.common.exception.ServiceException;
+import dev.langchain4j.model.anthropic.AnthropicChatModel;
+import dev.langchain4j.model.anthropic.AnthropicStreamingChatModel;
+import dev.langchain4j.model.chat.ChatLanguageModel;
+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) {
+        if (model.getBaseUrl() == null) {
+            throw new ServiceException(ChatErrorEnum.BASE_URL_IS_NULL.getErrorCode(),
+                    ChatErrorEnum.BASE_URL_IS_NULL.getErrorDesc(ProviderEnum.CLAUDE.name(), model.getType()));
+        }
+
+        return true;
+    }
+
+    @Override
+    public StreamingChatLanguageModel buildStreamingChat(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                return null;
+            }
+            if (!model.getBaseUrl().endsWith("/")) {
+                model.setBaseUrl(model.getBaseUrl() + "/");
+            }
+            return AnthropicStreamingChatModel
+                    .builder()
+                    .apiKey(model.getApiKey())
+                    .baseUrl(model.getBaseUrl())
+                    .modelName(model.getModel())
+                    .temperature(model.getTemperature())
+                    .topP(model.getTopP())
+                    .logRequests(true)
+                    .logResponses(true)
+                    .build();
+        } catch (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("Claude chat 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public ChatLanguageModel buildChatLanguageModel(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                return null;
+            }
+            if (!model.getBaseUrl().endsWith("/")) {
+                model.setBaseUrl(model.getBaseUrl() + "/");
+            }
+            return AnthropicChatModel
+                    .builder()
+                    .apiKey(model.getApiKey())
+                    .baseUrl(model.getBaseUrl())
+                    .modelName(model.getModel())
+                    .temperature(model.getTemperature())
+                    .topP(model.getTopP())
+                    .logRequests(true)
+                    .logResponses(true)
+                    .build();
+        } catch (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("Claude chat 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public Pair<String, DimensionAwareEmbeddingModel> buildEmbedding(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                return null;
+            }
+            if (!model.getBaseUrl().endsWith("/")) {
+                model.setBaseUrl(model.getBaseUrl() + "/");
+            }
+            return null;
+        } catch (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("Claude embedding 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public ImageModel buildImage(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                return null;
+            }
+            if (!model.getBaseUrl().endsWith("/")) {
+                model.setBaseUrl(model.getBaseUrl() + "/");
+            }
+            return null;
+        } catch (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("Claude image 配置报错", e);
+            return null;
+        }
+
+    }
+}

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

@@ -0,0 +1,139 @@
+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.common.enums.ChatErrorEnum;
+import cn.tycoding.langchat.common.exception.ServiceException;
+import dev.langchain4j.model.chat.ChatLanguageModel;
+import dev.langchain4j.model.chat.StreamingChatLanguageModel;
+import dev.langchain4j.model.embedding.DimensionAwareEmbeddingModel;
+import dev.langchain4j.model.image.ImageModel;
+import dev.langchain4j.model.vertexai.VertexAiGeminiChatModel;
+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) {
+        if (!StrUtil.isBlank(model.getApiKey())) {
+            throw new ServiceException(ChatErrorEnum.API_KEY_IS_NULL.getErrorCode(),
+                    ChatErrorEnum.BASE_URL_IS_NULL.getErrorDesc(ProviderEnum.GEMINI.name(), model.getType()));
+        }
+        if (!StrUtil.isBlank(model.getSecretKey())) {
+            throw new ServiceException(ChatErrorEnum.SECRET_KEY_IS_NULL.getErrorCode(),
+                    ChatErrorEnum.SECRET_KEY_IS_NULL.getErrorDesc(ProviderEnum.GEMINI.name(), model.getType()));
+        }
+        return !StrUtil.isBlank(model.getApiKey()) && !StrUtil.isBlank(model.getSecretKey());
+    }
+
+    @Override
+    public StreamingChatLanguageModel buildStreamingChat(AigcModel model) {
+        try {
+            if(!whetherCurrentModel(model)){
+                return null;
+            }
+            if (!basicCheck(model)) {
+                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 (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("Gemini 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public ChatLanguageModel buildChatLanguageModel(AigcModel model) {
+        try {
+            if(!whetherCurrentModel(model)){
+                return null;
+            }
+            if (!basicCheck(model)) {
+                return null;
+            }
+            return VertexAiGeminiChatModel
+                    .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 (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("Gemini 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public Pair<String, DimensionAwareEmbeddingModel> buildEmbedding(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                return null;
+            }
+            return null;
+        } catch (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            return null;
+        }
+
+    }
+
+    @Override
+    public ImageModel buildImage(AigcModel model) {
+        try {
+            if(!whetherCurrentModel(model)){
+                return null;
+            }
+            if (!basicCheck(model)) {
+                return null;
+            }
+            return null;
+        } catch (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            return null;
+        }
+
+    }
+}

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

@@ -0,0 +1,58 @@
+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.ChatLanguageModel;
+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);
+
+
+    /**
+     * streaming chat config
+     *
+     * @param model
+     * @return
+     */
+    StreamingChatLanguageModel buildStreamingChat(AigcModel model);
+
+    ChatLanguageModel buildChatLanguageModel(AigcModel model);
+
+    /**
+     * embedding config
+     *
+     * @param model
+     * @return
+     */
+    Pair<String, DimensionAwareEmbeddingModel> buildEmbedding(AigcModel model);
+
+    /**
+     * image config
+     *
+     * @param model
+     * @return
+     */
+    ImageModel buildImage(AigcModel model);
+
+
+}

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

@@ -0,0 +1,158 @@
+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.common.enums.ChatErrorEnum;
+import cn.tycoding.langchat.common.exception.ServiceException;
+import cn.tycoding.langchat.core.consts.EmbedConst;
+import dev.langchain4j.model.chat.ChatLanguageModel;
+import dev.langchain4j.model.chat.StreamingChatLanguageModel;
+import dev.langchain4j.model.embedding.DimensionAwareEmbeddingModel;
+import dev.langchain4j.model.image.ImageModel;
+import dev.langchain4j.model.openai.OpenAiChatModel;
+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)) {
+            throw new ServiceException(ChatErrorEnum.API_KEY_IS_NULL.getErrorCode(),
+                    ChatErrorEnum.API_KEY_IS_NULL.getErrorDesc(ProviderEnum.OPENAI.name(), model.getType()));
+        }
+        return true;
+    }
+
+    @Override
+    public StreamingChatLanguageModel buildStreamingChat(AigcModel model) {
+        try {
+            if(!whetherCurrentModel(model)){
+                return null;
+            }
+            if (!basicCheck(model)) {
+                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 (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("openai chat 模型配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public ChatLanguageModel buildChatLanguageModel(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                return null;
+            }
+            return OpenAiChatModel
+                    .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 (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("openai chat 模型配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public Pair<String, DimensionAwareEmbeddingModel> buildEmbedding(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                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 (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("openai embedding 模型配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public ImageModel buildImage(AigcModel model) {
+        try {
+            if(!whetherCurrentModel(model)){
+                return null;
+            }
+            if (!basicCheck(model)) {
+                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 (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("openai image 模型配置报错", e);
+            return null;
+        }
+
+
+    }
+}

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

@@ -0,0 +1,140 @@
+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.common.enums.ChatErrorEnum;
+import cn.tycoding.langchat.common.exception.ServiceException;
+import cn.tycoding.langchat.core.consts.EmbedConst;
+import dev.langchain4j.model.chat.ChatLanguageModel;
+import dev.langchain4j.model.chat.StreamingChatLanguageModel;
+import dev.langchain4j.model.embedding.DimensionAwareEmbeddingModel;
+import dev.langchain4j.model.image.ImageModel;
+import dev.langchain4j.model.ollama.OllamaChatModel;
+import dev.langchain4j.model.ollama.OllamaEmbeddingModel;
+import dev.langchain4j.model.ollama.OllamaStreamingChatModel;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+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) {
+        if (StringUtils.isBlank(model.getBaseUrl())) {
+            throw new ServiceException(ChatErrorEnum.BASE_URL_IS_NULL.getErrorCode(),
+                    ChatErrorEnum.BASE_URL_IS_NULL.getErrorDesc(ProviderEnum.OLLAMA.name(), model.getType()));
+        }
+        return true;
+    }
+
+    @Override
+    public StreamingChatLanguageModel buildStreamingChat(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                return null;
+            }
+            return OllamaStreamingChatModel
+                    .builder()
+                    .baseUrl(model.getBaseUrl())
+                    .modelName(model.getModel())
+                    .temperature(model.getTemperature())
+                    .topP(model.getTopP())
+                    .logRequests(true)
+                    .logResponses(true)
+                    .build();
+        } catch (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("Ollama streaming chat 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public ChatLanguageModel buildChatLanguageModel(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                return null;
+            }
+            return OllamaChatModel
+                    .builder()
+                    .baseUrl(model.getBaseUrl())
+                    .modelName(model.getModel())
+                    .temperature(model.getTemperature())
+                    .topP(model.getTopP())
+                    .logRequests(true)
+                    .logResponses(true)
+                    .build();
+        } catch (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("Ollama chat 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public Pair<String, DimensionAwareEmbeddingModel> buildEmbedding(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                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 (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("Ollama embedding 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public ImageModel buildImage(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                return null;
+            }
+            return null;
+        } catch (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("Ollama image 配置报错", e);
+            return null;
+        }
+    }
+}

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

@@ -0,0 +1,152 @@
+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.common.enums.ChatErrorEnum;
+import cn.tycoding.langchat.common.exception.ServiceException;
+import cn.tycoding.langchat.core.consts.EmbedConst;
+import dev.langchain4j.model.chat.ChatLanguageModel;
+import dev.langchain4j.model.chat.StreamingChatLanguageModel;
+import dev.langchain4j.model.embedding.DimensionAwareEmbeddingModel;
+import dev.langchain4j.model.image.ImageModel;
+import dev.langchain4j.model.qianfan.QianfanChatModel;
+import dev.langchain4j.model.qianfan.QianfanEmbeddingModel;
+import dev.langchain4j.model.qianfan.QianfanStreamingChatModel;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+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) {
+        if (StringUtils.isBlank(model.getApiKey())) {
+            throw new ServiceException(ChatErrorEnum.API_KEY_IS_NULL.getErrorCode(),
+                    ChatErrorEnum.API_KEY_IS_NULL.getErrorDesc(ProviderEnum.Q_FAN.name(), model.getType()));
+        }
+        if (StringUtils.isBlank(model.getSecretKey())) {
+            throw new ServiceException(ChatErrorEnum.SECRET_KEY_IS_NULL.getErrorCode(),
+                    ChatErrorEnum.SECRET_KEY_IS_NULL.getErrorDesc(ProviderEnum.Q_FAN.name(), model.getType()));
+        }
+        return true;
+    }
+
+    @Override
+    public StreamingChatLanguageModel buildStreamingChat(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                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 (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("Qianfan  streaming chat 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public ChatLanguageModel buildChatLanguageModel(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                return null;
+            }
+            return QianfanChatModel
+                    .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 (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("Qianfan chat 配置报错", e);
+            return null;
+        }
+
+
+    }
+
+    @Override
+    public Pair<String, DimensionAwareEmbeddingModel> buildEmbedding(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                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 (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("Qianfan embedding 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public ImageModel buildImage(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                return null;
+            }
+            return null;
+        } catch (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("Qianfan image 配置报错", e);
+            return null;
+        }
+
+    }
+}

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

@@ -0,0 +1,139 @@
+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.common.enums.ChatErrorEnum;
+import cn.tycoding.langchat.common.exception.ServiceException;
+import cn.tycoding.langchat.core.consts.EmbedConst;
+import dev.langchain4j.model.chat.ChatLanguageModel;
+import dev.langchain4j.model.chat.StreamingChatLanguageModel;
+import dev.langchain4j.model.dashscope.QwenChatModel;
+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.apache.commons.lang3.StringUtils;
+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) {
+        if (StringUtils.isBlank(model.getApiKey())) {
+            throw new ServiceException(ChatErrorEnum.API_KEY_IS_NULL.getErrorCode(),
+                    ChatErrorEnum.API_KEY_IS_NULL.getErrorDesc(ProviderEnum.Q_WEN.name(), model.getType()));
+        }
+        return true;
+    }
+
+    @Override
+    public StreamingChatLanguageModel buildStreamingChat(AigcModel model) {
+        if (!whetherCurrentModel(model)) {
+            return null;
+        }
+        if (!basicCheck(model)) {
+            return null;
+        }
+        try {
+            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 (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("qian wen streaming chat 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public ChatLanguageModel buildChatLanguageModel(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                return null;
+            }
+            return QwenChatModel
+                    .builder()
+                    .apiKey(model.getApiKey())
+                    .modelName(model.getModel())
+                    .baseUrl(model.getBaseUrl())
+                    .maxTokens(model.getResponseLimit())
+                    .temperature(Float.parseFloat(model.getTemperature().toString()))
+                    .topP(model.getTopP())
+                    .build();
+        } catch (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("qian wen chat 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public Pair<String, DimensionAwareEmbeddingModel> buildEmbedding(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                return null;
+            }
+            QwenEmbeddingModel qwenEmbeddingModel = QwenEmbeddingModel
+                    .builder()
+                    .apiKey(model.getApiKey())
+                    .modelName(model.getModel())
+                    .build();
+            return Pair.of(EmbedConst.CLAZZ_NAME_QIANWEN, qwenEmbeddingModel);
+        } catch (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("qian wen embedding 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public ImageModel buildImage(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                return null;
+            }
+            return null;
+        } catch (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("qian wen image 配置报错", e);
+            return null;
+        }
+
+    }
+}

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

@@ -0,0 +1,159 @@
+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.common.enums.ChatErrorEnum;
+import cn.tycoding.langchat.common.exception.ServiceException;
+import cn.tycoding.langchat.core.consts.EmbedConst;
+import dev.langchain4j.model.chat.ChatLanguageModel;
+import dev.langchain4j.model.chat.StreamingChatLanguageModel;
+import dev.langchain4j.model.embedding.DimensionAwareEmbeddingModel;
+import dev.langchain4j.model.image.ImageModel;
+import dev.langchain4j.model.zhipu.ZhipuAiChatModel;
+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.apache.commons.lang3.StringUtils;
+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) {
+        if (StringUtils.isBlank(model.getBaseUrl())) {
+            throw new ServiceException(ChatErrorEnum.BASE_URL_IS_NULL.getErrorCode(),
+                    ChatErrorEnum.BASE_URL_IS_NULL.getErrorDesc(ProviderEnum.ZHIPU.name(), model.getType()));
+        }
+        if (StringUtils.isBlank(model.getApiKey())) {
+            throw new ServiceException(ChatErrorEnum.API_KEY_IS_NULL.getErrorCode(),
+                    ChatErrorEnum.API_KEY_IS_NULL.getErrorDesc(ProviderEnum.ZHIPU.name(), model.getType()));
+        }
+        return true;
+    }
+
+    @Override
+    public StreamingChatLanguageModel buildStreamingChat(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                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 (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("zhipu streaming chat 配置报错", e);
+            return null;
+        }
+
+    }
+
+    @Override
+    public ChatLanguageModel buildChatLanguageModel(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                return null;
+            }
+            return ZhipuAiChatModel
+                    .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 (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("zhipu chat 配置报错", e);
+            return null;
+        }
+
+    }
+
+    @Override
+    public Pair<String, DimensionAwareEmbeddingModel> buildEmbedding(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                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 (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("zhipu embedding 配置报错", e);
+            return null;
+        }
+    }
+
+    @Override
+    public ImageModel buildImage(AigcModel model) {
+        try {
+            if (!whetherCurrentModel(model)) {
+                return null;
+            }
+            if (!basicCheck(model)) {
+                return null;
+            }
+            return ZhipuAiImageModel
+                    .builder()
+                    .apiKey(model.getApiKey())
+                    .model(model.getModel())
+                    .baseUrl(model.getBaseUrl())
+                    .logRequests(true)
+                    .logResponses(true)
+                    .build();
+        } catch (ServiceException e) {
+            log.error(e.getMessage());
+            throw e;
+        } catch (Exception e) {
+            log.error("zhipu image 配置报错", e);
+            return null;
+        }
+    }
+}