From a998168b3b62713821c15b5798115bc589eb98f4 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 1 Mar 2025 11:42:11 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E3=80=91AI=EF=BC=9A=E6=96=B0=E5=A2=9E=E7=9F=A5=E8=AF=86?= =?UTF-8?q?=E5=BA=93=E6=96=87=E6=A1=A3=E7=9A=84=E6=9B=B4=E6=96=B0=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E4=B8=8E=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AiKnowledgeDocumentController.java | 13 +++++-- .../AiKnowledgeSegmentController.java | 3 +- .../AiKnowledgeDocumentUpdateReqVO.java | 8 ++--- .../knowledge/AiKnowledgeSegmentMapper.java | 6 ++++ .../knowledge/AiKnowledgeDocumentService.java | 14 ++++++-- .../AiKnowledgeDocumentServiceImpl.java | 34 +++++++++++++++++-- .../knowledge/AiKnowledgeSegmentService.java | 7 ++++ .../AiKnowledgeSegmentServiceImpl.java | 16 +++++++++ 8 files changed, 87 insertions(+), 14 deletions(-) diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/AiKnowledgeDocumentController.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/AiKnowledgeDocumentController.java index 12e8ad1fcd..e828615ea1 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/AiKnowledgeDocumentController.java +++ b/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 import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentRespVO; import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentUpdateReqVO; import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentCreateListReqVO; +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentUpdateStatusReqVO; import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeDocumentCreateReqVO; import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO; import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeDocumentService; @@ -47,14 +48,14 @@ public class AiKnowledgeDocumentController { } @PostMapping("/create") - @Operation(summary = "新建文档") + @Operation(summary = "新建文档(单个)") public CommonResult createKnowledgeDocument(@RequestBody @Valid AiKnowledgeDocumentCreateReqVO reqVO) { Long id = documentService.createKnowledgeDocument(reqVO); return success(id); } @PostMapping("/create-list") - @Operation(summary = "批量新建文档") + @Operation(summary = "新建文档(多个)") public CommonResult> createKnowledgeDocumentList( @RequestBody @Valid AiKnowledgeDocumentCreateListReqVO reqVO) { List ids = documentService.createKnowledgeDocumentList(reqVO); @@ -68,4 +69,12 @@ public class AiKnowledgeDocumentController { return success(true); } + @PutMapping("/update-status") + @Operation(summary = "更新文档状态") + public CommonResult updateKnowledgeDocumentStatus( + @Valid @RequestBody AiKnowledgeDocumentUpdateStatusReqVO reqVO) { + documentService.updateKnowledgeDocumentStatus(reqVO); + return success(true); + } + } diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/AiKnowledgeSegmentController.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/AiKnowledgeSegmentController.java index 6177f5411a..2b21e0d1e4 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/AiKnowledgeSegmentController.java +++ b/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; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.validation.Valid; +import org.hibernate.validator.constraints.URL; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -62,7 +63,7 @@ public class AiKnowledgeSegmentController { @Parameter(name = "segmentMaxTokens", description = "分段的最大 Token 数", required = true) }) public CommonResult> splitContent( - @RequestParam("url") String url, + @RequestParam("url") @URL String url, @RequestParam(value = "segmentMaxTokens") Integer segmentMaxTokens) { List segments = segmentService.splitContent(url, segmentMaxTokens); return success(BeanUtils.toBean(segments, AiKnowledgeSegmentRespVO.class)); diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/document/AiKnowledgeDocumentUpdateReqVO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/document/AiKnowledgeDocumentUpdateReqVO.java index 1097f40606..e6dbe5cbd7 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/document/AiKnowledgeDocumentUpdateReqVO.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/knowledge/vo/document/AiKnowledgeDocumentUpdateReqVO.java @@ -1,12 +1,9 @@ package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.validation.InEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.Data; -// TODO @芋艿:稍后优化 @Schema(description = "管理后台 - AI 知识库文档更新 Request VO") @Data public class AiKnowledgeDocumentUpdateReqVO { @@ -18,8 +15,7 @@ public class AiKnowledgeDocumentUpdateReqVO { @Schema(description = "名称", example = "Java 开发手册") private String name; - @Schema(description = "是否启用", example = "1") - @InEnum(CommonStatusEnum.class) - private Integer status; + @Schema(description = "分片最大 Token 数", example = "1000") + private Integer segmentMaxTokens; } diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/knowledge/AiKnowledgeSegmentMapper.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/knowledge/AiKnowledgeSegmentMapper.java index 30b38f6c8c..8381c84300 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/knowledge/AiKnowledgeSegmentMapper.java +++ b/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 selectListByDocumentId(Long documentId) { + return selectList(new LambdaQueryWrapperX() + .eq(AiKnowledgeSegmentDO::getDocumentId, documentId) + .orderByDesc(AiKnowledgeSegmentDO::getId)); + } + } diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeDocumentService.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeDocumentService.java index 8bbee98179..4a45422d82 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeDocumentService.java +++ b/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; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentPageReqVO; import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentUpdateReqVO; +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentUpdateStatusReqVO; import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeDocumentCreateReqVO; import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentCreateListReqVO; import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO; @@ -10,14 +11,14 @@ import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO import java.util.List; /** - * AI 知识库-文档 Service 接口 + * AI 知识库文档 Service 接口 * * @author xiaoxin */ public interface AiKnowledgeDocumentService { /** - * 创建文档 + * 创建文档(单个) * * @param createReqVO 文档创建 Request VO * @return 文档编号 @@ -25,7 +26,7 @@ public interface AiKnowledgeDocumentService { Long createKnowledgeDocument(AiKnowledgeDocumentCreateReqVO createReqVO); /** - * 批量创建文档 + * 创建文档(多个) * * @param createListReqVO 批量创建 Request VO * @return 文档编号列表 @@ -55,6 +56,13 @@ public interface AiKnowledgeDocumentService { */ void updateKnowledgeDocument(AiKnowledgeDocumentUpdateReqVO reqVO); + /** + * 更新文档状态 + * + * @param reqVO 更新状态信息 + */ + void updateKnowledgeDocumentStatus(AiKnowledgeDocumentUpdateStatusReqVO reqVO); + /** * 校验文档是否存在 * diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeDocumentServiceImpl.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeDocumentServiceImpl.java index 6ed7fdd57d..4cff8324c6 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeDocumentServiceImpl.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeDocumentServiceImpl.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.ai.service.knowledge; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.http.HttpUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; @@ -8,6 +9,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentPageReqVO; import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentUpdateReqVO; +import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentUpdateStatusReqVO; import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentCreateListReqVO; import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeDocumentCreateReqVO; import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO; @@ -88,6 +90,7 @@ public class AiKnowledgeDocumentServiceImpl implements AiKnowledgeDocumentServic .setKnowledgeId(createListReqVO.getKnowledgeId()) .setContent(content).setContentLength(content.length()) .setTokens(tokenCountEstimator.estimate(content)) + .setSegmentMaxTokens(createListReqVO.getSegmentMaxTokens()) .setStatus(CommonStatusEnum.ENABLE.getStatus())); } knowledgeDocumentMapper.insertBatch(documentDOs); @@ -111,11 +114,38 @@ public class AiKnowledgeDocumentServiceImpl implements AiKnowledgeDocumentServic @Override public void updateKnowledgeDocument(AiKnowledgeDocumentUpdateReqVO reqVO) { // 1. 校验文档是否存在 - validateKnowledgeDocumentExists(reqVO.getId()); + AiKnowledgeDocumentDO oldDocument = validateKnowledgeDocumentExists(reqVO.getId()); + // 2. 更新文档 AiKnowledgeDocumentDO document = BeanUtils.toBean(reqVO, AiKnowledgeDocumentDO.class); knowledgeDocumentMapper.updateById(document); - // TODO @芋艿:这里要处理状态的变更 + + // 3. 如果处于开启状态,并且最大 tokens 发生变化,则 segment 需要重新索引 + if (CommonStatusEnum.isEnable(oldDocument.getStatus()) + && reqVO.getSegmentMaxTokens() != null + && ObjUtil.notEqual(reqVO.getSegmentMaxTokens(), oldDocument.getSegmentMaxTokens())) { + // 删除旧的文档切片 + knowledgeSegmentService.deleteKnowledgeSegmentByDocumentId(reqVO.getId()); + // 重新创建文档切片 + knowledgeSegmentService.createKnowledgeSegmentBySplitContentAsync(reqVO.getId(), oldDocument.getContent()); + } + } + + @Override + public void updateKnowledgeDocumentStatus(AiKnowledgeDocumentUpdateStatusReqVO reqVO) { + // 1. 校验存在 + AiKnowledgeDocumentDO document = validateKnowledgeDocumentExists(reqVO.getId()); + + // 2. 更新状态 + knowledgeDocumentMapper.updateById(new AiKnowledgeDocumentDO() + .setId(reqVO.getId()).setStatus(reqVO.getStatus())); + + // 3. 处理文档切片 + if (CommonStatusEnum.isEnable(reqVO.getStatus())) { + knowledgeSegmentService.createKnowledgeSegmentBySplitContentAsync(reqVO.getId(), document.getContent()); + } else { + knowledgeSegmentService.deleteKnowledgeSegmentByDocumentId(reqVO.getId()); + } } @Override diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentService.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentService.java index b105dcb8eb..137887af77 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentService.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentService.java @@ -58,6 +58,13 @@ public interface AiKnowledgeSegmentService { */ void updateKnowledgeSegmentStatus(AiKnowledgeSegmentUpdateStatusReqVO reqVO); + /** + * 根据文档编号删除段落 + * + * @param documentId 文档编号 + */ + void deleteKnowledgeSegmentByDocumentId(Long documentId); + /** * 召回段落 * diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java index 37599b01fc..a20a18e8c3 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java @@ -115,6 +115,22 @@ public class AiKnowledgeSegmentServiceImpl implements AiKnowledgeSegmentService } } + @Override + public void deleteKnowledgeSegmentByDocumentId(Long documentId) { + // 1. 查询需要删除的段落 + List segments = segmentMapper.selectListByDocumentId(documentId); + if (CollUtil.isEmpty(segments)) { + return; + } + + // 2. 批量删除段落记录 + segmentMapper.deleteByIds(convertList(segments, AiKnowledgeSegmentDO::getId)); + + // 3. 删除向量存储中的段落 + VectorStore vectorStore = getVectorStoreById(segments.get(0).getKnowledgeId()); + vectorStore.delete(convertList(segments, AiKnowledgeSegmentDO::getVectorId)); + } + @Override public void updateKnowledgeSegmentStatus(AiKnowledgeSegmentUpdateStatusReqVO reqVO) { // 1. 校验