tsurumure 1 месяц назад
Родитель
Сommit
8ed0dbeb90

+ 5 - 2
src/main/java/com/backendsys/config/ThreadPool/ThreadPoolConfig.java

@@ -6,6 +6,7 @@ import org.springframework.scheduling.annotation.EnableAsync;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 
 import java.util.concurrent.Executor;
+import java.util.concurrent.ThreadPoolExecutor;
 
 /**
  * 线程池
@@ -20,13 +21,15 @@ public class ThreadPoolConfig {
         // 设置核心线程数
         executor.setCorePoolSize(5);
         // 设置最大线程数
-        executor.setMaxPoolSize(20);
+        executor.setMaxPoolSize(10);
         // 配置队列大小
-        executor.setQueueCapacity(Integer.MAX_VALUE);
+        executor.setQueueCapacity(1000);
         // 设置线程活跃时间 (秒)
         executor.setKeepAliveSeconds(60);
         // 等待所有任务结束后再关闭线程池
         executor.setWaitForTasksToCompleteOnShutdown(true);
+        // 设置拒绝策略
+        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
         // 执行初始化
         executor.initialize();
         return executor;

+ 0 - 14
src/main/java/com/backendsys/modules/sdk/baidu/bce/utils/BaiduBceUtil.java

@@ -3,23 +3,9 @@ package com.backendsys.modules.sdk.baidu.bce.utils;
 import cn.hutool.http.HttpUtil;
 import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
-import org.apache.http.client.ClientProtocolException;
-import org.apache.http.client.methods.CloseableHttpResponse;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClients;
-import org.apache.http.util.EntityUtils;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.core.ParameterizedTypeReference;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpMethod;
-import org.springframework.http.MediaType;
 import org.springframework.stereotype.Component;
-import org.springframework.web.reactive.function.client.WebClient;
-import org.springframework.web.util.UriComponentsBuilder;
 
-import java.io.IOException;
-import java.net.URI;
 import java.util.HashMap;
 import java.util.Map;
 

+ 24 - 0
src/main/java/com/backendsys/modules/sdk/comfyui/enums/TypeEnums.java

@@ -0,0 +1,24 @@
+package com.backendsys.modules.sdk.comfyui.enums;
+
+public enum TypeEnums {
+
+    STATUS("status", "队列状态"),
+    EXECUTION_START("execution_start", "任务开始执行"),
+    EXECUTION_CACHED("execution_cached", "任务缓存"),
+    EXECUTING("executing", "当前任务执行的步骤"),
+    EXECUTION_SUCCESS("execution_success", "任务执行成功"),
+    EXECUTED("executed", "任务执行完成");
+
+    private final String value;
+    private final String label;
+    TypeEnums(String value, String label) {
+        this.value = value;
+        this.label = label;
+    }
+    public String getLabel() {
+        return this.label;
+    }
+    public String getValue() {
+        return this.value;
+    }
+}

+ 31 - 16
src/main/java/com/backendsys/modules/sdk/comfyui/service/impl/ComfyUISocketServiceImpl.java

@@ -1,10 +1,12 @@
 package com.backendsys.modules.sdk.comfyui.service.impl;
 
+import cn.hutool.core.convert.Convert;
 import cn.hutool.json.JSONArray;
 import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
 import com.backendsys.modules.ai.chat.entity.ChatSseMessage;
 import com.backendsys.modules.common.config.security.utils.SecurityUtil;
+import com.backendsys.modules.sdk.comfyui.enums.TypeEnums;
 import com.backendsys.modules.sdk.comfyui.service.ComfyUISocketService;
 import com.backendsys.modules.sse.entity.SseResponse;
 import com.backendsys.modules.sse.entity.SseResponseEnum;
@@ -22,6 +24,9 @@ import reactor.netty.http.client.HttpClient;
 
 import java.net.URI;
 import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
@@ -116,37 +121,47 @@ public class ComfyUISocketServiceImpl implements ComfyUISocketService {
                         .doOnNext(message -> {
                             System.out.println("(doOnNext) Received from " + clientId + ": " + message);
 
-                            JSONObject messageObj = new JSONObject();
-                            if (JSONUtil.isTypeJSON(message)) {
+                            JSONObject data = JSONUtil.parseObj(message);
+                            String type = Convert.toStr(data.get("type"));
 
-                                messageObj = JSONUtil.parseObj(message);
-                                // 记录生成数据
-                                JSONObject output = JSONUtil.parseObj(messageObj.get("output"));
+                            // == [任务执行成功] =======================================================
+                            // { "type": "executed", "data": { "output": { "images": [{ "filename": "ComfyUI_00117_.png" }] } } }
+                            if (TypeEnums.EXECUTED.getValue().equals(type)) {
 
+                                JSONObject dataChildren = JSONUtil.parseObj(data.get("data"));
+                                JSONObject output = JSONUtil.parseObj(dataChildren.get("output"));
+
+                                // -- [生成图片] ------------------------------------------------------
                                 Object imagesObj = output.get("images");
                                 if (imagesObj != null) {
                                     JSONArray images = JSONUtil.parseArray(imagesObj);
                                     // [{"filename": "ComfyUI_00122_.png", "subfolder": "", "type": "output"}]
-                                    // http://43.128.1.201:8001/api/view?filename=ComfyUI_00118_.png
-
+                                    // http://43.128.1.201:8001/api/view?filename=ComfyUI_00117_.png
+                                    // http://43.128.1.201:8001/api/view?filename=ComfyUI_00117_.png&preview=1
+                                    List<String> images_path = new ArrayList<>();
                                     if (images.size() > 0) {
                                         for (int i = 0; i < images.size(); i++) {
-
                                             JSONObject image = images.getJSONObject(i);
-//                                    JSONObject image = images.getJSONObject(i);
-//                                    String filename = image.getStr("filename");
-//                                    String subfolder = image.getStr("subfolder");
-//                                    String type = image.getStr("type");
-//                                    System.out.println("filename: " + filename + ", subfolder: " + subfolder + ", type: " + type);
-//                                    sseUtil.send(user_id, new SseResponse(SseResponseEnum.COMFYUI, "filename: " + filename + ", subfolder: " + subfolder + ", type: " + type).toJsonStr());
+                                            String filename = image.getStr("filename");
+                                            String filepath = "http://" + COMFYUI_HOST + ":" + port + "/api/view?filename=" + filename;
+                                            images_path.add(filepath);
+
+                                            // -- [图片转存储存桶] -------------------------------------
+
+                                            // ------------------------------------------------------
+
                                         }
                                     }
+                                    output.put("images_path", images_path);
+                                    dataChildren.put("output", output);
+                                    data.put("data", dataChildren);
                                 }
+                                // ------------------------------------------------------------------
 
                             }
+                            // ======================================================================
 
-
-                            sseUtil.send(user_id, new SseResponse(SseResponseEnum.COMFYUI, messageObj).toJsonStr());
+                            sseUtil.send(user_id, new SseResponse(SseResponseEnum.COMFYUI, data).toJsonStr());
                         })
                         .doOnError(e -> {
                             System.err.println("(doOnError) Error for " + clientId + ": " + e.getMessage());

+ 3 - 1
src/main/java/com/backendsys/modules/sdk/deepseek/service/impl/DeepSeekClientImpl.java

@@ -21,12 +21,14 @@ import com.backendsys.modules.sse.entity.SseResponseEnum;
 import com.backendsys.modules.sse.utils.SseUtil;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
-import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.StringEntity;
+
+import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
+
 import org.apache.http.util.EntityUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;

+ 127 - 220
src/main/java/com/backendsys/modules/sdk/deepseek/utils/OllamaUtil.java

@@ -1,10 +1,7 @@
 package com.backendsys.modules.sdk.deepseek.utils;
 
-import cn.hutool.core.convert.Convert;
-import cn.hutool.core.util.NumberUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
-import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSONObject;
 import com.backendsys.modules.ai.chat.entity.Chat;
 import com.backendsys.modules.ai.chat.entity.ChatCompletionParam;
@@ -12,7 +9,6 @@ import com.backendsys.modules.ai.chat.entity.ChatResult;
 import com.backendsys.modules.ai.chat.entity.ChatSseMessage;
 import com.backendsys.modules.common.config.redis.utils.RedisUtil;
 import com.backendsys.modules.sdk.bocha.entity.BochaParam;
-import com.backendsys.modules.sdk.bocha.entity.BochaResult;
 import com.backendsys.modules.sdk.bocha.service.BochaService;
 import com.backendsys.modules.sdk.deepseek.entity.DSRequest;
 import com.backendsys.modules.sdk.deepseek.entity.DSRequestMessage;
@@ -21,20 +17,22 @@ import com.backendsys.modules.sse.entity.SseResponseEnum;
 import com.backendsys.modules.sse.utils.SseUtil;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
-import org.apache.http.client.methods.CloseableHttpResponse;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClients;
+//import org.apache.http.client.methods.CloseableHttpResponse;
+//import org.apache.http.impl.client.CloseableHttpClient;
+//import org.apache.http.impl.client.HttpClients;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
 import java.nio.charset.StandardCharsets;
+import java.time.Duration;
 import java.util.*;
 import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * ollama run deepseek-r1:1.5b
@@ -72,7 +70,7 @@ public class OllamaUtil {
 
         // 定义作用于全局的变量
         Long contentDuration = 0L;
-        Boolean isThinking = false;
+        AtomicReference<Boolean> isThinking = new AtomicReference<>(false);
         StringBuilder allReplyContent = new StringBuilder();
         StringBuilder allThinkContent = new StringBuilder();
         String requestOfRedisKey = APPLICATION_NAME + "-chat-history-" + history_code;
@@ -134,246 +132,155 @@ public class OllamaUtil {
             });
             System.out.println("---------------------------------------------------------------------");
 
-            ObjectMapper objectMapper = new ObjectMapper();
-            try (CloseableHttpClient client = HttpClients.createDefault()) {
 
-                /*
-                【/api/generate】
-                它是一个相对基础的文本生成端点,主要用于根据给定的提示信息生成一段连续的文本。
-                这个端点会基于输入的提示,按照模型的语言生成能力输出一段完整的内容,更侧重于单纯的文本生成任务。
-                生成过程不依赖于上下文的历史对话信息,每次请求都是独立的,模型仅依据当前输入的提示进行文本生成。
-                {
-                    "model": "llama2", "prompt": "请描述一下美丽的海滩", "num_predict": 200, "temperature": 0.7
-                }
 
-                【/api/chat】
-                该端点专为模拟聊天场景设计,具备处理对话上下文的能力。它可以跟踪对话的历史记录,理解对话的上下文信息,从而生成更符合对话逻辑和连贯性的回复。
-                更注重模拟真实的人机对话交互,能够根据历史对话和当前输入生成合适的回应,适用于构建聊天机器人等交互式应用。
-                {
-                    "model": "deepseek-r1:1.5b",
-                    "messages": [
-                        {
-                            "role": "system",
-                            "content": "你是一个能够理解中文指令并帮助完成任务的智能助手。你的任务是根据用户的需求生成合适的分类任务或生成任务,并准确判断这些任务的类型。请确保你的回答简洁、准确且符合中英文语境。"
-                        },
-                        {
-                            // "role": "assistant",
-                            "role": "user",
-                            "content": "写一个简单的 Python 函数,用于计算两个数的和"
-                        }
-                    ],
-                    "stream": false,
-
-                    // 新增
-                    "context": ["引用1","引用2"]
-                }
-                 */
+            /*
+            【/api/generate】
+            它是一个相对基础的文本生成端点,主要用于根据给定的提示信息生成一段连续的文本。
+            这个端点会基于输入的提示,按照模型的语言生成能力输出一段完整的内容,更侧重于单纯的文本生成任务。
+            生成过程不依赖于上下文的历史对话信息,每次请求都是独立的,模型仅依据当前输入的提示进行文本生成。
+            {
+                "model": "llama2", "prompt": "请描述一下美丽的海滩", "num_predict": 200, "temperature": 0.7
+            }
+
+            【/api/chat】
+            该端点专为模拟聊天场景设计,具备处理对话上下文的能力。它可以跟踪对话的历史记录,理解对话的上下文信息,从而生成更符合对话逻辑和连贯性的回复。
+            更注重模拟真实的人机对话交互,能够根据历史对话和当前输入生成合适的回应,适用于构建聊天机器人等交互式应用。
+            {
+                "model": "deepseek-r1:1.5b",
+                "messages": [
+                    { "role": "system", "content": "你是一个能够理解中文指令并帮助完成任务的智能助手。" },
+                    { "role": "user", "content": "写一个简单的 Python 函数,用于计算两个数的和" }
+                ],
+                "stream": false,
+                // 新增
+                "context": ["引用1","引用2"]
+            }
+             */
+
+            try {
 
+                ObjectMapper objectMapper = new ObjectMapper();
+                HttpClient httpClient = HttpClient.newBuilder()
+                    .connectTimeout(Duration.ofSeconds(30))
+                    .build();
 
-                // [Chat] 构建请求体
-                HttpPost request = new HttpPost(DOMAIN + "/api/chat");
                 DSRequest body = new DSRequest();
                 body.setModel(model);
                 body.setMessages(messages);
                 body.setStream(true);
+
                 String requestBody = objectMapper.writeValueAsString(body);
 
-//                // [Generate] 构建请求体
-//                HttpPost request = new HttpPost(DOMAIN + "/api/generate");
-//                Map<String, Object> requestMap = new HashMap<>();
-//                requestMap.put("model", model);
-//                requestMap.put("prompt", prompt);
-//                requestMap.put("stream", true);
-//                String requestBody = objectMapper.writeValueAsString(requestMap);
-
-                request.setEntity(new StringEntity(requestBody, StandardCharsets.UTF_8));
-
-                try (CloseableHttpResponse response = client.execute(request);
-                     BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), StandardCharsets.UTF_8))) {
-
-                    long apiDuration = System.currentTimeMillis() - allStartTime;   // 接口耗时
-
-                    long thinkStartTime = 0L;                            // 开始思考时间
-                    long thinkDuration = 0L;                             // 思考耗时
-
-                    System.out.println("API 调用耗时: " + apiDuration + " 毫秒");
-                    System.out.println("---- 开始流式回答: ------------------------------------");
-
-                    // [SSE] 发送消息
-                    ChatSseMessage chatLoadingSseMessage = new ChatSseMessage("LOADING", "正在思考", null, history_code);
-                    sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, chatLoadingSseMessage).toJsonStr());
-
-                    String line;
-                    while ((line = reader.readLine()) != null) {
-
-                        // 判断是否中止
-                        if (ObjectUtil.isEmpty(redisUtil.getCacheObject(requestOfRedisKey))) {
-                            System.out.println("中止!");
-                            request.abort();
-                            // 流程结束后,删除锁
-                            redisUtil.delete(requestOfRedisKey);
-                            break;
-                        }
-
-
-                        // System.out.println(line);
-                        /*
-                            ---------------------- [Chat] line ----------------------
-                            {"model":"deepseek-r1:1.5b","created_at":"2025-03-18T07:37:06.483163789Z","message":{"role":"assistant","content":"\u003cthink\u003e"},"done":false}
-
-                            ---------------------- [Generate] line ------------------
-                            {"model":"deepseek-r1:1.5b","created_at":"2025-03-05T10:51:17.443189986Z","response":"\u003cthink\u003e","done":false}
-                            {"model":"deepseek-r1:1.5b","created_at":"2025-03-06T11:08:30.9219611Z","response":"\n\n","done":false}
-
-                            ---------------------- [Error] line ---------------------
-                            {"error":"llama runner process has terminated: error loading model: unable to allocate CUDA0 buffer"}
-                         */
-
-                        // 每行数据可以是一个JSON对象,根据实际情况处理
-                        JSONObject resJson = JSONObject.parseObject(line);
-
-                        // -- 判断内容是否为空 (或报错) --------------------------------------
-                        if (resJson == null) return null;
-                        String errJsonMessage = resJson.getString("error");
-                        if (errJsonMessage != null) {
-                            // [SSE] 发送消息
-                            sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, new ChatSseMessage("REPLY", errJsonMessage, contentDuration, history_code)).toJsonStr());
-                            // [SSE] 发送消息 (完成)
-                            sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, new ChatSseMessage("REPLY", "[DONE][REPLY]", contentDuration, history_code)).toJsonStr());
-                            //
-                            chatResult.setContent(errJsonMessage);
-                            return chatResult;
-                        }
-
-                        // --------------------------------------------------------------
-                        // [Chat]
-                        JSONObject resJsonMessage = resJson.getJSONObject("message");
-                        String content = resJsonMessage.getString("content");
-
-//                        // [Generate]
-//                        String content = resJson.getString("response");
-                        // --------------------------------------------------------------
-
-                        // 开始思考
-                        if (content.contains("<think>")) {
-                            isThinking = true;
-                            thinkStartTime = System.currentTimeMillis();
-                        }
-                        // 停止思考,并计算思考耗时
-                        if (content.contains("</think>")) {
-                            isThinking = false;
-                            thinkDuration = thinkStartTime - allStartTime;
-                            System.out.println("推理耗时: " + thinkDuration + "毫秒");
-                            System.out.println("-----------------------------------------------------");
-
-                            if (allThinkContent.length() > 0){
-                                // [SSE] 发送消息
-                                ChatSseMessage chatSseMessage = new ChatSseMessage("THINK", "[DONE][THINK]", thinkDuration, history_code);
-                                sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, chatSseMessage).toJsonStr());
-                            }
+                HttpRequest request = HttpRequest.newBuilder()
+                    .uri(URI.create(DOMAIN + "/api/chat"))
+                    .header("Content-Type", "application/json")
+                    .POST(HttpRequest.BodyPublishers.ofString(requestBody, StandardCharsets.UTF_8))
+                    .build();
 
