Commit 9126691ac0f699c8f4971b2b04f62ba539b2a962
1 parent
f286a813
【功能新增】AI:聊天角色,新增 document 的引用绑定
Showing
11 changed files
with
100 additions
and
10 deletions
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/AiKnowledgeDocumentController.java
| 1 | 1 | package cn.iocoder.yudao.module.ai.controller.admin.knowledge; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | |
| 3 | 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | 6 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| ... | ... | @@ -10,8 +11,10 @@ import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowl |
| 10 | 11 | import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentUpdateStatusReqVO; |
| 11 | 12 | import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeDocumentCreateReqVO; |
| 12 | 13 | import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO; |
| 14 | +import cn.iocoder.yudao.module.ai.dal.mysql.knowledge.AiKnowledgeDocumentMapper; | |
| 13 | 15 | import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeDocumentService; |
| 14 | 16 | import io.swagger.v3.oas.annotations.Operation; |
| 17 | +import io.swagger.v3.oas.annotations.Parameter; | |
| 15 | 18 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 16 | 19 | import jakarta.annotation.Resource; |
| 17 | 20 | import jakarta.validation.Valid; |
| ... | ... | @@ -22,6 +25,7 @@ import org.springframework.web.bind.annotation.*; |
| 22 | 25 | import java.util.List; |
| 23 | 26 | |
| 24 | 27 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 28 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | |
| 25 | 29 | |
| 26 | 30 | @Tag(name = "管理后台 - AI 知识库文档") |
| 27 | 31 | @RestController |
| ... | ... | @@ -91,4 +95,13 @@ public class AiKnowledgeDocumentController { |
| 91 | 95 | return success(true); |
| 92 | 96 | } |
| 93 | 97 | |
| 98 | + @GetMapping("/simple-list") | |
| 99 | + @Operation(summary = "获得知识库文档的精简列表") | |
| 100 | + public CommonResult<List<AiKnowledgeDocumentRespVO>> getKnowledgeDocumentSimpleList() { | |
| 101 | + List<AiKnowledgeDocumentDO> list = documentService | |
| 102 | + .getKnowledgeDocumentListByStatus(CommonStatusEnum.ENABLE.getStatus()); | |
| 103 | + return success(convertList(list, document -> new AiKnowledgeDocumentRespVO() | |
| 104 | + .setId(document.getId()).setName(document.getName()))); | |
| 105 | + } | |
| 106 | + | |
| 94 | 107 | } | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/AiChatRoleController.java
| ... | ... | @@ -75,7 +75,7 @@ public class AiChatRoleController { |
| 75 | 75 | @GetMapping("/category-list") |
| 76 | 76 | @Operation(summary = "获得聊天角色的分类列表") |
| 77 | 77 | public CommonResult<List<String>> getChatRoleCategoryList() { |
| 78 | - return success(chatRoleService.getChatRoleCategoryList()); | |
| 78 | + return success(chatRoleService.getChatRoleCategoryList()); | |
| 79 | 79 | } |
| 80 | 80 | |
| 81 | 81 | // ========== 角色管理 ========== | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/chatRole/AiChatRoleRespVO.java
| ... | ... | @@ -8,6 +8,7 @@ import io.swagger.v3.oas.annotations.media.Schema; |
| 8 | 8 | import lombok.Data; |
| 9 | 9 | |
| 10 | 10 | import java.time.LocalDateTime; |
| 11 | +import java.util.List; | |
| 11 | 12 | |
| 12 | 13 | @Schema(description = "管理后台 - AI 聊天角色 Response VO") |
| 13 | 14 | @Data |
| ... | ... | @@ -20,7 +21,7 @@ public class AiChatRoleRespVO implements VO { |
| 20 | 21 | private Long userId; |
| 21 | 22 | |
| 22 | 23 | @Schema(description = "模型编号", example = "17640") |
| 23 | - @Trans(type = TransType.SIMPLE, target = AiModelDO.class, fields = {"name", "model"}, refs = {"modelName", "model"}) | |
| 24 | + @Trans(type = TransType.SIMPLE, target = AiModelDO.class, fields = { "name", "model" }, refs = { "modelName", "model" }) | |
| 24 | 25 | private Long modelId; |
| 25 | 26 | @Schema(description = "模型名字", example = "张三") |
| 26 | 27 | private String modelName; |
| ... | ... | @@ -45,6 +46,9 @@ public class AiChatRoleRespVO implements VO { |
| 45 | 46 | @Schema(description = "角色设定", requiredMode = Schema.RequiredMode.REQUIRED) |
| 46 | 47 | private String systemMessage; |
| 47 | 48 | |
| 49 | + @Schema(description = "知识库文档编号列表", example = "1,2,3") | |
| 50 | + private List<Long> documentIds; | |
| 51 | + | |
| 48 | 52 | @Schema(description = "是否公开", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| 49 | 53 | private Boolean publicStatus; |
| 50 | 54 | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/chatRole/AiChatRoleSaveMyReqVO.java
| ... | ... | @@ -5,6 +5,8 @@ import jakarta.validation.constraints.NotEmpty; |
| 5 | 5 | import lombok.Data; |
| 6 | 6 | import org.hibernate.validator.constraints.URL; |
| 7 | 7 | |
| 8 | +import java.util.List; | |
| 9 | + | |
| 8 | 10 | @Schema(description = "管理后台 - AI 聊天角色新增/修改【我的】 Request VO") |
| 9 | 11 | @Data |
| 10 | 12 | public class AiChatRoleSaveMyReqVO { |
| ... | ... | @@ -29,4 +31,7 @@ public class AiChatRoleSaveMyReqVO { |
| 29 | 31 | @NotEmpty(message = "角色设定不能为空") |
| 30 | 32 | private String systemMessage; |
| 31 | 33 | |
| 34 | + @Schema(description = "知识库文档编号列表", example = "1,2,3") | |
| 35 | + private List<Long> documentIds; | |
| 36 | + | |
| 32 | 37 | } |
| 33 | 38 | \ No newline at end of file | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/chatRole/AiChatRoleSaveReqVO.java
| ... | ... | @@ -7,6 +7,8 @@ import lombok.*; |
| 7 | 7 | import jakarta.validation.constraints.*; |
| 8 | 8 | import org.hibernate.validator.constraints.URL; |
| 9 | 9 | |
| 10 | +import java.util.List; | |
| 11 | + | |
| 10 | 12 | @Schema(description = "管理后台 - AI 聊天角色新增/修改 Request VO") |
| 11 | 13 | @Data |
| 12 | 14 | public class AiChatRoleSaveReqVO { |
| ... | ... | @@ -42,6 +44,9 @@ public class AiChatRoleSaveReqVO { |
| 42 | 44 | @NotEmpty(message = "角色设定不能为空") |
| 43 | 45 | private String systemMessage; |
| 44 | 46 | |
| 47 | + @Schema(description = "知识库文档编号列表", example = "1,2,3") | |
| 48 | + private List<Long> documentIds; | |
| 49 | + | |
| 45 | 50 | @Schema(description = "是否公开", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| 46 | 51 | @NotNull(message = "是否公开不能为空") |
| 47 | 52 | private Boolean publicStatus; | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiChatRoleDO.java
| ... | ... | @@ -2,11 +2,16 @@ package cn.iocoder.yudao.module.ai.dal.dataobject.model; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 4 | 4 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; | |
| 6 | +import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO; | |
| 5 | 7 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 8 | +import com.baomidou.mybatisplus.annotation.TableField; | |
| 6 | 9 | import com.baomidou.mybatisplus.annotation.TableId; |
| 7 | 10 | import com.baomidou.mybatisplus.annotation.TableName; |
| 8 | 11 | import lombok.*; |
| 9 | 12 | |
| 13 | +import java.util.List; | |
| 14 | + | |
| 10 | 15 | /** |
| 11 | 16 | * AI 聊天角色 DO |
| 12 | 17 | * |
| ... | ... | @@ -63,6 +68,14 @@ public class AiChatRoleDO extends BaseDO { |
| 63 | 68 | private Long modelId; |
| 64 | 69 | |
| 65 | 70 | /** |
| 71 | + * 知识库文档编号列表 | |
| 72 | + * | |
| 73 | + * 关联 {@link AiKnowledgeDocumentDO#getId()} 字段 | |
| 74 | + */ | |
| 75 | + @TableField(typeHandler = LongListTypeHandler.class) | |
| 76 | + private List<Long> documentIds; | |
| 77 | + | |
| 78 | + /** | |
| 66 | 79 | * 是否公开 |
| 67 | 80 | * |
| 68 | 81 | * 1. true - 公开;由管理员在【角色管理】所创建 | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/knowledge/AiKnowledgeDocumentMapper.java
| ... | ... | @@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| 9 | 9 | import org.apache.ibatis.annotations.Mapper; |
| 10 | 10 | |
| 11 | 11 | import java.util.Collection; |
| 12 | +import java.util.List; | |
| 12 | 13 | |
| 13 | 14 | /** |
| 14 | 15 | * AI 知识库文档 Mapper |
| ... | ... | @@ -26,9 +27,13 @@ public interface AiKnowledgeDocumentMapper extends BaseMapperX<AiKnowledgeDocume |
| 26 | 27 | } |
| 27 | 28 | |
| 28 | 29 | default void updateRetrievalCountIncr(Collection<Long> ids) { |
| 29 | - update( new LambdaUpdateWrapper<AiKnowledgeDocumentDO>() | |
| 30 | + update(new LambdaUpdateWrapper<AiKnowledgeDocumentDO>() | |
| 30 | 31 | .setSql(" retrieval_count = retrieval_count + 1") |
| 31 | 32 | .in(AiKnowledgeDocumentDO::getId, ids)); |
| 32 | 33 | } |
| 33 | 34 | |
| 35 | + default List<AiKnowledgeDocumentDO> selectListByStatus(Integer status) { | |
| 36 | + return selectList(AiKnowledgeDocumentDO::getStatus, status); | |
| 37 | + } | |
| 38 | + | |
| 34 | 39 | } | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeDocumentService.java
| ... | ... | @@ -115,4 +115,12 @@ public interface AiKnowledgeDocumentService { |
| 115 | 115 | return convertMap(getKnowledgeDocumentList(ids), AiKnowledgeDocumentDO::getId); |
| 116 | 116 | } |
| 117 | 117 | |
| 118 | + /** | |
| 119 | + * 获取指定状态的文档列表 | |
| 120 | + * | |
| 121 | + * @param status 状态 | |
| 122 | + * @return 文档列表 | |
| 123 | + */ | |
| 124 | + List<AiKnowledgeDocumentDO> getKnowledgeDocumentListByStatus(Integer status); | |
| 125 | + | |
| 118 | 126 | } | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeDocumentServiceImpl.java
| ... | ... | @@ -7,6 +7,7 @@ import cn.hutool.http.HttpUtil; |
| 7 | 7 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 8 | 8 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 9 | 9 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 10 | +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | |
| 10 | 11 | import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentCreateListReqVO; |
| 11 | 12 | import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentPageReqVO; |
| 12 | 13 | import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentUpdateReqVO; |
| ... | ... | @@ -210,4 +211,9 @@ public class AiKnowledgeDocumentServiceImpl implements AiKnowledgeDocumentServic |
| 210 | 211 | return knowledgeDocumentMapper.selectByIds(ids); |
| 211 | 212 | } |
| 212 | 213 | |
| 214 | + @Override | |
| 215 | + public List<AiKnowledgeDocumentDO> getKnowledgeDocumentListByStatus(Integer status) { | |
| 216 | + return knowledgeDocumentMapper.selectListByStatus(status); | |
| 217 | + } | |
| 218 | + | |
| 213 | 219 | } | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatRoleService.java
| ... | ... | @@ -32,7 +32,7 @@ public interface AiChatRoleService { |
| 32 | 32 | * 创建【我的】聊天角色 |
| 33 | 33 | * |
| 34 | 34 | * @param createReqVO 创建信息 |
| 35 | - * @param userId 用户编号 | |
| 35 | + * @param userId 用户编号 | |
| 36 | 36 | * @return 编号 |
| 37 | 37 | */ |
| 38 | 38 | Long createChatRoleMy(AiChatRoleSaveMyReqVO createReqVO, Long userId); |
| ... | ... | @@ -48,7 +48,7 @@ public interface AiChatRoleService { |
| 48 | 48 | * 创建【我的】聊天角色 |
| 49 | 49 | * |
| 50 | 50 | * @param updateReqVO 更新信息 |
| 51 | - * @param userId 用户编号 | |
| 51 | + * @param userId 用户编号 | |
| 52 | 52 | */ |
| 53 | 53 | void updateChatRoleMy(AiChatRoleSaveMyReqVO updateReqVO, Long userId); |
| 54 | 54 | |
| ... | ... | @@ -62,7 +62,7 @@ public interface AiChatRoleService { |
| 62 | 62 | /** |
| 63 | 63 | * 删除【我的】聊天角色 |
| 64 | 64 | * |
| 65 | - * @param id 编号 | |
| 65 | + * @param id 编号 | |
| 66 | 66 | * @param userId 用户编号 |
| 67 | 67 | */ |
| 68 | 68 | void deleteChatRoleMy(Long id, Long userId); |
| ... | ... | @@ -106,7 +106,7 @@ public interface AiChatRoleService { |
| 106 | 106 | * 获得【我的】聊天角色分页 |
| 107 | 107 | * |
| 108 | 108 | * @param pageReqVO 分页查询 |
| 109 | - * @param userId 用户编号 | |
| 109 | + * @param userId 用户编号 | |
| 110 | 110 | * @return 聊天角色分页 |
| 111 | 111 | */ |
| 112 | 112 | PageResult<AiChatRoleDO> getChatRoleMyPage(AiChatRolePageReqVO pageReqVO, Long userId); | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatRoleServiceImpl.java
| ... | ... | @@ -5,12 +5,14 @@ import cn.hutool.core.util.ObjectUtil; |
| 5 | 5 | import cn.hutool.core.util.StrUtil; |
| 6 | 6 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 7 | 7 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 8 | +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | |
| 8 | 9 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 9 | 10 | import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRolePageReqVO; |
| 10 | 11 | import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRoleSaveMyReqVO; |
| 11 | 12 | import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRoleSaveReqVO; |
| 12 | 13 | import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; |
| 13 | 14 | import cn.iocoder.yudao.module.ai.dal.mysql.model.AiChatRoleMapper; |
| 15 | +import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeDocumentService; | |
| 14 | 16 | import jakarta.annotation.Resource; |
| 15 | 17 | import lombok.extern.slf4j.Slf4j; |
| 16 | 18 | import org.springframework.stereotype.Service; |
| ... | ... | @@ -35,8 +37,15 @@ public class AiChatRoleServiceImpl implements AiChatRoleService { |
| 35 | 37 | @Resource |
| 36 | 38 | private AiChatRoleMapper chatRoleMapper; |
| 37 | 39 | |
| 40 | + @Resource | |
| 41 | + private AiKnowledgeDocumentService knowledgeDocumentService; | |
| 42 | + | |
| 38 | 43 | @Override |
| 39 | 44 | public Long createChatRole(AiChatRoleSaveReqVO createReqVO) { |
| 45 | + // 校验文档 | |
| 46 | + validateDocuments(createReqVO.getDocumentIds()); | |
| 47 | + | |
| 48 | + // 保存角色 | |
| 40 | 49 | AiChatRoleDO chatRole = BeanUtils.toBean(createReqVO, AiChatRoleDO.class); |
| 41 | 50 | chatRoleMapper.insert(chatRole); |
| 42 | 51 | return chatRole.getId(); |
| ... | ... | @@ -44,6 +53,10 @@ public class AiChatRoleServiceImpl implements AiChatRoleService { |
| 44 | 53 | |
| 45 | 54 | @Override |
| 46 | 55 | public Long createChatRoleMy(AiChatRoleSaveMyReqVO createReqVO, Long userId) { |
| 56 | + // 校验文档 | |
| 57 | + validateDocuments(createReqVO.getDocumentIds()); | |
| 58 | + | |
| 59 | + // 保存角色 | |
| 47 | 60 | AiChatRoleDO chatRole = BeanUtils.toBean(createReqVO, AiChatRoleDO.class).setUserId(userId) |
| 48 | 61 | .setStatus(CommonStatusEnum.ENABLE.getStatus()).setPublicStatus(false); |
| 49 | 62 | chatRoleMapper.insert(chatRole); |
| ... | ... | @@ -54,7 +67,10 @@ public class AiChatRoleServiceImpl implements AiChatRoleService { |
| 54 | 67 | public void updateChatRole(AiChatRoleSaveReqVO updateReqVO) { |
| 55 | 68 | // 校验存在 |
| 56 | 69 | validateChatRoleExists(updateReqVO.getId()); |
| 57 | - // 更新 | |
| 70 | + // 校验文档 | |
| 71 | + validateDocuments(updateReqVO.getDocumentIds()); | |
| 72 | + | |
| 73 | + // 更新角色 | |
| 58 | 74 | AiChatRoleDO updateObj = BeanUtils.toBean(updateReqVO, AiChatRoleDO.class); |
| 59 | 75 | chatRoleMapper.updateById(updateObj); |
| 60 | 76 | } |
| ... | ... | @@ -66,12 +82,27 @@ public class AiChatRoleServiceImpl implements AiChatRoleService { |
| 66 | 82 | if (ObjectUtil.notEqual(chatRole.getUserId(), userId)) { |
| 67 | 83 | throw exception(CHAT_ROLE_NOT_EXISTS); |
| 68 | 84 | } |
| 85 | + // 校验文档 | |
| 86 | + validateDocuments(updateReqVO.getDocumentIds()); | |
| 69 | 87 | |
| 70 | 88 | // 更新 |
| 71 | 89 | AiChatRoleDO updateObj = BeanUtils.toBean(updateReqVO, AiChatRoleDO.class); |
| 72 | 90 | chatRoleMapper.updateById(updateObj); |
| 73 | 91 | } |
| 74 | 92 | |
| 93 | + /** | |
| 94 | + * 校验文档是否存在 | |
| 95 | + * | |
| 96 | + * @param documentIds 文档编号列表 | |
| 97 | + */ | |
| 98 | + private void validateDocuments(List<Long> documentIds) { | |
| 99 | + if (CollUtil.isEmpty(documentIds)) { | |
| 100 | + return; | |
| 101 | + } | |
| 102 | + // 校验文档是否存在 | |
| 103 | + documentIds.forEach(knowledgeDocumentService::validateKnowledgeDocumentExists); | |
| 104 | + } | |
| 105 | + | |
| 75 | 106 | @Override |
| 76 | 107 | public void deleteChatRole(Long id) { |
| 77 | 108 | // 校验存在 |
| ... | ... | @@ -134,7 +165,8 @@ public class AiChatRoleServiceImpl implements AiChatRoleService { |
| 134 | 165 | @Override |
| 135 | 166 | public List<String> getChatRoleCategoryList() { |
| 136 | 167 | List<AiChatRoleDO> list = chatRoleMapper.selectListGroupByCategory(CommonStatusEnum.ENABLE.getStatus()); |
| 137 | - return convertList(list, AiChatRoleDO::getCategory, role -> role != null && StrUtil.isNotBlank(role.getCategory())); | |
| 168 | + return convertList(list, AiChatRoleDO::getCategory, | |
| 169 | + role -> role != null && StrUtil.isNotBlank(role.getCategory())); | |
| 138 | 170 | } |
| 139 | 171 | |
| 140 | 172 | @Override |
| ... | ... | @@ -143,4 +175,3 @@ public class AiChatRoleServiceImpl implements AiChatRoleService { |
| 143 | 175 | } |
| 144 | 176 | |
| 145 | 177 | } |
| 146 | - | ... | ... |