Commit 2d11f085c8a1d65d3e7af6e1f196acc3936d1ac8

Authored by YunaiV
1 parent 4fddec5f

【新增】AI:对话管理 50%

Showing 16 changed files with 196 additions and 68 deletions
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/AiChatConversationController.java
1 package cn.iocoder.yudao.module.ai.controller.admin.chat; 1 package cn.iocoder.yudao.module.ai.controller.admin.chat;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
3 import cn.hutool.core.util.ObjUtil; 4 import cn.hutool.core.util.ObjUtil;
4 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 5 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 7 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
6 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationCreateMyReqVO; 8 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationCreateMyReqVO;
  9 +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationPageReqVO;
7 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationRespVO; 10 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationRespVO;
8 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateMyReqVO; 11 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateMyReqVO;
9 import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO; 12 import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO;
10 import cn.iocoder.yudao.module.ai.service.chat.AiChatConversationService; 13 import cn.iocoder.yudao.module.ai.service.chat.AiChatConversationService;
  14 +import cn.iocoder.yudao.module.ai.service.chat.AiChatMessageService;
11 import io.swagger.v3.oas.annotations.Operation; 15 import io.swagger.v3.oas.annotations.Operation;
12 import io.swagger.v3.oas.annotations.Parameter; 16 import io.swagger.v3.oas.annotations.Parameter;
13 import io.swagger.v3.oas.annotations.tags.Tag; 17 import io.swagger.v3.oas.annotations.tags.Tag;
14 import jakarta.annotation.Resource; 18 import jakarta.annotation.Resource;
15 import jakarta.validation.Valid; 19 import jakarta.validation.Valid;
  20 +import org.springframework.security.access.prepost.PreAuthorize;
16 import org.springframework.validation.annotation.Validated; 21 import org.springframework.validation.annotation.Validated;
17 import org.springframework.web.bind.annotation.*; 22 import org.springframework.web.bind.annotation.*;
18 23
19 import java.util.List; 24 import java.util.List;
  25 +import java.util.Map;
  26 +import java.util.function.Consumer;