-                        }
+                long apiDuration = System.currentTimeMillis() - allStartTime;   // 接口耗时
+                System.out.println("API 调用耗时: " + apiDuration + " 毫秒");
+                System.out.println("---- 开始流式回答: ------------------------------------");
 
-                        // [思考] Think
-                        if (isThinking) {
-                            if (!content.contains("<think>") && !content.contains("\n\n") && !content.contains("\n")) {
-                                // [SSE] 发送消息
-                                ChatSseMessage chatSseMessage = new ChatSseMessage("THINK", content, null, history_code);
-                                sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, chatSseMessage).toJsonStr());
-                                // 收集推理内容
-                                allThinkContent.append(content);
+                // [SSE] 发送消息
+                ChatSseMessage chatLoadingSseMessage = new ChatSseMessage("LOADING", "正在思考", null, history_code);
+                sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, chatLoadingSseMessage).toJsonStr());
+
+                // 使用异步流式处理
+                Long finalContentDuration = contentDuration;
+                CompletableFuture<Void> future = httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofLines())
+                    .thenAccept(resp -> {
+                        resp.body().forEach(line -> {
+                            if (ObjectUtil.isEmpty(redisUtil.getCacheObject(requestOfRedisKey))) {
+                                System.out.println("中止!");
+                                redisUtil.delete(requestOfRedisKey);
+                                return;
+                            }
+
+                            JSONObject resJson = JSONObject.parseObject(line);
+                            if (resJson == null) return;
+
+                            String errJsonMessage = resJson.getString("error");
+                            if (errJsonMessage != null) {
+                                ChatSseMessage errMsg = new ChatSseMessage("REPLY", errJsonMessage, finalContentDuration, history_code);
+                                sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, errMsg).toJsonStr());
+                                sseUtil.send(user_id,
+                                        new SseResponse(SseResponseEnum.OLLAMA,
+                                                new ChatSseMessage("REPLY", "[DONE][REPLY]", finalContentDuration, history_code)).toJsonStr());
+                                chatResult.setContent(errJsonMessage);
+                                return;
                             }
-                        }
 
-                        // [回答] Reply
-                        if (!isThinking) {
+                            JSONObject resJsonMessage = resJson.getJSONObject("message");
+                            String content = resJsonMessage.getString("content");
 
-                            // System.out.println("content: " + content);
+                            // 思考标记
+                            if (content.contains("<think>")) {
+                                isThinking.set(true);
+                            }
+                            if (content.contains("</think>")) {
+                                isThinking.set(false);
+                                long thinkDuration = System.currentTimeMillis() - allStartTime;
+                                if (allThinkContent.length() > 0) {
+                                    ChatSseMessage thinkMsg = new ChatSseMessage("THINK", "[DONE][THINK]", thinkDuration, history_code);
+                                    sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, thinkMsg).toJsonStr());
+                                }
+                            }
 
