Commit a998168b3b62713821c15b5798115bc589eb98f4
1 parent
d1e20789
【功能新增】AI:新增知识库文档的更新信息与状态
Showing
8 changed files
with
87 additions
and
14 deletions
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/AiKnowledgeDocumentController.java
| ... | ... | @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowl |
| 7 | 7 | import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentRespVO; |
| 8 | 8 | import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentUpdateReqVO; |
| 9 | 9 | import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentCreateListReqVO; |
| 10 | +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentUpdateStatusReqVO; | |
| 10 | 11 | import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeDocumentCreateReqVO; |
| 11 | 12 | import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO; |
| 12 | 13 | import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeDocumentService; |
| ... | ... | @@ -47,14 +48,14 @@ public class AiKnowledgeDocumentController { |
| 47 | 48 | } |
| 48 | 49 | |
| 49 | 50 | @PostMapping("/create") |
| 50 | - @Operation(summary = "新建文档") | |
| 51 | + @Operation(summary = "新建文档(单个)") | |
| 51 | 52 | public CommonResult<Long> createKnowledgeDocument(@RequestBody @Valid AiKnowledgeDocumentCreateReqVO reqVO) { |
| 52 | 53 | Long id = documentService.createKnowledgeDocument(reqVO); |
| 53 | 54 | return success(id); |
| 54 | 55 | } |
| 55 | 56 | |
| 56 | 57 | @PostMapping("/create-list") |
| 57 | - @Operation(summary = "批量新建文档") | |
| 58 | + @Operation(summary = "新建文档(多个)") | |
| 58 | 59 | public CommonResult<List<Long>> createKnowledgeDocumentList( |
| 59 | 60 | @RequestBody @Valid AiKnowledgeDocumentCreateListReqVO reqVO) { |
| 60 | 61 | List<Long> ids = documentService.createKnowledgeDocumentList(reqVO); |
| ... | ... | @@ -68,4 +69,12 @@ public class AiKnowledgeDocumentController { |
| 68 | 69 | return success(true); |
| 69 | 70 | } |
| 70 | 71 | |
| 72 | + @PutMapping("/update-status") | |
| 73 | + @Operation(summary = "更新文档状态") | |
| 74 | + public CommonResult<Boolean> updateKnowledgeDocumentStatus( | |
| 75 | + @Valid @RequestBody AiKnowledgeDocumentUpdateStatusReqVO reqVO) { | |
| 76 | + documentService.updateKnowledgeDocumentStatus(reqVO); | |
| 77 | + return success(true); | |
| 78 | + } | |
| 79 | + | |
| 71 | 80 | } | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/AiKnowledgeSegmentController.java
| ... | ... | @@ -15,6 +15,7 @@ import io.swagger.v3.oas.annotations.Parameters; |
| 15 | 15 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 16 | 16 | import jakarta.annotation.Resource; |
| 17 | 17 | import jakarta.validation.Valid; |
| 18 | +import org.hibernate.validator.constraints.URL; | |
| 18 | 19 | import org.springframework.validation.annotation.Validated; |
| 19 | 20 | import org.springframework.web.bind.annotation.*; |
| 20 | 21 | |
| ... | ... | @@ -62,7 +63,7 @@ public class AiKnowledgeSegmentController { |
| 62 | 63 | @Parameter(name = "segmentMaxTokens", description = "分段的最大 Token 数", required = true) |
| 63 | 64 | }) |
| 64 | 65 | public CommonResult<List<AiKnowledgeSegmentRespVO>> splitContent( |
| 65 | - @RequestParam("url") String url, | |
| 66 | + @RequestParam("url") @URL String url, | |
| 66 | 67 | @RequestParam(value = "segmentMaxTokens") Integer segmentMaxTokens) { |
| 67 | 68 | List<AiKnowledgeSegmentDO> segments = segmentService.splitContent(url, segmentMaxTokens); |
| 68 | 69 | return success(BeanUtils.toBean(segments, AiKnowledgeSegmentRespVO.class)); | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/document/AiKnowledgeDocumentUpdateReqVO.java
| 1 | 1 | package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document; |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | |
| 4 | -import cn.iocoder.yudao.framework.common.validation.InEnum; | |
| 5 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | 4 | import jakarta.validation.constraints.NotNull; |
| 7 | 5 | import lombok.Data; |
| 8 | 6 | |
| 9 | -// TODO @芋艿:稍后优化 | |
| 10 | 7 | @Schema(description = "管理后台 - AI 知识库文档更新 Request VO") |
| 11 | 8 | @Data |
| 12 | 9 | public class AiKnowledgeDocumentUpdateReqVO { |
| ... | ... | @@ -18,8 +15,7 @@ public class AiKnowledgeDocumentUpdateReqVO { |
| 18 | 15 | @Schema(description = "名称", example = "Java 开发手册") |
| 19 | 16 | private String name; |
| 20 | 17 | |
| 21 | - @Schema(description = "是否启用", example = "1") | |
| 22 | - @InEnum(CommonStatusEnum.class) | |
| 23 | - private Integer status; | |
| 18 | + @Schema(description = "分片最大 Token 数", example = "1000") | |
| 19 | + private Integer segmentMaxTokens; | |
| 24 | 20 | |
| 25 | 21 | } | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/knowledge/AiKnowledgeSegmentMapper.java
| ... | ... | @@ -31,4 +31,10 @@ public interface AiKnowledgeSegmentMapper extends BaseMapperX<AiKnowledgeSegment |
| 31 | 31 | .orderByDesc(AiKnowledgeSegmentDO::getId)); |
| 32 | 32 | } |
| 33 | 33 | |
| 34 | + default List<AiKnowledgeSegmentDO> selectListByDocumentId(Long documentId) { | |
| 35 | + return selectList(new LambdaQueryWrapperX<AiKnowledgeSegmentDO>() | |
| 36 | + .eq(AiKnowledgeSegmentDO::getDocumentId, documentId) | |
| 37 | + .orderByDesc(AiKnowledgeSegmentDO::getId)); | |
| 38 | + } | |
| 39 | + | |
| 34 | 40 | } | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeDocumentService.java
| ... | ... | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.ai.service.knowledge; |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | 4 | import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentPageReqVO; |
| 5 | 5 | import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentUpdateReqVO; |
| 6 | +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentUpdateStatusReqVO; | |
| 6 | 7 | import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeDocumentCreateReqVO; |
| 7 | 8 | import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentCreateListReqVO; |
| 8 | 9 | import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO; |
| ... | ... | @@ -10,14 +11,14 @@ import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO |
| 10 | 11 | import java.util.List; |
| 11 | 12 | |
| 12 | 13 | /** |
| 13 | - * AI 知识库-文档 Service 接口 | |
| 14 | + * AI 知识库文档 Service 接口 | |
| 14 | 15 | * |
| 15 | 16 | * @author xiaoxin |
| 16 | 17 | */ |
| 17 | 18 | public interface AiKnowledgeDocumentService { |
| 18 | 19 | |
| 19 | 20 | /** |
| 20 | - * 创建文档 | |
| 21 | + * 创建文档(单个) | |
| 21 | 22 | * |
| 22 | 23 | * @param createReqVO 文档创建 Request VO |
| 23 | 24 | * @return 文档编号 |
| ... | ... | @@ -25,7 +26,7 @@ public interface AiKnowledgeDocumentService { |
| 25 | 26 | Long createKnowledgeDocument(AiKnowledgeDocumentCreateReqVO createReqVO); |
| 26 | 27 | |
| 27 | 28 | /** |
| 28 | - * 批量创建文档 | |
| 29 | + * 创建文档(多个) | |
| 29 | 30 | * |
| 30 | 31 | * @param createListReqVO 批量创建 Request VO |
| 31 | 32 | * @return 文档编号列表 |
| ... | ... | @@ -56,6 +57,13 @@ public interface AiKnowledgeDocumentService { |
| 56 | 57 | void updateKnowledgeDocument(AiKnowledgeDocumentUpdateReqVO reqVO); |
| 57 | 58 | |
| 58 | 59 | /** |
| 60 | + * 更新文档状态 | |
| 61 | + * | |
| 62 | + * @param reqVO 更新状态信息 | |
| 63 | + */ | |
| 64 | + void updateKnowledgeDocumentStatus(AiKnowledgeDocumentUpdateStatusReqVO reqVO); | |
| 65 | + | |
| 66 | + /** | |
| 59 | 67 | * 校验文档是否存在 |
| 60 | 68 | * |
| 61 | 69 | * @param id 文档编号 | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeDocumentServiceImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.ai.service.knowledge; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | +import cn.hutool.core.util.ObjUtil; | |
| 4 | 5 | import cn.hutool.core.util.StrUtil; |
| 5 | 6 | import cn.hutool.http.HttpUtil; |
| 6 | 7 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| ... | ... | @@ -8,6 +9,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 8 | 9 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 9 | 10 | import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentPageReqVO; |
| 10 | 11 | import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentUpdateReqVO; |
| 12 | +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentUpdateStatusReqVO; | |
| 11 | 13 | import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentCreateListReqVO; |
| 12 | 14 | import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeDocumentCreateReqVO; |
| 13 | 15 | import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO; |
| ... | ... | @@ -88,6 +90,7 @@ public class AiKnowledgeDocumentServiceImpl implements AiKnowledgeDocumentServic |
| 88 | 90 | .setKnowledgeId(createListReqVO.getKnowledgeId()) |
| 89 | 91 | .setContent(content).setContentLength(content.length()) |
| 90 | 92 | .setTokens(tokenCountEstimator.estimate(content)) |
| 93 | + .setSegmentMaxTokens(createListReqVO.getSegmentMaxTokens()) | |
| 91 | 94 | .setStatus(CommonStatusEnum.ENABLE.getStatus())); |
| 92 | 95 | } |
| 93 | 96 | knowledgeDocumentMapper.insertBatch(documentDOs); |
| ... | ... | @@ -111,11 +114,38 @@ public class AiKnowledgeDocumentServiceImpl implements AiKnowledgeDocumentServic |
| 111 | 114 | @Override |
| 112 | 115 | public void updateKnowledgeDocument(AiKnowledgeDocumentUpdateReqVO reqVO) { |
| 113 | 116 | // 1. 校验文档是否存在 |
| 114 | - validateKnowledgeDocumentExists(reqVO.getId()); | |
| 117 | + AiKnowledgeDocumentDO oldDocument = validateKnowledgeDocumentExists(reqVO.getId()); | |
| 118 | + | |
| 115 | 119 | // 2. 更新文档 |
| 116 | 120 | AiKnowledgeDocumentDO document = BeanUtils.toBean(reqVO, AiKnowledgeDocumentDO.class); |
| 117 | 121 | knowledgeDocumentMapper.updateById(document); |
| 118 | - // TODO @芋艿:这里要处理状态的变更 | |
| 122 | + | |
| 123 | + // 3. 如果处于开启状态,并且最大 tokens 发生变化,则 segment 需要重新索引 | |
| 124 | + if (CommonStatusEnum.isEnable(oldDocument.getStatus()) | |
| 125 | + && reqVO.getSegmentMaxTokens() != null | |
| 126 | + && ObjUtil.notEqual(reqVO.getSegmentMaxTokens(), oldDocument.getSegmentMaxTokens())) { | |
| 127 | + // 删除旧的文档切片 | |
| 128 | + knowledgeSegmentService.deleteKnowledgeSegmentByDocumentId(reqVO.getId()); | |
| 129 | + // 重新创建文档切片 | |
| 130 | + knowledgeSegmentService.createKnowledgeSegmentBySplitContentAsync(reqVO.getId(), oldDocument.getContent()); | |
| 131 | + } | |
| 132 | + } | |
| 133 | + | |
| 134 | + @Override | |
| 135 | + public void updateKnowledgeDocumentStatus(AiKnowledgeDocumentUpdateStatusReqVO reqVO) { | |
| 136 | + // 1. 校验存在 | |
| 137 | + AiKnowledgeDocumentDO document = validateKnowledgeDocumentExists(reqVO.getId()); | |
| 138 | + | |
| 139 | + // 2. 更新状态 | |
| 140 | + knowledgeDocumentMapper.updateById(new AiKnowledgeDocumentDO() | |
| 141 | + .setId(reqVO.getId()).setStatus(reqVO.getStatus())); | |
| 142 | + | |
| 143 | + // 3. 处理文档切片 | |
| 144 | + if (CommonStatusEnum.isEnable(reqVO.getStatus())) { | |
| 145 | + knowledgeSegmentService.createKnowledgeSegmentBySplitContentAsync(reqVO.getId(), document.getContent()); | |
| 146 | + } else { | |
| 147 | + knowledgeSegmentService.deleteKnowledgeSegmentByDocumentId(reqVO.getId()); | |
| 148 | + } | |
| 119 | 149 | } |
| 120 | 150 | |
| 121 | 151 | @Override | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentService.java
| ... | ... | @@ -59,6 +59,13 @@ public interface AiKnowledgeSegmentService { |
| 59 | 59 | void updateKnowledgeSegmentStatus(AiKnowledgeSegmentUpdateStatusReqVO reqVO); |
| 60 | 60 | |
| 61 | 61 | /** |
| 62 | + * 根据文档编号删除段落 | |
| 63 | + * | |
| 64 | + * @param documentId 文档编号 | |
| 65 | + */ | |
| 66 | + void deleteKnowledgeSegmentByDocumentId(Long documentId); | |
| 67 | + | |
| 68 | + /** | |
| 62 | 69 | * 召回段落 |
| 63 | 70 | * |
| 64 | 71 | * @param reqVO 召回请求信息 | ... | ... |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java
| ... | ... | @@ -116,6 +116,22 @@ public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService |
| 116 | 116 | } |
| 117 | 117 | |
| 118 | 118 | @Override |
| 119 | + public void deleteKnowledgeSegmentByDocumentId(Long documentId) { | |
| 120 | + // 1. 查询需要删除的段落 | |
| 121 | + List<AiKnowledgeSegmentDO> segments = segmentMapper.selectListByDocumentId(documentId); | |
| 122 | + if (CollUtil.isEmpty(segments)) { | |
| 123 | + return; | |
| 124 | + } | |
| 125 | + | |
| 126 | + // 2. 批量删除段落记录 | |
| 127 | + segmentMapper.deleteByIds(convertList(segments, AiKnowledgeSegmentDO::getId)); | |
| 128 | + | |
| 129 | + // 3. 删除向量存储中的段落 | |
| 130 | + VectorStore vectorStore = getVectorStoreById(segments.get(0).getKnowledgeId()); | |
| 131 | + vectorStore.delete(convertList(segments, AiKnowledgeSegmentDO::getVectorId)); | |
| 132 | + } | |
| 133 | + | |
| 134 | + @Override | |
| 119 | 135 | public void updateKnowledgeSegmentStatus(AiKnowledgeSegmentUpdateStatusReqVO reqVO) { |
| 120 | 136 | // 1. 校验 |
| 121 | 137 | AiKnowledgeSegmentDO segment = validateKnowledgeSegmentExists(reqVO.getId()); | ... | ... |