package cn.iocoder.yudao.module.ai.controller.admin.knowledge; import cn.iocoder.yudao.framework.common.pojo.CommonResult; 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.segment.*; import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeSegmentDO; import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeDocumentService; import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeSegmentService; import cn.iocoder.yudao.module.ai.service.knowledge.bo.AiKnowledgeSegmentSearchReqBO; import cn.iocoder.yudao.module.ai.service.knowledge.bo.AiKnowledgeSegmentSearchRespBO; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.validation.Valid; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @Tag(name = "管理后台 - AI 知识库分段") @RestController @RequestMapping("/ai/knowledge/segment") public class AiKnowledgeSegmentController { @Resource private AiKnowledgeSegmentService segmentService; @Resource private AiKnowledgeDocumentService documentService; @GetMapping("/split") @Operation(summary = "预览文档切分结果") @PreAuthorize("@ss.hasPermission('ai:knowledge:query')") public CommonResult> previewSplit(@Valid AiKnowledgeSegmentSplitReqVO reqVO) { String fileUrl = reqVO.getUrl(); if (fileUrl == null || fileUrl.isEmpty()) { throw new IllegalArgumentException("文档 URL 不能为空"); } // 从 URL 路径中提取文件名 String name = fileUrl; int queryIdx = name.indexOf('?'); if (queryIdx > 0) name = name.substring(0, queryIdx); int slashIdx = name.lastIndexOf('/'); name = slashIdx >= 0 ? name.substring(slashIdx + 1) : name; List segments = documentService.previewSplit(fileUrl, name, reqVO.getSegmentMaxTokens()); List result = new ArrayList<>(); for (String content : segments) { result.add(new AiKnowledgeSegmentSplitRespVO() .setContent(content) .setContentLength(content.length()) .setTokens(estimateTokens(content))); } return success(result); } private int estimateTokens(String text) { if (text == null || text.isEmpty()) return 0; int chineseChars = 0, englishWords = 0; for (char c : text.toCharArray()) { if (c >= 0x4E00 && c <= 0x9FA5) chineseChars++; } for (String word : text.split("\\s+")) { if (word.matches(".*[a-zA-Z].*")) englishWords++; } return chineseChars + (int) (englishWords * 1.3); } @GetMapping("/get") @Operation(summary = "获取分段") @PreAuthorize("@ss.hasPermission('ai:knowledge:query')") public CommonResult getSegment(@RequestParam("id") Long id) { return success(BeanUtils.toBean(segmentService.getSegment(id), AiKnowledgeSegmentRespVO.class)); } @GetMapping("/page") @Operation(summary = "获取分段分页") @PreAuthorize("@ss.hasPermission('ai:knowledge:query')") public CommonResult> getSegmentPage(@Valid AiKnowledgeSegmentPageReqVO pageReqVO) { PageResult pageResult = segmentService.getSegmentPage(pageReqVO); return success(BeanUtils.toBean(pageResult, AiKnowledgeSegmentRespVO.class)); } @PostMapping("/create") @Operation(summary = "创建分段") @PreAuthorize("@ss.hasPermission('ai:knowledge:create')") public CommonResult createSegment(@Valid @RequestBody AiKnowledgeSegmentSaveReqVO saveReqVO) { return success(segmentService.createSegment(saveReqVO)); } @PutMapping("/update") @Operation(summary = "更新分段") @PreAuthorize("@ss.hasPermission('ai:knowledge:update')") public CommonResult updateSegment(@Valid @RequestBody AiKnowledgeSegmentSaveReqVO saveReqVO) { segmentService.updateSegment(saveReqVO); return success(true); } @DeleteMapping("/delete") @Operation(summary = "删除分段") @PreAuthorize("@ss.hasPermission('ai:knowledge:delete')") public CommonResult deleteSegment(@RequestParam("id") Long id) { segmentService.deleteSegment(id); return success(true); } @PutMapping("/update-status") @Operation(summary = "更新分段状态") @PreAuthorize("@ss.hasPermission('ai:knowledge:update')") public CommonResult updateSegmentStatus(@Valid @RequestBody AiKnowledgeSegmentUpdateStatusReqVO updateStatusReqVO) { segmentService.updateSegmentStatus(updateStatusReqVO); return success(true); } @GetMapping("/get-process-list") @Operation(summary = "获取文档处理进度") @PreAuthorize("@ss.hasPermission('ai:knowledge:query')") public CommonResult> getProcessList(@RequestParam("documentIds") List documentIds) { return success(documentService.getDocumentProcessingProgress(documentIds)); } @PostMapping("/search") @Operation(summary = "检索分段(RAG 向量检索)") @PreAuthorize("@ss.hasPermission('ai:knowledge:query')") public CommonResult> searchSegments(@Valid @RequestBody AiKnowledgeSegmentSearchReqVO searchReqVO) { AiKnowledgeSegmentSearchReqBO searchReqBO = BeanUtils.toBean(searchReqVO, AiKnowledgeSegmentSearchReqBO.class); List results = segmentService.searchSegments(searchReqBO); return success(results.stream() .map(bo -> BeanUtils.toBean(bo, AiKnowledgeSegmentSearchRespVO.class)) .collect(Collectors.toList())); } }