Commit ecb50c6511508e555797fdb58160d082fadc3b70

Authored by 芋道源码
Committed by Gitee
2 parents 698b2b24 29e42143

!14 【解决todo】AI 写作、脑图:model、systemMessage获取逻辑调整

Merge pull request !14 from 小新/master-jdk21-ai
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/mindmap/AiMindMapDO.java
@@ -12,8 +12,7 @@ import lombok.Data; @@ -12,8 +12,7 @@ import lombok.Data;
12 * 12 *
13 * @author xiaoxin 13 * @author xiaoxin
14 */ 14 */
15 -// TODO @xin:如果没 typehandler 的需求,autoResultMap 可以去掉哈  
16 -@TableName(value = "ai_mind_map", autoResultMap = true) 15 +@TableName(value = "ai_mind_map")
17 @Data 16 @Data
18 public class AiMindMapDO extends BaseDO { 17 public class AiMindMapDO extends BaseDO {
19 18
@@ -25,7 +24,7 @@ public class AiMindMapDO extends BaseDO { @@ -25,7 +24,7 @@ public class AiMindMapDO extends BaseDO {
25 24
26 /** 25 /**
27 * 用户编号 26 * 用户编号
28 - * 27 + * <p>
29 * 关联 AdminUserDO 的 userId 字段 28 * 关联 AdminUserDO 的 userId 字段
30 */ 29 */
31 private Long userId; 30 private Long userId;
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/mindmap/AiMindMapServiceImpl.java
1 package cn.iocoder.yudao.module.ai.service.mindmap; 1 package cn.iocoder.yudao.module.ai.service.mindmap;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.lang.Assert;
4 import cn.hutool.core.util.StrUtil; 5 import cn.hutool.core.util.StrUtil;
5 import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; 6 import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
6 import cn.iocoder.yudao.framework.ai.core.util.AiUtils; 7 import cn.iocoder.yudao.framework.ai.core.util.AiUtils;
@@ -57,33 +58,25 @@ public class AiMindMapServiceImpl implements AiMindMapService { @@ -57,33 +58,25 @@ public class AiMindMapServiceImpl implements AiMindMapService {
57 58
58 @Override 59 @Override
59 public Flux<CommonResult<String>> generateMindMap(AiMindMapGenerateReqVO generateReqVO, Long userId) { 60 public Flux<CommonResult<String>> generateMindMap(AiMindMapGenerateReqVO generateReqVO, Long userId) {
60 - // 1.1 获取脑图模型 尝试获取思维导图助手角色,如果没有则使用默认模型 61 + // 1 获取脑图模型 尝试获取思维导图助手角色,如果没有则使用默认模型
61 AiChatRoleDO mindMapRole = CollUtil.getFirst(chatRoleService.getChatRoleListByName(AiChatRoleEnum.AI_MIND_MAP_ROLE.getName())); 62 AiChatRoleDO mindMapRole = CollUtil.getFirst(chatRoleService.getChatRoleListByName(AiChatRoleEnum.AI_MIND_MAP_ROLE.getName()));
62 - AiChatModelDO model;  
63 - String systemMessage;  
64 - if (Objects.nonNull(mindMapRole) && Objects.nonNull(mindMapRole.getModelId())) {  
65 - model = chatModalService.getChatModel(mindMapRole.getModelId());  
66 - systemMessage = mindMapRole.getSystemMessage();  
67 - } else {  
68 - model = chatModalService.getRequiredDefaultChatModel();  
69 - systemMessage = AiChatRoleEnum.AI_MIND_MAP_ROLE.getSystemMessage();  
70 - }  
71 - 63 + // 1.1 获取脑图执行模型
  64 + AiChatModelDO model = getModel(mindMapRole);
  65 + // 1.2 获取角色设定消息
  66 + String systemMessage = Objects.nonNull(mindMapRole) && StrUtil.isNotBlank(mindMapRole.getSystemMessage())
  67 + ? mindMapRole.getSystemMessage() : AiChatRoleEnum.AI_MIND_MAP_ROLE.getSystemMessage();
  68 + // 1.3 校验平台
72 AiPlatformEnum platform = AiPlatformEnum.validatePlatform(model.getPlatform()); 69 AiPlatformEnum platform = AiPlatformEnum.validatePlatform(model.getPlatform());
73 ChatModel chatModel = apiKeyService.getChatModel(model.getKeyId()); 70 ChatModel chatModel = apiKeyService.getChatModel(model.getKeyId());
74 71
75 // 2 插入思维导图信息 72 // 2 插入思维导图信息
76 - AiMindMapDO mindMapDO = BeanUtils.toBean(generateReqVO, AiMindMapDO.class, e -> e.setUserId(userId).setModel(model.getModel()).setPlatform(platform.getPlatform())); 73 + AiMindMapDO mindMapDO = BeanUtils.toBean(generateReqVO, AiMindMapDO.class,
  74 + mindMap -> mindMap.setUserId(userId).setModel(model.getModel()).setPlatform(platform.getPlatform()));
77 mindMapMapper.insert(mindMapDO); 75 mindMapMapper.insert(mindMapDO);
78 76
79 ChatOptions chatOptions = AiUtils.buildChatOptions(platform, model.getModel(), model.getTemperature(), model.getMaxTokens()); 77 ChatOptions chatOptions = AiUtils.buildChatOptions(platform, model.getModel(), model.getTemperature(), model.getMaxTokens());
80 // 3.1 角色设定 78 // 3.1 角色设定
81 - List<Message> chatMessages = new ArrayList<>();  
82 - if (StrUtil.isNotBlank(systemMessage)) {  
83 - chatMessages.add(new SystemMessage(systemMessage));  
84 - }  
85 - // 3.2 用户输入  
86 - chatMessages.add(new UserMessage(generateReqVO.getPrompt())); 79 + List<Message> chatMessages = buildMessages(generateReqVO, systemMessage);
87 // 3.3 构建提示词 80 // 3.3 构建提示词
88 Prompt prompt = new Prompt(chatMessages, chatOptions); 81 Prompt prompt = new Prompt(chatMessages, chatOptions);
89 82
@@ -109,4 +102,28 @@ public class AiMindMapServiceImpl implements AiMindMapService { @@ -109,4 +102,28 @@ public class AiMindMapServiceImpl implements AiMindMapService {
109 102
110 } 103 }
111 104
  105 + private static List<Message> buildMessages(AiMindMapGenerateReqVO generateReqVO, String systemMessage) {
  106 + List<Message> chatMessages = new ArrayList<>();
  107 + if (StrUtil.isNotBlank(systemMessage)) {
  108 + // 1.1 角色设定
  109 + chatMessages.add(new SystemMessage(systemMessage));
  110 + }
  111 + // 1.2 用户输入
  112 + chatMessages.add(new UserMessage(generateReqVO.getPrompt()));
  113 + return chatMessages;
  114 + }
  115 +
  116 + // TODO 芋艿:这里脑图、写作都用到了,是不是可以抽哪里去
  117 + private AiChatModelDO getModel(AiChatRoleDO chatRoleDO) {
  118 + AiChatModelDO model = null;
  119 + if (Objects.nonNull(chatRoleDO) && Objects.nonNull(chatRoleDO.getModelId())) {
  120 + model = chatModalService.getChatModel(chatRoleDO.getModelId());
  121 + }
  122 + if (Objects.isNull(model)) {
  123 + model = chatModalService.getRequiredDefaultChatModel();
  124 + }
  125 + Assert.notNull(model, "[AI] 获取不到模型");
  126 + return model;
  127 + }
  128 +
112 } 129 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/write/AiWriteServiceImpl.java
1 package cn.iocoder.yudao.module.ai.service.write; 1 package cn.iocoder.yudao.module.ai.service.write;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.lang.Assert;
4 import cn.hutool.core.util.StrUtil; 5 import cn.hutool.core.util.StrUtil;
5 import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; 6 import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
6 import cn.iocoder.yudao.framework.ai.core.util.AiUtils; 7 import cn.iocoder.yudao.framework.ai.core.util.AiUtils;
@@ -67,19 +68,14 @@ public class AiWriteServiceImpl implements AiWriteService { @@ -67,19 +68,14 @@ public class AiWriteServiceImpl implements AiWriteService {
67 68
68 @Override 69 @Override
69 public Flux<CommonResult<String>> generateWriteContent(AiWriteGenerateReqVO generateReqVO, Long userId) { 70 public Flux<CommonResult<String>> generateWriteContent(AiWriteGenerateReqVO generateReqVO, Long userId) {
70 - // 1.1 获取写作模型 尝试获取写作助手角色,如果没有则使用默认模型 71 + // 1 获取写作模型 尝试获取写作助手角色,没有则使用默认模型
71 AiChatRoleDO writeRole = CollUtil.getFirst(chatRoleService.getChatRoleListByName(AiChatRoleEnum.AI_WRITE_ROLE.getName())); 72 AiChatRoleDO writeRole = CollUtil.getFirst(chatRoleService.getChatRoleListByName(AiChatRoleEnum.AI_WRITE_ROLE.getName()));
72 - // TODO @xin:如果有 writeRole,但是没 modeId,是不是也可以用 systemMessage 哈?建议的写法是:先通过 modelId 获取 model。如果 model == null,则 chatModalService.getRequiredDefaultChatModel();如果还是 null,则抛出异常;。。。。。。。。。。。。。。然后,systemMessage = writeRole != null && writeRole.systemPrompt != "" 这样处理。  
73 - AiChatModelDO model;  
74 - String systemMessage;  
75 - if (Objects.nonNull(writeRole) && Objects.nonNull(writeRole.getModelId())) {  
76 - model = chatModalService.getChatModel(writeRole.getModelId());  
77 - systemMessage = writeRole.getSystemMessage();  
78 - } else {  
79 - model = chatModalService.getRequiredDefaultChatModel();  
80 - systemMessage = AiChatRoleEnum.AI_WRITE_ROLE.getSystemMessage();  
81 - }  
82 - // 1.2 校验平台 73 + // 1.1 获取写作执行模型
  74 + AiChatModelDO model = getModel(writeRole);
  75 + // 1.2 获取角色设定消息
  76 + String systemMessage = Objects.nonNull(writeRole) && StrUtil.isNotBlank(writeRole.getSystemMessage())
  77 + ? writeRole.getSystemMessage() : AiChatRoleEnum.AI_WRITE_ROLE.getSystemMessage();
  78 + // 1.3 校验平台
83 AiPlatformEnum platform = AiPlatformEnum.validatePlatform(model.getPlatform()); 79 AiPlatformEnum platform = AiPlatformEnum.validatePlatform(model.getPlatform());
84 StreamingChatModel chatModel = apiKeyService.getChatModel(model.getKeyId()); 80 StreamingChatModel chatModel = apiKeyService.getChatModel(model.getKeyId());
85 81
@@ -90,16 +86,11 @@ public class AiWriteServiceImpl implements AiWriteService { @@ -90,16 +86,11 @@ public class AiWriteServiceImpl implements AiWriteService {
90 86
91 // 3. 调用大模型,写作生成 87 // 3. 调用大模型,写作生成
92 ChatOptions chatOptions = AiUtils.buildChatOptions(platform, model.getModel(), model.getTemperature(), model.getMaxTokens()); 88 ChatOptions chatOptions = AiUtils.buildChatOptions(platform, model.getModel(), model.getTemperature(), model.getMaxTokens());
93 - // 3.1 角色设定  
94 - // TODO @xin:要不把 90 到 97 这部分,合并到一个方法里。目的是:让这个方法的主干更明确  
95 - List<Message> chatMessages = new ArrayList<>();  
96 - if (StrUtil.isNotBlank(systemMessage)) {  
97 - chatMessages.add(new SystemMessage(systemMessage));  
98 - }  
99 - // 3.2 用户输入  
100 - chatMessages.add(new UserMessage(buildWritingPrompt(generateReqVO)));  
101 - // 3.3 构建提示词 89 + // 3.1 构建消息列表
  90 + List<Message> chatMessages = buildMessages(generateReqVO, systemMessage);
  91 + // 3.2 构建提示词
102 Prompt prompt = new Prompt(chatMessages, chatOptions); 92 Prompt prompt = new Prompt(chatMessages, chatOptions);
  93 + // 3.3 流式调用
103 Flux<ChatResponse> streamResponse = chatModel.stream(prompt); 94 Flux<ChatResponse> streamResponse = chatModel.stream(prompt);
104 95
105 // 4. 流式返回 96 // 4. 流式返回
@@ -122,6 +113,29 @@ public class AiWriteServiceImpl implements AiWriteService { @@ -122,6 +113,29 @@ public class AiWriteServiceImpl implements AiWriteService {
122 }).onErrorResume(error -> Flux.just(error(ErrorCodeConstants.WRITE_STREAM_ERROR))); 113 }).onErrorResume(error -> Flux.just(error(ErrorCodeConstants.WRITE_STREAM_ERROR)));
123 } 114 }
124 115
  116 + private AiChatModelDO getModel(AiChatRoleDO writeRole) {
  117 + AiChatModelDO model = null;
  118 + if (Objects.nonNull(writeRole) && Objects.nonNull(writeRole.getModelId())) {
  119 + model = chatModalService.getChatModel(writeRole.getModelId());
  120 + }
  121 + if (Objects.isNull(model)) {
  122 + model = chatModalService.getRequiredDefaultChatModel();
  123 + }
  124 + Assert.notNull(model, "[AI] 获取不到模型");
  125 + return model;
  126 + }
  127 +
  128 + private List<Message> buildMessages(AiWriteGenerateReqVO generateReqVO, String systemMessage) {
  129 + List<Message> chatMessages = new ArrayList<>();
  130 + if (StrUtil.isNotBlank(systemMessage)) {
  131 + // 1.1 角色设定
  132 + chatMessages.add(new SystemMessage(systemMessage));
  133 + }
  134 + // 1.2 用户输入
  135 + chatMessages.add(new UserMessage(buildWritingPrompt(generateReqVO)));
  136 + return chatMessages;
  137 + }
  138 +
125 private String buildWritingPrompt(AiWriteGenerateReqVO generateReqVO) { 139 private String buildWritingPrompt(AiWriteGenerateReqVO generateReqVO) {
126 String format = dictDataApi.getDictDataLabel(DictTypeConstants.AI_WRITE_FORMAT, generateReqVO.getFormat()); 140 String format = dictDataApi.getDictDataLabel(DictTypeConstants.AI_WRITE_FORMAT, generateReqVO.getFormat());
127 String tone = dictDataApi.getDictDataLabel(DictTypeConstants.AI_WRITE_TONE, generateReqVO.getTone()); 141 String tone = dictDataApi.getDictDataLabel(DictTypeConstants.AI_WRITE_TONE, generateReqVO.getTone());