Commit a48287611358f7b885ca0e7b99e14ede39af6347
1 parent
3b02bcf4
【优化】AI:聊天消息的 Service 实现
Showing
12 changed files
with
166 additions
and
195 deletions
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/ErrorCodeConstants.java
| @@ -30,8 +30,8 @@ public interface ErrorCodeConstants { | @@ -30,8 +30,8 @@ public interface ErrorCodeConstants { | ||
| 30 | ErrorCode CHAT_CONVERSATION_UPDATE_MAX_TOKENS_ERROR = new ErrorCode(1_040_003_002, "更新对话失败,最大 Token 超过上限"); | 30 | ErrorCode CHAT_CONVERSATION_UPDATE_MAX_TOKENS_ERROR = new ErrorCode(1_040_003_002, "更新对话失败,最大 Token 超过上限"); |
| 31 | ErrorCode CHAT_CONVERSATION_UPDATE_MAX_CONTEXTS_ERROR = new ErrorCode(1_040_003_002, "更新对话失败,最大 Context 超过上限"); | 31 | ErrorCode CHAT_CONVERSATION_UPDATE_MAX_CONTEXTS_ERROR = new ErrorCode(1_040_003_002, "更新对话失败,最大 Context 超过上限"); |
| 32 | 32 | ||
| 33 | - // chat | ||
| 34 | - ErrorCode AI_CHAT_MESSAGE_NOT_EXIST = new ErrorCode(1_022_000_100, "提问的 MessageId 不存在!"); | 33 | + // ========== API 聊天消息 1-040-004-000 ========== |
| 34 | + ErrorCode AI_CHAT_MESSAGE_NOT_EXIST = new ErrorCode(1_040_004_000, "消息不存在!"); | ||
| 35 | 35 | ||
| 36 | // midjourney | 36 | // midjourney |
| 37 | 37 |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/AiChatMessageController.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; | ||
| 4 | +import cn.hutool.core.util.ObjUtil; | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 6 | +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; | ||
| 7 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||
| 4 | import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.*; | 8 | import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.*; |
| 5 | -import cn.iocoder.yudao.module.ai.service.AiChatService; | 9 | +import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO; |
| 10 | +import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO; | ||
| 11 | +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; | ||
| 12 | +import cn.iocoder.yudao.module.ai.service.chat.AiChatConversationService; | ||
| 13 | +import cn.iocoder.yudao.module.ai.service.chat.AiChatMessageService; | ||
| 14 | +import cn.iocoder.yudao.module.ai.service.model.AiChatRoleService; | ||
| 15 | +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | ||
| 16 | +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | ||
| 6 | import io.swagger.v3.oas.annotations.Operation; | 17 | import io.swagger.v3.oas.annotations.Operation; |
| 7 | import io.swagger.v3.oas.annotations.Parameter; | 18 | import io.swagger.v3.oas.annotations.Parameter; |
| 8 | import io.swagger.v3.oas.annotations.tags.Tag; | 19 | import io.swagger.v3.oas.annotations.tags.Tag; |
| @@ -14,9 +25,12 @@ import org.springframework.validation.annotation.Validated; | @@ -14,9 +25,12 @@ import org.springframework.validation.annotation.Validated; | ||
| 14 | import org.springframework.web.bind.annotation.*; | 25 | import org.springframework.web.bind.annotation.*; |
| 15 | import reactor.core.publisher.Flux; | 26 | import reactor.core.publisher.Flux; |
| 16 | 27 | ||
| 28 | +import java.util.Collections; | ||
| 17 | import java.util.List; | 29 | import java.util.List; |
| 30 | +import java.util.Map; | ||
| 18 | 31 | ||
| 19 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 32 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 33 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | ||
| 20 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | 34 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| 21 | 35 | ||
| 22 | @Tag(name = "管理后台 - 聊天消息") | 36 | @Tag(name = "管理后台 - 聊天消息") |
| @@ -26,39 +40,65 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti | @@ -26,39 +40,65 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti | ||
| 26 | public class AiChatMessageController { | 40 | public class AiChatMessageController { |
| 27 | 41 | ||
| 28 | @Resource | 42 | @Resource |
| 29 | - private AiChatService chatService; | 43 | + private AiChatMessageService chatMessageService; |
| 44 | + @Resource | ||
| 45 | + private AiChatConversationService chatConversationService; | ||
| 46 | + @Resource | ||
| 47 | + private AiChatRoleService chatRoleService; | ||
| 48 | + | ||
| 49 | + @Resource | ||
| 50 | + private AdminUserApi adminUserApi; | ||
| 30 | 51 | ||
| 31 | @Operation(summary = "发送消息(段式)", description = "一次性返回,响应较慢") | 52 | @Operation(summary = "发送消息(段式)", description = "一次性返回,响应较慢") |
| 32 | @PostMapping("/send") | 53 | @PostMapping("/send") |
| 33 | public CommonResult<AiChatMessageRespVO> sendMessage(@Validated @RequestBody AiChatMessageSendReqVO sendReqVO) { | 54 | public CommonResult<AiChatMessageRespVO> sendMessage(@Validated @RequestBody AiChatMessageSendReqVO sendReqVO) { |
| 34 | - return success(chatService.chat(sendReqVO)); | 55 | + return success(chatMessageService.sendMessage(sendReqVO)); |
| 35 | } | 56 | } |
| 36 | 57 | ||
| 37 | @Operation(summary = "发送消息(流式)", description = "流式返回,响应较快") | 58 | @Operation(summary = "发送消息(流式)", description = "流式返回,响应较快") |
| 38 | @PostMapping(value = "/send-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) | 59 | @PostMapping(value = "/send-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) |
| 39 | @PermitAll // 解决 SSE 最终响应的时候,会被 Access Denied 拦截的问题 | 60 | @PermitAll // 解决 SSE 最终响应的时候,会被 Access Denied 拦截的问题 |
| 40 | public Flux<AiChatMessageSendRespVO> sendChatMessageStream(@Validated @RequestBody AiChatMessageSendReqVO sendReqVO) { | 61 | public Flux<AiChatMessageSendRespVO> sendChatMessageStream(@Validated @RequestBody AiChatMessageSendReqVO sendReqVO) { |
| 41 | - return chatService.sendChatMessageStream(sendReqVO, getLoginUserId()); | 62 | + return chatMessageService.sendChatMessageStream(sendReqVO, getLoginUserId()); |
| 42 | } | 63 | } |
| 43 | 64 | ||
| 44 | @Operation(summary = "获得指定会话的消息列表") | 65 | @Operation(summary = "获得指定会话的消息列表") |
| 45 | @GetMapping("/list-by-conversation-id") | 66 | @GetMapping("/list-by-conversation-id") |
| 46 | @Parameter(name = "conversationId", required = true, description = "会话编号", example = "1024") | 67 | @Parameter(name = "conversationId", required = true, description = "会话编号", example = "1024") |
| 47 | - public CommonResult<List<AiChatMessageRespVO>> getMessageListByConversationId(@RequestParam("conversationId") Long conversationId) { | ||
| 48 | - return success(chatService.getMessageListByConversationId(conversationId)); | 68 | + public CommonResult<List<AiChatMessageRespVO>> getChatMessageListByConversationId( |
| 69 | + @RequestParam("conversationId") Long conversationId) { | ||
| 70 | + AiChatConversationDO conversation = chatConversationService.getChatConversation(conversationId); | ||
| 71 | + if (conversation == null || ObjUtil.notEqual(conversation.getUserId(), getLoginUserId())) { | ||
| 72 | + return success(Collections.emptyList()); | ||
| 73 | + } | ||
| 74 | + List<AiChatMessageDO> messageList = chatMessageService.getChatMessageListByConversationId(conversationId); | ||
| 75 | + if (CollUtil.isEmpty(messageList)) { | ||
| 76 | + return success(Collections.emptyList()); | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + // 拼接数据 | ||
| 80 | + Map<Long, AiChatRoleDO> roleMap = chatRoleService.getChatRoleMap(convertSet(messageList, AiChatMessageDO::getRoleId)); | ||
| 81 | + AdminUserRespDTO user = adminUserApi.getUser(getLoginUserId()); | ||
| 82 | + return success(BeanUtils.toBean(messageList, AiChatMessageRespVO.class, respVO -> { | ||
| 83 | + MapUtils.findAndThen(roleMap, respVO.getRoleId(), role -> respVO.setRoleAvatar(role.getAvatar())); | ||
| 84 | + respVO.setUserAvatar(user.getAvatar()); | ||
| 85 | + })); | ||
| 49 | } | 86 | } |
| 50 | 87 | ||
| 51 | @Operation(summary = "删除消息") | 88 | @Operation(summary = "删除消息") |
| 52 | @DeleteMapping("/delete") | 89 | @DeleteMapping("/delete") |
| 53 | @Parameter(name = "id", required = true, description = "消息编号", example = "1024") | 90 | @Parameter(name = "id", required = true, description = "消息编号", example = "1024") |
| 54 | - public CommonResult<Boolean> deleteMessage(@RequestParam("id") Long id) { | ||
| 55 | - return success(chatService.deleteMessage(id)); | 91 | + public CommonResult<Boolean> deleteChatMessage(@RequestParam("id") Long id) { |
| 92 | + chatMessageService.deleteMessage(id, getLoginUserId()); | ||
| 93 | + return success(true); | ||
| 56 | } | 94 | } |
| 57 | 95 | ||
| 58 | - @Operation(summary = "删除消息-对于对话全部消息") | 96 | + @Operation(summary = "删除指定会话的消息") |
| 59 | @DeleteMapping("/delete-by-conversation-id") | 97 | @DeleteMapping("/delete-by-conversation-id") |
| 60 | - @Parameter(name = "id", required = true, description = "消息编号", example = "1024") | ||
| 61 | - public CommonResult<Boolean> deleteByConversationId(@RequestParam("conversationId") Long conversationId) { | ||
| 62 | - return success(chatService.deleteByConversationId(conversationId)); | 98 | + @Parameter(name = "conversationId", required = true, description = "会话编号", example = "1024") |
| 99 | + public CommonResult<Boolean> deleteChatMessageByConversationId(@RequestParam("conversationId") Long conversationId) { | ||
| 100 | + chatMessageService.deleteChatMessageByConversationId(conversationId, getLoginUserId()); | ||
| 101 | + return success(true); | ||
| 63 | } | 102 | } |
| 103 | + | ||
| 64 | } | 104 | } |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/message/AiChatMessageSendRespVO.java
| @@ -31,13 +31,14 @@ public class AiChatMessageSendRespVO { | @@ -31,13 +31,14 @@ 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 | - // ========= 扩展字段 | 34 | + // ========== 扩展字段 ========== |
| 35 | 35 | ||
| 36 | - @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "http://xxx") | 36 | + @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://iocoder.cn/1.png") |
| 37 | private String userAvatar; | 37 | private String userAvatar; |
| 38 | 38 | ||
| 39 | - @Schema(description = "角色头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "http://xxx") | 39 | + @Schema(description = "角色头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://iocoder.cn/2.png") |
| 40 | private String roleAvatar; | 40 | private String roleAvatar; |
| 41 | + | ||
| 41 | } | 42 | } |
| 42 | 43 | ||
| 43 | } | 44 | } |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/convert/AiChatMessageConvert.java deleted
| 1 | -package cn.iocoder.yudao.module.ai.convert; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO; | ||
| 4 | -import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageRespVO; | ||
| 5 | -import org.mapstruct.Mapper; | ||
| 6 | -import org.mapstruct.factory.Mappers; | ||
| 7 | - | ||
| 8 | -import java.util.List; | ||
| 9 | - | ||
| 10 | -/** | ||
| 11 | - * 聊天 对话 convert | ||
| 12 | - * | ||
| 13 | - * @author fansili | ||
| 14 | - * @time 2024/4/18 16:39 | ||
| 15 | - * @since 1.0 | ||
| 16 | - */ | ||
| 17 | -@Mapper | ||
| 18 | -public interface AiChatMessageConvert { | ||
| 19 | - | ||
| 20 | - AiChatMessageConvert INSTANCE = Mappers.getMapper(AiChatMessageConvert.class); | ||
| 21 | - | ||
| 22 | - /** | ||
| 23 | - * 转换 AiChatMessageRespVO | ||
| 24 | - * | ||
| 25 | - * @param aiChatMessageDOList | ||
| 26 | - * @return | ||
| 27 | - */ | ||
| 28 | - List<AiChatMessageRespVO> convertAiChatMessageRespVOList(List<AiChatMessageDO> aiChatMessageDOList); | ||
| 29 | - | ||
| 30 | -} |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/AiChatMessageMapper.java deleted
| 1 | -package cn.iocoder.yudao.module.ai.dal.mysql; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | ||
| 4 | -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | ||
| 5 | -import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO; | ||
| 6 | -import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO; | ||
| 7 | -import org.apache.ibatis.annotations.Mapper; | ||
| 8 | -import org.springframework.stereotype.Repository; | ||
| 9 | - | ||
| 10 | -import java.util.List; | ||
| 11 | - | ||
| 12 | -/** | ||
| 13 | - * message mapper | ||
| 14 | - * | ||
| 15 | - * @fansili | ||
| 16 | - * @since v1.0 | ||
| 17 | - */ | ||
| 18 | -@Repository | ||
| 19 | -@Mapper | ||
| 20 | -public interface AiChatMessageMapper extends BaseMapperX<AiChatMessageDO> { | ||
| 21 | - | ||
| 22 | - /** | ||
| 23 | - * 查询 - 根据 对话id查询 | ||
| 24 | - * | ||
| 25 | - * @param conversationId | ||
| 26 | - */ | ||
| 27 | - default List<AiChatMessageDO> selectByConversationId(Long conversationId) { | ||
| 28 | - return this.selectList( | ||
| 29 | - new LambdaQueryWrapperX<AiChatMessageDO>() | ||
| 30 | - .eq(AiChatMessageDO::getConversationId, conversationId) | ||
| 31 | - .orderByAsc(AiChatMessageDO::getId) | ||
| 32 | - ); | ||
| 33 | - } | ||
| 34 | - | ||
| 35 | - /** | ||
| 36 | - * 删除 - 根据 conversationId | ||
| 37 | - * | ||
| 38 | - * @param conversationId | ||
| 39 | - */ | ||
| 40 | - default int deleteByConversationId(Long conversationId) { | ||
| 41 | - return this.delete(new LambdaQueryWrapperX<AiChatMessageDO>().eq(AiChatMessageDO::getConversationId, conversationId)); | ||
| 42 | - } | ||
| 43 | -} |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/AiChatModelMapper.java
| 1 | package cn.iocoder.yudao.module.ai.dal.mysql; | 1 | package cn.iocoder.yudao.module.ai.dal.mysql; |
| 2 | 2 | ||
| 3 | -import cn.hutool.core.collection.CollUtil; | ||
| 4 | -import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||
| 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | 4 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 7 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | 5 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| 8 | import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; | 6 | import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; |
| 9 | import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatModel.AiChatModelPageReqVO; | 7 | import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatModel.AiChatModelPageReqVO; |
| 10 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; | 8 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; |
| 11 | -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | ||
| 12 | import org.apache.ibatis.annotations.Mapper; | 9 | import org.apache.ibatis.annotations.Mapper; |
| 13 | 10 | ||
| 14 | -import java.util.List; | ||
| 15 | - | ||
| 16 | import java.util.Collection; | 11 | import java.util.Collection; |
| 17 | import java.util.List; | 12 | import java.util.List; |
| 18 | 13 | ||
| @@ -42,7 +37,6 @@ public interface AiChatModelMapper extends BaseMapperX<AiChatModelDO> { | @@ -42,7 +37,6 @@ public interface AiChatModelMapper extends BaseMapperX<AiChatModelDO> { | ||
| 42 | return this.selectList(new LambdaQueryWrapperX<AiChatModelDO>().eq(AiChatModelDO::getId, modalIds)); | 37 | return this.selectList(new LambdaQueryWrapperX<AiChatModelDO>().eq(AiChatModelDO::getId, modalIds)); |
| 43 | } | 38 | } |
| 44 | 39 | ||
| 45 | - | ||
| 46 | default PageResult<AiChatModelDO> selectPage(AiChatModelPageReqVO reqVO) { | 40 | default PageResult<AiChatModelDO> selectPage(AiChatModelPageReqVO reqVO) { |
| 47 | return selectPage(reqVO, new LambdaQueryWrapperX<AiChatModelDO>() | 41 | return selectPage(reqVO, new LambdaQueryWrapperX<AiChatModelDO>() |
| 48 | .likeIfPresent(AiChatModelDO::getName, reqVO.getName()) | 42 | .likeIfPresent(AiChatModelDO::getName, reqVO.getName()) |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/AiImageMapper.java
| @@ -13,7 +13,6 @@ import org.springframework.stereotype.Repository; | @@ -13,7 +13,6 @@ import org.springframework.stereotype.Repository; | ||
| 13 | * @time 2024/4/28 14:01 | 13 | * @time 2024/4/28 14:01 |
| 14 | * @since 1.0 | 14 | * @since 1.0 |
| 15 | */ | 15 | */ |
| 16 | -@Repository | ||
| 17 | @Mapper | 16 | @Mapper |
| 18 | public interface AiImageMapper extends BaseMapperX<AiImageDO> { | 17 | public interface AiImageMapper extends BaseMapperX<AiImageDO> { |
| 19 | 18 |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/chat/AiChatMessageMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.dal.mysql.chat; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | ||
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | ||
| 5 | +import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO; | ||
| 6 | +import org.apache.ibatis.annotations.Mapper; | ||
| 7 | + | ||
| 8 | +import java.util.List; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * AI 聊天对话 Mapper | ||
| 12 | + * | ||
| 13 | + * @author fansili | ||
| 14 | + */ | ||
| 15 | +@Mapper | ||
| 16 | +public interface AiChatMessageMapper extends BaseMapperX<AiChatMessageDO> { | ||
| 17 | + | ||
| 18 | + default List<AiChatMessageDO> selectListByConversationId(Long conversationId) { | ||
| 19 | + return selectList(new LambdaQueryWrapperX<AiChatMessageDO>() | ||
| 20 | + .eq(AiChatMessageDO::getConversationId, conversationId) | ||
| 21 | + .orderByAsc(AiChatMessageDO::getId)); | ||
| 22 | + } | ||
| 23 | + | ||
| 24 | +} |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/AiChatService.java renamed to yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatMessageService.java
| 1 | -package cn.iocoder.yudao.module.ai.service; | 1 | +package cn.iocoder.yudao.module.ai.service.chat; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.*; | 3 | import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.*; |
| 4 | +import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO; | ||
| 4 | import reactor.core.publisher.Flux; | 5 | import reactor.core.publisher.Flux; |
| 5 | 6 | ||
| 6 | import java.util.List; | 7 | import java.util.List; |
| 7 | 8 | ||
| 8 | /** | 9 | /** |
| 9 | - * 聊天 chat | 10 | + * AI 聊天消息 Service 接口 |
| 10 | * | 11 | * |
| 11 | * @author fansili | 12 | * @author fansili |
| 12 | - * @time 2024/4/14 15:55 | ||
| 13 | - * @since 1.0 | ||
| 14 | */ | 13 | */ |
| 15 | -public interface AiChatService { | 14 | +public interface AiChatMessageService { |
| 16 | 15 | ||
| 17 | /** | 16 | /** |
| 18 | - * chat | 17 | + * 发送消息 |
| 19 | * | 18 | * |
| 20 | - * @param sendReqVO | ||
| 21 | - * @return | 19 | + * @param sendReqVO 发送信息 |
| 20 | + * @return 发送结果 | ||
| 22 | */ | 21 | */ |
| 23 | - AiChatMessageRespVO chat(AiChatMessageSendReqVO sendReqVO); | 22 | + AiChatMessageRespVO sendMessage(AiChatMessageSendReqVO sendReqVO); |
| 24 | 23 | ||
| 25 | /** | 24 | /** |
| 26 | - * 获取 - 获取对话 message list | 25 | + * 发送消息 |
| 27 | * | 26 | * |
| 28 | - * @param conversationId | ||
| 29 | - * @return | 27 | + * @param sendReqVO 发送信息 |
| 28 | + * @param userId 用户编号 | ||
| 29 | + * @return 发送结果 | ||
| 30 | */ | 30 | */ |
| 31 | - List<AiChatMessageRespVO> getMessageListByConversationId(Long conversationId); | 31 | + Flux<AiChatMessageSendRespVO> sendChatMessageStream(AiChatMessageSendReqVO sendReqVO, Long userId); |
| 32 | 32 | ||
| 33 | /** | 33 | /** |
| 34 | - * 删除 - 删除message | 34 | + * 获得指定会话的消息列表 |
| 35 | * | 35 | * |
| 36 | - * @param id | ||
| 37 | - * @return | 36 | + * @param conversationId 会话编号 |
| 37 | + * @return 消息列表 | ||
| 38 | */ | 38 | */ |
| 39 | - Boolean deleteMessage(Long id); | 39 | + List<AiChatMessageDO> getChatMessageListByConversationId(Long conversationId); |
| 40 | 40 | ||
| 41 | /** | 41 | /** |
| 42 | - * 发送消息 | 42 | + * 删除消息 |
| 43 | * | 43 | * |
| 44 | - * @param sendReqVO | ||
| 45 | - * @param userId | ||
| 46 | - * @return | 44 | + * @param id 消息编号 |
| 45 | + * @param userId 用户编号 | ||
| 47 | */ | 46 | */ |
| 48 | - Flux<AiChatMessageSendRespVO> sendChatMessageStream(AiChatMessageSendReqVO sendReqVO, Long userId); | 47 | + void deleteMessage(Long id, Long userId); |
| 49 | 48 | ||
| 50 | /** | 49 | /** |
| 51 | - * 删除消息-对于对话全部消息 | 50 | + * 删除指定会话的消息 |
| 52 | * | 51 | * |
| 53 | - * @param conversationId | ||
| 54 | - * @return | 52 | + * @param conversationId 会话编号 |
| 53 | + * @param userId 用户编号 | ||
| 55 | */ | 54 | */ |
| 56 | - Boolean deleteByConversationId(Long conversationId); | 55 | + void deleteChatMessageByConversationId(Long conversationId, Long userId); |
| 56 | + | ||
| 57 | } | 57 | } |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiChatServiceImpl.java renamed to yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatMessageServiceImpl.java
| 1 | -package cn.iocoder.yudao.module.ai.service.impl; | 1 | +package cn.iocoder.yudao.module.ai.service.chat; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | import cn.hutool.core.util.ObjUtil; | 4 | import cn.hutool.core.util.ObjUtil; |
| @@ -20,13 +20,10 @@ import org.springframework.ai.chat.prompt.Prompt; | @@ -20,13 +20,10 @@ import org.springframework.ai.chat.prompt.Prompt; | ||
| 20 | import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; | 20 | import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; |
| 21 | import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageRespVO; | 21 | import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageRespVO; |
| 22 | import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendReqVO; | 22 | import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendReqVO; |
| 23 | -import cn.iocoder.yudao.module.ai.convert.AiChatMessageConvert; | ||
| 24 | import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO; | 23 | import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO; |
| 25 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; | 24 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; |
| 26 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; | 25 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; |
| 27 | -import cn.iocoder.yudao.module.ai.dal.mysql.AiChatMessageMapper; | ||
| 28 | -import cn.iocoder.yudao.module.ai.service.AiChatService; | ||
| 29 | -import cn.iocoder.yudao.module.ai.service.chat.AiChatConversationService; | 26 | +import cn.iocoder.yudao.module.ai.dal.mysql.chat.AiChatMessageMapper; |
| 30 | import cn.iocoder.yudao.module.ai.service.model.AiChatModelService; | 27 | import cn.iocoder.yudao.module.ai.service.model.AiChatModelService; |
| 31 | import cn.iocoder.yudao.module.ai.service.model.AiChatRoleService; | 28 | import cn.iocoder.yudao.module.ai.service.model.AiChatRoleService; |
| 32 | import lombok.extern.slf4j.Slf4j; | 29 | import lombok.extern.slf4j.Slf4j; |
| @@ -37,21 +34,20 @@ import reactor.core.scheduler.Schedulers; | @@ -37,21 +34,20 @@ import reactor.core.scheduler.Schedulers; | ||
| 37 | 34 | ||
| 38 | import java.time.LocalDateTime; | 35 | import java.time.LocalDateTime; |
| 39 | import java.util.*; | 36 | import java.util.*; |
| 40 | -import java.util.stream.Collectors; | ||
| 41 | 37 | ||
| 42 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 38 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 39 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | ||
| 40 | +import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.AI_CHAT_MESSAGE_NOT_EXIST; | ||
| 43 | import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.CHAT_CONVERSATION_NOT_EXISTS; | 41 | import static cn.iocoder.yudao.module.ai.ErrorCodeConstants.CHAT_CONVERSATION_NOT_EXISTS; |
| 44 | 42 | ||
| 45 | /** | 43 | /** |
| 46 | - * 聊天 service | 44 | + * AI 聊天消息 Service 实现类 |
| 47 | * | 45 | * |
| 48 | * @author fansili | 46 | * @author fansili |
| 49 | - * @time 2024/4/14 15:55 | ||
| 50 | - * @since 1.0 | ||
| 51 | */ | 47 | */ |
| 52 | -@Slf4j | ||
| 53 | @Service | 48 | @Service |
| 54 | -public class AiChatServiceImpl implements AiChatService { | 49 | +@Slf4j |
| 50 | +public class AiChatMessageServiceImpl implements AiChatMessageService { | ||
| 55 | 51 | ||
| 56 | @Resource | 52 | @Resource |
| 57 | private AiChatMessageMapper chatMessageMapper; | 53 | private AiChatMessageMapper chatMessageMapper; |
| @@ -72,7 +68,7 @@ public class AiChatServiceImpl implements AiChatService { | @@ -72,7 +68,7 @@ public class AiChatServiceImpl implements AiChatService { | ||
| 72 | private AdminUserApi adminUserApi; | 68 | private AdminUserApi adminUserApi; |
| 73 | 69 | ||
| 74 | @Transactional(rollbackFor = Exception.class) | 70 | @Transactional(rollbackFor = Exception.class) |
| 75 | - public AiChatMessageRespVO chat(AiChatMessageSendReqVO req) { | 71 | + public AiChatMessageRespVO sendMessage(AiChatMessageSendReqVO req) { |
| 76 | return null; // TODO 芋艿:一起改 | 72 | return null; // TODO 芋艿:一起改 |
| 77 | // Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); | 73 | // Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); |
| 78 | // // 查询对话 | 74 | // // 查询对话 |
| @@ -117,10 +113,13 @@ public class AiChatServiceImpl implements AiChatService { | @@ -117,10 +113,13 @@ public class AiChatServiceImpl implements AiChatService { | ||
| 117 | if (ObjUtil.notEqual(conversation.getUserId(), userId)) { | 113 | if (ObjUtil.notEqual(conversation.getUserId(), userId)) { |
| 118 | throw exception(CHAT_CONVERSATION_NOT_EXISTS); // TODO 芋艿:异常情况的对接; | 114 | throw exception(CHAT_CONVERSATION_NOT_EXISTS); // TODO 芋艿:异常情况的对接; |
| 119 | } | 115 | } |
| 120 | - List<AiChatMessageDO> historyMessages = chatMessageMapper.selectByConversationId(conversation.getId()); | 116 | + List<AiChatMessageDO> historyMessages = chatMessageMapper.selectListByConversationId(conversation.getId()); |
| 121 | // 1.2 校验模型 | 117 | // 1.2 校验模型 |
| 122 | AiChatModelDO model = chatModalService.validateChatModel(conversation.getModelId()); | 118 | AiChatModelDO model = chatModalService.validateChatModel(conversation.getModelId()); |
| 123 | StreamingChatClient chatClient = apiKeyService.getStreamingChatClient(model.getKeyId()); | 119 | StreamingChatClient chatClient = apiKeyService.getStreamingChatClient(model.getKeyId()); |
| 120 | + // 1.3 获取用户头像、角色头像 | ||
| 121 | + AdminUserRespDTO user = adminUserApi.getUser(SecurityFrameworkUtils.getLoginUserId()); | ||
| 122 | + AiChatRoleDO role = conversation.getRoleId() != null ? chatRoleService.getChatRole(conversation.getRoleId()) : null; | ||
| 124 | 123 | ||
| 125 | // 2. 插入 user 发送消息 | 124 | // 2. 插入 user 发送消息 |
| 126 | AiChatMessageDO userMessage = createChatMessage(conversation.getId(), null, model, | 125 | AiChatMessageDO userMessage = createChatMessage(conversation.getId(), null, model, |
| @@ -136,19 +135,17 @@ public class AiChatServiceImpl implements AiChatService { | @@ -136,19 +135,17 @@ public class AiChatServiceImpl implements AiChatService { | ||
| 136 | 135 | ||
| 137 | // 3.3 流式返回 | 136 | // 3.3 流式返回 |
| 138 | // 注意:Schedulers.immediate() 目的是,避免默认 Schedulers.parallel() 并发消费 chunk 导致 SSE 响应前端会乱序问题 | 137 | // 注意:Schedulers.immediate() 目的是,避免默认 Schedulers.parallel() 并发消费 chunk 导致 SSE 响应前端会乱序问题 |
| 139 | - | ||
| 140 | - // 3.4 获取用户头像、角色头像 | ||
| 141 | - AdminUserRespDTO user = adminUserApi.getUser(SecurityFrameworkUtils.getLoginUserId()); | ||
| 142 | - AiChatRoleDO chatRole = chatRoleService.getChatRole(assistantMessage.getRoleId()); | ||
| 143 | - | ||
| 144 | StringBuffer contentBuffer = new StringBuffer(); | 138 | StringBuffer contentBuffer = new StringBuffer(); |
| 145 | return streamResponse.publishOn(Schedulers.single()).map(chunk -> { | 139 | return streamResponse.publishOn(Schedulers.single()).map(chunk -> { |
| 146 | String newContent = chunk.getResult() != null ? chunk.getResult().getOutput().getContent() : null; | 140 | String newContent = chunk.getResult() != null ? chunk.getResult().getOutput().getContent() : null; |
| 147 | newContent = StrUtil.nullToDefault(newContent, ""); // 避免 null 的 情况 | 141 | newContent = StrUtil.nullToDefault(newContent, ""); // 避免 null 的 情况 |
| 148 | contentBuffer.append(newContent); | 142 | contentBuffer.append(newContent); |
| 149 | // 响应结果 | 143 | // 响应结果 |
| 150 | - return new AiChatMessageSendRespVO().setSend(BeanUtils.toBean(userMessage, AiChatMessageSendRespVO.Message.class).setUserAvatar(user.getAvatar())) | ||
| 151 | - .setReceive(BeanUtils.toBean(assistantMessage, AiChatMessageSendRespVO.Message.class).setContent(newContent).setRoleAvatar(chatRole == null ? null : chatRole.getAvatar())); | 144 | + AiChatMessageSendRespVO.Message send = BeanUtils.toBean(userMessage, AiChatMessageSendRespVO.Message.class, |
| 145 | + o -> o.setUserAvatar(user.getAvatar())); | ||
| 146 | + AiChatMessageSendRespVO.Message receive = BeanUtils.toBean(assistantMessage, AiChatMessageSendRespVO.Message.class, | ||
| 147 | + o -> o.setRoleAvatar(role != null ? role.getAvatar() : null)).setContent(newContent); | ||
| 148 | + return new AiChatMessageSendRespVO().setSend(send).setReceive(receive); | ||
| 152 | }).doOnComplete(() -> { | 149 | }).doOnComplete(() -> { |
| 153 | chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId()).setContent(contentBuffer.toString())); | 150 | chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId()).setContent(contentBuffer.toString())); |
| 154 | }).doOnError(throwable -> { | 151 | }).doOnError(throwable -> { |
| @@ -157,11 +154,6 @@ public class AiChatServiceImpl implements AiChatService { | @@ -157,11 +154,6 @@ public class AiChatServiceImpl implements AiChatService { | ||
| 157 | }); | 154 | }); |
| 158 | } | 155 | } |
| 159 | 156 | ||
| 160 | - @Override | ||
| 161 | - public Boolean deleteByConversationId(Long conversationId) { | ||
| 162 | - return chatMessageMapper.deleteByConversationId(conversationId) > 0; | ||
| 163 | - } | ||
| 164 | - | ||
| 165 | private Prompt buildPrompt(AiChatConversationDO conversation, List<AiChatMessageDO> messages, | 157 | private Prompt buildPrompt(AiChatConversationDO conversation, List<AiChatMessageDO> messages, |
| 166 | AiChatModelDO model, AiChatMessageSendReqVO sendReqVO) { | 158 | AiChatModelDO model, AiChatMessageSendReqVO sendReqVO) { |
| 167 | // 1. 构建 Prompt Message 列表 | 159 | // 1. 构建 Prompt Message 列表 |
| @@ -174,12 +166,11 @@ public class AiChatServiceImpl implements AiChatService { | @@ -174,12 +166,11 @@ public class AiChatServiceImpl implements AiChatService { | ||
| 174 | // 1.3 user message 新发送消息 | 166 | // 1.3 user message 新发送消息 |
| 175 | chatMessages.add(new UserMessage(sendReqVO.getContent())); | 167 | chatMessages.add(new UserMessage(sendReqVO.getContent())); |
| 176 | 168 | ||
| 177 | - // 2. 构建 ChatOptions 对象 TODO 芋艿:临时注释掉;等文心一言兼容了; | 169 | + // 2. 构建 ChatOptions 对象 |
| 178 | AiPlatformEnum platform = AiPlatformEnum.validatePlatform(model.getPlatform()); | 170 | AiPlatformEnum platform = AiPlatformEnum.validatePlatform(model.getPlatform()); |
| 179 | ChatOptions chatOptions = clientFactory.buildChatOptions(platform, model.getModel(), | 171 | ChatOptions chatOptions = clientFactory.buildChatOptions(platform, model.getModel(), |
| 180 | conversation.getTemperature(), conversation.getMaxTokens()); | 172 | conversation.getTemperature(), conversation.getMaxTokens()); |
| 181 | return new Prompt(chatMessages, chatOptions); | 173 | return new Prompt(chatMessages, chatOptions); |
| 182 | -// return new Prompt(chatMessages); | ||
| 183 | } | 174 | } |
| 184 | 175 | ||
| 185 | /** | 176 | /** |
| @@ -231,42 +222,30 @@ public class AiChatServiceImpl implements AiChatService { | @@ -231,42 +222,30 @@ public class AiChatServiceImpl implements AiChatService { | ||
| 231 | } | 222 | } |
| 232 | 223 | ||
| 233 | @Override | 224 | @Override |
| 234 | - public List<AiChatMessageRespVO> getMessageListByConversationId(Long conversationId) { | ||
| 235 | - // 校验对话是否存在 | ||
| 236 | - chatConversationService.validateExists(conversationId); | ||
| 237 | - // 获取对话所有 message | ||
| 238 | - List<AiChatMessageDO> aiChatMessageDOList = chatMessageMapper.selectByConversationId(conversationId); | ||
| 239 | - // 获取模型信息 | ||
| 240 | - Set<Long> roleIds = aiChatMessageDOList.stream().map(AiChatMessageDO::getRoleId).collect(Collectors.toSet()); | ||
| 241 | - List<AiChatRoleDO> roleList; | ||
| 242 | - if (!CollUtil.isEmpty(roleIds)) { | ||
| 243 | - roleList = chatRoleService.getChatRoles(roleIds); | ||
| 244 | - } else { | ||
| 245 | - roleList = Collections.emptyList(); | 225 | + public List<AiChatMessageDO> getChatMessageListByConversationId(Long conversationId) { |
| 226 | + return chatMessageMapper.selectListByConversationId(conversationId); | ||
| 227 | + } | ||
| 228 | + | ||
| 229 | + @Override | ||
| 230 | + public void deleteMessage(Long id, Long userId) { | ||
| 231 | + // 1. 校验消息存在 | ||
| 232 | + AiChatMessageDO message = chatMessageMapper.selectById(id); | ||
| 233 | + if (message == null || ObjUtil.notEqual(message.getUserId(), userId)) { | ||
| 234 | + throw exception(AI_CHAT_MESSAGE_NOT_EXIST); | ||
| 246 | } | 235 | } |
| 247 | - Map<Long, AiChatRoleDO> roleMap = roleList.stream().collect(Collectors.toMap(AiChatRoleDO::getId, o -> o)); | ||
| 248 | - // 转换 AiChatMessageRespVO | ||
| 249 | - List<AiChatMessageRespVO> aiChatMessageRespList = AiChatMessageConvert.INSTANCE.convertAiChatMessageRespVOList(aiChatMessageDOList); | ||
| 250 | - // 获取用户信息 | ||
| 251 | - AdminUserRespDTO user = adminUserApi.getUser(SecurityFrameworkUtils.getLoginUserId()); | ||
| 252 | - // 设置用户头像 和 模型头像 | ||
| 253 | - return aiChatMessageRespList.stream().map(item -> { | ||
| 254 | - // 设置 role 头像 | ||
| 255 | - if (roleMap.containsKey(item.getRoleId())) { | ||
| 256 | - AiChatRoleDO role = roleMap.get(item.getRoleId()); | ||
| 257 | - item.setRoleAvatar(role.getAvatar()); | ||
| 258 | - } | ||
| 259 | - // 设置 user 头像 | ||
| 260 | - if (user != null) { | ||
| 261 | - item.setUserAvatar(user.getAvatar()); | ||
| 262 | - } | ||
| 263 | - return item; | ||
| 264 | - }).collect(Collectors.toList()); | 236 | + // 2. 执行删除 |
| 237 | + chatMessageMapper.deleteById(id); | ||
| 265 | } | 238 | } |
| 266 | 239 | ||
| 267 | @Override | 240 | @Override |
| 268 | - public Boolean deleteMessage(Long id) { | ||
| 269 | - return chatMessageMapper.deleteById(id) > 0; | 241 | + public void deleteChatMessageByConversationId(Long conversationId, Long userId) { |
| 242 | + // 1. 校验消息存在 | ||
| 243 | + List<AiChatMessageDO> messages = chatMessageMapper.selectListByConversationId(conversationId); | ||
| 244 | + if (CollUtil.isEmpty(messages) || ObjUtil.notEqual(messages.get(0).getUserId(), userId)) { | ||
| 245 | + throw exception(AI_CHAT_MESSAGE_NOT_EXIST); | ||
| 246 | + } | ||
| 247 | + // 2. 执行删除 | ||
| 248 | + chatMessageMapper.deleteBatchIds(convertList(messages, AiChatMessageDO::getId)); | ||
| 270 | } | 249 | } |
| 271 | 250 | ||
| 272 | } | 251 | } |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatRoleService.java
| @@ -4,12 +4,14 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; | @@ -4,12 +4,14 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 4 | import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRolePageReqVO; | 4 | import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRolePageReqVO; |
| 5 | import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRoleSaveMyReqVO; | 5 | import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRoleSaveMyReqVO; |
| 6 | import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRoleSaveReqVO; | 6 | import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRoleSaveReqVO; |
| 7 | -import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO; | ||
| 8 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; | 7 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; |
| 9 | import jakarta.validation.Valid; | 8 | import jakarta.validation.Valid; |
| 10 | 9 | ||
| 10 | +import java.util.Collection; | ||
| 11 | import java.util.List; | 11 | import java.util.List; |
| 12 | -import java.util.Set; | 12 | +import java.util.Map; |
| 13 | + | ||
| 14 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | ||
| 13 | 15 | ||
| 14 | /** | 16 | /** |
| 15 | * AI 聊天角色 Service 接口 | 17 | * AI 聊天角色 Service 接口 |
| @@ -74,12 +76,16 @@ public interface AiChatRoleService { | @@ -74,12 +76,16 @@ public interface AiChatRoleService { | ||
| 74 | AiChatRoleDO getChatRole(Long id); | 76 | AiChatRoleDO getChatRole(Long id); |
| 75 | 77 | ||
| 76 | /** | 78 | /** |
| 77 | - * 获得聊天角色 - 根据 ids | 79 | + * 获得聊天角色列表 |
| 78 | * | 80 | * |
| 79 | - * @param roleIds | ||
| 80 | - * @return | 81 | + * @param ids 编号数组 |
| 82 | + * @return 聊天角色列表 | ||
| 81 | */ | 83 | */ |
| 82 | - List<AiChatRoleDO> getChatRoles(Set<Long> roleIds); | 84 | + List<AiChatRoleDO> getChatRoleList(Collection<Long> ids); |
| 85 | + | ||
| 86 | + default Map<Long, AiChatRoleDO> getChatRoleMap(Collection<Long> ids) { | ||
| 87 | + return convertMap(getChatRoleList(ids), AiChatRoleDO::getId); | ||
| 88 | + } | ||
| 83 | 89 | ||
| 84 | /** | 90 | /** |
| 85 | * 校验聊天角色是否合法 | 91 | * 校验聊天角色是否合法 |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatRoleServiceImpl.java
| 1 | package cn.iocoder.yudao.module.ai.service.model; | 1 | package cn.iocoder.yudao.module.ai.service.model; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 3 | import cn.hutool.core.util.ObjectUtil; | 4 | import cn.hutool.core.util.ObjectUtil; |
| 4 | import cn.hutool.core.util.StrUtil; | 5 | import cn.hutool.core.util.StrUtil; |
| 5 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | 6 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| @@ -14,12 +15,9 @@ import jakarta.annotation.Resource; | @@ -14,12 +15,9 @@ import jakarta.annotation.Resource; | ||
| 14 | import lombok.extern.slf4j.Slf4j; | 15 | import lombok.extern.slf4j.Slf4j; |
| 15 | import org.springframework.stereotype.Service; | 16 | import org.springframework.stereotype.Service; |
| 16 | 17 | ||
| 18 | +import java.util.Collection; | ||
| 19 | +import java.util.Collections; | ||
| 17 | import java.util.List; | 20 | import java.util.List; |
| 18 | -import java.util.Objects; | ||
| 19 | -import java.util.Set; | ||
| 20 | -import java.util.function.Function; | ||
| 21 | -import java.util.function.Predicate; | ||
| 22 | -import java.util.stream.Collectors; | ||
| 23 | 21 | ||
| 24 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 22 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 25 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | 23 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; |
| @@ -107,8 +105,11 @@ public class AiChatRoleServiceImpl implements AiChatRoleService { | @@ -107,8 +105,11 @@ public class AiChatRoleServiceImpl implements AiChatRoleService { | ||
| 107 | } | 105 | } |
| 108 | 106 | ||
| 109 | @Override | 107 | @Override |
| 110 | - public List<AiChatRoleDO> getChatRoles(Set<Long> roleIds) { | ||
| 111 | - return chatRoleMapper.selectBatchIds(roleIds); | 108 | + public List<AiChatRoleDO> getChatRoleList(Collection<Long> ids) { |
| 109 | + if (CollUtil.isEmpty(ids)) { | ||
| 110 | + return Collections.emptyList(); | ||
| 111 | + } | ||
| 112 | + return chatRoleMapper.selectBatchIds(ids); | ||
| 112 | } | 113 | } |
| 113 | 114 | ||
| 114 | @Override | 115 | @Override |