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<List<AiKnowledgeSegmentSplitRespVO>> 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<String> segments = documentService.previewSplit(fileUrl, name, reqVO.getSegmentMaxTokens());
|
List<AiKnowledgeSegmentSplitRespVO> 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<AiKnowledgeSegmentRespVO> 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<PageResult<AiKnowledgeSegmentRespVO>> getSegmentPage(@Valid AiKnowledgeSegmentPageReqVO pageReqVO) {
|
PageResult<AiKnowledgeSegmentDO> pageResult = segmentService.getSegmentPage(pageReqVO);
|
return success(BeanUtils.toBean(pageResult, AiKnowledgeSegmentRespVO.class));
|
}
|
|
@PostMapping("/create")
|
@Operation(summary = "创建分段")
|
@PreAuthorize("@ss.hasPermission('ai:knowledge:create')")
|
public CommonResult<Long> createSegment(@Valid @RequestBody AiKnowledgeSegmentSaveReqVO saveReqVO) {
|
return success(segmentService.createSegment(saveReqVO));
|
}
|
|
@PutMapping("/update")
|
@Operation(summary = "更新分段")
|
@PreAuthorize("@ss.hasPermission('ai:knowledge:update')")
|
public CommonResult<Boolean> updateSegment(@Valid @RequestBody AiKnowledgeSegmentSaveReqVO saveReqVO) {
|
segmentService.updateSegment(saveReqVO);
|
return success(true);
|
}
|
|
@DeleteMapping("/delete")
|
@Operation(summary = "删除分段")
|
@PreAuthorize("@ss.hasPermission('ai:knowledge:delete')")
|
public CommonResult<Boolean> deleteSegment(@RequestParam("id") Long id) {
|
segmentService.deleteSegment(id);
|
return success(true);
|
}
|
|
@PutMapping("/update-status")
|
@Operation(summary = "更新分段状态")
|
@PreAuthorize("@ss.hasPermission('ai:knowledge:update')")
|
public CommonResult<Boolean> 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<List<AiKnowledgeSegmentProcessRespVO>> getProcessList(@RequestParam("documentIds") List<Long> documentIds) {
|
return success(documentService.getDocumentProcessingProgress(documentIds));
|
}
|
|
@PostMapping("/search")
|
@Operation(summary = "检索分段(RAG 向量检索)")
|
@PreAuthorize("@ss.hasPermission('ai:knowledge:query')")
|
public CommonResult<List<AiKnowledgeSegmentSearchRespVO>> searchSegments(@Valid @RequestBody AiKnowledgeSegmentSearchReqVO searchReqVO) {
|
AiKnowledgeSegmentSearchReqBO searchReqBO = BeanUtils.toBean(searchReqVO, AiKnowledgeSegmentSearchReqBO.class);
|
List<AiKnowledgeSegmentSearchRespBO> results = segmentService.searchSegments(searchReqBO);
|
return success(results.stream()
|
.map(bo -> BeanUtils.toBean(bo, AiKnowledgeSegmentSearchRespVO.class))
|
.collect(Collectors.toList()));
|
}
|
|
}
|