package com.emotion.service.impl; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.emotion.entity.Message; import com.emotion.entity.Conversation; import com.emotion.entity.CozeApiCall; import com.emotion.service.AIChatService; import com.emotion.service.MessageService; import com.emotion.service.ConversationService; import com.emotion.service.CozeApiCallService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.HashMap; import java.util.Map; import java.util.UUID; /** * AI聊天服务实现类 * * @author emotion-museum * @date 2025-07-24 */ @Slf4j @Service public class AiChatServiceImpl implements AIChatService { @Autowired private RestTemplate restTemplate; @Autowired private MessageService messageService; @Autowired private ConversationService conversationService; @Autowired private CozeApiCallService cozeApiCallService; @Value("${emotion.coze.api.token:}") private String cozeApiToken; @Value("${emotion.coze.api.base-url:https://api.coze.cn}") private String cozeBaseUrl; @Value("${emotion.coze.api.chat.path:/v3/chat}") private String chatPath; @Value("${emotion.coze.api.chat.talk.bot-id:}") private String chatBotId; @Value("${emotion.coze.api.chat.talk.workflow-id:}") private String chatWorkflowId; @Value("${emotion.coze.api.chat.summary.bot-id:}") private String summaryBotId; @Value("${emotion.coze.api.chat.summary.workflow-id:}") private String summaryWorkflowId; @Value("${emotion.coze.api.timeout:30000}") private int timeout; @Value("${emotion.coze.api.retry-count:3}") private int retryCount; @Value("${emotion.coze.api.retry-delay:1000}") private int retryDelay; private static final String DEFAULT_USER_ID = "emotion-museum-user"; // API 相关常量 private static final String CONTENT_KEY = "content"; private static final String ROLE_KEY = "role"; private static final String USER_ROLE = "user"; private static final String ASSISTANT_ROLE = "assistant"; private static final String CONTENT_TYPE_KEY = "content_type"; private static final String TEXT_TYPE = "text"; private static final String ANSWER_TYPE = "answer"; @Override public String sendChatMessage(String conversationId, String message, String userId) { log.info("发送聊天消息: conversationId={}, userId={}, message={}", conversationId, userId, message); try { // 调用Coze API String aiReply = sendMessage(conversationId, message, userId); // 保存用户消息 Message userMessage = new Message(); userMessage.setConversationId(conversationId); userMessage.setCreateBy(userId); userMessage.setContent(message); userMessage.setType("text"); userMessage.setSender("user"); userMessage = messageService.createMessage(userMessage); // 保存AI回复 Message aiMessage = new Message(); aiMessage.setConversationId(conversationId); aiMessage.setCreateBy("ai"); aiMessage.setContent(aiReply); aiMessage.setType("text"); aiMessage.setSender("ai"); aiMessage = messageService.createMessage(aiMessage); log.info("聊天消息处理完成: userMessageId={}, aiMessageId={}", userMessage.getId(), aiMessage.getId()); return aiReply; } catch (Exception e) { log.error("发送聊天消息失败", e); return "抱歉,我暂时无法回复,请稍后再试。"; } } @Override public String generateConversationSummary(String conversationId, String userId) { log.info("生成对话总结: conversationId={}, userId={}", conversationId, userId); try { // 获取对话历史 String conversationHistory = getConversationHistory(conversationId); // 构建总结请求 String summaryPrompt = "请为以下对话生成一个简洁的总结:\n\n" + conversationHistory; // 调用AI生成总结 - 使用专门的总结bot String summary = sendSummaryMessage(conversationId, summaryPrompt, userId); log.info("对话总结生成完成: conversationId={}", conversationId); return summary; } catch (Exception e) { log.error("生成对话总结失败", e); return "无法生成对话总结,请稍后再试。"; } } @Override public boolean isServiceAvailable() { try { // 简单的健康检查 return cozeApiToken != null && !cozeApiToken.isEmpty() && chatBotId != null && !chatBotId.isEmpty(); } catch (Exception e) { log.error("检查AI服务可用性失败", e); return false; } } @Override public String getServiceStatus() { if (isServiceAvailable()) { return "available"; } else { return "unavailable"; } } @Override public String sendMessage(String conversationId, String userMessage, String userId) { log.info("发送消息到Coze AI: conversationId={}, userId={}", conversationId, userId); // 创建API调用记录 CozeApiCall apiCall = createApiCallRecord(conversationId, userMessage, userId, "chat"); try { // 构建请求头 HttpHeaders headers = new HttpHeaders(); headers.set("Authorization", "Bearer " + cozeApiToken); headers.set("Content-Type", "application/json"); // 构建请求体 - 使用正确的Coze API格式 Map requestBody = buildCozeRequest(conversationId, userMessage, userId); // 更新API调用记录的请求信息 updateApiCallRequest(apiCall, cozeBaseUrl + chatPath, requestBody, headers); HttpEntity> request = new HttpEntity<>(requestBody, headers); // 构建完整的API URL String cozeApiUrl = cozeBaseUrl + chatPath; log.info("发送Coze请求到: {}, 请求体: {}", cozeApiUrl, requestBody); // 发送请求 ResponseEntity response = restTemplate.exchange( cozeApiUrl, HttpMethod.POST, request, String.class); log.info("收到Coze初始响应: {}", response.getBody()); // 更新API调用记录的响应信息 updateApiCallResponse(apiCall, response); // 解析响应获取chat_id和conversation_id JSONObject responseJson = JSON.parseObject(response.getBody()); String chatId = extractChatIdFromResponse(responseJson); String cozeConversationId = extractConversationIdFromResponse(responseJson); if (chatId != null && cozeConversationId != null) { // 更新API调用记录的Coze ID信息 updateApiCallCozeIds(apiCall, chatId, cozeConversationId); // 轮询聊天状态直到完成并获取回复内容 String aiReply = waitForChatCompletionWithTracking(chatId, cozeConversationId, apiCall); log.info("Coze AI响应成功: reply={}", aiReply); // 更新API调用记录的最终结果 updateApiCallSuccess(apiCall, aiReply); return aiReply; } else { log.error("无法从Coze响应中获取chat_id或conversation_id"); updateApiCallError(apiCall, "INVALID_RESPONSE", "无法从Coze响应中获取chat_id或conversation_id"); return "抱歉,AI服务响应异常,请稍后再试。"; } } catch (Exception e) { log.error("发送消息到Coze AI失败", e); updateApiCallError(apiCall, "REQUEST_FAILED", e.getMessage()); return "抱歉,AI服务暂时不可用,请稍后再试。"; } } @Override public Map guestChat(String message, String clientIp) { log.info("访客聊天: message={}, clientIp={}", message, clientIp); Map result = new HashMap<>(); try { // 生成访客会话ID String guestConversationId = "guest_" + clientIp.replace(".", "_") + "_" + System.currentTimeMillis(); // 调用AI服务 String aiReply = sendMessage(guestConversationId, message, "guest"); // 保存访客消息 Message guestMessage = new Message(); guestMessage.setConversationId(guestConversationId); guestMessage.setCreateBy("guest"); guestMessage.setContent(message); guestMessage.setType("text"); guestMessage.setSender("guest"); guestMessage = messageService.createMessage(guestMessage); // 保存AI回复 Message aiMessage = new Message(); aiMessage.setConversationId(guestConversationId); aiMessage.setCreateBy("ai"); aiMessage.setContent(aiReply); aiMessage.setType("text"); aiMessage.setSender("ai"); aiMessage = messageService.createMessage(aiMessage); result.put("message", aiReply); result.put("messageId", aiMessage.getId()); result.put("timestamp", System.currentTimeMillis()); result.put("error", false); log.info("访客聊天处理完成: guestMessageId={}, aiMessageId={}", guestMessage.getId(), aiMessage.getId()); } catch (Exception e) { log.error("访客聊天失败", e); result.put("message", "抱歉,服务暂时不可用,请稍后再试。"); result.put("messageId", null); result.put("timestamp", System.currentTimeMillis()); result.put("error", true); } return result; } @Override public Map createConversation(String userId, String title) { log.info("创建对话: userId={}, title={}", userId, title); Map result = new HashMap<>(); try { // 调用数据库服务创建对话 Conversation conversation = conversationService.createConversation(userId, title, "user"); result.put("conversationId", conversation.getId()); result.put("title", title); result.put("userId", userId); result.put("createTime", System.currentTimeMillis()); result.put("success", true); log.info("对话创建成功: conversationId={}", conversation.getId()); } catch (Exception e) { log.error("创建对话失败", e); result.put("success", false); result.put("error", "创建对话失败"); } return result; } @Override public Map getGuestUserInfo(String clientIp) { log.info("获取访客用户信息: clientIp={}", clientIp); Map result = new HashMap<>(); try { // 生成访客用户信息 String guestId = "guest_" + clientIp.replace(".", "_"); String guestUsername = "访客_" + clientIp.substring(clientIp.lastIndexOf(".") + 1); result.put("id", guestId); result.put("username", guestUsername); result.put("nickname", guestUsername); result.put("type", "guest"); result.put("clientIp", clientIp); result.put("createTime", System.currentTimeMillis()); log.info("访客用户信息获取成功: guestId={}", guestId); } catch (Exception e) { log.error("获取访客用户信息失败", e); result.put("error", "获取用户信息失败"); } return result; } @Override public String streamChat(String conversationId, String message, String userId) { log.info("流式聊天: conversationId={}, userId={}", conversationId, userId); try { // 构建流式请求 Map requestBody = buildCozeRequest(conversationId, message, userId); requestBody.put("stream", true); // 这里应该实现流式处理,暂时降级到普通聊天 return sendMessage(conversationId, message, userId); } catch (Exception e) { log.error("流式聊天失败", e); return "抱歉,流式聊天暂时不可用,请稍后再试。"; } } @Override public boolean healthCheck() { try { // 简化健康检查 - 检查必要配置是否存在 boolean configValid = cozeApiToken != null && !cozeApiToken.trim().isEmpty() && chatBotId != null && !chatBotId.trim().isEmpty() && cozeBaseUrl != null && !cozeBaseUrl.trim().isEmpty(); if (!configValid) { log.warn("Coze API 配置不完整"); return false; } // 可选:发送一个简单的测试请求 // 这里可以调用一个轻量级的API来验证连接 return true; } catch (Exception e) { log.error("健康检查失败: {}", e.getMessage()); return false; } } /** * 构建Coze API请求 - 根据官方文档修正格式 */ private Map buildCozeRequest(String conversationId, String userMessage, String userId) { Map cozeRequest = new HashMap<>(); cozeRequest.put("bot_id", chatBotId); // 如果有workflow_id,则添加 if (chatWorkflowId != null && !chatWorkflowId.trim().isEmpty()) { cozeRequest.put("workflow_id", chatWorkflowId); } cozeRequest.put("user_id", userId != null ? userId : DEFAULT_USER_ID); cozeRequest.put("stream", false); // 构建消息列表 - 按照 Coze API 标准格式 java.util.List> messages = new java.util.ArrayList<>(); // 添加当前用户消息 Map currentMsg = new HashMap<>(); currentMsg.put(ROLE_KEY, USER_ROLE); currentMsg.put(CONTENT_KEY, userMessage); currentMsg.put(CONTENT_TYPE_KEY, TEXT_TYPE); currentMsg.put("type", "question"); messages.add(currentMsg); cozeRequest.put("additional_messages", messages); cozeRequest.put("parameters", new HashMap<>()); return cozeRequest; } /** * 从Coze响应中提取chat_id */ private String extractChatIdFromResponse(JSONObject responseJson) { try { if (responseJson != null && responseJson.getJSONObject("data") != null) { return responseJson.getJSONObject("data").getString("id"); } } catch (Exception e) { log.error("提取chat_id失败: {}", e.getMessage()); } return null; } /** * 从Coze响应中提取conversation_id */ private String extractConversationIdFromResponse(JSONObject responseJson) { try { if (responseJson != null && responseJson.getJSONObject("data") != null) { return responseJson.getJSONObject("data").getString("conversation_id"); } } catch (Exception e) { log.error("提取conversation_id失败: {}", e.getMessage()); } return null; } /** * 等待聊天完成并获取回复内容 */ private String waitForChatCompletion(String chatId, String conversationId) { try { // 最多等待30秒,每2秒轮询一次 int maxAttempts = 15; int attempt = 0; while (attempt < maxAttempts) { log.info("轮询聊天状态,第{}次尝试: chatId={}, conversationId={}", attempt + 1, chatId, conversationId); // 构建状态查询URL String statusUrl = cozeBaseUrl + "/v3/chat/retrieve?chat_id=" + chatId + "&conversation_id=" + conversationId; // 构建请求头 HttpHeaders headers = new HttpHeaders(); headers.set("Authorization", "Bearer " + cozeApiToken); headers.set("Content-Type", "application/json"); HttpEntity request = new HttpEntity<>(headers); // 发送状态查询请求 ResponseEntity response = restTemplate.exchange( statusUrl, HttpMethod.GET, request, String.class); JSONObject statusResponse = JSON.parseObject(response.getBody()); log.info("轮询响应: {}", statusResponse); if (statusResponse != null && statusResponse.getJSONObject("data") != null) { JSONObject data = statusResponse.getJSONObject("data"); String status = data.getString("status"); log.info("聊天状态: {}", status); if ("completed".equals(status)) { // 聊天完成,获取消息 log.info("聊天完成,开始获取消息: chatId={}, conversationId={}", chatId, conversationId); return getChatMessages(chatId, conversationId); } else if ("failed".equals(status)) { log.error("Coze聊天失败: chatId={}, conversationId={}", chatId, conversationId); return "抱歉,AI服务暂时不可用,请稍后再试。"; } } else { log.warn("轮询响应为空或无data字段: {}", statusResponse); } // 等待2秒后重试 Thread.sleep(2000); attempt++; } log.warn("Coze聊天超时: chatId={}, conversationId={}", chatId, conversationId); return "抱歉,AI响应超时,请稍后再试。"; } catch (Exception e) { log.error("等待Coze聊天完成失败: chatId={}, conversationId={}, error={}", chatId, conversationId, e.getMessage(), e); return "抱歉,AI服务出现错误,请稍后再试。"; } } /** * 获取聊天消息 */ private String getChatMessages(String chatId, String conversationId) { try { log.info("获取聊天消息: chatId={}, conversationId={}", chatId, conversationId); // 构建消息查询URL String messagesUrl = cozeBaseUrl + "/v3/chat/message/list?chat_id=" + chatId + "&conversation_id=" + conversationId; // 构建请求头 HttpHeaders headers = new HttpHeaders(); headers.set("Authorization", "Bearer " + cozeApiToken); headers.set("Content-Type", "application/json"); HttpEntity request = new HttpEntity<>(headers); // 发送消息查询请求 ResponseEntity response = restTemplate.exchange( messagesUrl, HttpMethod.GET, request, String.class); JSONObject messagesResponse = JSON.parseObject(response.getBody()); log.info("消息响应: {}", messagesResponse); if (messagesResponse != null && messagesResponse.getJSONArray("data") != null) { java.util.List messages = messagesResponse.getJSONArray("data").toJavaList(JSONObject.class); log.info("收到{}条消息", messages.size()); // 查找AI的回复消息(role=assistant, type=answer) for (JSONObject message : messages) { String role = message.getString("role"); String type = message.getString("type"); log.info("消息详情: role={}, type={}, content={}", role, type, message.getString("content")); if (ASSISTANT_ROLE.equals(role) && ANSWER_TYPE.equals(type)) { String content = message.getString("content"); log.info("找到AI回复: {}", content); return content; } } log.warn("未找到AI回复消息"); } else { log.warn("消息响应为空或无data字段"); } return "抱歉,未能获取到AI回复。"; } catch (Exception e) { log.error("获取Coze聊天消息失败: chatId={}, conversationId={}, error={}", chatId, conversationId, e.getMessage(), e); return "抱歉,获取AI回复失败。"; } } /** * 发送总结消息到Coze AI */ private String sendSummaryMessage(String conversationId, String userMessage, String userId) { log.info("发送总结消息到Coze AI: conversationId={}, userId={}", conversationId, userId); // 创建API调用记录 CozeApiCall apiCall = createSummaryApiCallRecord(conversationId, userMessage, userId, "summary"); try { // 构建请求头 HttpHeaders headers = new HttpHeaders(); headers.set("Authorization", "Bearer " + cozeApiToken); headers.set("Content-Type", "application/json"); // 构建请求体 - 使用总结专用的bot和workflow Map requestBody = buildSummaryRequest(conversationId, userMessage, userId); // 更新API调用记录的请求信息 updateApiCallRequest(apiCall, cozeBaseUrl + chatPath, requestBody, headers); HttpEntity> request = new HttpEntity<>(requestBody, headers); // 构建完整的API URL String cozeApiUrl = cozeBaseUrl + chatPath; log.info("发送Coze总结请求到: {}, 请求体: {}", cozeApiUrl, requestBody); // 发送请求 ResponseEntity response = restTemplate.exchange( cozeApiUrl, HttpMethod.POST, request, String.class); log.info("收到Coze总结初始响应: {}", response.getBody()); // 更新API调用记录的响应信息 updateApiCallResponse(apiCall, response); // 解析响应获取chat_id和conversation_id JSONObject responseJson = JSON.parseObject(response.getBody()); String chatId = extractChatIdFromResponse(responseJson); String cozeConversationId = extractConversationIdFromResponse(responseJson); if (chatId != null && cozeConversationId != null) { // 更新API调用记录的Coze ID信息 updateApiCallCozeIds(apiCall, chatId, cozeConversationId); // 轮询聊天状态直到完成并获取回复内容 String aiReply = waitForChatCompletionWithTracking(chatId, cozeConversationId, apiCall); log.info("Coze AI总结响应成功: reply={}", aiReply); // 更新API调用记录的最终结果 updateApiCallSuccess(apiCall, aiReply); return aiReply; } else { log.error("无法从Coze总结响应中获取chat_id或conversation_id"); updateApiCallError(apiCall, "INVALID_RESPONSE", "无法从Coze总结响应中获取chat_id或conversation_id"); return "抱歉,AI总结服务响应异常,请稍后再试。"; } } catch (Exception e) { log.error("发送总结消息到Coze AI失败", e); updateApiCallError(apiCall, "REQUEST_FAILED", e.getMessage()); return "抱歉,AI总结服务暂时不可用,请稍后再试。"; } } /** * 构建总结请求 - 使用专门的总结bot和workflow */ private Map buildSummaryRequest(String conversationId, String userMessage, String userId) { Map cozeRequest = new HashMap<>(); cozeRequest.put("bot_id", summaryBotId != null && !summaryBotId.trim().isEmpty() ? summaryBotId : chatBotId); // 如果有总结workflow_id,则添加 if (summaryWorkflowId != null && !summaryWorkflowId.trim().isEmpty()) { cozeRequest.put("workflow_id", summaryWorkflowId); } cozeRequest.put("user_id", userId != null ? userId : DEFAULT_USER_ID); cozeRequest.put("stream", false); cozeRequest.put("auto_save_history", true); // 如果有会话ID,则添加 if (conversationId != null && !conversationId.trim().isEmpty()) { cozeRequest.put("conversation_id", conversationId); } // 构建消息列表 - 按照 Coze API 标准格式 java.util.List> messages = new java.util.ArrayList<>(); // 添加当前用户消息 Map currentMsg = new HashMap<>(); currentMsg.put(ROLE_KEY, USER_ROLE); currentMsg.put(CONTENT_KEY, userMessage); currentMsg.put(CONTENT_TYPE_KEY, TEXT_TYPE); messages.add(currentMsg); cozeRequest.put("additional_messages", messages); return cozeRequest; } /** * 获取对话历史 */ private String getConversationHistory(String conversationId) { try { // 这里应该从数据库获取对话历史 // 暂时返回空字符串 return ""; } catch (Exception e) { log.error("获取对话历史失败", e); return ""; } } /** * 创建API调用记录 */ private CozeApiCall createApiCallRecord(String conversationId, String userMessage, String userId, String requestType) { CozeApiCall apiCall = CozeApiCall.builder() .conversationId(conversationId) .userId(userId) .requestType(requestType) .userMessage(userMessage) .userMessageType("text") .botId(chatBotId) .workflowId(chatWorkflowId) .status("pending") .startTime(LocalDateTime.now()) .traceId(UUID.randomUUID().toString()) .build(); // 获取客户端信息 try { HttpServletRequest request = getCurrentRequest(); if (request != null) { apiCall.setClientIp(getClientIp(request)); apiCall.setUserAgent(request.getHeader("User-Agent")); apiCall.setSessionId(request.getSession().getId()); } } catch (Exception e) { log.warn("获取客户端信息失败: {}", e.getMessage()); } // 保存API调用记录 cozeApiCallService.save(apiCall); log.info("创建API调用记录: id={}, traceId={}", apiCall.getId(), apiCall.getTraceId()); return apiCall; } /** * 创建总结API调用记录 */ private CozeApiCall createSummaryApiCallRecord(String conversationId, String userMessage, String userId, String requestType) { CozeApiCall apiCall = CozeApiCall.builder() .conversationId(conversationId) .userId(userId) .requestType(requestType) .userMessage(userMessage) .userMessageType("text") .botId(summaryBotId) .workflowId(summaryWorkflowId) .status("pending") .startTime(LocalDateTime.now()) .traceId(UUID.randomUUID().toString()) .build(); // 获取客户端信息 try { HttpServletRequest request = getCurrentRequest(); if (request != null) { apiCall.setClientIp(getClientIp(request)); apiCall.setUserAgent(request.getHeader("User-Agent")); apiCall.setSessionId(request.getSession().getId()); } } catch (Exception e) { log.warn("获取客户端信息失败: {}", e.getMessage()); } // 保存API调用记录 cozeApiCallService.save(apiCall); log.info("创建总结API调用记录: id={}, traceId={}", apiCall.getId(), apiCall.getTraceId()); return apiCall; } /** * 更新API调用记录的请求信息 */ private void updateApiCallRequest(CozeApiCall apiCall, String requestUrl, Map requestBody, HttpHeaders headers) { try { apiCall.setRequestUrl(requestUrl); apiCall.setRequestBody(JSON.toJSONString(requestBody)); apiCall.setRequestHeaders(JSON.toJSONString(headers.toSingleValueMap())); cozeApiCallService.updateById(apiCall); } catch (Exception e) { log.error("更新API调用记录请求信息失败: {}", e.getMessage(), e); } } /** * 更新API调用记录的响应信息 */ private void updateApiCallResponse(CozeApiCall apiCall, ResponseEntity response) { try { apiCall.setResponseStatus(response.getStatusCodeValue()); apiCall.setResponseBody(response.getBody()); apiCall.setResponseHeaders(JSON.toJSONString(response.getHeaders().toSingleValueMap())); cozeApiCallService.updateById(apiCall); } catch (Exception e) { log.error("更新API调用记录响应信息失败: {}", e.getMessage(), e); } } /** * 更新API调用记录的Coze ID信息 */ private void updateApiCallCozeIds(CozeApiCall apiCall, String cozeChatId, String cozeConversationId) { try { apiCall.setCozeChatId(cozeChatId); apiCall.setCozeConversationId(cozeConversationId); cozeApiCallService.updateById(apiCall); } catch (Exception e) { log.error("更新API调用记录Coze ID信息失败: {}", e.getMessage(), e); } } /** * 更新API调用记录的成功结果 */ private void updateApiCallSuccess(CozeApiCall apiCall, String aiReply) { try { LocalDateTime endTime = LocalDateTime.now(); long durationMs = java.time.Duration.between(apiCall.getStartTime(), endTime).toMillis(); apiCall.setAiReply(aiReply); apiCall.setAiReplyType("text"); apiCall.setStatus("success"); apiCall.setFinalStatus("completed"); apiCall.setEndTime(endTime); apiCall.setDurationMs((int) durationMs); cozeApiCallService.updateById(apiCall); log.info("API调用成功: id={}, duration={}ms", apiCall.getId(), durationMs); } catch (Exception e) { log.error("更新API调用记录成功结果失败: {}", e.getMessage(), e); } } /** * 更新API调用记录的错误信息 */ private void updateApiCallError(CozeApiCall apiCall, String errorCode, String errorMessage) { try { LocalDateTime endTime = LocalDateTime.now(); long durationMs = java.time.Duration.between(apiCall.getStartTime(), endTime).toMillis(); apiCall.setErrorCode(errorCode); apiCall.setErrorMessage(errorMessage); apiCall.setStatus("failed"); apiCall.setFinalStatus("failed"); apiCall.setEndTime(endTime); apiCall.setDurationMs((int) durationMs); cozeApiCallService.updateById(apiCall); log.error("API调用失败: id={}, errorCode={}, errorMessage={}", apiCall.getId(), errorCode, errorMessage); } catch (Exception e) { log.error("更新API调用记录错误信息失败: {}", e.getMessage(), e); } } /** * 获取当前HTTP请求 */ private HttpServletRequest getCurrentRequest() { try { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); return attributes != null ? attributes.getRequest() : null; } catch (Exception e) { return null; } } /** * 获取客户端IP地址 */ private String getClientIp(HttpServletRequest request) { String ip = request.getHeader("X-Forwarded-For"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } return ip; } /** * 带跟踪的轮询聊天完成状态 */ private String waitForChatCompletionWithTracking(String chatId, String cozeConversationId, CozeApiCall apiCall) { try { // 更新轮询开始时间 apiCall.setPollStartTime(LocalDateTime.now()); apiCall.setPollCount(0); cozeApiCallService.updateById(apiCall); // 调用原有的轮询方法 String result = waitForChatCompletion(chatId, cozeConversationId); // 更新轮询结束时间 apiCall.setPollEndTime(LocalDateTime.now()); cozeApiCallService.updateById(apiCall); return result; } catch (Exception e) { log.error("轮询聊天完成状态失败", e); throw e; } } }