20 27
21 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 28 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  29 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
22 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; 30 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
23 31
24 -@Tag(name = "管理后台 - AI 聊天会话") 32 +@Tag(name = "管理后台 - AI 聊天对话")
25 @RestController 33 @RestController
26 @RequestMapping("/ai/chat/conversation") 34 @RequestMapping("/ai/chat/conversation")
27 @Validated 35 @Validated
@@ -29,30 +37,32 @@ public class AiChatConversationController { @@ -29,30 +37,32 @@ public class AiChatConversationController {
29 37
30 @Resource 38 @Resource
31 private AiChatConversationService chatConversationService; 39 private AiChatConversationService chatConversationService;
  40 + @Resource
  41 + private AiChatMessageService chatMessageService;
32 42
33 @PostMapping("/create-my") 43 @PostMapping("/create-my")
34 - @Operation(summary = "创建【我的】聊天会话") 44 + @Operation(summary = "创建【我的】聊天对话")
35 public CommonResult<Long> createChatConversationMy(@RequestBody @Valid AiChatConversationCreateMyReqVO createReqVO) { 45 public CommonResult<Long> createChatConversationMy(@RequestBody @Valid AiChatConversationCreateMyReqVO createReqVO) {
36 return success(chatConversationService.createChatConversationMy(createReqVO, getLoginUserId())); 46 return success(chatConversationService.createChatConversationMy(createReqVO, getLoginUserId()));
37 } 47 }
38 48
39 @PutMapping("/update-my") 49 @PutMapping("/update-my")
40 - @Operation(summary = "更新【我的】聊天会话") 50 + @Operation(summary = "更新【我的】聊天对话")
41 public CommonResult<Boolean> updateChatConversationMy(@RequestBody @Valid AiChatConversationUpdateMyReqVO updateReqVO) { 51 public CommonResult<Boolean> updateChatConversationMy(@RequestBody @Valid AiChatConversationUpdateMyReqVO updateReqVO) {
42 chatConversationService.updateChatConversationMy(updateReqVO, getLoginUserId()); 52 chatConversationService.updateChatConversationMy(updateReqVO, getLoginUserId());
43 return success(true); 53 return success(true);
44 } 54 }
45 55
46 @GetMapping("/my-list") 56 @GetMapping("/my-list")
47 - @Operation(summary = "获得【我的】聊天会话列表") 57 + @Operation(summary = "获得【我的】聊天对话列表")
48 public CommonResult<List<AiChatConversationRespVO>> getChatConversationMyList() { 58 public CommonResult<List<AiChatConversationRespVO>> getChatConversationMyList() {
49 List<AiChatConversationDO> list = chatConversationService.getChatConversationListByUserId(getLoginUserId()); 59 List<AiChatConversationDO> list = chatConversationService.getChatConversationListByUserId(getLoginUserId());
50 return success(BeanUtils.toBean(list, AiChatConversationRespVO.class)); 60 return success(BeanUtils.toBean(list, AiChatConversationRespVO.class));
51 } 61 }
52 62
53 @GetMapping("/get-my") 63 @GetMapping("/get-my")
54 - @Operation(summary = "获得【我的】聊天会话")  
55 - @Parameter(name = "id", required = true, description = "会话编号", example = "1024") 64 + @Operation(summary = "获得【我的】聊天对话")
  65 + @Parameter(name = "id", required = true, description = "对话编号", example = "1024")
56 public CommonResult<AiChatConversationRespVO> getChatConversationMy(@RequestParam("id") Long id) { 66 public CommonResult<AiChatConversationRespVO> getChatConversationMy(@RequestParam("id") Long id) {
57 AiChatConversationDO conversation = chatConversationService.getChatConversation(id); 67 AiChatConversationDO conversation = chatConversationService.getChatConversation(id);
58 if (conversation != null && ObjUtil.notEqual(conversation.getUserId(), getLoginUserId())) { 68 if (conversation != null && ObjUtil.notEqual(conversation.getUserId(), getLoginUserId())) {
@@ -62,20 +72,36 @@ public class AiChatConversationController { @@ -62,20 +72,36 @@ public class AiChatConversationController {
62 } 72 }
63 73
64 @DeleteMapping("/delete-my") 74 @DeleteMapping("/delete-my")
65 - @Operation(summary = "删除聊天会话")  
66 - @Parameter(name = "id", required = true, description = "会话编号", example = "1024") 75 + @Operation(summary = "删除聊天对话")
  76 + @Parameter(name = "id", required = true, description = "对话编号", example = "1024")
67 public CommonResult<Boolean> deleteChatConversationMy(@RequestParam("id") Long id) { 77 public CommonResult<Boolean> deleteChatConversationMy(@RequestParam("id") Long id) {
68 chatConversationService.deleteChatConversationMy(id, getLoginUserId()); 78 chatConversationService.deleteChatConversationMy(id, getLoginUserId());
69 return success(true); 79 return success(true);
70 } 80 }
71 81
  82 + // TODO 芋艿:这个 url 可以改下
72 @DeleteMapping("/delete-my-all-except-pinned") 83 @DeleteMapping("/delete-my-all-except-pinned")
73 @Operation(summary = "删除所有对话(置顶除外)") 84 @Operation(summary = "删除所有对话(置顶除外)")
74 - @Parameter(name = "id", required = true, description = "会话编号", example = "1024")  
75 - public CommonResult<Boolean> deleteMyAllExceptPinned() {  
76 - chatConversationService.deleteMyAllExceptPinned(getLoginUserId()); 85 + public CommonResult<Boolean> deleteChatConversationMyByUnpinned() {
  86 + chatConversationService.deleteChatConversationMyByUnpinned(getLoginUserId());
77 return success(true); 87 return success(true);
78 } 88 }
79 - // ========== 会话管理 ========== 89 +
  90 + // ========== 对话管理 ==========
  91 +
  92 + @GetMapping("/page")
  93 + @Operation(summary = "获得对话分页", description = "用于【对话管理】菜单")
  94 + @PreAuthorize("@ss.hasPermission('ai:chat-conversation:query')")
  95 + public CommonResult<PageResult<AiChatConversationRespVO>> getChatConversationPage(AiChatConversationPageReqVO pageReqVO) {
  96 + PageResult<AiChatConversationDO> pageResult = chatConversationService.getChatConversationPage(pageReqVO);
  97 + if (CollUtil.isEmpty(pageResult.getList())) {
  98 + return success(PageResult.empty());
  99 + }
  100 + // 拼接关联数据
  101 + Map<Long, Integer> messageCountMap = chatMessageService.getChatMessageCountMap(
  102 + convertList(pageResult.getList(), AiChatConversationDO::getId));
  103 + return success(BeanUtils.toBean(pageResult, AiChatConversationRespVO.class,
  104 + conversation -> conversation.setMessageCount(messageCountMap.getOrDefault(conversation.getId(), 0))));
  105 + }
80 106
81 } 107 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/AiChatMessageController.java
@@ -62,9 +62,9 @@ public class AiChatMessageController { @@ -62,9 +62,9 @@ public class AiChatMessageController {
62 return chatMessageService.sendChatMessageStream(sendReqVO, getLoginUserId()); 62 return chatMessageService.sendChatMessageStream(sendReqVO, getLoginUserId());
63 } 63 }
64 64
65 - @Operation(summary = "获得指定会话的消息列表") 65 + @Operation(summary = "获得指定对话的消息列表")
66 @GetMapping("/list-by-conversation-id") 66 @GetMapping("/list-by-conversation-id")
67 - @Parameter(name = "conversationId", required = true, description = "会话编号", example = "1024") 67 + @Parameter(name = "conversationId", required = true, description = "对话编号", example = "1024")
68 public CommonResult<List<AiChatMessageRespVO>> getChatMessageListByConversationId( 68 public CommonResult<List<AiChatMessageRespVO>> getChatMessageListByConversationId(
69 @RequestParam("conversationId") Long conversationId) { 69 @RequestParam("conversationId") Long conversationId) {
70 AiChatConversationDO conversation = chatConversationService.getChatConversation(conversationId); 70 AiChatConversationDO conversation = chatConversationService.getChatConversation(conversationId);
@@ -93,12 +93,16 @@ public class AiChatMessageController { @@ -93,12 +93,16 @@ public class AiChatMessageController {
93 return success(true); 93 return success(true);
94 } 94 }
95 95
96 - @Operation(summary = "删除指定会话的消息") 96 + @Operation(summary = "删除指定对话的消息")
97 @DeleteMapping("/delete-by-conversation-id") 97 @DeleteMapping("/delete-by-conversation-id")
98 - @Parameter(name = "conversationId", required = true, description = "会话编号", example = "1024") 98 + @Parameter(name = "conversationId", required = true, description = "对话编号", example = "1024")
99 public CommonResult<Boolean> deleteChatMessageByConversationId(@RequestParam("conversationId") Long conversationId) { 99 public CommonResult<Boolean> deleteChatMessageByConversationId(@RequestParam("conversationId") Long conversationId) {
100 chatMessageService.deleteChatMessageByConversationId(conversationId, getLoginUserId()); 100 chatMessageService.deleteChatMessageByConversationId(conversationId, getLoginUserId());
101 return success(true); 101 return success(true);
102 } 102 }
103 103
  104 + // ========== 对话管理 ==========
  105 +
  106 +
  107 +
104 } 108 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationCreateMyReqVO.java
@@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation; @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation;
3 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
4 import lombok.Data; 4 import lombok.Data;
5 5
6 -@Schema(description = "管理后台 - AI 聊天会话创建【我的】 Request VO") 6 +@Schema(description = "管理后台 - AI 聊天对话创建【我的】 Request VO")
7 @Data 7 @Data
8 public class AiChatConversationCreateMyReqVO { 8 public class AiChatConversationCreateMyReqVO {
9 9
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +import org.springframework.format.annotation.DateTimeFormat;
  7 +
  8 +import java.time.LocalDateTime;
  9 +
  10 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  11 +
  12 +@Schema(description = "管理后台 - AI 聊天对话的分页 Request VO")
  13 +@Data
  14 +public class AiChatConversationPageReqVO extends PageParam {
  15 +
  16 + @Schema(description = "用户编号", example = "1024")
  17 + private Long userId;
  18 +
  19 + @Schema(description = "对话标题", example = "你好")
  20 + private String title;
  21 +
  22 + @Schema(description = "创建时间")
  23 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  24 + private LocalDateTime[] createTime;
  25 +
  26 +}
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationRespVO.java
@@ -10,24 +10,24 @@ import lombok.Data; @@ -10,24 +10,24 @@ import lombok.Data;
10 10
11 import java.time.LocalDateTime; 11 import java.time.LocalDateTime;
12 12
13 -@Schema(description = "管理后台 - AI 聊天会话 Response VO") 13 +@Schema(description = "管理后台 - AI 聊天对话 Response VO")
14 @Data 14 @Data
15 public class AiChatConversationRespVO implements VO { 15 public class AiChatConversationRespVO implements VO {
16 16
17 - @Schema(description = "会话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") 17 + @Schema(description = "对话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
18 private Long id; 18 private Long id;
19 19
20 @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") 20 @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
21 private Long userId; 21 private Long userId;
22 22
23 - @Schema(description = "会话标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是一个标题") 23 + @Schema(description = "对话标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是一个标题")
24 private String title; 24 private String title;
25 25
26 @Schema(description = "是否置顶", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") 26 @Schema(description = "是否置顶", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
27 private Boolean pinned; 27 private Boolean pinned;
28 28
29 - @Schema(description = "角色编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "1")  
30 - @Trans(type = TransType.SIMPLE, target = AiChatRoleDO.class, fields = "avatar", ref = "roleAvatar") 29 + @Schema(description = "角色编号", example = "1")
  30 + @Trans(type = TransType.SIMPLE, target = AiChatRoleDO.class, fields = {"name", "avatar"}, refs = {"roleName", "roleAvatar"})
31 private Long roleId; 31 private Long roleId;
32 32
33 @Schema(description = "模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 33 @Schema(description = "模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@@ -52,12 +52,20 @@ public class AiChatConversationRespVO implements VO { @@ -52,12 +52,20 @@ public class AiChatConversationRespVO implements VO {
52 @Schema(description = "上下文的最大 Message 数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") 52 @Schema(description = "上下文的最大 Message 数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
53 private Integer maxContexts; 53 private Integer maxContexts;
54 54
55 - @Schema(description = "最后更新时间", requiredMode = Schema.RequiredMode.REQUIRED)  
56 - private LocalDateTime updateTime; 55 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  56 + private LocalDateTime createTime;
57 57
58 // ========== 关联 role 信息 ========== 58 // ========== 关联 role 信息 ==========
59 59
60 - @Schema(description = "角色头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png") 60 + @Schema(description = "角色头像", example = "https://www.iocoder.cn/1.png")
61 private String roleAvatar; 61 private String roleAvatar;
62 62
  63 + @Schema(description = "角色名字", example = "小黄")
  64 + private String roleName;
  65 +
  66 + // ========== 仅在【对话管理】时加载 ==========
  67 +
  68 + @Schema(description = "消息数量", example = "20")
  69 + private Integer messageCount;
  70 +
63 } 71 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/conversation/AiChatConversationUpdateMyReqVO.java
@@ -4,15 +4,15 @@ import io.swagger.v3.oas.annotations.media.Schema; @@ -4,15 +4,15 @@ import io.swagger.v3.oas.annotations.media.Schema;
4 import jakarta.validation.constraints.NotNull; 4 import jakarta.validation.constraints.NotNull;
5 import lombok.Data; 5 import lombok.Data;
6 6
7 -@Schema(description = "管理后台 - AI 聊天会话更新【我的】 Request VO") 7 +@Schema(description = "管理后台 - AI 聊天对话更新【我的】 Request VO")
8 @Data 8 @Data
9 public class AiChatConversationUpdateMyReqVO { 9 public class AiChatConversationUpdateMyReqVO {
10 10
11 - @Schema(description = "会话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")  
12 - @NotNull(message = "会话编号不能为空") 11 + @Schema(description = "对话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  12 + @NotNull(message = "对话编号不能为空")
13 private Long id; 13 private Long id;
14 14
15 - @Schema(description = "会话标题", example = "我是一个标题") 15 + @Schema(description = "对话标题", example = "我是一个标题")
16 private String title; 16 private String title;
17 17
18 @Schema(description = "是否置顶", example = "true") 18 @Schema(description = "是否置顶", example = "true")
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/message/AiChatMessageRespVO.java
@@ -12,7 +12,7 @@ public class AiChatMessageRespVO { @@ -12,7 +12,7 @@ public class AiChatMessageRespVO {
12 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") 12 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
13 private Long id; 13 private Long id;
14 14
15 - @Schema(description = "会话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") 15 + @Schema(description = "对话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
16 private Long conversationId; 16 private Long conversationId;
17 17
18 @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "role") 18 @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "role")
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/chat/AiChatConversationDO.java
@@ -13,7 +13,7 @@ import java.time.LocalDateTime; @@ -13,7 +13,7 @@ import java.time.LocalDateTime;
13 import java.util.Date; 13 import java.util.Date;
14 14
15 /** 15 /**
16 - * AI Chat 会话 DO 16 + * AI Chat 对话 DO
17 * 17 *
18 * 用户每次发起 Chat 聊天时,会创建一个 {@link AiChatConversationDO} 对象,将它的消息关联在一起 18 * 用户每次发起 Chat 聊天时,会创建一个 {@link AiChatConversationDO} 对象,将它的消息关联在一起
19 * 19 *
@@ -45,7 +45,7 @@ public class AiChatConversationDO extends BaseDO { @@ -45,7 +45,7 @@ public class AiChatConversationDO extends BaseDO {
45 private Long userId; 45 private Long userId;
46 46
47 /** 47 /**
48 - * 会话标题 48 + * 对话标题
49 * 49 *
50 * 默认由系统自动生成,可用户手动修改 50 * 默认由系统自动生成,可用户手动修改
51 */ 51 */
@@ -79,7 +79,7 @@ public class AiChatConversationDO extends BaseDO { @@ -79,7 +79,7 @@ public class AiChatConversationDO extends BaseDO {
79 */ 79 */
80 private String model; 80 private String model;
81 81
82 - // ========== 会话配置 ========== 82 + // ========== 对话配置 ==========
83 83
84 /** 84 /**
85 * 角色设定 85 * 角色设定
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/chat/AiChatMessageDO.java
@@ -32,7 +32,7 @@ public class AiChatMessageDO extends BaseDO { @@ -32,7 +32,7 @@ public class AiChatMessageDO extends BaseDO {
32 private Long id; 32 private Long id;
33 33
34 /** 34 /**
35 - * 会话编号 35 + * 对话编号
36 * 36 *
37 * 关联 {@link AiChatConversationDO#getId()} 字段 37 * 关联 {@link AiChatConversationDO#getId()} 字段
38 */ 38 */
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiChatModelDO.java
@@ -62,7 +62,7 @@ public class AiChatModelDO extends BaseDO { @@ -62,7 +62,7 @@ public class AiChatModelDO extends BaseDO {
62 */ 62 */
63 private Integer status; 63 private Integer status;
64 64
65 - // ========== 会话配置 ========== 65 + // ========== 对话配置 ==========
66 66
67 /** 67 /**
68 * 温度参数 68 * 温度参数
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/chat/AiChatConversationMapper.java
1 package cn.iocoder.yudao.module.ai.dal.mysql.chat; 1 package cn.iocoder.yudao.module.ai.dal.mysql.chat;
2 2
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
4 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationPageReqVO;
5 import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO; 7 import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO;
6 import org.apache.ibatis.annotations.Mapper; 8 import org.apache.ibatis.annotations.Mapper;
7 9
@@ -22,4 +24,18 @@ public interface AiChatConversationMapper extends BaseMapperX&lt;AiChatConversation @@ -22,4 +24,18 @@ public interface AiChatConversationMapper extends BaseMapperX&lt;AiChatConversation
22 .orderByAsc(AiChatConversationDO::getCreateTime)); 24 .orderByAsc(AiChatConversationDO::getCreateTime));
23 } 25 }
24 26
  27 + default List<AiChatConversationDO> selectListByUserIdAndPinned(Long userId, boolean pinned) {
  28 + return selectList(new LambdaQueryWrapperX<AiChatConversationDO>()
  29 + .eq(AiChatConversationDO::getUserId, userId)
  30 + .eq(AiChatConversationDO::getPinned, pinned));
  31 + }
  32 +
  33 + default PageResult<AiChatConversationDO> selectChatConversationPage(AiChatConversationPageReqVO pageReqVO) {
  34 + return selectPage(pageReqVO, new LambdaQueryWrapperX<AiChatConversationDO>()
  35 + .eqIfPresent(AiChatConversationDO::getUserId, pageReqVO.getUserId())
  36 + .likeIfPresent(AiChatConversationDO::getTitle, pageReqVO.getTitle())
  37 + .betweenIfPresent(AiChatConversationDO::getCreateTime, pageReqVO.getCreateTime())
  38 + .orderByDesc(AiChatConversationDO::getId));
  39 + }
  40 +
25 } 41 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/chat/AiChatMessageMapper.java
1 package cn.iocoder.yudao.module.ai.dal.mysql.chat; 1 package cn.iocoder.yudao.module.ai.dal.mysql.chat;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.map.MapUtil;
  5 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 6 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
4 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 7 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
5 import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO; 8 import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO;
  9 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
6 import org.apache.ibatis.annotations.Mapper; 10 import org.apache.ibatis.annotations.Mapper;
7 11
  12 +import java.util.Collection;
  13 +import java.util.Collections;
8 import java.util.List; 14 import java.util.List;
  15 +import java.util.Map;
9 16
10 /** 17 /**
11 * AI 聊天对话 Mapper 18 * AI 聊天对话 Mapper
@@ -21,4 +28,19 @@ public interface AiChatMessageMapper extends BaseMapperX&lt;AiChatMessageDO&gt; { @@ -21,4 +28,19 @@ public interface AiChatMessageMapper extends BaseMapperX&lt;AiChatMessageDO&gt; {
21 .orderByAsc(AiChatMessageDO::getId)); 28 .orderByAsc(AiChatMessageDO::getId));
22 } 29 }
23 30
  31 + default Map<Long, Integer> selectCountMapByConversationId(Collection<Long> conversationIds) {
  32 + // SQL count 查询
  33 + List<Map<String, Object>> result = selectMaps(new QueryWrapper<AiChatMessageDO>()
  34 + .select("COUNT(id) AS count, conversation_id AS conversationId")
  35 + .in("conversation_id", conversationIds)
  36 + .groupBy("conversation_id"));
  37 + if (CollUtil.isEmpty(result)) {
  38 + return Collections.emptyMap();
  39 + }
  40 + // 转换数据
  41 + return CollectionUtils.convertMap(result,
  42 + record -> MapUtil.getLong(record, "conversationId"),
  43 + record -> MapUtil.getInt(record, "count" ));
  44 + }
  45 +
24 } 46 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatConversationService.java
1 package cn.iocoder.yudao.module.ai.service.chat; 1 package cn.iocoder.yudao.module.ai.service.chat;
2 2
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
3 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationCreateMyReqVO; 4 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationCreateMyReqVO;
  5 +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationPageReqVO;
4 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateMyReqVO; 6 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateMyReqVO;
5 import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO; 7 import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO;
6 8
@@ -14,7 +16,7 @@ import java.util.List; @@ -14,7 +16,7 @@ import java.util.List;
14 public interface AiChatConversationService { 16 public interface AiChatConversationService {
15 17
16 /** 18 /**
17 - * 创建【我的】聊天会话 19 + * 创建【我的】聊天对话
18 * 20 *
19 * @param createReqVO 创建信息 21 * @param createReqVO 创建信息
20 * @param userId 用户编号 22 * @param userId 用户编号
@@ -23,7 +25,7 @@ public interface AiChatConversationService { @@ -23,7 +25,7 @@ public interface AiChatConversationService {
23 Long createChatConversationMy(AiChatConversationCreateMyReqVO createReqVO, Long userId); 25 Long createChatConversationMy(AiChatConversationCreateMyReqVO createReqVO, Long userId);
24 26
25 /** 27 /**
26 - * 更新【我的】聊天会话 28 + * 更新【我的】聊天对话
27 * 29 *
28 * @param updateReqVO 更新信息 30 * @param updateReqVO 更新信息
29 * @param userId 用户编号 31 * @param userId 用户编号
@@ -31,23 +33,23 @@ public interface AiChatConversationService { @@ -31,23 +33,23 @@ public interface AiChatConversationService {
31 void updateChatConversationMy(AiChatConversationUpdateMyReqVO updateReqVO, Long userId); 33 void updateChatConversationMy(AiChatConversationUpdateMyReqVO updateReqVO, Long userId);
32 34
33 /** 35 /**
34 - * 获得【我的】聊天会话列表 36 + * 获得【我的】聊天对话列表
35 * 37 *
36 * @param userId 用户编号 38 * @param userId 用户编号
37 - * @return 聊天会话列表 39 + * @return 聊天对话列表
38 */ 40 */
39 List<AiChatConversationDO> getChatConversationListByUserId(Long userId); 41 List<AiChatConversationDO> getChatConversationListByUserId(Long userId);
40 42
41 /** 43 /**
42 - * 获得聊天会话 44 + * 获得聊天对话
43 * 45 *
44 * @param id 编号 46 * @param id 编号
45 - * @return 聊天会话 47 + * @return 聊天对话
46 */ 48 */
47 AiChatConversationDO getChatConversation(Long id); 49 AiChatConversationDO getChatConversation(Long id);
48 50
49 /** 51 /**
50 - * 删除【我的】聊天会话 52 + * 删除【我的】聊天对话
51 * 53 *
52 * @param id 编号 54 * @param id 编号
53 * @param userId 用户编号 55 * @param userId 用户编号
@@ -55,17 +57,20 @@ public interface AiChatConversationService { @@ -55,17 +57,20 @@ public interface AiChatConversationService {
55 void deleteChatConversationMy(Long id, Long userId); 57 void deleteChatConversationMy(Long id, Long userId);
56 58
57 /** 59 /**
58 - * 校验 - 是否存在 60 + * 校验聊天对话是否存在
59 * 61 *
60 - * @param id  
61 - * @return 62 + * @param id 编号
  63 + * @return 聊天对话
62 */ 64 */
63 - AiChatConversationDO validateExists(Long id); 65 + AiChatConversationDO validateChatConversationExists(Long id);
64 66
65 /** 67 /**
66 - * 删除 - 所有对话,置顶除外 68 + * 删除【我的】 + 非置顶的聊天对话
67 * 69 *
68 - * @param loginUserId 70 + * @param userId 用户编号
69 */ 71 */
70 - void deleteMyAllExceptPinned(Long loginUserId); 72 + void deleteChatConversationMyByUnpinned(Long userId);
  73 +
  74 + PageResult<AiChatConversationDO> getChatConversationPage(AiChatConversationPageReqVO pageReqVO);
  75 +
71 } 76 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatConversationServiceImpl.java
1 package cn.iocoder.yudao.module.ai.service.chat; 1 package cn.iocoder.yudao.module.ai.service.chat;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
3 import cn.hutool.core.lang.Assert; 4 import cn.hutool.core.lang.Assert;
4 import cn.hutool.core.util.ObjUtil; 5 import cn.hutool.core.util.ObjUtil;
5 import cn.hutool.core.util.ObjectUtil; 6 import cn.hutool.core.util.ObjectUtil;
  7 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 8 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
7 -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;  
8 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationCreateMyReqVO; 9 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationCreateMyReqVO;
  10 +import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationPageReqVO;
9 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateMyReqVO; 11 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateMyReqVO;
10 import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO; 12 import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO;
11 import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; 13 import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO;
@@ -22,6 +24,8 @@ import java.time.LocalDateTime; @@ -22,6 +24,8 @@ import java.time.LocalDateTime;
22 import java.util.List; 24 import java.util.List;
23 25
24 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 26 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  27 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  28 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
25 import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.CHAT_CONVERSATION_MODEL_ERROR; 29 import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.CHAT_CONVERSATION_MODEL_ERROR;
26 import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.CHAT_CONVERSATION_NOT_EXISTS; 30 import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.CHAT_CONVERSATION_NOT_EXISTS;
27 31
@@ -69,7 +73,7 @@ public class AiChatConversationServiceImpl implements AiChatConversationService @@ -69,7 +73,7 @@ public class AiChatConversationServiceImpl implements AiChatConversationService
69 @Override 73 @Override
70 public void updateChatConversationMy(AiChatConversationUpdateMyReqVO updateReqVO, Long userId) { 74 public void updateChatConversationMy(AiChatConversationUpdateMyReqVO updateReqVO, Long userId) {
71 // 1.1 校验对话是否存在 75 // 1.1 校验对话是否存在
72 - AiChatConversationDO conversation = validateExists(updateReqVO.getId()); 76 + AiChatConversationDO conversation = validateChatConversationExists(updateReqVO.getId());
73 if (ObjUtil.notEqual(conversation.getUserId(), userId)) { 77 if (ObjUtil.notEqual(conversation.getUserId(), userId)) {
74 throw exception(CHAT_CONVERSATION_NOT_EXISTS); 78 throw exception(CHAT_CONVERSATION_NOT_EXISTS);
75 } 79 }
@@ -103,7 +107,7 @@ public class AiChatConversationServiceImpl implements AiChatConversationService @@ -103,7 +107,7 @@ public class AiChatConversationServiceImpl implements AiChatConversationService
103 @Override 107 @Override
104 public void deleteChatConversationMy(Long id, Long userId) { 108 public void deleteChatConversationMy(Long id, Long userId) {
105 // 1. 校验对话是否存在 109 // 1. 校验对话是否存在
106 - AiChatConversationDO conversation = validateExists(id); 110 + AiChatConversationDO conversation = validateChatConversationExists(id);
107 if (ObjUtil.notEqual(conversation.getUserId(), userId)) { 111 if (ObjUtil.notEqual(conversation.getUserId(), userId)) {
108 throw exception(CHAT_CONVERSATION_NOT_EXISTS); 112 throw exception(CHAT_CONVERSATION_NOT_EXISTS);
109 } 113 }
@@ -119,7 +123,7 @@ public class AiChatConversationServiceImpl implements AiChatConversationService @@ -119,7 +123,7 @@ public class AiChatConversationServiceImpl implements AiChatConversationService
119 throw exception(CHAT_CONVERSATION_MODEL_ERROR); 123 throw exception(CHAT_CONVERSATION_MODEL_ERROR);
120 } 124 }
121 125
122 - public AiChatConversationDO validateExists(Long id) { 126 + public AiChatConversationDO validateChatConversationExists(Long id) {
123 AiChatConversationDO conversation = chatConversationMapper.selectById(id); 127 AiChatConversationDO conversation = chatConversationMapper.selectById(id);
124 if (conversation == null) { 128 if (conversation == null) {
125 throw exception(CHAT_CONVERSATION_NOT_EXISTS); 129 throw exception(CHAT_CONVERSATION_NOT_EXISTS);
@@ -128,12 +132,17 @@ public class AiChatConversationServiceImpl implements AiChatConversationService @@ -128,12 +132,17 @@ public class AiChatConversationServiceImpl implements AiChatConversationService
128 } 132 }
129 133
130 @Override 134 @Override
131 - public void deleteMyAllExceptPinned(Long loginUserId) {  
132 - chatConversationMapper.delete(  
133 - new LambdaQueryWrapperX<AiChatConversationDO>()  
134 - .eq(AiChatConversationDO::getUserId, loginUserId)  
135 - .eq(AiChatConversationDO::getPinned, false)  
136 - ); 135 + public void deleteChatConversationMyByUnpinned(Long userId) {
  136 + List<AiChatConversationDO> list = chatConversationMapper.selectListByUserIdAndPinned(userId, false);
  137 + if (CollUtil.isEmpty(list)) {
  138 + return;
  139 + }
  140 + chatConversationMapper.deleteBatchIds(convertList(list, AiChatConversationDO::getId));
  141 + }
  142 +
  143 + @Override
  144 + public PageResult<AiChatConversationDO> getChatConversationPage(AiChatConversationPageReqVO pageReqVO) {
  145 + return chatConversationMapper.selectChatConversationPage(pageReqVO);
137 } 146 }
138 147
139 } 148 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatMessageService.java
@@ -5,7 +5,9 @@ import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.*; @@ -5,7 +5,9 @@ import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.*;
5 import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO; 5 import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO;
6 import reactor.core.publisher.Flux; 6 import reactor.core.publisher.Flux;
7 7
  8 +import java.util.Collection;
8 import java.util.List; 9 import java.util.List;
  10 +import java.util.Map;
9 11
10 /** 12 /**
11 * AI 聊天消息 Service 接口 13 * AI 聊天消息 Service 接口
@@ -32,9 +34,9 @@ public interface AiChatMessageService { @@ -32,9 +34,9 @@ public interface AiChatMessageService {
32 Flux<CommonResult<AiChatMessageSendRespVO>> sendChatMessageStream(AiChatMessageSendReqVO sendReqVO, Long userId); 34 Flux<CommonResult<AiChatMessageSendRespVO>> sendChatMessageStream(AiChatMessageSendReqVO sendReqVO, Long userId);
33 35
34 /** 36 /**
35 - * 获得指定会话的消息列表 37 + * 获得指定对话的消息列表
36 * 38 *
37 - * @param conversationId 会话编号 39 + * @param conversationId 对话编号
38 * @return 消息列表 40 * @return 消息列表
39 */ 41 */
40 List<AiChatMessageDO> getChatMessageListByConversationId(Long conversationId); 42 List<AiChatMessageDO> getChatMessageListByConversationId(Long conversationId);
@@ -48,11 +50,19 @@ public interface AiChatMessageService { @@ -48,11 +50,19 @@ public interface AiChatMessageService {
48 void deleteChatMessage(Long id, Long userId); 50 void deleteChatMessage(Long id, Long userId);
49 51
50 /** 52 /**
51 - * 删除指定会话的消息 53 + * 删除指定对话的消息
52 * 54 *
53 - * @param conversationId 会话编号 55 + * @param conversationId 对话编号
54 * @param userId 用户编号 56 * @param userId 用户编号
55 */ 57 */
56 void deleteChatMessageByConversationId(Long conversationId, Long userId); 58 void deleteChatMessageByConversationId(Long conversationId, Long userId);
57 59
  60 + /**
  61 + * 获得聊天对话的消息数量 Map
  62 + *
  63 + * @param conversationIds 对话编号数组
  64 + * @return 消息数量 Map
  65 + */
  66 + Map<Long, Integer> getChatMessageCountMap(Collection<Long> conversationIds);
  67 +
58 } 68 }
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatMessageServiceImpl.java
@@ -5,7 +5,6 @@ import cn.hutool.core.util.ObjUtil; @@ -5,7 +5,6 @@ import cn.hutool.core.util.ObjUtil;
5 import cn.hutool.core.util.StrUtil; 5 import cn.hutool.core.util.StrUtil;
6 import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; 6 import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
7 import cn.iocoder.yudao.framework.ai.core.factory.AiClientFactory; 7 import cn.iocoder.yudao.framework.ai.core.factory.AiClientFactory;
8 -import cn.iocoder.yudao.framework.common.exception.ErrorCode;  
9 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 8 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
10 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 9 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
11 import cn.iocoder.yudao.module.ai.ErrorCodeConstants; 10 import cn.iocoder.yudao.module.ai.ErrorCodeConstants;
@@ -15,7 +14,6 @@ import cn.iocoder.yudao.module.ai.service.model.AiApiKeyService; @@ -15,7 +14,6 @@ import cn.iocoder.yudao.module.ai.service.model.AiApiKeyService;
15 import cn.iocoder.yudao.module.system.api.user.AdminUserApi; 14 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
16 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; 15 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
17 import jakarta.annotation.Resource; 16 import jakarta.annotation.Resource;
18 -import org.reactivestreams.Publisher;  
19 import org.springframework.ai.chat.ChatResponse; 17 import org.springframework.ai.chat.ChatResponse;
20 import org.springframework.ai.chat.StreamingChatClient; 18 import org.springframework.ai.chat.StreamingChatClient;
21 import org.springframework.ai.chat.messages.*; 19 import org.springframework.ai.chat.messages.*;
@@ -34,7 +32,6 @@ import lombok.extern.slf4j.Slf4j; @@ -34,7 +32,6 @@ import lombok.extern.slf4j.Slf4j;
34 import org.springframework.stereotype.Service; 32 import org.springframework.stereotype.Service;
35 import org.springframework.transaction.annotation.Transactional; 33 import org.springframework.transaction.annotation.Transactional;
36 import reactor.core.publisher.Flux; 34 import reactor.core.publisher.Flux;
37 -import reactor.core.scheduler.Schedulers;  
38 35
39 import java.time.LocalDateTime; 36 import java.time.LocalDateTime;
40 import java.util.*; 37 import java.util.*;
@@ -115,7 +112,7 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { @@ -115,7 +112,7 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
115 @Override 112 @Override
116 public Flux<CommonResult<AiChatMessageSendRespVO>> sendChatMessageStream(AiChatMessageSendReqVO sendReqVO, Long userId) { 113 public Flux<CommonResult<AiChatMessageSendRespVO>> sendChatMessageStream(AiChatMessageSendReqVO sendReqVO, Long userId) {
117 // 1.1 校验对话存在 114 // 1.1 校验对话存在
118 - AiChatConversationDO conversation = chatConversationService.validateExists(sendReqVO.getConversationId()); 115 + AiChatConversationDO conversation = chatConversationService.validateChatConversationExists(sendReqVO.getConversationId());
119 if (ObjUtil.notEqual(conversation.getUserId(), userId)) { 116 if (ObjUtil.notEqual(conversation.getUserId(), userId)) {
120 throw exception(CHAT_CONVERSATION_NOT_EXISTS); // TODO 芋艿:异常情况的对接; 117 throw exception(CHAT_CONVERSATION_NOT_EXISTS); // TODO 芋艿:异常情况的对接;
121 } 118 }
@@ -189,7 +186,7 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { @@ -189,7 +186,7 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
189 * n 组:指的是 user + assistant 形成一组 186 * n 组:指的是 user + assistant 形成一组
190 * 187 *
191 * @param messages 消息列表 188 * @param messages 消息列表
192 - * @param conversation 会话 189 + * @param conversation 对话
193 * @param sendReqVO 发送请求 190 * @param sendReqVO 发送请求
194 * @return 消息上下文 191 * @return 消息上下文
195 */ 192 */
@@ -258,4 +255,9 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { @@ -258,4 +255,9 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
258 chatMessageMapper.deleteBatchIds(convertList(messages, AiChatMessageDO::getId)); 255 chatMessageMapper.deleteBatchIds(convertList(messages, AiChatMessageDO::getId));
259 } 256 }
260 257
  258 + @Override
  259 + public Map<Long, Integer> getChatMessageCountMap(Collection<Long> conversationIds) {
  260 + return chatMessageMapper.selectCountMapByConversationId(conversationIds);
  261 + }
  262 +
261 } 263 }