feat(ai): 新增AI对话与知识库功能模块

- 集成Fastjson2依赖优化JSON处理性能
- 配置专用文档处理异步线程池,提升任务并发处理能力
- 实现基于Spring AI的PgVectorStore向量存储配置
- 新增AI对话控制器,支持SSE流式对话及会话管理接口
- 新增AI知识库控制器,支持文件上传、文档管理及重新索引功能
- 定义AI对话和知识库相关的数据传输对象DTO与视图对象VO
- 建立AI对话消息和文档向量的数据库实体与MyBatis Mapper
- 实现AI对话服务接口及其具体业务逻辑,包括会话管理和RAG检索
- 完善安全校验和错误处理,确保接口调用的用户权限和参数有效性
- 提供对话消息流式响应机制,支持实时传输用户互动内容和引用文档信息
This commit is contained in:
2026-03-30 16:33:47 +08:00
parent e7a21ba665
commit d338490640
28 changed files with 2838 additions and 0 deletions

View File

@@ -0,0 +1,138 @@
package cn.yinlihupo.controller.ai;
import cn.yinlihupo.common.core.BaseResponse;
import cn.yinlihupo.common.util.ResultUtils;
import cn.yinlihupo.common.util.SecurityUtils;
import cn.yinlihupo.domain.vo.KbDocumentVO;
import cn.yinlihupo.service.ai.AiKnowledgeBaseService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import java.util.UUID;
/**
* AI知识库控制器
* 提供知识库文件上传、管理等功能
*/
@Slf4j
@RestController
@RequestMapping("/ai/kb")
@RequiredArgsConstructor
@Tag(name = "AI知识库", description = "AI知识库文档管理相关接口")
public class AiKnowledgeBaseController {
private final AiKnowledgeBaseService knowledgeBaseService;
/**
* 上传文件到知识库
*
* @param projectId 项目ID
* @param file 文件
* @return 文档信息
*/
@PostMapping("/upload")
@Operation(summary = "上传文件", description = "上传文件到项目知识库支持PDF、Word、TXT等格式")
public BaseResponse<KbDocumentVO> uploadFile(
@RequestParam Long projectId,
@RequestParam MultipartFile file) {
Long userId = SecurityUtils.getCurrentUserId();
if (userId == null) {
return ResultUtils.error("用户未登录");
}
if (projectId == null) {
return ResultUtils.error("项目ID不能为空");
}
if (file == null || file.isEmpty()) {
return ResultUtils.error("文件不能为空");
}
try {
KbDocumentVO doc = knowledgeBaseService.uploadFile(projectId, file, userId);
return ResultUtils.success("上传成功", doc);
} catch (Exception e) {
log.error("上传文件失败: {}", e.getMessage(), e);
return ResultUtils.error("上传失败: " + e.getMessage());
}
}
/**
* 获取项目知识库文档列表
*
* @param projectId 项目ID
* @return 文档列表
*/
@GetMapping("/documents")
@Operation(summary = "获取文档列表", description = "获取指定项目的知识库文档列表")
public BaseResponse<List<KbDocumentVO>> getDocuments(
@RequestParam Long projectId) {
Long userId = SecurityUtils.getCurrentUserId();
if (userId == null) {
return ResultUtils.error("用户未登录");
}
if (projectId == null) {
return ResultUtils.error("项目ID不能为空");
}
try {
List<KbDocumentVO> documents = knowledgeBaseService.getProjectDocuments(projectId);
return ResultUtils.success("查询成功", documents);
} catch (Exception e) {
log.error("获取文档列表失败: {}", e.getMessage(), e);
return ResultUtils.error("获取文档列表失败: " + e.getMessage());
}
}
/**
* 删除知识库文档
*
* @param docId 文档UUID
* @return 操作结果
*/
@DeleteMapping("/document/{docId}")
@Operation(summary = "删除文档", description = "删除指定的知识库文档")
public BaseResponse<Void> deleteDocument(@PathVariable UUID docId) {
Long userId = SecurityUtils.getCurrentUserId();
if (userId == null) {
return ResultUtils.error("用户未登录");
}
try {
knowledgeBaseService.deleteDocument(docId, userId);
return ResultUtils.success("删除成功", null);
} catch (Exception e) {
log.error("删除文档失败: {}", e.getMessage(), e);
return ResultUtils.error("删除失败: " + e.getMessage());
}
}
/**
* 重新索引文档
*
* @param docId 文档UUID
* @return 操作结果
*/
@PostMapping("/document/{docId}/reindex")
@Operation(summary = "重新索引文档", description = "重新解析并索引指定的文档")
public BaseResponse<Void> reindexDocument(@PathVariable UUID docId) {
Long userId = SecurityUtils.getCurrentUserId();
if (userId == null) {
return ResultUtils.error("用户未登录");
}
try {
knowledgeBaseService.reindexDocument(docId, userId);
return ResultUtils.success("重新索引已启动", null);
} catch (Exception e) {
log.error("重新索引文档失败: {}", e.getMessage(), e);
return ResultUtils.error("重新索引失败: " + e.getMessage());
}
}
}