-                            if (!content.contains("</think>") && !content.contains("\n\n")) {
+                            if (isThinking.get() && !content.contains("<think>") && !content.equals("\n\n") && !content.equals("\n")) {
+                                ChatSseMessage thinkMsg = new ChatSseMessage("THINK", content, null, history_code);
+                                sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, thinkMsg).toJsonStr());
+                                allThinkContent.append(content);
+                            }
 
+                            if (!isThinking.get() && !content.contains("</think>") && !content.equals("\n\n")) {
                                 Boolean done = resJson.getBoolean("done");
                                 if (!done) {
-
-                                    // [SSE] 发送消息
-                                    ChatSseMessage chatSseMessage = new ChatSseMessage("REPLY", content, null, history_code);
-                                    sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, chatSseMessage).toJsonStr());
-                                    // 收集回答内容
+                                    ChatSseMessage replyMsg = new ChatSseMessage("REPLY", content, null, history_code);
+                                    sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, replyMsg).toJsonStr());
                                     allReplyContent.append(content);
-
                                 }
                             }
-                        }
-
-                    }
-
+                        });
+                    });
 
-                    System.out.println("-------------------- 结束流式回答. --------------------");
-                    contentDuration = System.currentTimeMillis() - allStartTime;
+                future.join(); // 阻塞直至流结束
 
