Bläddra i källkod

Merge remote-tracking branch 'origin/master-jdk21-ai' into master-jdk21-ai

# Conflicts:
#	yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiChatServiceImpl.java
YunaiV 11 månader sedan
förälder
incheckning
fd0e0de164

+ 7 - 0
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/message/AiChatMessageSendRespVO.java

@@ -31,6 +31,13 @@ public class AiChatMessageSendRespVO {
         @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
         private LocalDateTime createTime;
 
+        // ========= 扩展字段
+
+        @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "http://xxx")
+        private String userAvatar;
+
+        @Schema(description = "角色头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "http://xxx")
+        private String roleAvatar;
     }
 
 }

+ 20 - 2
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiChatServiceImpl.java

@@ -9,12 +9,16 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendRespVO;
 import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO;
 import cn.iocoder.yudao.module.ai.service.model.AiApiKeyService;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
 import jakarta.annotation.Resource;
 import org.springframework.ai.chat.ChatResponse;
 import org.springframework.ai.chat.StreamingChatClient;
 import org.springframework.ai.chat.messages.*;
 import org.springframework.ai.chat.prompt.ChatOptions;
 import org.springframework.ai.chat.prompt.Prompt;
+import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
+import cn.iocoder.yudao.module.ai.config.AiChatClientFactory;
 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageRespVO;
 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendReqVO;
 import cn.iocoder.yudao.module.ai.convert.AiChatMessageConvert;
@@ -65,6 +69,9 @@ public class AiChatServiceImpl implements AiChatService {
     @Resource
     private AiApiKeyService apiKeyService;
 
+    @Resource
+    private AdminUserApi adminUserApi;
+
     @Transactional(rollbackFor = Exception.class)
     public AiChatMessageRespVO chat(AiChatMessageSendReqVO req) {
          return null; // TODO 芋艿:一起改
@@ -130,14 +137,19 @@ public class AiChatServiceImpl implements AiChatService {
 
         // 3.3 流式返回
         // 注意:Schedulers.immediate() 目的是,避免默认 Schedulers.parallel() 并发消费 chunk 导致 SSE 响应前端会乱序问题
+
+        // 3.4 获取用户头像、角色头像
+        AdminUserRespDTO user = adminUserApi.getUser(SecurityFrameworkUtils.getLoginUserId());
+        AiChatRoleDO chatRole = chatRoleService.getChatRole(assistantMessage.getRoleId());
+
         StringBuffer contentBuffer = new StringBuffer();
         return streamResponse.publishOn(Schedulers.single()).map(chunk -> {
             String newContent = chunk.getResult() != null ? chunk.getResult().getOutput().getContent() : null;
             newContent = StrUtil.nullToDefault(newContent, ""); // 避免 null 的 情况
             contentBuffer.append(newContent);
             // 响应结果
-            return new AiChatMessageSendRespVO().setSend(BeanUtils.toBean(userMessage, AiChatMessageSendRespVO.Message.class))
-                    .setReceive(BeanUtils.toBean(assistantMessage, AiChatMessageSendRespVO.Message.class).setContent(newContent));
+            return new AiChatMessageSendRespVO().setSend(BeanUtils.toBean(userMessage, AiChatMessageSendRespVO.Message.class).setUserAvatar(user.getAvatar()))
+                    .setReceive(BeanUtils.toBean(assistantMessage, AiChatMessageSendRespVO.Message.class).setContent(newContent).setRoleAvatar(chatRole == null ? null : chatRole.getAvatar()));
         }).doOnComplete(() -> {
             chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId()).setContent(contentBuffer.toString()));
         }).doOnError(throwable -> {
@@ -236,6 +248,8 @@ public class AiChatServiceImpl implements AiChatService {
         Map<Long, AiChatRoleDO> roleMap = roleList.stream().collect(Collectors.toMap(AiChatRoleDO::getId, o -> o));
         // 转换 AiChatMessageRespVO
         List<AiChatMessageRespVO> aiChatMessageRespList = AiChatMessageConvert.INSTANCE.convertAiChatMessageRespVOList(aiChatMessageDOList);
+        // 获取用户信息
+        AdminUserRespDTO user = adminUserApi.getUser(SecurityFrameworkUtils.getLoginUserId());
         // 设置用户头像 和 模型头像
         return aiChatMessageRespList.stream().map(item -> {
             // 设置 role 头像
@@ -243,6 +257,10 @@ public class AiChatServiceImpl implements AiChatService {
                 AiChatRoleDO role = roleMap.get(item.getRoleId());
                 item.setRoleAvatar(role.getAvatar());
             }
+            // 设置 user 头像
+            if (user != null) {
+                item.setUserAvatar(user.getAvatar());
+            }
             return item;
         }).collect(Collectors.toList());
     }

+ 4 - 0
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/dto/AdminUserRespDTO.java

@@ -40,5 +40,9 @@ public class AdminUserRespDTO {
      * 手机号码
      */
     private String mobile;
+    /**
+     * 用户头像
+     */
+    private String avatar;
 
 }