cr vor 4 Monaten
Ursprung
Commit
7025ae1916

+ 131 - 62
blade-common/src/main/java/org/springblade/common/utils/DeepSeekClient.java

@@ -1,17 +1,17 @@
 package org.springblade.common.utils;
 
-import okhttp3.*;
 import com.google.gson.Gson;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
-import org.springblade.common.vo.DeepSeekResponse;
+import okhttp3.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 
 import java.io.IOException;
-import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 @Component
 public class DeepSeekClient {
@@ -21,90 +21,66 @@ public class DeepSeekClient {
 
     private static final String API_URL = "https://api.deepseek.com/v1/chat/completions";
 
-    private final OkHttpClient client = new OkHttpClient();
+    private final OkHttpClient client;
     private final Gson gson = new Gson();
 
+    public DeepSeekClient() {
+        this.client = new OkHttpClient.Builder()
+                .connectTimeout(30, TimeUnit.SECONDS)
+                .readTimeout(60, TimeUnit.SECONDS)
+                .writeTimeout(30, TimeUnit.SECONDS)
+                .build();
+    }
+
     /**
      * 请求 DeepSeek API
-     * @param prompt 需要发送的文字
-     * @return API 响应
-     * @throws IOException
      */
     public String callDeepSeek(String prompt) throws IOException {
-        // 使用 V3 模型
         DeepSeekRequest request = new DeepSeekRequest(prompt, "deepseek-chat");
-
-        // 构造请求体
         String requestJson = gson.toJson(request);
-        logger.debug("Sending request to DeepSeek: {}", requestJson);
 
-        RequestBody body = RequestBody.create(
-                requestJson,
-                MediaType.parse("application/json")
-        );
+        logger.debug("Sending request to DeepSeek: {}", requestJson);
 
-        // 构造请求
         Request httpRequest = new Request.Builder()
                 .url(API_URL)
-                .post(body)
+                .post(RequestBody.create(requestJson, MediaType.parse("application/json")))
                 .addHeader("Authorization", "Bearer " + API_KEY)
                 .addHeader("Content-Type", "application/json")
                 .addHeader("Accept", "application/json")
                 .build();
 
-        // 发送请求并获取响应
         try (Response response = client.newCall(httpRequest).execute()) {
             if (!response.isSuccessful()) {
                 String errorBody = response.body() != null ? response.body().string() : "No error body";
                 logger.error("API request failed with code: {}, Body: {}", response.code(), errorBody);
-                throw new IOException("API request failed with code: " + response.code() + ", Body: " + errorBody);
+                throw new IOException("API request failed with code: " + response.code());
             }
-
-            String responseBody = response.body().string();
-            logger.debug("Received response from DeepSeek: {}", responseBody);
-            return responseBody;
+            return response.body().string();
         }
     }
 
     /**
      * 解析响应获取结果
-     * @param responseJson 请求 deepseek 返回响应值
-     * @return 消息内容
      */
     public String analysisResponse(String responseJson) {
         try {
-            // 使用 JsonParser 替代 Gson.fromJson 以便更好的错误处理
             JsonObject jsonObject = JsonParser.parseString(responseJson).getAsJsonObject();
 
-            // 检查是否有错误
             if (jsonObject.has("error")) {
                 JsonObject error = jsonObject.getAsJsonObject("error");
                 String errorMsg = error.get("message").getAsString();
                 logger.error("API returned error: {}", errorMsg);
-                return "API Error: " + errorMsg;
+                return "Error: " + errorMsg;
             }
 
-            // 解析为对象
             DeepSeekResponse response = gson.fromJson(jsonObject, DeepSeekResponse.class);
 
-            // 安全地获取 content 内容
-            if (response == null) {
-                logger.error("Failed to parse response JSON");
-                return "Error: Failed to parse response";
-            }
-
-            if (response.getChoices() == null || response.getChoices().isEmpty()) {
-                logger.error("No choices in response");
-                return "Error: No choices in response";
-            }
-
-            DeepSeekResponse.Choice firstChoice = response.getChoices().get(0);
-            if (firstChoice.getMessage() == null) {
-                logger.error("No message in choice");
-                return "Error: No message in choice";
+            if (response == null || response.getChoices() == null || response.getChoices().isEmpty()) {
+                logger.error("Invalid response structure");
+                return "Error: Invalid response structure";
             }
 
-            return firstChoice.getMessage().getContent();
+            return response.getChoices().get(0).getMessage().getContent();
         } catch (Exception e) {
             logger.error("Error parsing response: {}", e.getMessage());
             return "Error: " + e.getMessage();
@@ -112,9 +88,7 @@ public class DeepSeekClient {
     }
 
     /**
-     * 直接获取精简后的内容(一步完成调用和解析)
-     * @param prompt 提示词
-     * @return 精简后的内容
+     * 直接获取精简后的内容
      */
     public String getSimplifiedContent(String prompt) {
         try {
@@ -126,33 +100,128 @@ public class DeepSeekClient {
         }
     }
 
-    // 请求参数类 - 支持多种模型
     static class DeepSeekRequest {
-        String model;
-        Message[] messages;
-        double temperature = 0.7;
-        int max_tokens = 2000;
-        boolean stream = false;
+        private String model;
+        private Message[] messages;
+        private double temperature = 0.7;
+        private int max_tokens = 2000;
+        private boolean stream = false;
 
-        public DeepSeekRequest(String prompt) {
-            this(prompt, "deepseek-chat"); // 默认使用 V3 模型
+        // 构造函数
+        public DeepSeekRequest(String prompt, String model) {
+            this.model = model;
+            this.messages = new Message[]{new Message("user", prompt)};
         }
 
-        public DeepSeekRequest(String prompt, String model) {
+        // Getters and Setters
+        public String getModel() {
+            return model;
+        }
+
+        public void setModel(String model) {
             this.model = model;
-            this.messages = new Message[]{
-                    new Message("user", prompt)
-            };
+        }
+
+        public Message[] getMessages() {
+            return messages;
+        }
+
+        public void setMessages(Message[] messages) {
+            this.messages = messages;
+        }
+
+        public double getTemperature() {
+            return temperature;
+        }
+
+        public void setTemperature(double temperature) {
+            this.temperature = temperature;
+        }
+
+        public int getMax_tokens() {
+            return max_tokens;
+        }
+
+        public void setMax_tokens(int max_tokens) {
+            this.max_tokens = max_tokens;
+        }
+
+        public boolean isStream() {
+            return stream;
+        }
+
+        public void setStream(boolean stream) {
+            this.stream = stream;
         }
     }
 
     static class Message {
-        String role;
-        String content;
+        private String role;
+        private String content;
 
+        // 构造函数
         public Message(String role, String content) {
             this.role = role;
             this.content = content;
         }
+
+        // Getters and Setters
+        public String getRole() {
+            return role;
+        }
+
+        public void setRole(String role) {
+            this.role = role;
+        }
+
+        public String getContent() {
+            return content;
+        }
+
+        public void setContent(String content) {
+            this.content = content;
+        }
+    }
+
+    static class DeepSeekResponse {
+        private List<Choice> choices;
+
+        public List<Choice> getChoices() {
+            return choices;
+        }
+
+        public void setChoices(List<Choice> choices) {
+            this.choices = choices;
+        }
+
+        static class Choice {
+            private Message message;
+            private int index;
+            private String finish_reason;
+
+            public Message getMessage() {
+                return message;
+            }
+
+            public void setMessage(Message message) {
+                this.message = message;
+            }
+
+            public int getIndex() {
+                return index;
+            }
+
+            public void setIndex(int index) {
+                this.index = index;
+            }
+
+            public String getFinish_reason() {
+                return finish_reason;
+            }
+
+            public void setFinish_reason(String finish_reason) {
+                this.finish_reason = finish_reason;
+            }
+        }
     }
 }

+ 42 - 11
blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchiveAiNameServiceImpl.java

@@ -35,10 +35,14 @@ import org.springframework.stereotype.Service;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import org.springframework.transaction.annotation.Transactional;
 
+import javax.annotation.Resource;
 import java.io.IOException;
 import java.text.SimpleDateFormat;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.ThreadPoolExecutor;
 import java.util.stream.Collectors;
 
 import static java.util.stream.Collectors.groupingBy;
@@ -52,24 +56,51 @@ import static java.util.stream.Collectors.groupingBy;
 @Service
 public class ArchiveAiNameServiceImpl extends BaseServiceImpl<ArchiveAiNameMapper, ArchiveAiName> implements IArchiveAiNameService {
 
-	 static String DEEPSEEK_ARCHIVE_NAME = ".这是一段案卷题名,精简案卷题名重复啰嗦的内容,不要加以上内容没有的词语 返回值不要有任何多余得废话,只要结果";
+	 private static String DEEPSEEK_ARCHIVE_NAME = ".这是一段案卷题名,精简案卷题名重复啰嗦的内容,不要加以上内容没有的词语 返回值不要有任何多余得废话,只要结果";
+	 private static final int MAX_CONCURRENT_REQUESTS = 5;
 
-	 @Autowired
-	 private  JdbcTemplate jdbcTemplate;
+	@Autowired
+	private JdbcTemplate jdbcTemplate;
 
 	@Autowired
 	private DeepSeekClient deepSeekClient;
 
+	@Resource(name = "taskExecutor1")
+	private ThreadPoolExecutor executor;
+
+	private final Semaphore apiSemaphore = new Semaphore(MAX_CONCURRENT_REQUESTS);
+
 	@Override
-	@Async
-	public void syncCreatAiName(List<ArchiveAiName> aiNames) throws IOException {
-		for (ArchiveAiName name : aiNames) {
-			String archiveNameAi = deepSeekClient.callDeepSeek(name.getArchiveName()+DEEPSEEK_ARCHIVE_NAME);
-			String content = deepSeekClient.analysisResponse(archiveNameAi);
-			name.setArchiveNameAi(content);
-			name.setStatus(2);
+	@Async("taskExecutor1")
+	@Transactional
+	public void syncCreatAiName(List<ArchiveAiName> aiNames) {
+		aiNames.parallelStream().forEach(name -> {
+			try {
+				apiSemaphore.acquire();
+				try {
+					String content = deepSeekClient.getSimplifiedContent(name.getArchiveName() + DEEPSEEK_ARCHIVE_NAME);
+					name.setArchiveNameAi(content);
+					name.setStatus(2);
+				} finally {
+					apiSemaphore.release();
+				}
+			} catch (InterruptedException e) {
+				Thread.currentThread().interrupt();
+				name.setStatus(2); // 设置失败状态
+				name.setArchiveNameAi("获取失败");
+			} catch (Exception e) {
+				name.setStatus(2); // 设置失败状态
+				name.setArchiveNameAi("获取失败");
+			}
+		});
+
+		// 分批更新数据库
+		int batchSize = 100;
+		for (int i = 0; i < aiNames.size(); i += batchSize) {
+			int end = Math.min(i + batchSize, aiNames.size());
+			List<ArchiveAiName> batch = aiNames.subList(i, end);
+			this.updateBatchById(batch);
 		}
-		this.updateBatchById(aiNames);
 	}
 
 	@Override