-                    System.out.println("全部推理: " + allThinkContent);
-                    System.out.println("全部回答: " + allReplyContent);
-                    System.out.println("总输出耗时: " + contentDuration + " 毫秒");
-                    System.out.println("---------------------------------------------------");
-
-                    if (StrUtil.isNotEmpty(allThinkContent.toString())) {
-                        chatResult.setReasoning_content(allThinkContent.toString());
-                        chatResult.setReasoning_duration(thinkDuration);
-                    }
-                    chatResult.setContent(allReplyContent.toString());
-                    chatResult.setContent_duration(contentDuration);
-                    return chatResult;
-
-                } catch (Exception e) {
-                    System.out.println("Exception(1): " + e.getMessage());
-                    String message = e.getMessage();
-                    if (message.contains("failed to respond")) {
-                        message = "(系统繁忙,请稍后再试)";
-                    }
-                    if (message.contains("Premature end of chunk coded message body: closing chunk expected")) {
-                        message = "(请求中止)";
-                    }
-                    // [SSE] 发送消息
-                    String contentType = (isThinking ? "THINK_ABORT" : "REPLY_ABORT");
-                    ChatSseMessage chatSseMessage = new ChatSseMessage(contentType, message, contentDuration, history_code);
-                    sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, chatSseMessage).toJsonStr());
-
-//                    chatResult.setContent(e.getMessage());
-
-                    // 由于中止导致的错误信息叠加 (一并保存进数据库)
-                    if (StrUtil.isNotEmpty(allThinkContent.toString())) {
-                        if (isThinking) {
-                            chatResult.setReasoning_content(allThinkContent.toString() + " " + message);
-                        } else {
-                            chatResult.setReasoning_content(allThinkContent.toString());
-                        }
-                    }
-                    chatResult.setContent(allReplyContent.toString() + " " + message);
+                System.out.println("-------------------- 结束流式回答. --------------------");
 
-                    redisUtil.delete(requestOfRedisKey);
+                contentDuration = System.currentTimeMillis() - allStartTime;
 
-                    return chatResult;
+                System.out.println("全部推理: " + allThinkContent);
+                System.out.println("全部回答: " + allReplyContent);
+                System.out.println("总输出耗时: " + contentDuration + " 毫秒");
+                System.out.println("---------------------------------------------------");
 
-//                    return chatResult;
+                if (StrUtil.isNotEmpty(allThinkContent.toString())) {
+                    chatResult.setReasoning_content(allThinkContent.toString());
+                    chatResult.setReasoning_duration(System.currentTimeMillis() - allStartTime);
                 }
-            } catch (Exception e) {
-                System.out.println("Exception(2): " + e.getMessage());
-                // [SSE] 发送消息
-                String contentType = (isThinking ? "THINK_ABORT" : "REPLY_ABORT");
-                ChatSseMessage chatSseMessage = new ChatSseMessage(contentType, e.getMessage(), contentDuration, history_code);
-                sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, chatSseMessage).toJsonStr());
+                chatResult.setContent(allReplyContent.toString());
+                chatResult.setContent_duration(contentDuration);
+                return chatResult;
 
-                redisUtil.delete(requestOfRedisKey);
+        } catch (Exception e) {
+            System.out.println("Exception(2): " + e.getMessage());
+            // [SSE] 发送消息
+            String contentType = (isThinking.get() ? "THINK_ABORT" : "REPLY_ABORT");
+            ChatSseMessage chatSseMessage = new ChatSseMessage(contentType, e.getMessage(), contentDuration, history_code);
+            sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, chatSseMessage).toJsonStr());
 
-                chatResult.setContent(e.getMessage());
-                return chatResult;
-            } finally {
+            redisUtil.delete(requestOfRedisKey);
 
-                // [SSE] 发送消息 (完成)
-                ChatSseMessage chatSseMessage = new ChatSseMessage("REPLY", "[DONE][REPLY]", contentDuration, history_code);
-                sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, chatSseMessage).toJsonStr());
+            chatResult.setContent(e.getMessage());
+            return chatResult;
+        } finally {
 
-            }
+            // [SSE] 发送消息 (完成)
+            ChatSseMessage chatSseMessage = new ChatSseMessage("REPLY", "[DONE][REPLY]", contentDuration, history_code);
+            sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, chatSseMessage).toJsonStr());
+
+        }
 
     }
 }

+ 378 - 0
src/main/java/com/backendsys/modules/sdk/deepseek/utils/OllamaUtil_bak.java

