sorelythrob 2 тижнів тому
батько
коміт
8f52f8eff4

+ 15 - 0
webchat-aigc/src/main/java/com/webchat/aigc/config/properties/AliBaiLianLLMPropertiesConfig.java

@@ -0,0 +1,15 @@
+package com.webchat.aigc.config.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Data
+@Component
+@ConfigurationProperties(prefix = "llm.config.bailian")
+public class AliBaiLianLLMPropertiesConfig {
+
+    private String apiKey;
+    
+    private String model;
+}

+ 4 - 2
webchat-aigc/src/main/java/com/webchat/aigc/llm/AiFunctionCallService.java

@@ -25,8 +25,10 @@ import java.util.Map;
 public class AiFunctionCallService {
 
 
-    @Value("${llm.config.model}")
-    private String model;
+//    @Value("${llm.config.model}")
+//    private String model;
+
+    private String model="bailian";
 
     @Autowired
     private FreeMarkEngineService freeMarkEngineService;

+ 102 - 0
webchat-aigc/src/main/java/com/webchat/aigc/llm/AliBaiLianAIService.java

@@ -0,0 +1,102 @@
+package com.webchat.aigc.llm;
+
+import com.webchat.aigc.config.properties.AliBaiLianLLMPropertiesConfig;
+import com.webchat.aigc.config.properties.DeepseekLLMPropertiesConfig;
+import com.webchat.common.util.llm.AliBaiLianAIClient;
+import com.webchat.common.util.llm.DeepSeekAIClient;
+import com.webchat.domain.vo.llm.ChatCompletionMessage;
+import com.webchat.domain.vo.llm.ChatCompletionRequest;
+import com.webchat.domain.vo.llm.ChatCompletionResponse;
+import com.webchat.domain.vo.llm.ChatCompletionStreamChoice;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+
+import java.util.List;
+
+/**
+ * @Author 程序员七七
+ * @webSite https://www.coderutil.com
+ * @Date 2024/10/29 23:15
+ * @description
+ */
+@Service
+public class AliBaiLianAIService extends AbstractLLMChatService {
+
+    @Autowired
+    private AliBaiLianLLMPropertiesConfig aliBaiLianLLMPropertiesConfig;
+
+    /**
+     * 同步对话
+     *
+     * @param messageList
+     * @return
+     * @throws Exception
+     */
+    public ChatCompletionResponse chat(List<ChatCompletionMessage> messageList) throws Exception {
+        DeepSeekAIClient client = new DeepSeekAIClient(aliBaiLianLLMPropertiesConfig.getApiKey());
+        final List<ChatCompletionMessage> messages = messageList;
+        return client.ChatCompletion(new ChatCompletionRequest(
+                aliBaiLianLLMPropertiesConfig.getModel(),
+                messages,
+                2000,
+                0.3f,
+                1
+        ));
+    }
+
+    /**
+     * 流式对话
+     *
+     * @param emitter
+     * @param messageList
+     * @throws Exception
+     */
+    public String chat(SseEmitter emitter, List<ChatCompletionMessage> messageList) throws Exception {
+
+        // 用于记录流式推理完整结果,返回用于,用于对话消息持久化
+        StringBuilder aiMessage = new StringBuilder();
+
+        AliBaiLianAIClient client = new AliBaiLianAIClient(aliBaiLianLLMPropertiesConfig.getApiKey());
+        final List<ChatCompletionMessage> messages = messageList;
+        try {
+            client.ChatCompletionStream(new ChatCompletionRequest(
+                    aliBaiLianLLMPropertiesConfig.getModel(),
+                    messages,
+                    2000,
+                    0.3f,
+                    1
+            )).subscribe(
+                    streamResponse -> {
+                        if (streamResponse.getChoices().isEmpty()) {
+                            return;
+                        }
+                        for (ChatCompletionStreamChoice choice : streamResponse.getChoices()) {
+                            String finishReason = choice.getFinishReason();
+                            if (finishReason != null) {
+                                emitter.send("finished");
+                                continue;
+                            }
+                            String responseContent = choice.getDelta().getContent();
+                            if (responseContent.equals("```") || responseContent.equals("json") ) {
+                                continue;
+                            }
+                            responseContent = responseContent.replaceAll("\n", "<br>");
+                            System.out.println(responseContent);
+                            emitter.send(responseContent);
+                            aiMessage.append(responseContent);
+                        }
+                    },
+                    error -> {
+                        error.printStackTrace();
+                    },
+                    () -> {
+//                        emitter.complete(); // 完成事件流发送
+                    }
+            );
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return aiMessage.toString();
+    }
+}

+ 5 - 0
webchat-aigc/src/main/java/com/webchat/aigc/llm/LLMServiceFactory.java

@@ -48,6 +48,11 @@ public class LLMServiceFactory implements InitializingBean, ApplicationContextAw
         serviceMap.put(LlmModelEnum.DEEPSEEK.getModel(), applicationContext.getBean(DeepSeekAIService.class));
 
         /**
+         * bailian,阿里云的ai平台
+         */
+        serviceMap.put(LlmModelEnum.ALI.getModel(), applicationContext.getBean(DeepSeekAIService.class));
+
+        /**
          * ollama
          */
         serviceMap.put(LlmModelEnum.OLLAMA.getModel(), applicationContext.getBean(OllamaService.class));

+ 2 - 0
webchat-common/src/main/java/com/webchat/common/enums/LlmModelEnum.java

@@ -9,6 +9,8 @@ public enum LlmModelEnum {
 
     DEEPSEEK("deepseek"),
 
+    ALI("ALI"),
+
     OLLAMA("ollama");
 
     private String model;

+ 151 - 0
webchat-common/src/main/java/com/webchat/common/util/llm/AliBaiLianAIClient.java

@@ -0,0 +1,151 @@
+package com.webchat.common.util.llm;
+
+import com.google.gson.Gson;
+import com.webchat.domain.vo.llm.ChatCompletionRequest;
+import com.webchat.domain.vo.llm.ChatCompletionResponse;
+import com.webchat.domain.vo.llm.ChatCompletionStreamResponse;
+import com.webchat.domain.vo.llm.ModelsList;
+import io.reactivex.BackpressureStrategy;
+import io.reactivex.Flowable;
+import okhttp3.OkHttpClient;
+
+import java.io.IOException;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @Author 程序员七七
+ * @webSite https://www.coderutil.com
+ * @Date 2024/3/21 01:34
+ * @description
+ */
+public class AliBaiLianAIClient {
+
+    private static final String DEFAULT_BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1";
+
+    private static final String CHAT_COMPLETION_SUFFIX = "/chat/completions";
+    private static final String MODELS_SUFFIX = "/models";
+    private static final String FILES_SUFFIX = "/files";
+
+    private String baseUrl;
+    private String apiKey;
+
+    public AliBaiLianAIClient(String apiKey) {
+        this(apiKey, DEFAULT_BASE_URL);
+    }
+
+    public AliBaiLianAIClient(String apiKey, String baseUrl) {
+        this.apiKey = apiKey;
+        if (baseUrl.endsWith("/")) {
+            baseUrl = baseUrl.substring(0, baseUrl.length() - 1);
+        }
+        this.baseUrl = baseUrl;
+    }
+
+    public String getChatCompletionUrl() {
+        return baseUrl + CHAT_COMPLETION_SUFFIX;
+    }
+
+    public String getModelsUrl() {
+        return baseUrl + MODELS_SUFFIX;
+    }
+
+    public String getFilesUrl() {
+        return baseUrl + FILES_SUFFIX;
+    }
+
+    public String getApiKey() {
+        return apiKey;
+    }
+
+//    public ModelsList ListModels() throws IOException {
+//        OkHttpClient client = new OkHttpClient();
+//        okhttp3.Request request = new okhttp3.Request.Builder()
+//                .url(getModelsUrl())
+//                .addHeader("Authorization", "Bearer " + getApiKey())
+//                .build();
+//        try {
+//            okhttp3.Response response = client.newCall(request).execute();
+//            String body = response.body().string();
+//            Gson gson = new Gson();
+//            return gson.fromJson(body, ModelsList.class);
+//        } catch (IOException e) {
+//            e.printStackTrace();
+//            throw e;
+//        }
+//    }
+
+
+    public ChatCompletionResponse ChatCompletion(ChatCompletionRequest request) throws IOException {
+        request.stream = false;
+        OkHttpClient client = new OkHttpClient.Builder()
+                .connectTimeout(2, TimeUnit.MINUTES)
+                .readTimeout(2, TimeUnit.MINUTES)
+                .writeTimeout(2, TimeUnit.MINUTES)
+                .build();
+        okhttp3.MediaType mediaType = okhttp3.MediaType.parse("application/json");
+        okhttp3.RequestBody body = okhttp3.RequestBody.create(mediaType, new Gson().toJson(request));
+        okhttp3.Request httpRequest = new okhttp3.Request.Builder()
+                .url(getChatCompletionUrl())
+                .addHeader("Authorization", "Bearer " + getApiKey())
+                .addHeader("Content-Type", "application/json")
+                .post(body)
+                .build();
+        try {
+            okhttp3.Response response = client.newCall(httpRequest).execute();
+            String responseBody = response.body().string();
+            System.out.println(responseBody);
+            Gson gson = new Gson();
+            return gson.fromJson(responseBody, ChatCompletionResponse.class);
+        } catch (IOException e) {
+            e.printStackTrace();
+            throw e;
+        }
+    }
+
+    // return a stream of ChatCompletionStreamResponse
+    public Flowable<ChatCompletionStreamResponse> ChatCompletionStream(ChatCompletionRequest request) throws IOException {
+        request.stream = true;
+        OkHttpClient client = new OkHttpClient();
+        okhttp3.MediaType mediaType = okhttp3.MediaType.parse("application/json");
+        okhttp3.RequestBody body = okhttp3.RequestBody.create(mediaType, new Gson().toJson(request));
+        okhttp3.Request httpRequest = new okhttp3.Request.Builder()
+                .url(getChatCompletionUrl())
+                .addHeader("Authorization", "Bearer " + getApiKey())
+                .addHeader("Content-Type", "application/json")
+                .post(body)
+                .build();
+        okhttp3.Response response = client.newCall(httpRequest).execute();
+        if (response.code() != 200) {
+            throw new RuntimeException("Failed to start stream: " + response.body().string());
+        }
+
+        // get response body line by line
+        return Flowable.create(emitter -> {
+            okhttp3.ResponseBody responseBody = response.body();
+            if (responseBody == null) {
+                emitter.onError(new RuntimeException("Response body is null"));
+                return;
+            }
+            String line;
+            while ((line = responseBody.source().readUtf8Line()) != null) {
+                if (line.startsWith("data:")) {
+                    line = line.substring(5);
+                    line = line.trim();
+                }
+                if (Objects.equals(line, "[DONE]")) {
+                    emitter.onComplete();
+                    return;
+                }
+                line = line.trim();
+                if (line.isEmpty()) {
+                    continue;
+                }
+                Gson gson = new Gson();
+                ChatCompletionStreamResponse streamResponse = gson.fromJson(line, ChatCompletionStreamResponse.class);
+                emitter.onNext(streamResponse);
+            }
+            emitter.onComplete();
+        }, BackpressureStrategy.BUFFER);
+    }
+}