diff --git a/srs-admin/src/main/java/com/srs/web/controller/aitutor/AiChatController.java b/srs-admin/src/main/java/com/srs/web/controller/aitutor/AiChatController.java index b5f7b87..3eef491 100644 --- a/srs-admin/src/main/java/com/srs/web/controller/aitutor/AiChatController.java +++ b/srs-admin/src/main/java/com/srs/web/controller/aitutor/AiChatController.java @@ -88,16 +88,17 @@ public class AiChatController extends BaseController { * 配置了5分钟的读取超时时间,用于与Dify API进行通信 */ private final OkHttpClient client = new OkHttpClient.Builder() - .connectTimeout(Duration.ofSeconds(5)) // 建连超时 - .readTimeout(Duration.ofSeconds(12)) // 读超时(服务端应在此内有数据返回) - .writeTimeout(Duration.ofSeconds(12)) // 写超时 + .connectTimeout(Duration.ofSeconds(5)) // 建连超时 + .readTimeout(Duration.ofSeconds(12)) // 读超时(服务端应在此内有数据返回) + .writeTimeout(Duration.ofSeconds(12)) // 写超时 .retryOnConnectionFailure(true) .build(); + /** 为本次请求设置 “总超时”(含连接/读写),避免无限挂起 */ private Response execWithTimeouts(Request req, int callSecs, int readSecs, int writeSecs) throws IOException { OkHttpClient shortClient = client.newBuilder() - .callTimeout(java.time.Duration.ofSeconds(callSecs)) // 整次调用最大时长 - .readTimeout(java.time.Duration.ofSeconds(readSecs)) // 读超时(这段时间没有字节到达就超时) + .callTimeout(java.time.Duration.ofSeconds(callSecs)) // 整次调用最大时长 + .readTimeout(java.time.Duration.ofSeconds(readSecs)) // 读超时(这段时间没有字节到达就超时) .writeTimeout(java.time.Duration.ofSeconds(writeSecs)) // 写超时 .build(); return shortClient.newCall(req).execute(); @@ -173,13 +174,14 @@ public class AiChatController extends BaseController { * @param currentUsername * @throws IOException 当网络请求或IO操作失败时抛出 */ - private void sendToDifyAndStream(Map requestData, SseEmitter emitter, String currentUsername) throws IOException { + private void sendToDifyAndStream(Map requestData, SseEmitter emitter, String currentUsername) + throws IOException { // 构建请求体参数 Map bodyMap = new HashMap<>(); bodyMap.put("query", requestData.get("query")); // 用户消息内容 - bodyMap.put("user", currentUsername); // 用户标识 - bodyMap.put("response_mode", "streaming"); // 设置为流式响应模式 + bodyMap.put("user", currentUsername); // 用户标识 + bodyMap.put("response_mode", "streaming"); // 设置为流式响应模式 // 如果请求中没有提供conversation_id,则尝试获取或创建一个 if (!requestData.containsKey("conversation_id") || requestData.get("conversation_id") == null) { @@ -232,10 +234,10 @@ public class AiChatController extends BaseController { // 构建HTTP请求 Request httpRequest = new Request.Builder() - .url(DIFY_API_URL) // 设置请求URL + .url(DIFY_API_URL) // 设置请求URL .addHeader("Authorization", "Bearer " + DIFY_API_KEY) // 添加认证头 - .addHeader("Content-Type", "application/json") // 设置内容类型 - .post(body) // 设置为POST请求 + .addHeader("Content-Type", "application/json") // 设置内容类型 + .post(body) // 设置为POST请求 .build(); // 执行HTTP请求 @@ -258,7 +260,8 @@ public class AiChatController extends BaseController { try (BufferedReader reader = new BufferedReader(httpResponse.body().charStream())) { String line; while ((line = reader.readLine()) != null) { - if (line.isEmpty() || !line.startsWith("data:")) continue; + if (line.isEmpty() || !line.startsWith("data:")) + continue; String jsonData = line.substring(5).trim(); if ("[DONE]".equals(jsonData)) { break; @@ -307,13 +310,14 @@ public class AiChatController extends BaseController { * { * "message_id": "msg-123", * "user": "user-1", - * "rating": "like", // "like", "dislike", 或 null + * "rating": "like", // "like", "dislike", 或 null * "content": "回答很好" * } * @return 统一响应结果 */ @PostMapping("/feedback") - public AjaxResult submitFeedback(@org.springframework.web.bind.annotation.RequestBody Map feedbackData) { + public AjaxResult submitFeedback( + @org.springframework.web.bind.annotation.RequestBody Map feedbackData) { // 校验必要字段 String messageId = (String) feedbackData.get("message_id"); if (messageId == null || messageId.trim().isEmpty()) { @@ -349,16 +353,15 @@ public class AiChatController extends BaseController { // 构建请求体(发送给 Dify) Map bodyMap = new HashMap<>(); bodyMap.put("user", user); - bodyMap.put("rating", rating); // 可以是 "like", "dislike", 或 null - bodyMap.put("content", content); // 可选文本反馈 + bodyMap.put("rating", rating); // 可以是 "like", "dislike", 或 null + bodyMap.put("content", content); // 可选文本反馈 try { // 序列化为 JSON String jsonBody = mapper.writeValueAsString(bodyMap); okhttp3.RequestBody body = okhttp3.RequestBody.create( MediaType.get("application/json; charset=utf-8"), - jsonBody - ); + jsonBody); // 调用 Dify API Request request = new Request.Builder() @@ -431,12 +434,19 @@ public class AiChatController extends BaseController { // 提取反馈信息 feedbackItem.put("id", feedbackNode.has("id") ? feedbackNode.get("id").asText() : null); - feedbackItem.put("message_id", feedbackNode.has("message_id") ? feedbackNode.get("message_id").asText() : null); - feedbackItem.put("rating", feedbackNode.has("rating") ? feedbackNode.get("rating").asText() : null); - feedbackItem.put("content", feedbackNode.has("content") ? feedbackNode.get("content").asText() : null); - feedbackItem.put("created_at", feedbackNode.has("created_at") ? feedbackNode.get("created_at").asLong() : null); - feedbackItem.put("app_id", feedbackNode.has("app_id") ? feedbackNode.get("app_id").asText() : null); - feedbackItem.put("conversation_id", feedbackNode.has("conversation_id") ? feedbackNode.get("conversation_id").asText() : null); + feedbackItem.put("message_id", + feedbackNode.has("message_id") ? feedbackNode.get("message_id").asText() : null); + feedbackItem.put("rating", + feedbackNode.has("rating") ? feedbackNode.get("rating").asText() : null); + feedbackItem.put("content", + feedbackNode.has("content") ? feedbackNode.get("content").asText() : null); + feedbackItem.put("created_at", + feedbackNode.has("created_at") ? feedbackNode.get("created_at").asLong() : null); + feedbackItem.put("app_id", + feedbackNode.has("app_id") ? feedbackNode.get("app_id").asText() : null); + feedbackItem.put("conversation_id", + feedbackNode.has("conversation_id") ? feedbackNode.get("conversation_id").asText() + : null); feedbackList.add(feedbackItem); } @@ -472,13 +482,13 @@ public class AiChatController extends BaseController { } } - // 权限标识为辅导员 + // 权限标识为辅导员 @PreAuthorize("@ss.hasPermi('cph:teacher:list')") @GetMapping("/getMessagesToAdmin") public AjaxResult getMessagesToAdmin(@RequestParam String user, - @RequestParam(required = false) String firstId, - @RequestParam(defaultValue = "20") int limit, - @RequestParam(defaultValue = "-updated_at") String sortBy) { + @RequestParam(required = false) String firstId, + @RequestParam(defaultValue = "20") int limit, + @RequestParam(defaultValue = "-updated_at") String sortBy) { try { List conversations = getConversations(user); @@ -501,14 +511,15 @@ public class AiChatController extends BaseController { } } - // 权限标识为学生 + // 权限标识为学生 @GetMapping("/getMessagesToUser") public AjaxResult getMessagesToUser(@RequestParam(required = false) String firstId, - @RequestParam(defaultValue = "20") int limit, - @RequestParam(defaultValue = "-updated_at") String sortBy) { + @RequestParam(defaultValue = "20") int limit, + @RequestParam(defaultValue = "-updated_at") String sortBy) { try { String user = SecurityUtils.getLoginUser().getUsername(); + List conversations = getConversations(user); if (conversations == null || conversations.isEmpty()) { @@ -516,6 +527,7 @@ public class AiChatController extends BaseController { } String conversation_id = conversations.get(0).getId(); + Map result = getConversationHistoryMessages(conversation_id, user, firstId, limit); AjaxResult successResult = success(result); @@ -529,11 +541,11 @@ public class AiChatController extends BaseController { } } - /* * 获取会话列表 - * */ - public List getConversations(String user, String lastId, int limit, String sortBy) throws IOException { + */ + public List getConversations(String user, String lastId, int limit, String sortBy) + throws IOException { // 构建带查询参数的 URL HttpUrl.Builder urlBuilder = HttpUrl.parse(DIFY_CONVERSATIONS_URL).newBuilder(); urlBuilder.addQueryParameter("user", user); @@ -599,8 +611,7 @@ public class AiChatController extends BaseController { return getConversations(user, null, limit, sortBy); } - - //获取历史消息 + // 获取历史消息 private Map getConversationHistoryMessages( String conversationId, String user, @@ -688,11 +699,6 @@ public class AiChatController extends BaseController { return result; } - - - - - /** * 文件上传接口 *

@@ -706,7 +712,7 @@ public class AiChatController extends BaseController { */ @PostMapping("/files/upload") public AjaxResult uploadFile(@RequestParam("file") MultipartFile file, - @RequestParam("user") String user) { + @RequestParam("user") String user) { try { // 检查文件是否为空 if (file.isEmpty()) { @@ -718,7 +724,7 @@ public class AiChatController extends BaseController { .setType(MultipartBody.FORM) .addFormDataPart("user", user) .addFormDataPart("file", file.getOriginalFilename(), - RequestBody.create(MediaType.parse("application/octet-stream"),file.getBytes())) + RequestBody.create(MediaType.parse("application/octet-stream"), file.getBytes())) .build(); // 构建请求