Commit fd0e0de164310dd463d11253ade9e01dc55f851d

Authored by YunaiV
2 parents 2fefcf88 2a01f6b9

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
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 { @@ -31,6 +31,13 @@ public class AiChatMessageSendRespVO {
31 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) 31 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
32 private LocalDateTime createTime; 32 private LocalDateTime createTime;
33 33
  34 + // ========= 扩展字段
  35 +
  36 + @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "http://xxx")
  37 + private String userAvatar;
  38 +
  39 + @Schema(description = "角色头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "http://xxx")
  40 + private String roleAvatar;
34 } 41 }
35 42
36 } 43 }
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; @@ -9,12 +9,16 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
9 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendRespVO; 9 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendRespVO;
10 import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO; 10 import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO;
11 import cn.iocoder.yudao.module.ai.service.model.AiApiKeyService; 11 import cn.iocoder.yudao.module.ai.service.model.AiApiKeyService;
  12 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  13 +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
12 import jakarta.annotation.Resource; 14 import jakarta.annotation.Resource;
13 import org.springframework.ai.chat.ChatResponse; 15 import org.springframework.ai.chat.ChatResponse;
14 import org.springframework.ai.chat.StreamingChatClient; 16 import org.springframework.ai.chat.StreamingChatClient;
15 import org.springframework.ai.chat.messages.*; 17 import org.springframework.ai.chat.messages.*;
16 import org.springframework.ai.chat.prompt.ChatOptions; 18 import org.springframework.ai.chat.prompt.ChatOptions;
17 import org.springframework.ai.chat.prompt.Prompt; 19 import org.springframework.ai.chat.prompt.Prompt;
  20 +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
  21 +import cn.iocoder.yudao.module.ai.config.AiChatClientFactory;
