Commit 1ab1538afebe6bfa3de9206c56fa6660e387e94f
1 parent
dc44fe1c
增加创建role对话
Showing
9 changed files
with
123 additions
and
67 deletions
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/ChatConversationTypeEnum.java
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/ChatConversationController.java
| ... | ... | @@ -2,7 +2,8 @@ package cn.iocoder.yudao.module.ai.controller; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | 4 | import cn.iocoder.yudao.module.ai.service.ChatConversationService; |
| 5 | -import cn.iocoder.yudao.module.ai.vo.ChatConversationCreateReq; | |
| 5 | +import cn.iocoder.yudao.module.ai.vo.ChatConversationCreateRoleReq; | |
| 6 | +import cn.iocoder.yudao.module.ai.vo.ChatConversationCreateUserReq; | |
| 6 | 7 | import cn.iocoder.yudao.module.ai.vo.ChatConversationListReq; |
| 7 | 8 | import cn.iocoder.yudao.module.ai.vo.ChatConversationRes; |
| 8 | 9 | import io.swagger.v3.oas.annotations.Operation; |
| ... | ... | @@ -30,10 +31,16 @@ public class ChatConversationController { |
| 30 | 31 | |
| 31 | 32 | private final ChatConversationService chatConversationService; |
| 32 | 33 | |
| 33 | - @Operation(summary = "创建 - 对话") | |
| 34 | - @PostMapping("/create") | |
| 35 | - public CommonResult<ChatConversationRes> create(@RequestBody @Validated ChatConversationCreateReq req) { | |
| 36 | - return CommonResult.success(chatConversationService.create(req)); | |
| 34 | + @Operation(summary = "创建 - 对话普通对话") | |
| 35 | + @PostMapping("/createConversation") | |
| 36 | + public CommonResult<ChatConversationRes> createConversation(@RequestBody @Validated ChatConversationCreateUserReq req) { | |
| 37 | + return CommonResult.success(chatConversationService.createConversation(req)); | |
| 38 | + } | |
| 39 | + | |
| 40 | + @Operation(summary = "创建 - 对话角色对话") | |
| 41 | + @PostMapping("/createRoleConversation") | |
| 42 | + public CommonResult<ChatConversationRes> createRoleConversation(@RequestBody @Validated ChatConversationCreateRoleReq req) { | |
| 43 | + return CommonResult.success(chatConversationService.createRoleConversation(req)); | |
| 37 | 44 | } |
| 38 | 45 | |
| 39 | 46 | @Operation(summary = "获取 - 获取对话") | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/mapper/AiChatConversationMapper.java
| ... | ... | @@ -24,7 +24,11 @@ import java.util.List; |
| 24 | 24 | @Mapper |
| 25 | 25 | public interface AiChatConversationMapper extends BaseMapperX<AiChatConversationDO> { |
| 26 | 26 | |
| 27 | - | |
| 27 | + /** | |
| 28 | + * 更新 - chat count | |
| 29 | + * | |
| 30 | + * @param id | |
| 31 | + */ | |
| 28 | 32 | @Update("update ai_chat_conversation set chat_count = chat_count + 1 where id = #{id}") |
| 29 | 33 | void updateIncrChatCount(@Param("id") Long id); |
| 30 | 34 | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/ChatConversationService.java
| 1 | 1 | package cn.iocoder.yudao.module.ai.service; |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.module.ai.vo.ChatConversationCreateReq; | |
| 3 | +import cn.iocoder.yudao.module.ai.vo.ChatConversationCreateRoleReq; | |
| 4 | +import cn.iocoder.yudao.module.ai.vo.ChatConversationCreateUserReq; | |
| 4 | 5 | import cn.iocoder.yudao.module.ai.vo.ChatConversationListReq; |
| 5 | 6 | import cn.iocoder.yudao.module.ai.vo.ChatConversationRes; |
| 6 | 7 | |
| ... | ... | @@ -15,12 +16,21 @@ import java.util.List; |
| 15 | 16 | public interface ChatConversationService { |
| 16 | 17 | |
| 17 | 18 | /** |
| 18 | - * 对话 - 创建 | |
| 19 | + * 对话 - 创建普通对话 | |
| 19 | 20 | * |
| 20 | 21 | * @param req |
| 21 | 22 | * @return |
| 22 | 23 | */ |
| 23 | - ChatConversationRes create(ChatConversationCreateReq req); | |
| 24 | + ChatConversationRes createConversation(ChatConversationCreateUserReq req); | |
| 25 | + | |
| 26 | + /** | |
| 27 | + * 对话 - 创建role对话 | |
| 28 | + * | |
| 29 | + * @param req | |
| 30 | + * @return | |
| 31 | + */ | |
| 32 | + ChatConversationRes createRoleConversation(ChatConversationCreateRoleReq req); | |
| 33 | + | |
| 24 | 34 | |
| 25 | 35 | /** |
| 26 | 36 | * 获取 - 对话 |
| ... | ... | @@ -44,4 +54,5 @@ public interface ChatConversationService { |
| 44 | 54 | * @param id |
| 45 | 55 | */ |
| 46 | 56 | void delete(Long id); |
| 57 | + | |
| 47 | 58 | } | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/ChatConversationServiceImpl.java
| ... | ... | @@ -5,13 +5,18 @@ import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; |
| 5 | 5 | import cn.iocoder.yudao.module.ai.ErrorCodeConstants; |
| 6 | 6 | import cn.iocoder.yudao.module.ai.convert.ChatConversationConvert; |
| 7 | 7 | import cn.iocoder.yudao.module.ai.dal.dataobject.AiChatConversationDO; |
| 8 | +import cn.iocoder.yudao.module.ai.dal.dataobject.AiChatRoleDO; | |
| 9 | +import cn.iocoder.yudao.module.ai.enums.ChatConversationTypeEnum; | |
| 8 | 10 | import cn.iocoder.yudao.module.ai.mapper.AiChatConversationMapper; |
| 11 | +import cn.iocoder.yudao.module.ai.mapper.AiChatRoleMapper; | |
| 9 | 12 | import cn.iocoder.yudao.module.ai.service.ChatConversationService; |
| 10 | -import cn.iocoder.yudao.module.ai.vo.ChatConversationCreateReq; | |
| 13 | +import cn.iocoder.yudao.module.ai.vo.ChatConversationCreateRoleReq; | |
| 14 | +import cn.iocoder.yudao.module.ai.vo.ChatConversationCreateUserReq; | |
| 11 | 15 | import cn.iocoder.yudao.module.ai.vo.ChatConversationListReq; |
| 12 | 16 | import cn.iocoder.yudao.module.ai.vo.ChatConversationRes; |
| 13 | 17 | import lombok.AllArgsConstructor; |
| 14 | 18 | import lombok.extern.slf4j.Slf4j; |
| 19 | +import org.jetbrains.annotations.NotNull; | |
| 15 | 20 | import org.springframework.stereotype.Service; |
| 16 | 21 | |
| 17 | 22 | import java.util.List; |
| ... | ... | @@ -27,10 +32,11 @@ import java.util.List; |
| 27 | 32 | @AllArgsConstructor |
| 28 | 33 | public class ChatConversationServiceImpl implements ChatConversationService { |
| 29 | 34 | |
| 35 | + private final AiChatRoleMapper aiChatRoleMapper; | |
| 30 | 36 | private final AiChatConversationMapper aiChatConversationMapper; |
| 31 | 37 | |
| 32 | 38 | @Override |
| 33 | - public ChatConversationRes create(ChatConversationCreateReq req) { | |
| 39 | + public ChatConversationRes createConversation(ChatConversationCreateUserReq req) { | |
| 34 | 40 | // 获取用户id |
| 35 | 41 | Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); |
| 36 | 42 | // 查询最新的对话 |
| ... | ... | @@ -40,17 +46,45 @@ public class ChatConversationServiceImpl implements ChatConversationService { |
| 40 | 46 | return ChatConversationConvert.INSTANCE.covnertChatConversationRes(latestConversation); |
| 41 | 47 | } |
| 42 | 48 | // 创建新的 Conversation |
| 49 | + AiChatConversationDO insertConversation = saveConversation(req.getTitle(), loginUserId, | |
| 50 | + null, null, ChatConversationTypeEnum.USER_CHAT); | |
| 51 | + // 转换 res | |
| 52 | + return ChatConversationConvert.INSTANCE.covnertChatConversationRes(insertConversation); | |
| 53 | + } | |
| 54 | + | |
| 55 | + @Override | |
| 56 | + public ChatConversationRes createRoleConversation(ChatConversationCreateRoleReq req) { | |
| 57 | + // 获取用户id | |
| 58 | + Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); | |
| 59 | + // 查询最新的对话 | |
| 60 | + AiChatConversationDO latestConversation = aiChatConversationMapper.selectLatestConversation(loginUserId); | |
| 61 | + // 如果有对话没有被使用过,那就返回这个 | |
| 62 | + if (latestConversation != null && latestConversation.getChatCount() <= 0) { | |
| 63 | + return ChatConversationConvert.INSTANCE.covnertChatConversationRes(latestConversation); | |
| 64 | + } | |
| 65 | + AiChatRoleDO aiChatRoleDO = aiChatRoleMapper.selectById(req.getChatRoleId()); | |
| 66 | + // 创建新的 Conversation | |
| 67 | + AiChatConversationDO insertConversation = saveConversation(req.getTitle(), loginUserId, | |
| 68 | + req.getChatRoleId(), aiChatRoleDO.getRoleName(), ChatConversationTypeEnum.ROLE_CHAT); | |
| 69 | + // 转换 res | |
| 70 | + return ChatConversationConvert.INSTANCE.covnertChatConversationRes(insertConversation); | |
| 71 | + } | |
| 72 | + | |
| 73 | + private @NotNull AiChatConversationDO saveConversation(String title, | |
| 74 | + Long userId, | |
| 75 | + Long chatRoleId, | |
| 76 | + String chatRoleName, | |
| 77 | + ChatConversationTypeEnum typeEnum) { | |
| 43 | 78 | AiChatConversationDO insertConversation = new AiChatConversationDO(); |
| 44 | 79 | insertConversation.setId(null); |
| 45 | - insertConversation.setUserId(loginUserId); | |
| 46 | - insertConversation.setChatRoleId(null); | |
| 47 | - insertConversation.setChatRoleName(null); | |
| 48 | - insertConversation.setTitle(null); | |
| 80 | + insertConversation.setUserId(userId); | |
| 81 | + insertConversation.setChatRoleId(chatRoleId); | |
| 82 | + insertConversation.setChatRoleName(chatRoleName); | |
| 83 | + insertConversation.setTitle(title); | |
| 49 | 84 | insertConversation.setChatCount(0); |
| 50 | - insertConversation.setType(req.getChatType()); | |
| 85 | + insertConversation.setType(typeEnum.getType()); | |
| 51 | 86 | aiChatConversationMapper.insert(insertConversation); |
| 52 | - // 转换 res | |
| 53 | - return ChatConversationConvert.INSTANCE.covnertChatConversationRes(insertConversation); | |
| 87 | + return insertConversation; | |
| 54 | 88 | } |
| 55 | 89 | |
| 56 | 90 | @Override | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/ChatServiceImpl.java
| ... | ... | @@ -5,15 +5,10 @@ import cn.iocoder.yudao.framework.ai.chat.ChatResponse; |
| 5 | 5 | import cn.iocoder.yudao.framework.ai.chat.messages.MessageType; |
| 6 | 6 | import cn.iocoder.yudao.framework.ai.chat.prompt.Prompt; |
| 7 | 7 | import cn.iocoder.yudao.framework.ai.config.AiClient; |
| 8 | -import cn.iocoder.yudao.framework.common.exception.ServerException; | |
| 9 | 8 | import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; |
| 10 | -import cn.iocoder.yudao.module.ai.ErrorCodeConstants; | |
| 11 | 9 | import cn.iocoder.yudao.module.ai.controller.Utf8SseEmitter; |
| 12 | -import cn.iocoder.yudao.module.ai.dal.dataobject.AiChatConversationDO; | |
| 13 | 10 | import cn.iocoder.yudao.module.ai.dal.dataobject.AiChatMessageDO; |
| 14 | -import cn.iocoder.yudao.module.ai.dal.dataobject.AiChatRoleDO; | |
| 15 | 11 | import cn.iocoder.yudao.module.ai.enums.AiClientNameEnum; |
| 16 | -import cn.iocoder.yudao.module.ai.enums.ChatTypeEnum; | |
| 17 | 12 | import cn.iocoder.yudao.module.ai.mapper.AiChatConversationMapper; |
| 18 | 13 | import cn.iocoder.yudao.module.ai.mapper.AiChatMessageMapper; |
| 19 | 14 | import cn.iocoder.yudao.module.ai.mapper.AiChatRoleMapper; |
| ... | ... | @@ -49,7 +44,6 @@ public class ChatServiceImpl implements ChatService { |
| 49 | 44 | private final AiChatConversationMapper aiChatConversationMapper; |
| 50 | 45 | private final ChatConversationService chatConversationService; |
| 51 | 46 | |
| 52 | - | |
| 53 | 47 | /** |
| 54 | 48 | * chat |
| 55 | 49 | * |
| ... | ... | @@ -64,7 +58,7 @@ public class ChatServiceImpl implements ChatService { |
| 64 | 58 | // 获取对话信息 |
| 65 | 59 | ChatConversationRes conversationRes = chatConversationService.getConversation(req.getConversationId()); |
| 66 | 60 | // 保存 chat message |
| 67 | - saveChatMessage(req, conversationRes.getId(), loginUserId); | |
| 61 | + saveChatMessage(req, conversationRes, loginUserId); | |
| 68 | 62 | String content = null; |
| 69 | 63 | try { |
| 70 | 64 | // 创建 chat 需要的 Prompt |
| ... | ... | @@ -75,16 +69,19 @@ public class ChatServiceImpl implements ChatService { |
| 75 | 69 | // 发送 call 调用 |
| 76 | 70 | ChatResponse call = aiClient.call(prompt, clientNameEnum.getName()); |
| 77 | 71 | content = call.getResult().getOutput().getContent(); |
| 72 | + // 更新 conversation | |
| 73 | + | |
| 78 | 74 | } catch (Exception e) { |
| 79 | 75 | content = ExceptionUtil.getMessage(e); |
| 80 | 76 | } finally { |
| 81 | 77 | // 保存 chat message |
| 82 | - saveSystemChatMessage(req, conversationRes.getId(), loginUserId, content); | |
| 78 | + saveSystemChatMessage(req, conversationRes, loginUserId, content); | |
| 83 | 79 | } |
| 84 | 80 | return content; |
| 85 | 81 | } |
| 86 | 82 | |
| 87 | - private void saveChatMessage(ChatReq req, Long chatConversationId, Long loginUserId) { | |
| 83 | + private void saveChatMessage(ChatReq req, ChatConversationRes conversationRes, Long loginUserId) { | |
| 84 | + Long chatConversationId = conversationRes.getId(); | |
| 88 | 85 | // 增加 chat message 记录 |
| 89 | 86 | aiChatMessageMapper.insert( |
| 90 | 87 | new AiChatMessageDO() |
| ... | ... | @@ -97,12 +94,12 @@ public class ChatServiceImpl implements ChatService { |
| 97 | 94 | .setTopP(req.getTopP()) |
| 98 | 95 | .setTemperature(req.getTemperature()) |
| 99 | 96 | ); |
| 100 | - | |
| 101 | 97 | // chat count 先+1 |
| 102 | 98 | aiChatConversationMapper.updateIncrChatCount(req.getConversationId()); |
| 103 | 99 | } |
| 104 | 100 | |
| 105 | - public void saveSystemChatMessage(ChatReq req, Long chatConversationId, Long loginUserId, String systemPrompts) { | |
| 101 | + public void saveSystemChatMessage(ChatReq req, ChatConversationRes conversationRes, Long loginUserId, String systemPrompts) { | |
| 102 | + Long chatConversationId = conversationRes.getId(); | |
| 106 | 103 | // 增加 chat message 记录 |
| 107 | 104 | aiChatMessageMapper.insert( |
| 108 | 105 | new AiChatMessageDO() |
| ... | ... | @@ -120,34 +117,6 @@ public class ChatServiceImpl implements ChatService { |
| 120 | 117 | aiChatConversationMapper.updateIncrChatCount(req.getConversationId()); |
| 121 | 118 | } |
| 122 | 119 | |
| 123 | - private AiChatConversationDO createNewChatConversation(ChatReq req, Long loginUserId) { | |
| 124 | - // 获取 chat 角色 | |
| 125 | - String chatRoleName = null; | |
| 126 | - ChatTypeEnum chatTypeEnum = null; | |
| 127 | - Long chatRoleId = req.getChatRoleId(); | |
| 128 | - if (req.getChatRoleId() != null) { | |
| 129 | - AiChatRoleDO aiChatRoleDO = aiChatRoleMapper.selectById(chatRoleId); | |
| 130 | - if (aiChatRoleDO == null) { | |
| 131 | - throw new ServerException(ErrorCodeConstants.AI_CHAT_ROLE_NOT_EXISTENT); | |
| 132 | - } | |
| 133 | - chatTypeEnum = ChatTypeEnum.ROLE_CHAT; | |
| 134 | - chatRoleName = aiChatRoleDO.getRoleName(); | |
| 135 | - } else { | |
| 136 | - chatTypeEnum = ChatTypeEnum.USER_CHAT; | |
| 137 | - } | |
| 138 | - // | |
| 139 | - AiChatConversationDO insertChatConversation = new AiChatConversationDO() | |
| 140 | - .setId(null) | |
| 141 | - .setUserId(loginUserId) | |
| 142 | - .setChatRoleId(req.getChatRoleId()) | |
| 143 | - .setChatRoleName(chatRoleName) | |
| 144 | - .setType(chatTypeEnum.getType()) | |
| 145 | - .setChatCount(1) | |
| 146 | - .setTitle(req.getPrompt().substring(0, 20) + "..."); | |
| 147 | - aiChatConversationMapper.insert(insertChatConversation); | |
| 148 | - return insertChatConversation; | |
| 149 | - } | |
| 150 | - | |
| 151 | 120 | /** |
| 152 | 121 | * chat stream |
| 153 | 122 | * |
| ... | ... | @@ -168,7 +137,7 @@ public class ChatServiceImpl implements ChatService { |
| 168 | 137 | req.setTopP(req.getTopP()); |
| 169 | 138 | req.setTemperature(req.getTemperature()); |
| 170 | 139 | // 保存 chat message |
| 171 | - saveChatMessage(req, conversationRes.getId(), loginUserId); | |
| 140 | + saveChatMessage(req, conversationRes, loginUserId); | |
| 172 | 141 | Flux<ChatResponse> streamResponse = aiClient.stream(prompt, clientNameEnum.getName()); |
| 173 | 142 | |
| 174 | 143 | StringBuffer contentBuffer = new StringBuffer(); |
| ... | ... | @@ -195,7 +164,7 @@ public class ChatServiceImpl implements ChatService { |
| 195 | 164 | log.info("发送完成!"); |
| 196 | 165 | sseEmitter.complete(); |
| 197 | 166 | // 保存 chat message |
| 198 | - saveSystemChatMessage(req, conversationRes.getId(), loginUserId, contentBuffer.toString()); | |
| 167 | + saveSystemChatMessage(req, conversationRes, loginUserId, contentBuffer.toString()); | |
| 199 | 168 | } |
| 200 | 169 | ); |
| 201 | 170 | } | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/vo/ChatConversationCreateRoleReq.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.vo; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import jakarta.validation.constraints.NotNull; | |
| 5 | +import lombok.Data; | |
| 6 | +import lombok.experimental.Accessors; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * 聊天对话 | |
| 10 | + * | |
| 11 | + * @author fansili | |
| 12 | + * @time 2024/4/18 16:24 | |
| 13 | + * @since 1.0 | |
| 14 | + */ | |
| 15 | +@Data | |
| 16 | +@Accessors(chain = true) | |
| 17 | +public class ChatConversationCreateRoleReq { | |
| 18 | + | |
| 19 | + @Schema(description = "chat角色Id") | |
| 20 | + @NotNull(message = "聊天角色id不能为空!") | |
| 21 | + private Long chatRoleId; | |
| 22 | + | |
| 23 | + @Schema(description = "标题(有程序自动生成)") | |
| 24 | + @NotNull(message = "标题不能为空!") | |
| 25 | + private String title; | |
| 26 | +} | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/vo/ChatConversationCreateReq.java renamed to yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/vo/ChatConversationCreateUserReq.java
| ... | ... | @@ -14,10 +14,9 @@ import lombok.experimental.Accessors; |
| 14 | 14 | */ |
| 15 | 15 | @Data |
| 16 | 16 | @Accessors(chain = true) |
| 17 | -public class ChatConversationCreateReq { | |
| 18 | - | |
| 19 | - @Schema(description = "对话类型(roleChat、userChat)") | |
| 20 | - @NotNull(message = "聊天类型不能为空!") | |
| 21 | - private String chatType; | |
| 17 | +public class ChatConversationCreateUserReq { | |
| 22 | 18 | |
| 19 | + @Schema(description = "对话标题") | |
| 20 | + @NotNull(message = "标题不能为空!") | |
| 21 | + private String title; | |
| 23 | 22 | } | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/resources/http/chat-conversation.http
| ... | ... | @@ -16,7 +16,12 @@ GET {{baseUrl}}/ai/chat/conversation/1781604279872581644 |
| 16 | 16 | Authorization: {{token}} |
| 17 | 17 | |
| 18 | 18 | |
| 19 | -### 对话 - id获取 | |
| 19 | +### 对话 - list | |
| 20 | +GET {{baseUrl}}/ai/chat/conversation/list | |
| 21 | +Authorization: {{token}} | |
| 22 | + | |
| 23 | + | |
| 24 | +### 对话 - 删除 | |
| 20 | 25 | DELETE {{baseUrl}}/ai/chat/conversation/1781604279872581644 |
| 21 | 26 | Authorization: {{token}} |
| 22 | 27 | ... | ... |