对话bug修复

This commit is contained in:
2025-10-30 17:34:05 +08:00
parent 8f2133f3af
commit 69ffda358f
@@ -901,6 +901,7 @@ public class AiChatServiceImpl implements AiChatService {
// 发送请求并处理流式响应 // 发送请求并处理流式响应
StringBuilder responseBuilder = new StringBuilder(); StringBuilder responseBuilder = new StringBuilder();
StringBuilder fullStreamData = new StringBuilder(); StringBuilder fullStreamData = new StringBuilder();
final String[] currentEvent = {null}; // 使用数组来解决lambda中的final问题
java.net.http.HttpResponse<java.util.stream.Stream<String>> response = client.send(request, java.net.http.HttpResponse<java.util.stream.Stream<String>> response = client.send(request,
java.net.http.HttpResponse.BodyHandlers.ofLines()); java.net.http.HttpResponse.BodyHandlers.ofLines());
@@ -913,72 +914,143 @@ public class AiChatServiceImpl implements AiChatService {
return "流式请求失败,状态码: " + response.statusCode(); return "流式请求失败,状态码: " + response.statusCode();
} }
// 处理流式数据 // 处理流式数据 - 正确处理SSE格式
response.body().forEach(line -> { response.body().forEach(line -> {
fullStreamData.append(line).append("\n"); fullStreamData.append(line).append("\n");
log.debug("收到流式数据行: {}", line);
if (line.startsWith("data: ")) { // 处理SSE事件格式
if (line.startsWith("event:")) {
currentEvent[0] = line.substring(6).trim();
log.debug("当前事件类型: {}", currentEvent[0]);
} else if (line.startsWith("data: ")) {
String data = line.substring(6).trim(); String data = line.substring(6).trim();
log.debug("解析流式数据: {}", data);
// 检查是否为结束标记
if ("[DONE]".equals(data)) { if ("[DONE]".equals(data)) {
log.info("流式响应完成"); log.info("流式响应完成");
return; return;
} }
// 只处理消息增量事件
if ("conversation.message.delta".equals(currentEvent[0])) {
try { try {
JSONObject jsonData = JSON.parseObject(data); JSONObject jsonData = JSON.parseObject(data);
log.debug("解析后的JSON数据: {}", jsonData);
// 提取消息内容 // 提取content字段
if (jsonData.containsKey("choices")) { if (jsonData.containsKey("content")) {
com.alibaba.fastjson2.JSONArray choices = jsonData.getJSONArray("choices"); String content = jsonData.getString("content");
if (choices != null && !choices.isEmpty()) { if (content != null && !content.trim().isEmpty()) {
JSONObject choice = choices.getJSONObject(0); log.debug("提取增量内容: {}", content);
if (choice != null && choice.containsKey("delta")) {
JSONObject delta = choice.getJSONObject("delta");
if (delta != null && delta.containsKey("content")) {
String content = delta.getString("content");
if (content != null) {
responseBuilder.append(content); responseBuilder.append(content);
} }
} }
}
}
}
// Coze特定格式处理
if (jsonData.containsKey("event")) {
String event = jsonData.getString("event");
if ("conversation.message.delta".equals(event) && jsonData.containsKey("data")) {
JSONObject eventData = jsonData.getJSONObject("data");
if (eventData != null && eventData.containsKey("content")) {
String content = eventData.getString("content");
if (content != null) {
responseBuilder.append(content);
}
}
}
}
} catch (Exception e) { } catch (Exception e) {
log.warn("解析流式数据失败: {}, 数据: {}", e.getMessage(), data); log.warn("解析流式数据失败: {}, 数据: {}", e.getMessage(), data);
} }
} else if ("conversation.message.completed".equals(currentEvent[0])) {
// 处理完整消息事件,可以用作备用方案
try {
JSONObject jsonData = JSON.parseObject(data);
// 检查是否为answer类型的消息
if (jsonData.containsKey("type") && "answer".equals(jsonData.getString("type"))) {
String content = jsonData.getString("content");
if (content != null && !content.trim().isEmpty() && responseBuilder.length() == 0) {
log.debug("使用完整消息内容作为备用: {}", content);
responseBuilder.append(content);
}
}
} catch (Exception e) {
log.warn("解析完整消息数据失败: {}, 数据: {}", e.getMessage(), data);
}
}
// 重置当前事件
currentEvent[0] = null;
} else if (line.trim().isEmpty()) {
// 空行表示事件结束
currentEvent[0] = null;
} }
}); });
// 记录完整的流式数据用于调试 // 记录完整的流式数据用于调试
updateApiCallStreamData(apiCall, fullStreamData.toString()); updateApiCallStreamData(apiCall, fullStreamData.toString());
log.info("流式响应处理完成,提取内容长度: {}", responseBuilder.length());
String finalResponse = responseBuilder.toString(); String finalResponse = responseBuilder.toString();
if (finalResponse.isEmpty()) { if (finalResponse.isEmpty()) {
log.warn("流式响应为空,返回默认消息"); log.warn("流式响应为空,尝试降级到非流式处理");
return "收到了流式响应,但内容为空。"; // 降级到非流式处理
return handleNonStreamFallback(url, headers, requestBody, apiCall);
} }
return finalResponse; return finalResponse;
} catch (Exception e) { } catch (Exception e) {
log.error("处理流式响应失败", e); log.error("处理流式响应失败", e);
throw new RuntimeException("处理流式响应失败: " + e.getMessage(), e); // 降级到非流式处理
return handleNonStreamFallback(url, headers, requestBody, apiCall);
}
}
/**
* 非流式处理降级方案
*/
private String handleNonStreamFallback(String url, HttpHeaders headers, Map<String, Object> requestBody, CozeApiCall apiCall) {
try {
log.info("执行非流式降级处理");
// 移除stream参数,改为非流式请求
Map<String, Object> nonStreamBody = new HashMap<>(requestBody);
nonStreamBody.put("stream", false);
// 构建请求头(移除流式相关头)
HttpHeaders nonStreamHeaders = new HttpHeaders();
headers.forEach((key, values) -> {
if (!"Accept".equals(key) || !"text/event-stream".equals(values.get(0))) {
nonStreamHeaders.put(key, values);
}
});
nonStreamHeaders.set("Content-Type", "application/json");
HttpEntity<Map<String, Object>> request = new HttpEntity<>(nonStreamBody, nonStreamHeaders);
log.info("发送非流式降级请求到: {}", url);
// 发送请求
ResponseEntity<String> response = restTemplate.exchange(
url,
HttpMethod.POST,
request,
String.class);
log.info("收到非流式降级响应: {}", response.getBody());
// 解析响应获取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("非流式降级处理成功: reply={}", aiReply);
return aiReply;
} else {
log.error("非流式降级处理失败:无法从响应中获取chat_id或conversation_id");
return "抱歉,AI服务暂时不可用,请稍后再试。";
}
} catch (Exception e) {
log.error("非流式降级处理失败", e);
return "抱歉,AI服务暂时不可用,请稍后再试。";
} }
} }
@@ -987,8 +1059,14 @@ public class AiChatServiceImpl implements AiChatService {
*/ */
private void updateApiCallStreamData(CozeApiCall apiCall, String streamData) { private void updateApiCallStreamData(CozeApiCall apiCall, String streamData) {
try { try {
// 可以将流式数据存储到响应体字段中,用于调试和分析 // 将流式数据包装成有效的JSON格式存储
apiCall.setResponseBody(streamData); Map<String, Object> streamDataWrapper = new HashMap<>();
streamDataWrapper.put("type", "stream");
streamDataWrapper.put("data", streamData);
streamDataWrapper.put("timestamp", System.currentTimeMillis());
String jsonStreamData = JSON.toJSONString(streamDataWrapper);
apiCall.setResponseBody(jsonStreamData);
cozeApiCallService.updateById(apiCall); cozeApiCallService.updateById(apiCall);
} catch (Exception e) { } catch (Exception e) {
log.error("更新API调用记录流式数据失败: {}", e.getMessage(), e); log.error("更新API调用记录流式数据失败: {}", e.getMessage(), e);
@@ -1097,6 +1175,13 @@ public class AiChatServiceImpl implements AiChatService {
boolean useStream = config.getSupportStream() != null && config.getSupportStream() == 1; boolean useStream = config.getSupportStream() != null && config.getSupportStream() == 1;
cozeRequest.put("stream", useStream); cozeRequest.put("stream", useStream);
// 添加auto_save_history参数,确保对话历史被保存
cozeRequest.put("auto_save_history", true);
// 如果有conversationId,添加到请求中(但不是必需的,Coze会自动创建)
// 注意:这里的conversationId是我们系统内部的ID,不是Coze的conversation_id
// Coze会自动创建新的conversation_id
// 构建消息列表 - 按照 Coze API 标准格式 // 构建消息列表 - 按照 Coze API 标准格式
java.util.List<Map<String, Object>> messages = new java.util.ArrayList<>(); java.util.List<Map<String, Object>> messages = new java.util.ArrayList<>();
@@ -1105,11 +1190,14 @@ public class AiChatServiceImpl implements AiChatService {
currentMsg.put(ROLE_KEY, USER_ROLE); currentMsg.put(ROLE_KEY, USER_ROLE);
currentMsg.put(CONTENT_KEY, userMessage); currentMsg.put(CONTENT_KEY, userMessage);
currentMsg.put(CONTENT_TYPE_KEY, TEXT_TYPE); currentMsg.put(CONTENT_TYPE_KEY, TEXT_TYPE);
currentMsg.put("type", "question"); // 移除type字段,可能不是必需的
messages.add(currentMsg); messages.add(currentMsg);
cozeRequest.put("additional_messages", messages); cozeRequest.put("additional_messages", messages);
cozeRequest.put("parameters", new HashMap<>());
// 确保parameters不为空,添加一些默认参数
Map<String, Object> parameters = new HashMap<>();
cozeRequest.put("parameters", parameters);
return cozeRequest; return cozeRequest;
} }
@@ -1435,7 +1523,27 @@ public class AiChatServiceImpl implements AiChatService {
private void updateApiCallResponse(CozeApiCall apiCall, ResponseEntity<String> response) { private void updateApiCallResponse(CozeApiCall apiCall, ResponseEntity<String> response) {
try { try {
apiCall.setResponseStatus(response.getStatusCodeValue()); apiCall.setResponseStatus(response.getStatusCodeValue());
apiCall.setResponseBody(response.getBody());
// 确保响应体是有效的JSON格式
String responseBody = response.getBody();
if (responseBody != null && !responseBody.trim().isEmpty()) {
try {
// 尝试解析为JSON,如果失败则包装成JSON
JSON.parseObject(responseBody);
apiCall.setResponseBody(responseBody);
} catch (Exception jsonException) {
// 如果不是有效JSON,则包装成JSON格式
Map<String, Object> wrapper = new HashMap<>();
wrapper.put("type", "raw_response");
wrapper.put("data", responseBody);
wrapper.put("timestamp", System.currentTimeMillis());
apiCall.setResponseBody(JSON.toJSONString(wrapper));
}
} else {
// 空响应体,设置为空JSON对象
apiCall.setResponseBody("{}");
}
apiCall.setResponseHeaders(JSON.toJSONString(response.getHeaders().toSingleValueMap())); apiCall.setResponseHeaders(JSON.toJSONString(response.getHeaders().toSingleValueMap()));
cozeApiCallService.updateById(apiCall); cozeApiCallService.updateById(apiCall);
} catch (Exception e) { } catch (Exception e) {