|
@@ -31,7 +31,7 @@ public class DifyServiceImpl implements IDifyService {
|
|
|
JSONObject requestBody = new JSONObject();
|
|
JSONObject requestBody = new JSONObject();
|
|
|
requestBody.set("inputs", inputs);
|
|
requestBody.set("inputs", inputs);
|
|
|
requestBody.set("query", userMessage);
|
|
requestBody.set("query", userMessage);
|
|
|
- requestBody.set("response_mode", "blocking");
|
|
|
|
|
|
|
+ requestBody.set("response_mode", "streaming");
|
|
|
requestBody.set("user", "user-" + userId);
|
|
requestBody.set("user", "user-" + userId);
|
|
|
|
|
|
|
|
// 如果有对话ID,添加到请求中以支持上下文回顾
|
|
// 如果有对话ID,添加到请求中以支持上下文回顾
|
|
@@ -55,40 +55,74 @@ public class DifyServiceImpl implements IDifyService {
|
|
|
.build();
|
|
.build();
|
|
|
|
|
|
|
|
Response response = httpClient.newCall(request).execute();
|
|
Response response = httpClient.newCall(request).execute();
|
|
|
- String responseBody = response.body().string();
|
|
|
|
|
|
|
|
|
|
- log.info("Dify API 响应: {}", responseBody);
|
|
|
|
|
|
|
+ // 处理流式响应
|
|
|
|
|
+ StringBuilder fullAnswer = new StringBuilder();
|
|
|
|
|
+ String newConversationId = null;
|
|
|
|
|
+ String ttsVcn = null;
|
|
|
|
|
|
|
|
- // 解析响应
|
|
|
|
|
- JSONObject result = new JSONObject(responseBody);
|
|
|
|
|
- Map<String, String> aiResponse = new HashMap<>();
|
|
|
|
|
|
|
+ try (ResponseBody responseBody = response.body()) {
|
|
|
|
|
+ if (responseBody == null) {
|
|
|
|
|
+ throw new RuntimeException("响应体为空");
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // 检查是否有错误响应
|
|
|
|
|
- if (result.containsKey("code") && result.containsKey("message")) {
|
|
|
|
|
- String errorCode = result.getStr("code");
|
|
|
|
|
- String errorMessage = result.getStr("message");
|
|
|
|
|
- log.error("Dify API 返回错误: code={}, message={}", errorCode, errorMessage);
|
|
|
|
|
- throw new RuntimeException("Dify API 错误: " + errorMessage);
|
|
|
|
|
|
|
+ // 逐行读取 SSE 流
|
|
|
|
|
+ java.io.BufferedReader reader = new java.io.BufferedReader(
|
|
|
|
|
+ new java.io.InputStreamReader(responseBody.byteStream(), java.nio.charset.StandardCharsets.UTF_8)
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ String line;
|
|
|
|
|
+ while ((line = reader.readLine()) != null) {
|
|
|
|
|
+ // SSE 格式: data: {...}
|
|
|
|
|
+ if (line.startsWith("data: ")) {
|
|
|
|
|
+ String jsonData = line.substring(6); // 去掉 "data: " 前缀
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ JSONObject event = new JSONObject(jsonData);
|
|
|
|
|
+ String eventType = event.getStr("event");
|
|
|
|
|
+
|
|
|
|
|
+ if ("message".equals(eventType)) {
|
|
|
|
|
+ // 累积回复文本
|
|
|
|
|
+ String answer = event.getStr("answer");
|
|
|
|
|
+ if (answer != null) {
|
|
|
|
|
+ fullAnswer.append(answer);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if ("message_end".equals(eventType)) {
|
|
|
|
|
+ // 最后一个事件,获取 conversation_id
|
|
|
|
|
+ newConversationId = event.getStr("conversation_id");
|
|
|
|
|
+
|
|
|
|
|
+ // 从 metadata 中获取 outputs
|
|
|
|
|
+ if (event.containsKey("metadata")) {
|
|
|
|
|
+ JSONObject metadata = event.getJSONObject("metadata");
|
|
|
|
|
+ if (metadata != null && metadata.containsKey("outputs")) {
|
|
|
|
|
+ JSONObject outputs = metadata.getJSONObject("outputs");
|
|
|
|
|
+ if (outputs != null) {
|
|
|
|
|
+ ttsVcn = outputs.getStr("ttsVcn");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if ("error".equals(eventType)) {
|
|
|
|
|
+ String errorMessage = event.getStr("message");
|
|
|
|
|
+ log.error("Dify API 返回错误: {}", errorMessage);
|
|
|
|
|
+ throw new RuntimeException("Dify API 错误: " + errorMessage);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("解析 SSE 事件失败: {}", line, e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Dify API 直接返回 answer 字段,不是嵌套在 data 中
|
|
|
|
|
- String replyText = result.getStr("answer");
|
|
|
|
|
- if (replyText == null) {
|
|
|
|
|
- log.error("Dify API 响应中没有 answer 字段,完整响应: {}", responseBody);
|
|
|
|
|
|
|
+ Map<String, String> aiResponse = new HashMap<>();
|
|
|
|
|
+
|
|
|
|
|
+ String replyText = fullAnswer.toString();
|
|
|
|
|
+ if (replyText.isEmpty()) {
|
|
|
|
|
+ log.error("Dify API 未返回任何回复文本");
|
|
|
throw new RuntimeException("Dify API 响应格式错误");
|
|
throw new RuntimeException("Dify API 响应格式错误");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
aiResponse.put("replyText", replyText);
|
|
aiResponse.put("replyText", replyText);
|
|
|
|
|
|
|
|
- // 从 outputs 中获取 ttsVcn(如果有的话)
|
|
|
|
|
- String ttsVcn = null;
|
|
|
|
|
- if (result.containsKey("outputs")) {
|
|
|
|
|
- JSONObject outputs = result.getJSONObject("outputs");
|
|
|
|
|
- if (outputs != null) {
|
|
|
|
|
- ttsVcn = outputs.getStr("ttsVcn");
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
// 如果AI没有返回发言人,使用客服配置中的默认发言人
|
|
// 如果AI没有返回发言人,使用客服配置中的默认发言人
|
|
|
if (ttsVcn == null) {
|
|
if (ttsVcn == null) {
|
|
|
ttsVcn = inputs.get("currentVcn") != null ? inputs.get("currentVcn").toString() : "x4_yezi";
|
|
ttsVcn = inputs.get("currentVcn") != null ? inputs.get("currentVcn").toString() : "x4_yezi";
|
|
@@ -96,11 +130,12 @@ public class DifyServiceImpl implements IDifyService {
|
|
|
aiResponse.put("ttsVcn", ttsVcn);
|
|
aiResponse.put("ttsVcn", ttsVcn);
|
|
|
|
|
|
|
|
// 返回对话ID以便前端保存,用于下次请求
|
|
// 返回对话ID以便前端保存,用于下次请求
|
|
|
- String newConversationId = result.getStr("conversation_id");
|
|
|
|
|
if (newConversationId != null) {
|
|
if (newConversationId != null) {
|
|
|
aiResponse.put("conversationId", newConversationId);
|
|
aiResponse.put("conversationId", newConversationId);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ log.info("Dify 流式响应处理完成,回复长度: {}", replyText.length());
|
|
|
|
|
+
|
|
|
return aiResponse;
|
|
return aiResponse;
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
log.error("调用 Dify 工作流失败", e);
|
|
log.error("调用 Dify 工作流失败", e);
|