Files
happy-life-star/backend-single/src/main/java/com/emotion/service/impl/AiChatServiceImpl.java
T
peanut 3292a74698 实现Coze API调用记录功能
- 在AiChatServiceImpl中添加完整的API调用记录功能
- 每次调用Coze API时自动记录请求和响应信息
- 支持聊天和总结两种类型的API调用记录
- 记录详细信息包括:
  * 请求信息:URL、请求体、请求头、用户消息
  * 响应信息:HTTP状态码、响应体、响应头
  * Coze信息:Bot ID、Workflow ID、Chat ID、Conversation ID
  * 用户信息:用户ID、客户端IP、User Agent、会话ID
  * 性能指标:开始时间、结束时间、耗时、轮询次数
  * 状态跟踪:调用状态、最终状态、错误信息
  * 追踪信息:唯一追踪ID
- 添加集成测试验证记录功能
- 支持错误处理和异常情况记录
2025-07-25 00:39:51 +08:00

900 lines
34 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<String, Object> requestBody = buildCozeRequest(conversationId, userMessage, userId);
// 更新API调用记录的请求信息
updateApiCallRequest(apiCall, cozeBaseUrl + chatPath, requestBody, headers);
HttpEntity<Map<String, Object>> request = new HttpEntity<>(requestBody, headers);
// 构建完整的API URL
String cozeApiUrl = cozeBaseUrl + chatPath;
log.info("发送Coze请求到: {}, 请求体: {}", cozeApiUrl, requestBody);
// 发送请求
ResponseEntity<String> 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<String, Object> guestChat(String message, String clientIp) {
log.info("访客聊天: message={}, clientIp={}", message, clientIp);
Map<String, Object> 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<String, Object> createConversation(String userId, String title) {
log.info("创建对话: userId={}, title={}", userId, title);
Map<String, Object> 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<String, Object> getGuestUserInfo(String clientIp) {
log.info("获取访客用户信息: clientIp={}", clientIp);
Map<String, Object> 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<String, Object> 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<String, Object> buildCozeRequest(String conversationId, String userMessage, String userId) {
Map<String, Object> 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<Map<String, Object>> messages = new java.util.ArrayList<>();
// 添加当前用户消息
Map<String, Object> 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<String> request = new HttpEntity<>(headers);
// 发送状态查询请求
ResponseEntity<String> 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<String> request = new HttpEntity<>(headers);
// 发送消息查询请求
ResponseEntity<String> 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<JSONObject> 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<String, Object> requestBody = buildSummaryRequest(conversationId, userMessage, userId);
// 更新API调用记录的请求信息
updateApiCallRequest(apiCall, cozeBaseUrl + chatPath, requestBody, headers);
HttpEntity<Map<String, Object>> request = new HttpEntity<>(requestBody, headers);
// 构建完整的API URL
String cozeApiUrl = cozeBaseUrl + chatPath;
log.info("发送Coze总结请求到: {}, 请求体: {}", cozeApiUrl, requestBody);
// 发送请求
ResponseEntity<String> 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<String, Object> buildSummaryRequest(String conversationId, String userMessage, String userId) {
Map<String, Object> 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<Map<String, Object>> messages = new java.util.ArrayList<>();
// 添加当前用户消息
Map<String, Object> 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<String, Object> 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<String> 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;
}
}
}