Commit 1ab1538afebe6bfa3de9206c56fa6660e387e94f

Authored by cherishsince
1 parent dc44fe1c

增加创建role对话

yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/ChatConversationTypeEnum.java
... ... @@ -15,8 +15,9 @@ import lombok.Getter;
15 15 @Getter
16 16 public enum ChatConversationTypeEnum {
17 17  
18   - NEW("new", "新建对话"),
19   - CONTINUE("continue", "继续对话"),
  18 + // roleChat、userChat
  19 + ROLE_CHAT("roleChat", "角色对话"),
  20 + USER_CHAT("userChat", "用户对话"),
20 21  
21 22 ;
22 23  
... ...
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  
... ...