@@ -0,0 +1,378 @@
+//package com.backendsys.modules.sdk.deepseek.utils;
+//
+//import cn.hutool.core.util.ObjectUtil;
+//import cn.hutool.core.util.StrUtil;
+//import com.alibaba.fastjson.JSONObject;
+//import com.backendsys.modules.ai.chat.entity.Chat;
+//import com.backendsys.modules.ai.chat.entity.ChatCompletionParam;
+//import com.backendsys.modules.ai.chat.entity.ChatResult;
+//import com.backendsys.modules.ai.chat.entity.ChatSseMessage;
+//import com.backendsys.modules.common.config.redis.utils.RedisUtil;
+//import com.backendsys.modules.sdk.bocha.entity.BochaParam;
+//import com.backendsys.modules.sdk.bocha.service.BochaService;
+//import com.backendsys.modules.sdk.deepseek.entity.DSRequest;
+//import com.backendsys.modules.sdk.deepseek.entity.DSRequestMessage;
+//import com.backendsys.modules.sse.entity.SseResponse;
+//import com.backendsys.modules.sse.entity.SseResponseEnum;
+//import com.backendsys.modules.sse.utils.SseUtil;
+//import com.fasterxml.jackson.databind.JsonNode;
+//import com.fasterxml.jackson.databind.ObjectMapper;
+//import org.apache.http.client.methods.HttpPost;
+//import org.apache.http.entity.StringEntity;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.beans.factory.annotation.Value;
+//import org.springframework.stereotype.Component;
+//import org.apache.http.client.methods.CloseableHttpResponse;
+//import org.apache.http.impl.client.CloseableHttpClient;
+//import org.apache.http.impl.client.HttpClients;
+//
+//
+//
+//import java.io.BufferedReader;
+//import java.io.InputStreamReader;
+//import java.nio.charset.StandardCharsets;
+//import java.util.ArrayList;
+//import java.util.Collections;
+//import java.util.List;
+//
+///**
+// * ollama run deepseek-r1:1.5b
+// *
+// * Ollama API
+// * https://github.com/ollama/ollama/blob/main/docs/api.md
+// */
+//@Component
+//public class OllamaUtil {
+//
+//    @Autowired
+//    private SseUtil sseUtil;
+//    @Autowired
+//    private RedisUtil redisUtil;
+//    @Autowired
+//    private BochaService bochaService;
+//
+//    @Value("${spring.application.name}")
+//    private String APPLICATION_NAME;
+//    @Value("${deepseek-r1.domain}")
+//    private String DOMAIN;
+//
+//    /**
+//     * 流式对话
+//     */
+//    public ChatResult chatCompletion(ChatCompletionParam chatCompletionParam) {
+//
+//        // 参数化
+//        Long user_id = chatCompletionParam.getUser_id();
+//        String model = chatCompletionParam.getModel();
+//        String prompt = chatCompletionParam.getPrompt();
+//        String history_code = chatCompletionParam.getHistory_code();
+//        List<Chat> chatList = chatCompletionParam.getChatList();
+//        Boolean internet = chatCompletionParam.getInternet();
+//
+//        // 定义作用于全局的变量
+//        Long contentDuration = 0L;
+//        Boolean isThinking = false;
+//        StringBuilder allReplyContent = new StringBuilder();
+//        StringBuilder allThinkContent = new StringBuilder();
+//        String requestOfRedisKey = APPLICATION_NAME + "-chat-history-" + history_code;
+//
+//        ChatResult chatResult = new ChatResult();
+////        try {
+//            System.out.println("向模型: " + model + " 提问: " + prompt);
+//
+//            // 记录请求开始时间
+//            long allStartTime = System.currentTimeMillis();
+//
+//            // 加入上下文历史对话
+//            System.out.println("---- 历史对话 (history_code): " + history_code + " ----");
+//
+//            List<DSRequestMessage> messages = new ArrayList<>();
+//
+//            if (chatList != null && !chatList.isEmpty()) {
+//                chatList.stream().forEach(chat -> {
+//                    if (!"THINK".equals(chat.getContent_type())) {
+//                        messages.add(new DSRequestMessage(chat.getRole(), chat.getContent()));
+//                    }
+//                });
+//                // 反转列表
+//                Collections.reverse(messages);
+//            }
+//
+//            // 【要把搜索到的内容塞到 'user' 里?】
+//
+//            // -- [博查] Web Search API ----------------------------------------------
+//            if (internet) {
+//
+//                // 远程查询、统计接口时间、设置返回参数
+//                long internetStartTime = System.currentTimeMillis();
+//                JsonNode searchResult = bochaService.WebSearch(new BochaParam(prompt));
+//                String context = bochaService.WebSearchToString(searchResult);
+//                context = context.replace("\n", "\\n");
+//
+//                long internetEndTime = System.currentTimeMillis();
+//                chatResult.setInternet_duration(internetStartTime - internetEndTime);
+//                chatResult.setInternet_content(context);
+//
+//                // 将搜索结果作为上下文添加到消息中
+//                messages.add(new DSRequestMessage("system", context));
+//                messages.add(new DSRequestMessage("user", "在回答时引用以上全部数据进行分析")); // 的 "name"、"summary"
+//                messages.add(new DSRequestMessage("assistant", "好的"));
+//
+//                // [SSE] 发送消息
+//                ChatSseMessage chatSearchSseMessage = new ChatSseMessage("SEARCH", context, null, history_code);
+//                sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, chatSearchSseMessage).toJsonStr());
+//            }
+//            // -----------------------------------------------------------------------
+//
+//            // 新的对话内容
+//            messages.add(new DSRequestMessage("user", prompt));
+//
+//            // 输出全部对话内容
+//            messages.stream().forEach(msg -> {
+//                System.out.println("[" + msg.getRole() + "]: " + msg.getContent());
+//            });
+//            System.out.println("---------------------------------------------------------------------");
+//
+//            ObjectMapper objectMapper = new ObjectMapper();
+//            try (CloseableHttpClient client = HttpClients.createDefault()) {
+//
+//                /*
+//                【/api/generate】
+//                它是一个相对基础的文本生成端点,主要用于根据给定的提示信息生成一段连续的文本。
+//                这个端点会基于输入的提示,按照模型的语言生成能力输出一段完整的内容,更侧重于单纯的文本生成任务。
+//                生成过程不依赖于上下文的历史对话信息,每次请求都是独立的,模型仅依据当前输入的提示进行文本生成。
+//                {
+//                    "model": "llama2", "prompt": "请描述一下美丽的海滩", "num_predict": 200, "temperature": 0.7
+//                }
+//
+//                【/api/chat】
+//                该端点专为模拟聊天场景设计,具备处理对话上下文的能力。它可以跟踪对话的历史记录,理解对话的上下文信息,从而生成更符合对话逻辑和连贯性的回复。
+//                更注重模拟真实的人机对话交互,能够根据历史对话和当前输入生成合适的回应,适用于构建聊天机器人等交互式应用。
+//                {
+//                    "model": "deepseek-r1:1.5b",
+//                    "messages": [
+//                        {
+//                            "role": "system",
+//                            "content": "你是一个能够理解中文指令并帮助完成任务的智能助手。你的任务是根据用户的需求生成合适的分类任务或生成任务,并准确判断这些任务的类型。请确保你的回答简洁、准确且符合中英文语境。"
+//                        },
+//                        {
+//                            // "role": "assistant",
+//                            "role": "user",
+//                            "content": "写一个简单的 Python 函数,用于计算两个数的和"
+//                        }
+//                    ],
+//                    "stream": false,
+//
+//                    // 新增
+//                    "context": ["引用1","引用2"]
+//                }
+//                 */
+//
+//
+//                // [Chat] 构建请求体
+//                HttpPost request = new HttpPost(DOMAIN + "/api/chat");
+//                DSRequest body = new DSRequest();
+//                body.setModel(model);
+//                body.setMessages(messages);
+//                body.setStream(true);
+//                String requestBody = objectMapper.writeValueAsString(body);
+//
+////                // [Generate] 构建请求体
+////                HttpPost request = new HttpPost(DOMAIN + "/api/generate");
+////                Map<String, Object> requestMap = new HashMap<>();
+////                requestMap.put("model", model);
+////                requestMap.put("prompt", prompt);
+////                requestMap.put("stream", true);
+////                String requestBody = objectMapper.writeValueAsString(requestMap);
+//
+//                request.setEntity(new StringEntity(requestBody, StandardCharsets.UTF_8));
+//
+//                try (CloseableHttpResponse response = client.execute(request);
+//                     BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), StandardCharsets.UTF_8))) {
+//
+//                    long apiDuration = System.currentTimeMillis() - allStartTime;   // 接口耗时
+//
+//                    long thinkStartTime = 0L;                            // 开始思考时间
+//                    long thinkDuration = 0L;                             // 思考耗时
+//
+//                    System.out.println("API 调用耗时: " + apiDuration + " 毫秒");
+//                    System.out.println("---- 开始流式回答: ------------------------------------");
+//
+//                    // [SSE] 发送消息
+//                    ChatSseMessage chatLoadingSseMessage = new ChatSseMessage("LOADING", "正在思考", null, history_code);
+//                    sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, chatLoadingSseMessage).toJsonStr());
+//
+//                    String line;
+//                    while ((line = reader.readLine()) != null) {
+//
+//                        // 判断是否中止
+//                        if (ObjectUtil.isEmpty(redisUtil.getCacheObject(requestOfRedisKey))) {
+//                            System.out.println("中止!");
+//                            request.abort();
+//                            // 流程结束后,删除锁
+//                            redisUtil.delete(requestOfRedisKey);
+//                            break;
+//                        }
+//
+//
+//                        // System.out.println(line);
+//                        /*
+//                            ---------------------- [Chat] line ----------------------
+//                            {"model":"deepseek-r1:1.5b","created_at":"2025-03-18T07:37:06.483163789Z","message":{"role":"assistant","content":"\u003cthink\u003e"},"done":false}
+//
+//                            ---------------------- [Generate] line ------------------
+//                            {"model":"deepseek-r1:1.5b","created_at":"2025-03-05T10:51:17.443189986Z","response":"\u003cthink\u003e","done":false}
+//                            {"model":"deepseek-r1:1.5b","created_at":"2025-03-06T11:08:30.9219611Z","response":"\n\n","done":false}
+//
+//                            ---------------------- [Error] line ---------------------
+//                            {"error":"llama runner process has terminated: error loading model: unable to allocate CUDA0 buffer"}
+//                         */
+//
+//                        // 每行数据可以是一个JSON对象,根据实际情况处理
+//                        JSONObject resJson = JSONObject.parseObject(line);
+//
+//                        // -- 判断内容是否为空 (或报错) --------------------------------------
+//                        if (resJson == null) return null;
+//                        String errJsonMessage = resJson.getString("error");
+//                        if (errJsonMessage != null) {
+//                            // [SSE] 发送消息
+//                            sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, new ChatSseMessage("REPLY", errJsonMessage, contentDuration, history_code)).toJsonStr());
+//                            // [SSE] 发送消息 (完成)
+//                            sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, new ChatSseMessage("REPLY", "[DONE][REPLY]", contentDuration, history_code)).toJsonStr());
+//                            //
+//                            chatResult.setContent(errJsonMessage);
+//                            return chatResult;
+//                        }
+//
+//                        // --------------------------------------------------------------
+//                        // [Chat]
+//                        JSONObject resJsonMessage = resJson.getJSONObject("message");
+//                        String content = resJsonMessage.getString("content");
+//
+////                        // [Generate]
+////                        String content = resJson.getString("response");
+//                        // --------------------------------------------------------------
+//
+//                        // 开始思考
+//                        if (content.contains("<think>")) {
+//                            isThinking = true;
+//                            thinkStartTime = System.currentTimeMillis();
+//                        }
+//                        // 停止思考,并计算思考耗时
+//                        if (content.contains("</think>")) {
+//                            isThinking = false;
+//                            thinkDuration = thinkStartTime - allStartTime;
+//                            System.out.println("推理耗时: " + thinkDuration + "毫秒");
+//                            System.out.println("-----------------------------------------------------");
+//
+//                            if (allThinkContent.length() > 0){
+//                                // [SSE] 发送消息
+//                                ChatSseMessage chatSseMessage = new ChatSseMessage("THINK", "[DONE][THINK]", thinkDuration, history_code);
+//                                sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, chatSseMessage).toJsonStr());
+//                            }
+//
+//                        }
+//
+//                        // [思考] Think
+//                        if (isThinking) {
+//                            if (!content.contains("<think>") && !content.contains("\n\n") && !content.contains("\n")) {
+//                                // [SSE] 发送消息
+//                                ChatSseMessage chatSseMessage = new ChatSseMessage("THINK", content, null, history_code);
+//                                sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, chatSseMessage).toJsonStr());
+//                                // 收集推理内容
+//                                allThinkContent.append(content);
+//                            }
+//                        }
+//
+//                        // [回答] Reply
+//                        if (!isThinking) {
+//
+//                            // System.out.println("content: " + content);
+//
+//                            if (!content.contains("</think>") && !content.contains("\n\n")) {
+//
+//                                Boolean done = resJson.getBoolean("done");
+//                                if (!done) {
+//
+//                                    // [SSE] 发送消息
+//                                    ChatSseMessage chatSseMessage = new ChatSseMessage("REPLY", content, null, history_code);
+//                                    sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, chatSseMessage).toJsonStr());
+//                                    // 收集回答内容
+//                                    allReplyContent.append(content);
+//
+//                                }
+//                            }
+//                        }
+//
+//                    }
+//
+//
+//                    System.out.println("-------------------- 结束流式回答. --------------------");
+//                    contentDuration = System.currentTimeMillis() - allStartTime;
+//
+//                    System.out.println("全部推理: " + allThinkContent);
+//                    System.out.println("全部回答: " + allReplyContent);
+//                    System.out.println("总输出耗时: " + contentDuration + " 毫秒");
+//                    System.out.println("---------------------------------------------------");
+//
+//                    if (StrUtil.isNotEmpty(allThinkContent.toString())) {
+//                        chatResult.setReasoning_content(allThinkContent.toString());
+//                        chatResult.setReasoning_duration(thinkDuration);
+//                    }
+//                    chatResult.setContent(allReplyContent.toString());
+//                    chatResult.setContent_duration(contentDuration);
+//                    return chatResult;
+//
+//                } catch (Exception e) {
+//                    System.out.println("Exception(1): " + e.getMessage());
+//                    String message = e.getMessage();
+//                    if (message.contains("failed to respond")) {
+//                        message = "(系统繁忙,请稍后再试)";
+//                    }
+//                    if (message.contains("Premature end of chunk coded message body: closing chunk expected")) {
+//                        message = "(请求中止)";
+//                    }
+//                    // [SSE] 发送消息
+//                    String contentType = (isThinking ? "THINK_ABORT" : "REPLY_ABORT");
+//                    ChatSseMessage chatSseMessage = new ChatSseMessage(contentType, message, contentDuration, history_code);
+//                    sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, chatSseMessage).toJsonStr());
+//
+////                    chatResult.setContent(e.getMessage());
+//
+//                    // 由于中止导致的错误信息叠加 (一并保存进数据库)
+//                    if (StrUtil.isNotEmpty(allThinkContent.toString())) {
+//                        if (isThinking) {
+//                            chatResult.setReasoning_content(allThinkContent.toString() + " " + message);
+//                        } else {
+//                            chatResult.setReasoning_content(allThinkContent.toString());
+//                        }
+//                    }
+//                    chatResult.setContent(allReplyContent.toString() + " " + message);
+//
+//                    redisUtil.delete(requestOfRedisKey);
+//
+//                    return chatResult;
+//
+////                    return chatResult;
+//                }
+//            } catch (Exception e) {
+//                System.out.println("Exception(2): " + e.getMessage());
+//                // [SSE] 发送消息
+//                String contentType = (isThinking ? "THINK_ABORT" : "REPLY_ABORT");
+//                ChatSseMessage chatSseMessage = new ChatSseMessage(contentType, e.getMessage(), contentDuration, history_code);
+//                sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, chatSseMessage).toJsonStr());
+//
+//                redisUtil.delete(requestOfRedisKey);
+//
+//                chatResult.setContent(e.getMessage());
+//                return chatResult;
+//            } finally {
+//
+//                // [SSE] 发送消息 (完成)
+//                ChatSseMessage chatSseMessage = new ChatSseMessage("REPLY", "[DONE][REPLY]", contentDuration, history_code);
+//                sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, chatSseMessage).toJsonStr());
+//
+//            }
+//
+//    }
+//}

