Commit a998168b3b62713821c15b5798115bc589eb98f4

Authored by YunaiV
1 parent d1e20789

【功能新增】AI:新增知识库文档的更新信息与状态

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&lt;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());
... ...