Commit 8f0c5998aad17f50faca1ae857616c98e1bc47f6

Authored by cherishsince
1 parent f0e4e535

【解决todo】Chat Stream 处理失败的逻辑

yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/ErrorCodeConstants.java
@@ -32,6 +32,7 @@ public interface ErrorCodeConstants { @@ -32,6 +32,7 @@ public interface ErrorCodeConstants {
32 32
33 // ========== API 聊天消息 1-040-004-000 ========== 33 // ========== API 聊天消息 1-040-004-000 ==========
34 ErrorCode AI_CHAT_MESSAGE_NOT_EXIST = new ErrorCode(1_040_004_000, "消息不存在!"); 34 ErrorCode AI_CHAT_MESSAGE_NOT_EXIST = new ErrorCode(1_040_004_000, "消息不存在!");
  35 + ErrorCode AI_CHAT_STREAM_ERROR = new ErrorCode(1_040_004_001, "Stream 对话异常!");
35 36
36 // midjourney 37 // midjourney
37 38
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/AiChatMessageController.java
@@ -58,7 +58,7 @@ public class AiChatMessageController { @@ -58,7 +58,7 @@ public class AiChatMessageController {
58 @Operation(summary = "发送消息(流式)", description = "流式返回,响应较快") 58 @Operation(summary = "发送消息(流式)", description = "流式返回,响应较快")
59 @PostMapping(value = "/send-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) 59 @PostMapping(value = "/send-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
60 @PermitAll // 解决 SSE 最终响应的时候,会被 Access Denied 拦截的问题 60 @PermitAll // 解决 SSE 最终响应的时候,会被 Access Denied 拦截的问题
61 - public Flux<AiChatMessageSendRespVO> sendChatMessageStream(@Validated @RequestBody AiChatMessageSendReqVO sendReqVO) { 61 + public Flux<CommonResult<AiChatMessageSendRespVO>> sendChatMessageStream(@Validated @RequestBody AiChatMessageSendReqVO sendReqVO) {
62 return chatMessageService.sendChatMessageStream(sendReqVO, getLoginUserId()); 62 return chatMessageService.sendChatMessageStream(sendReqVO, getLoginUserId());
63 } 63 }
64 64
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatMessageService.java
1 package cn.iocoder.yudao.module.ai.service.chat; 1 package cn.iocoder.yudao.module.ai.service.chat;
2 2
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
3 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.*; 4 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.*;
4 import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO; 5 import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO;
5 import reactor.core.publisher.Flux; 6 import reactor.core.publisher.Flux;
@@ -28,7 +29,7 @@ public interface AiChatMessageService { @@ -28,7 +29,7 @@ public interface AiChatMessageService {
28 * @param userId 用户编号 29 * @param userId 用户编号
29 * @return 发送结果 30 * @return 发送结果
30 */ 31 */
31 - Flux<AiChatMessageSendRespVO> sendChatMessageStream(AiChatMessageSendReqVO sendReqVO, Long userId); 32 + Flux<CommonResult<AiChatMessageSendRespVO>> sendChatMessageStream(AiChatMessageSendReqVO sendReqVO, Long userId);
32 33
33 /** 34 /**
34 * 获得指定会话的消息列表 35 * 获得指定会话的消息列表
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatMessageServiceImpl.java
@@ -5,13 +5,17 @@ import cn.hutool.core.util.ObjUtil; @@ -5,13 +5,17 @@ import cn.hutool.core.util.ObjUtil;
5 import cn.hutool.core.util.StrUtil; 5 import cn.hutool.core.util.StrUtil;
6 import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; 6 import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
7 import cn.iocoder.yudao.framework.ai.core.factory.AiClientFactory; 7 import cn.iocoder.yudao.framework.ai.core.factory.AiClientFactory;
  8 +import cn.iocoder.yudao.framework.common.exception.ErrorCode;
  9 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
8 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 10 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  11 +import cn.iocoder.yudao.module.ai.ErrorCodeConstants;
9 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendRespVO; 12 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendRespVO;
10 import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO; 13 import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO;
11 import cn.iocoder.yudao.module.ai.service.model.AiApiKeyService; 14 import cn.iocoder.yudao.module.ai.service.model.AiApiKeyService;
12 import cn.iocoder.yudao.module.system.api.user.AdminUserApi; 15 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
13 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; 16 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
14 import jakarta.annotation.Resource; 17 import jakarta.annotation.Resource;
  18 +import org.reactivestreams.Publisher;
15 import org.springframework.ai.chat.ChatResponse; 19 import org.springframework.ai.chat.ChatResponse;
16 import org.springframework.ai.chat.StreamingChatClient; 20 import org.springframework.ai.chat.StreamingChatClient;
17 import org.springframework.ai.chat.messages.*; 21 import org.springframework.ai.chat.messages.*;
@@ -107,7 +111,7 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { @@ -107,7 +111,7 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
107 } 111 }
108 112
109 @Override 113 @Override
110 - public Flux<AiChatMessageSendRespVO> sendChatMessageStream(AiChatMessageSendReqVO sendReqVO, Long userId) { 114 + public Flux<CommonResult<AiChatMessageSendRespVO>> sendChatMessageStream(AiChatMessageSendReqVO sendReqVO, Long userId) {
111 // 1.1 校验对话存在 115 // 1.1 校验对话存在
112 AiChatConversationDO conversation = chatConversationService.validateExists(sendReqVO.getConversationId()); 116 AiChatConversationDO conversation = chatConversationService.validateExists(sendReqVO.getConversationId());
113 if (ObjUtil.notEqual(conversation.getUserId(), userId)) { 117 if (ObjUtil.notEqual(conversation.getUserId(), userId)) {
@@ -145,12 +149,14 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { @@ -145,12 +149,14 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
145 o -> o.setUserAvatar(user.getAvatar())); 149 o -> o.setUserAvatar(user.getAvatar()));
146 AiChatMessageSendRespVO.Message receive = BeanUtils.toBean(assistantMessage, AiChatMessageSendRespVO.Message.class, 150 AiChatMessageSendRespVO.Message receive = BeanUtils.toBean(assistantMessage, AiChatMessageSendRespVO.Message.class,
147 o -> o.setRoleAvatar(role != null ? role.getAvatar() : null)).setContent(newContent); 151 o -> o.setRoleAvatar(role != null ? role.getAvatar() : null)).setContent(newContent);
148 - return new AiChatMessageSendRespVO().setSend(send).setReceive(receive); 152 + return CommonResult.success(new AiChatMessageSendRespVO().setSend(send).setReceive(receive));
149 }).doOnComplete(() -> { 153 }).doOnComplete(() -> {
150 chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId()).setContent(contentBuffer.toString())); 154 chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId()).setContent(contentBuffer.toString()));
151 }).doOnError(throwable -> { 155 }).doOnError(throwable -> {
152 log.error("[sendChatMessageStream][userId({}) sendReqVO({}) 发生异常]", userId, sendReqVO, throwable); 156 log.error("[sendChatMessageStream][userId({}) sendReqVO({}) 发生异常]", userId, sendReqVO, throwable);
153 chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId()).setContent(throwable.getMessage())); 157 chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId()).setContent(throwable.getMessage()));
  158 + }).onErrorResume( error -> {
  159 + return Flux.just(CommonResult.error(ErrorCodeConstants.AI_CHAT_STREAM_ERROR));
154 }); 160 });
155 } 161 }
156 162