+ 0 - 4
src/main/java/com/backendsys/modules/sdk/tencentcloud/huanyuan/service/impl/HunYuanClientImpl.java

@@ -7,10 +7,8 @@ import com.backendsys.modules.ai.chat.entity.ChatCompletionParam;
 import com.backendsys.modules.ai.chat.entity.ChatResult;
 import com.backendsys.modules.ai.chat.entity.ChatSseMessage;
 import com.backendsys.modules.common.config.redis.utils.RedisUtil;
-import com.backendsys.modules.common.config.security.utils.SecurityUtil;
 import com.backendsys.modules.sdk.bocha.entity.BochaParam;
 import com.backendsys.modules.sdk.bocha.service.BochaService;
-import com.backendsys.modules.sdk.deepseek.entity.DSRequestMessage;
 import com.backendsys.modules.sdk.tencentcloud.huanyuan.service.HunYuanClient;
 import com.backendsys.modules.sse.entity.SseResponse;
 import com.backendsys.modules.sse.entity.SseResponseEnum;
@@ -29,8 +27,6 @@ import com.tencentcloudapi.hunyuan.v20230901.models.ChatStdResponse;
 import com.tencentcloudapi.hunyuan.v20230901.models.Message;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.stereotype.Service;
 
 import java.util.ArrayList;

