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,6 +7,7 @@ import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowl
7 import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentRespVO; 7 import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentRespVO;
8 import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentUpdateReqVO; 8 import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentUpdateReqVO;
9 import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentCreateListReqVO; 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 import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeDocumentCreateReqVO; 11 import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeDocumentCreateReqVO;
11 import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO; 12 import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO;
12 import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeDocumentService; 13 import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeDocumentService;
@@ -47,14 +48,14 @@ public class AiKnowledgeDocumentController { @@ -47,14 +48,14 @@ public class AiKnowledgeDocumentController {
47 } 48 }
48 49
49 @PostMapping("/create") 50 @PostMapping("/create")
50 - @Operation(summary = "新建文档") 51 + @Operation(summary = "新建文档(单个)")
51 public CommonResult<Long> createKnowledgeDocument(@RequestBody @Valid AiKnowledgeDocumentCreateReqVO reqVO) { 52 public CommonResult<Long> createKnowledgeDocument(@RequestBody @Valid AiKnowledgeDocumentCreateReqVO reqVO) {
52 Long id = documentService.createKnowledgeDocument(reqVO); 53 Long id = documentService.createKnowledgeDocument(reqVO);
53 return success(id); 54 return success(id);
54 } 55 }
55 56
56 @PostMapping("/create-list") 57 @PostMapping("/create-list")
57 - @Operation(summary = "批量新建文档") 58 + @Operation(summary = "新建文档(多个)")
58 public CommonResult<List<Long>> createKnowledgeDocumentList( 59 public CommonResult<List<Long>> createKnowledgeDocumentList(
59 @RequestBody @Valid AiKnowledgeDocumentCreateListReqVO reqVO) { 60 @RequestBody @Valid AiKnowledgeDocumentCreateListReqVO reqVO) {
60 List<Long> ids = documentService.createKnowledgeDocumentList(reqVO); 61 List<Long> ids = documentService.createKnowledgeDocumentList(reqVO);
@@ -68,4 +69,12 @@ public class AiKnowledgeDocumentController { @@ -68,4 +69,12 @@ public class AiKnowledgeDocumentController {
68 return success(true); 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,6 +15,7 @@ import io.swagger.v3.oas.annotations.Parameters;
15 import io.swagger.v3.oas.annotations.tags.Tag; 15 import io.swagger.v3.oas.annotations.tags.Tag;
16 import jakarta.annotation.Resource; 16 import jakarta.annotation.Resource;
17 import jakarta.validation.Valid; 17 import jakarta.validation.Valid;
  18 +import org.hibernate.validator.constraints.URL;
18 import org.springframework.validation.annotation.Validated; 19 import org.springframework.validation.annotation.Validated;
19 import org.springframework.web.bind.annotation.*; 20 import org.springframework.web.bind.annotation.*;
20 21
@@ -62,7 +63,7 @@ public class AiKnowledgeSegmentController { @@ -62,7 +63,7 @@ public class AiKnowledgeSegmentController {
62 @Parameter(name = "segmentMaxTokens", description = "分段的最大 Token 数", required = true) 63 @Parameter(name = "segmentMaxTokens", description = "分段的最大 Token 数", required = true)
63 }) 64 })
64 public CommonResult<List<AiKnowledgeSegmentRespVO>> splitContent( 65 public CommonResult<List<AiKnowledgeSegmentRespVO>> splitContent(
65 - @RequestParam("url") String url, 66 + @RequestParam("url") @URL String url,
66 @RequestParam(value = "segmentMaxTokens") Integer segmentMaxTokens) { 67 @RequestParam(value = "segmentMaxTokens") Integer segmentMaxTokens) {
67 List<AiKnowledgeSegmentDO> segments = segmentService.splitContent(url, segmentMaxTokens); 68 List<AiKnowledgeSegmentDO> segments = segmentService.splitContent(url, segmentMaxTokens);
68 return success(BeanUtils.toBean(segments, AiKnowledgeSegmentRespVO.class)); 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 package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document; 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 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
6 import jakarta.validation.constraints.NotNull; 4 import jakarta.validation.constraints.NotNull;
7 import lombok.Data; 5 import lombok.Data;
8 6
9 -// TODO @芋艿:稍后优化  
10 @Schema(description = "管理后台 - AI 知识库文档更新 Request VO") 7 @Schema(description = "管理后台 - AI 知识库文档更新 Request VO")
11 @Data 8 @Data
12 public class AiKnowledgeDocumentUpdateReqVO { 9 public class AiKnowledgeDocumentUpdateReqVO {
@@ -18,8 +15,7 @@ public class AiKnowledgeDocumentUpdateReqVO { @@ -18,8 +15,7 @@ public class AiKnowledgeDocumentUpdateReqVO {
18 @Schema(description = "名称", example = "Java 开发手册") 15 @Schema(description = "名称", example = "Java 开发手册")
19 private String name; 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,4 +31,10 @@ public interface AiKnowledgeSegmentMapper extends BaseMapperX&lt;AiKnowledgeSegment
31 .orderByDesc(AiKnowledgeSegmentDO::getId)); 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,6 +3,7 @@ package cn.iocoder.yudao.module.ai.service.knowledge;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentPageReqVO; 4 import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentPageReqVO;
5 import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentUpdateReqVO; 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 import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeDocumentCreateReqVO; 7 import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeDocumentCreateReqVO;
7 import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentCreateListReqVO; 8 import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentCreateListReqVO;
8 import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO; 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,14 +11,14 @@ import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO
10 import java.util.List; 11 import java.util.List;
11 12
12 /** 13 /**
13 - * AI 知识库-文档 Service 接口 14 + * AI 知识库文档 Service 接口
14 * 15 *
15 * @author xiaoxin 16 * @author xiaoxin
16 */ 17 */
17 public interface AiKnowledgeDocumentService { 18 public interface AiKnowledgeDocumentService {
18 19
19 /** 20 /**
20 - * 创建文档 21 + * 创建文档(单个)
21 * 22 *
22 * @param createReqVO 文档创建 Request VO 23 * @param createReqVO 文档创建 Request VO
23 * @return 文档编号 24 * @return 文档编号
@@ -25,7 +26,7 @@ public interface AiKnowledgeDocumentService { @@ -25,7 +26,7 @@ public interface AiKnowledgeDocumentService {
25 Long createKnowledgeDocument(AiKnowledgeDocumentCreateReqVO createReqVO); 26 Long createKnowledgeDocument(AiKnowledgeDocumentCreateReqVO createReqVO);
26 27
27 /** 28 /**
28 - * 批量创建文档 29 + * 创建文档(多个)
29 * 30 *
30 * @param createListReqVO 批量创建 Request VO 31 * @param createListReqVO 批量创建 Request VO
31 * @return 文档编号列表 32 * @return 文档编号列表
@@ -56,6 +57,13 @@ public interface AiKnowledgeDocumentService { @@ -56,6 +57,13 @@ public interface AiKnowledgeDocumentService {
56 void updateKnowledgeDocument(AiKnowledgeDocumentUpdateReqVO reqVO); 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 * @param id 文档编号 69 * @param id 文档编号
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeDocumentServiceImpl.java
1 package cn.iocoder.yudao.module.ai.service.knowledge; 1 package cn.iocoder.yudao.module.ai.service.knowledge;
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.StrUtil; 5 import cn.hutool.core.util.StrUtil;
5 import cn.hutool.http.HttpUtil; 6 import cn.hutool.http.HttpUtil;
6 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 7 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
@@ -8,6 +9,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; @@ -8,6 +9,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
8 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 9 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
9 import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentPageReqVO; 10 import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentPageReqVO;
10 import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentUpdateReqVO; 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 import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentCreateListReqVO; 13 import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentCreateListReqVO;
12 import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeDocumentCreateReqVO; 14 import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeDocumentCreateReqVO;
13 import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO; 15 import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO;
@@ -88,6 +90,7 @@ public class AiKnowledgeDocumentServiceImpl implements AiKnowledgeDocumentServic @@ -88,6 +90,7 @@ public class AiKnowledgeDocumentServiceImpl implements AiKnowledgeDocumentServic
88 .setKnowledgeId(createListReqVO.getKnowledgeId()) 90 .setKnowledgeId(createListReqVO.getKnowledgeId())
89 .setContent(content).setContentLength(content.length()) 91 .setContent(content).setContentLength(content.length())
90 .setTokens(tokenCountEstimator.estimate(content)) 92 .setTokens(tokenCountEstimator.estimate(content))
  93 + .setSegmentMaxTokens(createListReqVO.getSegmentMaxTokens())
91 .setStatus(CommonStatusEnum.ENABLE.getStatus())); 94 .setStatus(CommonStatusEnum.ENABLE.getStatus()));
92 } 95 }
93 knowledgeDocumentMapper.insertBatch(documentDOs); 96 knowledgeDocumentMapper.insertBatch(documentDOs);
@@ -111,11 +114,38 @@ public class AiKnowledgeDocumentServiceImpl implements AiKnowledgeDocumentServic @@ -111,11 +114,38 @@ public class AiKnowledgeDocumentServiceImpl implements AiKnowledgeDocumentServic
111 @Override 114 @Override
112 public void updateKnowledgeDocument(AiKnowledgeDocumentUpdateReqVO reqVO) { 115 public void updateKnowledgeDocument(AiKnowledgeDocumentUpdateReqVO reqVO) {
113 // 1. 校验文档是否存在 116 // 1. 校验文档是否存在
114 - validateKnowledgeDocumentExists(reqVO.getId()); 117 + AiKnowledgeDocumentDO oldDocument = validateKnowledgeDocumentExists(reqVO.getId());
  118 +
115 // 2. 更新文档 119 // 2. 更新文档
116 AiKnowledgeDocumentDO document = BeanUtils.toBean(reqVO, AiKnowledgeDocumentDO.class); 120 AiKnowledgeDocumentDO document = BeanUtils.toBean(reqVO, AiKnowledgeDocumentDO.class);
117 knowledgeDocumentMapper.updateById(document); 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 @Override 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,6 +59,13 @@ public interface AiKnowledgeSegmentService {
59 void updateKnowledgeSegmentStatus(AiKnowledgeSegmentUpdateStatusReqVO reqVO); 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 * @param reqVO 召回请求信息 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,6 +116,22 @@ public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService
116 } 116 }
117 117
118 @Override 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 public void updateKnowledgeSegmentStatus(AiKnowledgeSegmentUpdateStatusReqVO reqVO) { 135 public void updateKnowledgeSegmentStatus(AiKnowledgeSegmentUpdateStatusReqVO reqVO) {
120 // 1. 校验 136 // 1. 校验
121 AiKnowledgeSegmentDO segment = validateKnowledgeSegmentExists(reqVO.getId()); 137 AiKnowledgeSegmentDO segment = validateKnowledgeSegmentExists(reqVO.getId());