18 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageRespVO; 22 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageRespVO;
19 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendReqVO; 23 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendReqVO;
20 import cn.iocoder.yudao.module.ai.convert.AiChatMessageConvert; 24 import cn.iocoder.yudao.module.ai.convert.AiChatMessageConvert;
@@ -65,6 +69,9 @@ public class AiChatServiceImpl implements AiChatService { @@ -65,6 +69,9 @@ public class AiChatServiceImpl implements AiChatService {
65 @Resource 69 @Resource
66 private AiApiKeyService apiKeyService; 70 private AiApiKeyService apiKeyService;
67 71
  72 + @Resource
  73 + private AdminUserApi adminUserApi;
  74 +
68 @Transactional(rollbackFor = Exception.class) 75 @Transactional(rollbackFor = Exception.class)
69 public AiChatMessageRespVO chat(AiChatMessageSendReqVO req) { 76 public AiChatMessageRespVO chat(AiChatMessageSendReqVO req) {
70 return null; // TODO 芋艿:一起改 77 return null; // TODO 芋艿:一起改
@@ -130,14 +137,19 @@ public class AiChatServiceImpl implements AiChatService { @@ -130,14 +137,19 @@ public class AiChatServiceImpl implements AiChatService {
130 137
131 // 3.3 流式返回 138 // 3.3 流式返回
132 // 注意:Schedulers.immediate() 目的是,避免默认 Schedulers.parallel() 并发消费 chunk 导致 SSE 响应前端会乱序问题 139 // 注意:Schedulers.immediate() 目的是,避免默认 Schedulers.parallel() 并发消费 chunk 导致 SSE 响应前端会乱序问题
  140 +
  141 + // 3.4 获取用户头像、角色头像
  142 + AdminUserRespDTO user = adminUserApi.getUser(SecurityFrameworkUtils.getLoginUserId());
  143 + AiChatRoleDO chatRole = chatRoleService.getChatRole(assistantMessage.getRoleId());
  144 +
133 StringBuffer contentBuffer = new StringBuffer(); 145 StringBuffer contentBuffer = new StringBuffer();
134 return streamResponse.publishOn(Schedulers.single()).map(chunk -> { 146 return streamResponse.publishOn(Schedulers.single()).map(chunk -> {
135 String newContent = chunk.getResult() != null ? chunk.getResult().getOutput().getContent() : null; 147 String newContent = chunk.getResult() != null ? chunk.getResult().getOutput().getContent() : null;
136 newContent = StrUtil.nullToDefault(newContent, ""); // 避免 null 的 情况 148 newContent = StrUtil.nullToDefault(newContent, ""); // 避免 null 的 情况
137 contentBuffer.append(newContent); 149 contentBuffer.append(newContent);
138 // 响应结果 150 // 响应结果
139 - return new AiChatMessageSendRespVO().setSend(BeanUtils.toBean(userMessage, AiChatMessageSendRespVO.Message.class))  
140 - .setReceive(BeanUtils.toBean(assistantMessage, AiChatMessageSendRespVO.Message.class).setContent(newContent)); 151 + return new AiChatMessageSendRespVO().setSend(BeanUtils.toBean(userMessage, AiChatMessageSendRespVO.Message.class).setUserAvatar(user.getAvatar()))
  152 + .setReceive(BeanUtils.toBean(assistantMessage, AiChatMessageSendRespVO.Message.class).setContent(newContent).setRoleAvatar(chatRole == null ? null : chatRole.getAvatar()));
141 }).doOnComplete(() -> { 153 }).doOnComplete(() -> {
142 chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId()).setContent(contentBuffer.toString())); 154 chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId()).setContent(contentBuffer.toString()));
143 }).doOnError(throwable -> { 155 }).doOnError(throwable -> {
@@ -236,6 +248,8 @@ public class AiChatServiceImpl implements AiChatService { @@ -236,6 +248,8 @@ public class AiChatServiceImpl implements AiChatService {
236 Map<Long, AiChatRoleDO> roleMap = roleList.stream().collect(Collectors.toMap(AiChatRoleDO::getId, o -> o)); 248 Map<Long, AiChatRoleDO> roleMap = roleList.stream().collect(Collectors.toMap(AiChatRoleDO::getId, o -> o));
237 // 转换 AiChatMessageRespVO 249 // 转换 AiChatMessageRespVO
238 List<AiChatMessageRespVO> aiChatMessageRespList = AiChatMessageConvert.INSTANCE.convertAiChatMessageRespVOList(aiChatMessageDOList); 250 List<AiChatMessageRespVO> aiChatMessageRespList = AiChatMessageConvert.INSTANCE.convertAiChatMessageRespVOList(aiChatMessageDOList);
  251 + // 获取用户信息
  252 + AdminUserRespDTO user = adminUserApi.getUser(SecurityFrameworkUtils.getLoginUserId());
239 // 设置用户头像 和 模型头像 253 // 设置用户头像 和 模型头像
240 return aiChatMessageRespList.stream().map(item -> { 254 return aiChatMessageRespList.stream().map(item -> {
241 // 设置 role 头像 255 // 设置 role 头像
@@ -243,6 +257,10 @@ public class AiChatServiceImpl implements AiChatService { @@ -243,6 +257,10 @@ public class AiChatServiceImpl implements AiChatService {
243 AiChatRoleDO role = roleMap.get(item.getRoleId()); 257 AiChatRoleDO role = roleMap.get(item.getRoleId());
244 item.setRoleAvatar(role.getAvatar()); 258 item.setRoleAvatar(role.getAvatar());
245 } 259 }
  260 + // 设置 user 头像
  261 + if (user != null) {
  262 + item.setUserAvatar(user.getAvatar());
  263 + }
246 return item; 264 return item;
247 }).collect(Collectors.toList()); 265 }).collect(Collectors.toList());
248 } 266 }
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 { @@ -40,5 +40,9 @@ public class AdminUserRespDTO {
40 * 手机号码 40 * 手机号码
41 */ 41 */
42 private String mobile; 42 private String mobile;
  43 + /**
  44 + * 用户头像
  45 + */
  46 + private String avatar;
43 47
44 } 48 }