+ 297 - 0
src/main/java/com/backendsys/modules/sdk/tencentcloud/huanyuan/service/impl/HunYuanClientImpl222.java

@@ -0,0 +1,297 @@
+//package com.backendsys.modules.sdk.tencentcloud.huanyuan.service.impl;
+//
+//import cn.hutool.core.util.ArrayUtil;
+//import cn.hutool.core.util.ObjectUtil;
+//import com.backendsys.modules.ai.chat.entity.Chat;
+//import com.backendsys.modules.ai.chat.entity.ChatCompletionParam;
+//import com.backendsys.modules.ai.chat.entity.ChatResult;
+//import com.backendsys.modules.ai.chat.entity.ChatSseMessage;
+//import com.backendsys.modules.common.config.redis.utils.RedisUtil;
+//import com.backendsys.modules.sdk.bocha.entity.BochaParam;
+//import com.backendsys.modules.sdk.bocha.service.BochaService;
+//import com.backendsys.modules.sdk.tencentcloud.huanyuan.service.HunYuanClient;
+//import com.backendsys.modules.sse.entity.SseResponse;
+//import com.backendsys.modules.sse.entity.SseResponseEnum;
+//import com.backendsys.modules.sse.utils.SseUtil;
+//import com.fasterxml.jackson.core.JsonProcessingException;
+//import com.fasterxml.jackson.databind.JsonMappingException;
+//import com.fasterxml.jackson.databind.JsonNode;
+//import com.fasterxml.jackson.databind.ObjectMapper;
+//import com.google.gson.Gson;
+//import com.google.gson.GsonBuilder;
+//import com.tencentcloudapi.common.Credential;
+//import com.tencentcloudapi.common.SSEResponseModel;
+//import com.tencentcloudapi.common.exception.TencentCloudSDKException;
+//import com.tencentcloudapi.common.profile.ClientProfile;
+//import com.tencentcloudapi.hunyuan.v20230901.HunyuanClient;
+//import com.tencentcloudapi.hunyuan.v20230901.models.ChatCompletionsRequest;
+//import com.tencentcloudapi.hunyuan.v20230901.models.ChatCompletionsResponse;
+//import com.tencentcloudapi.hunyuan.v20230901.models.Choice;
+//import com.tencentcloudapi.hunyuan.v20230901.models.Message;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.beans.factory.annotation.Value;
+//import org.springframework.stereotype.Service;
+//
+//import java.util.ArrayList;
+//import java.util.Collections;
+//import java.util.List;
+//
+//@Service
+//public class HunYuanClientImpl implements HunYuanClient {
+//
+//    @Value("${tencent.hunyuan.secret-id}")
+//    private String SECRET_ID;
+//    @Value("${tencent.hunyuan.secret-key}")
+//    private String SECRET_KEY;
+//    @Value("${tencent.hunyuan.region}")
+//    private String REGION;
+//
+//    @Value("${spring.application.name}")
+//    private String APPLICATION_NAME;
+//
+//    @Autowired
+//    private SseUtil sseUtil;
+//    @Autowired
+//    private RedisUtil redisUtil;
+//    @Autowired
+//    private BochaService bochaService;
+//
+//    private Message setMessage(String role, String content) {
+//        Message msg = new Message();
+//        msg.setRole(role);
+//        msg.setContent(content);
+//        return msg;
+//    }
+//
+//    /**
+//     * [HunYuan] 发起对话
+//     * https://cloud.tencent.com/document/product/1729/101836
+//     */
+//    @Override
+//    public ChatResult chatCompletion(ChatCompletionParam chatCompletionParam) {
+//
+//        // 参数化
+//        String prompt = chatCompletionParam.getPrompt();
+//        System.out.println("向混元模型 提问: " + prompt);
+//
+//        Long user_id = chatCompletionParam.getUser_id();
+//        String history_code = chatCompletionParam.getHistory_code();
+//        List<Chat> chatList = chatCompletionParam.getChatList();
+//        Boolean internet = chatCompletionParam.getInternet();
+//
+//        // 定义作用于全局的变量
+//        Long replyDuration = 0L;
+//        String requestOfRedisKey = APPLICATION_NAME + "-chat-history-" + history_code;
+//        StringBuilder allReplyContent = new StringBuilder();
+//
+//        // 记录请求开始时间
+//        long allStartTime = System.currentTimeMillis();
+//
+//        // 加入上下文历史对话
+//        System.out.println("---- 历史对话 (history_code): " + history_code + " ----");
+//
+//        List<Message> messages = new ArrayList<>();
+//        if (chatList != null && !chatList.isEmpty()) {
+//            chatList.stream().forEach(chat -> {
+//                // 混元没有 THINK
+//                messages.add(setMessage(chat.getRole(), chat.getContent()));
+//            });
+//            // 反转列表
+//            Collections.reverse(messages);
+//        }
+//
+//        // 返回值结构体
+//        ChatResult chatResult = new ChatResult();
+//
+//        // -- [博查] Web Search API ----------------------------------------------
+//        if (internet) {
+//
+//            // 远程查询、统计接口时间、设置返回参数
+//            long internetStartTime = System.currentTimeMillis();
+//            JsonNode searchResult = bochaService.WebSearch(new BochaParam(prompt));
+//            String context = bochaService.WebSearchToString(searchResult);
+//            long internetEndTime = System.currentTimeMillis();
+//            chatResult.setInternet_duration(internetStartTime - internetEndTime);
+//            chatResult.setInternet_content(context);
+//
+//            // 将搜索结果作为上下文添加到消息中
+//            messages.add(setMessage("system", context));
+//            messages.add(setMessage("user", "在回答时引用以上全部数据进行分析")); // 的 "name"、"summary"
+//            messages.add(setMessage("assistant", "好的"));
+//
+//            // [SSE] 发送消息
+//            ChatSseMessage chatSearchSseMessage = new ChatSseMessage("SEARCH", context, null, history_code);
+//            sseUtil.send(user_id, new SseResponse(SseResponseEnum.OLLAMA, chatSearchSseMessage).toJsonStr());
+//        }
+//        // -----------------------------------------------------------------------
+//
+//        // 新的对话内容
+//        messages.add(setMessage("user", prompt));
+//
+//        // 输出全部对话内容
+//        messages.stream().forEach(msg -> {
+//            System.out.println("[" + msg.getRole() + "]: " + msg.getContent());
+//        });
+//        System.out.println("---------------------------------------------------------------------");
+//
+//
+//        // [混元大模型]
+//        Credential cred = new Credential(SECRET_ID, SECRET_KEY);
+//        ClientProfile clientProfile = new ClientProfile();
+//        HunyuanClient client = new HunyuanClient(cred, REGION, clientProfile);
+//
+//        ChatCompletionsRequest req = new ChatCompletionsRequest();
+//        // 模型名称,可选值包括 hunyuan-lite、hunyuan-standard、hunyuan-standard-256K、hunyuan-pro、
+//        //      hunyuan-code、 hunyuan-role、 hunyuan-functioncall、 hunyuan-vision、 hunyuan-turbo。
+//        // 各模型介绍请阅读 [产品概述](https://cloud.tencent.com/document/product/1729/104753) 中的说明。
+//        // 注意:不同的模型计费不同,请根据 [购买指南](https://cloud.tencent.com/document/product/1729/97731) 按需调用。
+//        req.setModel("hunyuan-standard");
+//        req.setMessages(ArrayUtil.toArray(messages, Message.class));
+//
+//        try {
+//
+//            try (ChatCompletionsResponse resp = client.ChatCompletions(req)) {
+//                Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
+//                for (SSEResponseModel.SSE e : resp) {
+//                    ChatCompletionsResponse eventModel = gson.fromJson(e.Data, ChatCompletionsResponse.class);
+//                    Choice[] choices = eventModel.getChoices();
+//                    if (choices.length > 0) {
+//                        System.out.println(choices[0].getDelta().getContent());
+//                    }
+//                }
+//            }
+//
+////            // 发送对话
+////            try (ChatCompletionsResponse resp = client.ChatCompletions(req)) {
+////
+////                // hunyuan ChatCompletions 同时支持 stream 和非 stream 的情况
+////                req.setStream(true);
+////                if (req.getStream()) {
+////
+////                    // stream 示例
+////                    Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
+////                    for (SSEResponseModel.SSE e : resp) {
+////
+////                        System.out.println("e = " + e);
+////                        System.out.println("data = " + e.Data);
+////
+////                        ChatCompletionsResponse eventModel = gson.fromJson(e.Data, ChatCompletionsResponse.class);
+////                        Choice[] choices = eventModel.getChoices();
+////
+////                        System.out.println("choices = " + choices);
+////
+////                        if (choices.length > 0) {
+////
+////                            String content = choices[0].getDelta().getContent();
+////                            System.out.println("content = " + content);
+////
+////                            // [SSE] 发送消息
+////                            ChatSseMessage chatSseMessage = new ChatSseMessage("REPLY", content, null, history_code);
+////                            sseUtil.send(user_id, new SseResponse(SseResponseEnum.HUNYUAN, chatSseMessage).toJsonStr());
+////
+////                            // 收集回答内容
+////                            allReplyContent.append(content);
+////
+////                            // 判断是否中止
+////                            if (ObjectUtil.isEmpty(redisUtil.getCacheObject(requestOfRedisKey))) {
+////                                System.out.println("中止!");
+////                                allReplyContent.append(" (请求中止)");
+////                                //                    request.abort();
+////                                // 流程结束后,删除锁
+////                                redisUtil.delete(requestOfRedisKey);
+////                                break;
+////                            }
+////
+////                        }
+////
+//////                        // 如果希望在任意时刻中止事件流, 使用 break 即可
+//////                        boolean iWantToCancelNow = false;
+//////                        if (iWantToCancelNow) {
+//////                            break;
+//////                        }
+////                    }
+////
+////
+//////                    for (SSEResponseModel.SSE e : resp) {
+//////
+//////                        //                 System.out.println(e.Data);
+//////                        /**
+//////                         *
+//////                         * .Data:
+//////                         *  {"Note":"以上内容为AI生成,不代表开发者立场,请勿删除或修改本标记","Choices":[{"FinishReason":"","Delta":{"Role":"assistant","Content":"当然"}}],"Created":1709618061,"Id":"e73c0a71-5c98-4893-ba90-ad5056d5871a","Usage":{"PromptTokens":7,"CompletionTokens":1,"TotalTokens":8}}
+//////                         * e.Data:
+//////                         *  {"Note":"以上内容为AI生成,不代表开发者立场,请勿删除或修改本标记","Choices":[{"FinishReason":"","Delta":{"Role":"assistant","Content":"可以"}}],"Created":1709618061,"Id":"e73c0a71-5c98-4893-ba90-ad5056d5871a","Usage":{"PromptTokens":7,"CompletionTokens":2,"TotalTokens":9}}
+//////                         * e.Data:
+//////                         *  {"Note":"以上内容为AI生成,不代表开发者立场,请勿删除或修改本标记","Choices":[{"FinishReason":"","Delta":{"Role":"assistant","Content":","}}],"Created":1709618061,"Id":"e73c0a71-5c98-4893-ba90-ad5056d5871a","Usage":{"PromptTokens":7,"CompletionTokens":3,"TotalTokens":10}}
+//////                         * e.Data:
+//////                         */
+//////
+//////                        ObjectMapper objectMapper = new ObjectMapper();
+//////                        JsonNode node = objectMapper.readTree(e.Data.toString());
+//////                        JsonNode delta = node.path("Choices").path(0).path("Delta");
+//////                        String content = delta.path("Content").asText("");
+//////
+//////                        // [SSE] 发送消息
+//////                        ChatSseMessage chatSseMessage = new ChatSseMessage("REPLY", content, null, history_code);
+//////                        sseUtil.send(user_id, new SseResponse(SseResponseEnum.HUNYUAN, chatSseMessage).toJsonStr());
+//////
+//////                        // 收集回答内容
+//////                        allReplyContent.append(content);
+//////
+//////                        // 判断是否中止
+//////                        if (ObjectUtil.isEmpty(redisUtil.getCacheObject(requestOfRedisKey))) {
+//////                            System.out.println("中止!");
+//////                            allReplyContent.append(" (请求中止)");
+//////                            //                    request.abort();
+//////                            // 流程结束后,删除锁
+//////                            redisUtil.delete(requestOfRedisKey);
+//////                            break;
+//////                        }
+//////
+//////                    }
+//////
+////                    System.out.println("-------------------- 结束流式回答. --------------------");
+////                    replyDuration = System.currentTimeMillis() - allStartTime;
+////
+////                    System.out.println("全部回答: " + allReplyContent);
+////                    System.out.println("总输出耗时: " + replyDuration + " 毫秒");
+////
+////                    chatResult.setContent(allReplyContent.toString());
+////                    chatResult.setContent_duration(replyDuration);
+////                    return chatResult;
+////
+////                } else {
+////                    // 非 stream 示例
+////                    // 通过 Stream=false 参数来指定非 stream 协议, 一次性拿到结果
+////                    String content = client.ChatCompletions(req).getChoices()[0].getMessage().getContent();
+////                    System.out.println("content = " + content);
+////                    chatResult.setContent(content);
+////                    return chatResult;
+////                }
+//////
+//////            } catch (JsonMappingException e) {
+//////                throw new RuntimeException(e);
+//////            } catch (JsonProcessingException e) {
+//////                throw new RuntimeException(e);
+////            }
+//
+//        } catch (TencentCloudSDKException e) {
+//            System.out.println("TencentCloudSDKException: " + e.getMessage());
+//            // [SSE] 发送消息
+//            ChatSseMessage chatSseMessage = new ChatSseMessage("REPLY", e.getMessage(), replyDuration, history_code);
+//            sseUtil.send(user_id, new SseResponse(SseResponseEnum.HUNYUAN, chatSseMessage).toJsonStr());
+//
+//            chatResult.setContent(e.getMessage());
+//            return chatResult;
+//        } finally {
+//            // [SSE] 发送消息
+//            ChatSseMessage chatSseMessage = new ChatSseMessage("REPLY", "[DONE][REPLY]", replyDuration, history_code);
+//            sseUtil.send(user_id, new SseResponse(SseResponseEnum.HUNYUAN, chatSseMessage).toJsonStr());
+//
+//            redisUtil.delete(requestOfRedisKey);
+//        }
+//
+//        return null;
+//
+//    }
+//}