Commit 56bd131e authored by alex yao's avatar alex yao

refactor(chat): 重构Dify聊天服务实现

- 将think标签常量改为大写命名规范
- 为blockingChat和streamChat方法添加完整的JavaDoc注释
- 移除冗余的注释代码
- 重命名内部解析方法提高可读性
- 优化流式聊天中的异常处理逻辑
- 为SSEUtil构造函数添加异常捕获机制
- 统一使用StringUtils.EMPTY替代空字符串
- 改进代码结构和错误处理流程
parent 8ef4f9e1
...@@ -45,15 +45,21 @@ public class DifyChatServiceImpl implements DifyChatService { ...@@ -45,15 +45,21 @@ public class DifyChatServiceImpl implements DifyChatService {
private final Logger logger = LoggerFactory.getLogger(DifyChatServiceImpl.class); private final Logger logger = LoggerFactory.getLogger(DifyChatServiceImpl.class);
private final String thinkStartTag = "<think>"; private final String THINK_START_TAG = "<think>";
private final String thinkEndTag = "</think>"; private final String THINK_END_TAG = "</think>";
@Autowired @Autowired
private DifyConfigProperties difyConfigProperties; private DifyConfigProperties difyConfigProperties;
/** /**
* 阻塞式聊天请求 * 阻塞式聊天请求
*
* @param fileUrls 文件地址
* @param question 问题
* @param data 拓展参数
* @param user 用户
* @param apiKey API密钥
*/ */
public AgentResultEntity blockingChat(List<String> fileUrls, public AgentResultEntity blockingChat(List<String> fileUrls,
String question, String question,
...@@ -61,7 +67,6 @@ public class DifyChatServiceImpl implements DifyChatService { ...@@ -61,7 +67,6 @@ public class DifyChatServiceImpl implements DifyChatService {
String user, String user,
String apiKey) { String apiKey) {
// 从配置中获取API密钥,如果传入的apiKey为null或空,则从配置中查找
String actualApiKey = apiKey; String actualApiKey = apiKey;
if (StringUtils.isEmpty(actualApiKey)) { if (StringUtils.isEmpty(actualApiKey)) {
actualApiKey = difyConfigProperties.getApiKeys().get(user); actualApiKey = difyConfigProperties.getApiKeys().get(user);
...@@ -100,16 +105,16 @@ public class DifyChatServiceImpl implements DifyChatService { ...@@ -100,16 +105,16 @@ public class DifyChatServiceImpl implements DifyChatService {
AgentResultEntity agentResultEntity = new AgentResultEntity(); AgentResultEntity agentResultEntity = new AgentResultEntity();
String answer = chatMessageResponse.getAnswer(); String answer = chatMessageResponse.getAnswer();
int startIndex = answer.indexOf(thinkStartTag); int startIndex = answer.indexOf(THINK_START_TAG);
int endIndex = answer.indexOf(thinkEndTag); int endIndex = answer.indexOf(THINK_END_TAG);
if (startIndex != -1 && endIndex != -1 && endIndex > startIndex) { if (startIndex != -1 && endIndex != -1 && endIndex > startIndex) {
// 提取<think>标签内的内容 // 提取<think>标签内的内容
String reasoningContent = answer.substring(startIndex + thinkStartTag.length(), endIndex); String reasoningContent = answer.substring(startIndex + THINK_START_TAG.length(), endIndex);
agentResultEntity.setReasoningContent(reasoningContent.trim()); agentResultEntity.setReasoningContent(reasoningContent.trim());
// 提取其余内容(去除<think>标签部分) // 提取其余内容(去除<think>标签部分)
String message = answer.substring(0, startIndex) + answer.substring(endIndex + thinkEndTag.length()); String message = answer.substring(0, startIndex) + answer.substring(endIndex + THINK_END_TAG.length());
agentResultEntity.setMessage(message); agentResultEntity.setMessage(message);
} else { } else {
// 如果没有找到<think>标签,将整个answer作为message // 如果没有找到<think>标签,将整个answer作为message
...@@ -126,12 +131,18 @@ public class DifyChatServiceImpl implements DifyChatService { ...@@ -126,12 +131,18 @@ public class DifyChatServiceImpl implements DifyChatService {
/** /**
* 流式聊天请求 * 流式聊天请求
*
* @param fileUrls 文件地址
* @param question 问题
* @param data 拓展参数
* @param user 用户
* @param apiKey API密钥
*/ */
public AgentResultEntity streamChat(List<String> fileUrls, public AgentResultEntity streamChat(List<String> fileUrls,
String question, String question,
Map<String, Object> data, Map<String, Object> data,
String user, String user,
String apiKey) throws IOException, DifyApiException, InterruptedException { String apiKey) {
AgentResultEntity agentResultEntity = new AgentResultEntity(); AgentResultEntity agentResultEntity = new AgentResultEntity();
StringBuilder messageBuilder = new StringBuilder(); StringBuilder messageBuilder = new StringBuilder();
...@@ -170,34 +181,40 @@ public class DifyChatServiceImpl implements DifyChatService { ...@@ -170,34 +181,40 @@ public class DifyChatServiceImpl implements DifyChatService {
ServletRequestAttributes servletRequestAttributes = ServletRequestAttributes servletRequestAttributes =
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletResponse response = servletRequestAttributes.getResponse(); HttpServletResponse response = servletRequestAttributes.getResponse();
// 发送消息并获取响应
chatClient.sendChatMessageStream(message, new ChatStreamCallback() {
SSEUtil sseUtil = new SSEUtil(response);
// 发送消息并获取响应
try {
chatClient.sendChatMessageStream(message, new ChatStreamCallback() {
SSEUtil sseUtil = new SSEUtil(response);
boolean isThink = false; boolean isThink = false;
private String think(String content) { /**
if (!isThink) { * 解析深度思考文本内容
if (content.contains(thinkStartTag)) { * 处理思考标记的开始和结束标签,提取纯文本内容
isThink = true; *
return content.replaceFirst(thinkStartTag, ""); * @param content 原始内容
} * @return 解析后的文本内容,如果内容不完整则返回空字符串
return content; */
} else { String parseDeepThinkingContent(String content) {
if (content.contains(thinkEndTag)) { if (!isThink) {
isThink = false; if (content.contains(THINK_START_TAG)) {
return content.replaceFirst(thinkEndTag, ""); isThink = true;
return content.replaceFirst(THINK_START_TAG, StringUtils.EMPTY);
}
return content;
} else {
if (content.contains(THINK_END_TAG)) {
isThink = false;
return content.replaceFirst(THINK_END_TAG, StringUtils.EMPTY);
}
return StringUtils.EMPTY;
} }
return null;
} }
}
@Override void responseMess(MessageEvent event) throws IOException {
public void onMessage(MessageEvent event) {
try {
if (StringUtils.isNotEmpty(event.getAnswer())) { if (StringUtils.isNotEmpty(event.getAnswer())) {
String think = think(event.getAnswer()); String think = parseDeepThinkingContent(event.getAnswer());
LargeModelDemandResult largeModelDemandResult = new LargeModelDemandResult(); LargeModelDemandResult largeModelDemandResult = new LargeModelDemandResult();
if (isThink || StringUtils.isNotBlank(think)) { if (isThink || StringUtils.isNotBlank(think)) {
largeModelDemandResult.setReasoningContent(think); largeModelDemandResult.setReasoningContent(think);
...@@ -212,30 +229,44 @@ public class DifyChatServiceImpl implements DifyChatService { ...@@ -212,30 +229,44 @@ public class DifyChatServiceImpl implements DifyChatService {
largeModelDemandResult.setCode("0"); largeModelDemandResult.setCode("0");
sseUtil.send(JsonUtils.serialize(largeModelDemandResult)); sseUtil.send(JsonUtils.serialize(largeModelDemandResult));
} }
} catch (Exception e) {
logger.error("发送SSE消息时出错: {}", e.getMessage(), e);
sseUtil.completeByError(e.getMessage());
throw new RuntimeException(e);
} }
}
@Override @Override
public void onMessageEnd(MessageEndEvent event) { public void onMessage(MessageEvent event) {
try { try {
sseUtil.send("[DONE]"); responseMess(event);
} catch (IOException e) { } catch (Exception e) {
logger.error("发送SSE结束消息时出错: {}", e.getMessage(), e); logger.error("发送SSE消息时出错: {}", e.getMessage(), e);
sseUtil.completeByError(e.getMessage()); sseUtil.completeByError(e.getMessage());
throw new RuntimeException(e); throw new RuntimeException(e);
} finally { }
sseUtil.complete();
agentResultEntity.setMessage(messageBuilder.toString());
agentResultEntity.setReasoningContent(reasoningContentBuilder.toString());
} }
countDownLatch.countDown();
} @Override
}); public void onMessageEnd(MessageEndEvent event) {
countDownLatch.await(120, TimeUnit.SECONDS); try {
return agentResultEntity; sseUtil.send("[DONE]");
} catch (IOException e) {
logger.error("发送SSE结束消息时出错: {}", e.getMessage(), e);
sseUtil.completeByError(e.getMessage());
throw new RuntimeException(e);
} finally {
sseUtil.complete();
agentResultEntity.setMessage(messageBuilder.toString());
agentResultEntity.setReasoningContent(reasoningContentBuilder.toString());
}
countDownLatch.countDown();
}
});
countDownLatch.await(120, TimeUnit.SECONDS);
return agentResultEntity;
} catch (Exception e) {
countDownLatch.notify();
SSEUtil sseUtil = new SSEUtil(response);
sseUtil.completeByError(e.getMessage());
throw new BusinessException(e.getMessage());
}
} }
} }
\ No newline at end of file
...@@ -35,9 +35,13 @@ public class SSEUtil implements AutoCloseable { ...@@ -35,9 +35,13 @@ public class SSEUtil implements AutoCloseable {
outputStream = response.getOutputStream(); outputStream = response.getOutputStream();
} }
public SSEUtil(HttpServletResponse response) throws IOException { public SSEUtil(HttpServletResponse response) {
response.setContentType("text/event-stream;charset=UTF-8"); try {
outputStream = response.getOutputStream(); response.setContentType("text/event-stream;charset=UTF-8");
outputStream = response.getOutputStream();
} catch (IOException e) {
throw new RuntimeException("无法获取HttpServletResponse");
}
} }
public void send(String data) throws IOException { public void send(String data) throws IOException {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment