From a82cf6e30001723788a3e2bd9dd0db4e7dee4be1 Mon Sep 17 00:00:00 2001 From: rainv123 <2148537152@qq.com> Date: Wed, 5 Nov 2025 09:13:44 +0800 Subject: [PATCH] =?UTF-8?q?update=EF=BC=9A=E6=A0=BC=E5=BC=8F=E8=B0=83?= =?UTF-8?q?=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xiaozhi/common/constant/Constant.java | 4 +- .../xiaozhi/common/exception/ErrorCode.java | 4 +- .../handler/FieldMetaObjectHandler.java | 2 +- .../service/impl/ConfigServiceImpl.java | 5 +- .../controller/KnowledgeBaseController.java | 14 +- .../controller/KnowledgeFilesController.java | 60 +- .../knowledge/dao/KnowledgeBaseDao.java | 2 +- .../knowledge/dto/KnowledgeFilesDTO.java | 2 +- .../service/KnowledgeBaseService.java | 8 +- .../service/KnowledgeFilesService.java | 215 ++++--- .../impl/KnowledgeBaseServiceImpl.java | 239 ++++---- .../impl/KnowledgeFilesServiceImpl.java | 555 +++++++++--------- .../src/apis/module/knowledgeBase.js | 429 ++++++-------- main/manager-web/src/i18n/en.js | 2 +- main/manager-web/src/i18n/zh_CN.js | 2 +- main/manager-web/src/i18n/zh_TW.js | 2 +- .../src/views/KnowledgeBaseManagement.vue | 2 +- .../src/views/KnowledgeFileUpload.vue | 189 +----- 18 files changed, 733 insertions(+), 1003 deletions(-) diff --git a/main/manager-api/src/main/java/xiaozhi/common/constant/Constant.java b/main/manager-api/src/main/java/xiaozhi/common/constant/Constant.java index 8085f079..df5cb29d 100644 --- a/main/manager-api/src/main/java/xiaozhi/common/constant/Constant.java +++ b/main/manager-api/src/main/java/xiaozhi/common/constant/Constant.java @@ -150,12 +150,12 @@ public interface Constant { * 火山引擎双声道语音克隆 */ String VOICE_CLONE_HUOSHAN_DOUBLE_STREAM = "huoshan_double_stream"; - + /** * RAG配置类型 */ String RAG_CONFIG_TYPE = "RAG"; - + /** * 默认RAG模型配置ID */ diff --git a/main/manager-api/src/main/java/xiaozhi/common/exception/ErrorCode.java b/main/manager-api/src/main/java/xiaozhi/common/exception/ErrorCode.java index 1adbb9d2..58ffeee4 100644 --- a/main/manager-api/src/main/java/xiaozhi/common/exception/ErrorCode.java +++ b/main/manager-api/src/main/java/xiaozhi/common/exception/ErrorCode.java @@ -202,13 +202,13 @@ public interface ErrorCode { // 知识库数据集相关错误码 int Knowledge_Base_RECORD_NOT_EXISTS = 10163; // 知识库记录不存在 - + // RAG配置相关错误码 int RAG_CONFIG_NOT_FOUND = 10164; // RAG配置未找到 int RAG_CONFIG_TYPE_ERROR = 10165; // RAG配置类型错误 int RAG_DEFAULT_CONFIG_NOT_FOUND = 10166; // 默认RAG配置未找到 int RAG_CONFIG_MISSING_PARAMS = 10167; // RAG配置缺少必要参数 - + // RAG API调用相关错误码 int RAG_API_CREATE_FAILED = 10168; // RAG API创建数据集失败 int RAG_API_UPDATE_FAILED = 10169; // RAG API更新数据集失败 diff --git a/main/manager-api/src/main/java/xiaozhi/common/handler/FieldMetaObjectHandler.java b/main/manager-api/src/main/java/xiaozhi/common/handler/FieldMetaObjectHandler.java index 3b8585cf..95add2f0 100644 --- a/main/manager-api/src/main/java/xiaozhi/common/handler/FieldMetaObjectHandler.java +++ b/main/manager-api/src/main/java/xiaozhi/common/handler/FieldMetaObjectHandler.java @@ -57,7 +57,7 @@ public class FieldMetaObjectHandler implements MetaObjectHandler { @Override public void updateFill(MetaObject metaObject) { Date date = new Date(); - + // 更新者 strictUpdateFill(metaObject, UPDATER, Long.class, SecurityUser.getUserId()); // 更新时间 - 支持updateDate和updatedAt两种字段名 diff --git a/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java index dce101cf..7883b8c1 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java @@ -378,8 +378,9 @@ public class ConfigServiceImpl implements ConfigService { boolean isCache) { Map selectedModule = new HashMap<>(); - String[] modelTypes = { "VAD", "ASR", "TTS", "Memory", "Intent", "LLM", "VLLM","RAG" }; - String[] modelIds = { vadModelId, asrModelId, ttsModelId, memModelId, intentModelId, llmModelId, vllmModelId, ragModelId }; + String[] modelTypes = { "VAD", "ASR", "TTS", "Memory", "Intent", "LLM", "VLLM", "RAG" }; + String[] modelIds = { vadModelId, asrModelId, ttsModelId, memModelId, intentModelId, llmModelId, vllmModelId, + ragModelId }; String intentLLMModelId = null; String memLocalShortLLMModelId = null; diff --git a/main/manager-api/src/main/java/xiaozhi/modules/knowledge/controller/KnowledgeBaseController.java b/main/manager-api/src/main/java/xiaozhi/modules/knowledge/controller/KnowledgeBaseController.java index 13dbc3eb..c28d6716 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/knowledge/controller/KnowledgeBaseController.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/knowledge/controller/KnowledgeBaseController.java @@ -25,7 +25,6 @@ import xiaozhi.modules.knowledge.dto.KnowledgeBaseDTO; import xiaozhi.modules.knowledge.service.KnowledgeBaseService; import java.util.Map; - @AllArgsConstructor @RestController @RequestMapping("/api/v1") @@ -47,7 +46,8 @@ public class KnowledgeBaseController { KnowledgeBaseDTO knowledgeBaseDTO = new KnowledgeBaseDTO(); knowledgeBaseDTO.setName(name); knowledgeBaseDTO.setDatasetId(id); - PageData pageData = knowledgeBaseService.getPageList(knowledgeBaseDTO, String.valueOf(page), String.valueOf(page_size)); + PageData pageData = knowledgeBaseService.getPageList(knowledgeBaseDTO, String.valueOf(page), + String.valueOf(page_size)); return new Result>().ok(pageData); } @@ -70,8 +70,8 @@ public class KnowledgeBaseController { @PutMapping("/datasets/{dataset_id}") @Operation(summary = "更新知识库") @RequiresPermissions("sys:role:normal") - public Result update(@PathVariable("dataset_id") String datasetId, - @RequestBody @Validated KnowledgeBaseDTO knowledgeBaseDTO) { + public Result update(@PathVariable("dataset_id") String datasetId, + @RequestBody @Validated KnowledgeBaseDTO knowledgeBaseDTO) { knowledgeBaseDTO.setDatasetId(datasetId); KnowledgeBaseDTO resp = knowledgeBaseService.update(knowledgeBaseDTO); return new Result().ok(resp); @@ -85,7 +85,7 @@ public class KnowledgeBaseController { knowledgeBaseService.deleteByDatasetId(datasetId); return new Result<>(); } - + @DeleteMapping("/datasets/batch") @Operation(summary = "批量删除知识库") @Parameter(name = "ids", description = "知识库ID列表,用逗号分隔", required = true) @@ -94,7 +94,7 @@ public class KnowledgeBaseController { if (StringUtils.isBlank(ids)) { throw new RenException(ErrorCode.PARAMS_GET_ERROR); } - + String[] idArray = ids.split(","); for (String datasetId : idArray) { if (StringUtils.isNotBlank(datasetId)) { @@ -103,7 +103,7 @@ public class KnowledgeBaseController { } return new Result<>(); } - + @GetMapping("/rag-config/default") @Operation(summary = "获取默认RAG配置") @RequiresPermissions("sys:role:normal") diff --git a/main/manager-api/src/main/java/xiaozhi/modules/knowledge/controller/KnowledgeFilesController.java b/main/manager-api/src/main/java/xiaozhi/modules/knowledge/controller/KnowledgeFilesController.java index cd08aae6..ec7c9ce0 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/knowledge/controller/KnowledgeFilesController.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/knowledge/controller/KnowledgeFilesController.java @@ -53,11 +53,11 @@ public class KnowledgeFilesController { @RequestParam(required = false) String chunkMethod, @RequestParam(required = false) String metaFields, @RequestParam(required = false) String parserConfig) { - - KnowledgeFilesDTO resp = knowledgeFilesService.uploadDocument(datasetId, file, name, - metaFields != null ? parseJsonMap(metaFields) : null, - chunkMethod, - parserConfig != null ? parseJsonMap(parserConfig) : null); + + KnowledgeFilesDTO resp = knowledgeFilesService.uploadDocument(datasetId, file, name, + metaFields != null ? parseJsonMap(metaFields) : null, + chunkMethod, + parserConfig != null ? parseJsonMap(parserConfig) : null); return new Result().ok(resp); } @@ -66,21 +66,21 @@ public class KnowledgeFilesController { @Parameter(name = "document_id", description = "文档ID", required = true) @RequiresPermissions("sys:role:normal") public Result delete(@PathVariable("dataset_id") String datasetId, - @PathVariable("document_id") String documentId) { + @PathVariable("document_id") String documentId) { knowledgeFilesService.deleteByDocumentId(documentId, datasetId); return new Result<>(); } - + @PostMapping("/chunks") @Operation(summary = "批量解析文档(切块)") @RequiresPermissions("sys:role:normal") public Result parseDocuments(@PathVariable("dataset_id") String datasetId, - @RequestBody Map> requestBody) { + @RequestBody Map> requestBody) { List documentIds = requestBody.get("document_ids"); if (documentIds == null || documentIds.isEmpty()) { return new Result().error("document_ids参数不能为空"); } - + boolean success = knowledgeFilesService.parseDocuments(datasetId, documentIds); if (success) { return new Result(); @@ -88,14 +88,14 @@ public class KnowledgeFilesController { return new Result().error("文档解析失败,文档可能正在处理中"); } } - + @PostMapping("/documents/{document_id}/parse") @Operation(summary = "解析单个文档(切块)") @RequiresPermissions("sys:role:normal") public Result parseDocument(@PathVariable("dataset_id") String datasetId, - @PathVariable("document_id") String documentId) { + @PathVariable("document_id") String documentId) { List documentIds = java.util.Arrays.asList(documentId); - + boolean success = knowledgeFilesService.parseDocuments(datasetId, documentIds); if (success) { return new Result(); @@ -108,13 +108,14 @@ public class KnowledgeFilesController { @Operation(summary = "添加切片到指定文档") @RequiresPermissions("sys:role:normal") public Result> addChunk(@PathVariable("dataset_id") String datasetId, - @PathVariable("document_id") String documentId, - @RequestBody Map requestBody) { + @PathVariable("document_id") String documentId, + @RequestBody Map requestBody) { String content = (String) requestBody.get("content"); List importantKeywords = (List) requestBody.get("important_keywords"); List questions = (List) requestBody.get("questions"); - - Map result = knowledgeFilesService.addChunk(datasetId, documentId, content, importantKeywords, questions); + + Map result = knowledgeFilesService.addChunk(datasetId, documentId, content, importantKeywords, + questions); return new Result>().ok(result); } @@ -122,12 +123,13 @@ public class KnowledgeFilesController { @Operation(summary = "列出指定文档的切片") @RequiresPermissions("sys:role:normal") public Result> listChunks(@PathVariable("dataset_id") String datasetId, - @PathVariable("document_id") String documentId, - @RequestParam(required = false) String keywords, - @RequestParam(required = false, defaultValue = "1") Integer page, - @RequestParam(required = false, defaultValue = "1024") Integer page_size, - @RequestParam(required = false) String id) { - Map result = knowledgeFilesService.listChunks(datasetId, documentId, keywords, page, page_size, id); + @PathVariable("document_id") String documentId, + @RequestParam(required = false) String keywords, + @RequestParam(required = false, defaultValue = "1") Integer page, + @RequestParam(required = false, defaultValue = "1024") Integer page_size, + @RequestParam(required = false) String id) { + Map result = knowledgeFilesService.listChunks(datasetId, documentId, keywords, page, page_size, + id); return new Result>().ok(result); } @@ -138,7 +140,7 @@ public class KnowledgeFilesController { @Operation(summary = "召回测试") @RequiresPermissions("sys:role:normal") public Result> retrievalTest(@PathVariable("dataset_id") String datasetId, - @RequestBody Map params) { + @RequestBody Map params) { try { // 提取参数 String question = (String) params.get("question"); @@ -165,23 +167,23 @@ public class KnowledgeFilesController { } Map result = knowledgeFilesService.retrievalTest( - question, datasetIds, documentIds, page, pageSize, similarityThreshold, - vectorSimilarityWeight, topK, rerankId, keyword, highlight, crossLanguages, metadataCondition - ); - + question, datasetIds, documentIds, page, pageSize, similarityThreshold, + vectorSimilarityWeight, topK, rerankId, keyword, highlight, crossLanguages, metadataCondition); + return new Result>().ok(result); } catch (Exception e) { return new Result>().error("召回测试失败: " + e.getMessage()); } } - + /** * 解析JSON字符串为Map对象 */ private Map parseJsonMap(String jsonString) { try { ObjectMapper objectMapper = new ObjectMapper(); - return objectMapper.readValue(jsonString, new TypeReference>() {}); + return objectMapper.readValue(jsonString, new TypeReference>() { + }); } catch (Exception e) { throw new RuntimeException("解析JSON字符串失败: " + jsonString, e); } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/knowledge/dao/KnowledgeBaseDao.java b/main/manager-api/src/main/java/xiaozhi/modules/knowledge/dao/KnowledgeBaseDao.java index e49e5e22..7f94b0af 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/knowledge/dao/KnowledgeBaseDao.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/knowledge/dao/KnowledgeBaseDao.java @@ -10,5 +10,5 @@ import xiaozhi.modules.knowledge.entity.KnowledgeBaseEntity; */ @Mapper public interface KnowledgeBaseDao extends BaseDao { - + } \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/knowledge/dto/KnowledgeFilesDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/knowledge/dto/KnowledgeFilesDTO.java index 12bcb678..2d614723 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/knowledge/dto/KnowledgeFilesDTO.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/knowledge/dto/KnowledgeFilesDTO.java @@ -16,7 +16,7 @@ public class KnowledgeFilesDTO implements Serializable { private static final long serialVersionUID = 1L; @Schema(description = "唯一标识") private String id; - + @Schema(description = "文档ID") private String documentId; diff --git a/main/manager-api/src/main/java/xiaozhi/modules/knowledge/service/KnowledgeBaseService.java b/main/manager-api/src/main/java/xiaozhi/modules/knowledge/service/KnowledgeBaseService.java index 6a41375f..8ed34d46 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/knowledge/service/KnowledgeBaseService.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/knowledge/service/KnowledgeBaseService.java @@ -16,8 +16,8 @@ public interface KnowledgeBaseService extends BaseService { * 分页查询知识库列表 * * @param knowledgeBaseDTO 查询条件 - * @param page 页码 - * @param limit 每页数量 + * @param page 页码 + * @param limit 每页数量 * @return 分页数据 */ PageData getPageList(KnowledgeBaseDTO knowledgeBaseDTO, String page, String limit); @@ -67,7 +67,7 @@ public interface KnowledgeBaseService extends BaseService { * @param datasetId 知识库ID */ void deleteByDatasetId(String datasetId); - + /** * 获取RAG配置信息 * @@ -75,7 +75,7 @@ public interface KnowledgeBaseService extends BaseService { * @return RAG配置信息 */ Map getRAGConfig(String ragModelId); - + /** * 获取默认RAG配置信息 * diff --git a/main/manager-api/src/main/java/xiaozhi/modules/knowledge/service/KnowledgeFilesService.java b/main/manager-api/src/main/java/xiaozhi/modules/knowledge/service/KnowledgeFilesService.java index 2422a4fb..f090f60a 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/knowledge/service/KnowledgeFilesService.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/knowledge/service/KnowledgeFilesService.java @@ -13,121 +13,120 @@ import xiaozhi.modules.knowledge.dto.KnowledgeFilesDTO; */ public interface KnowledgeFilesService { - /** - * 分页查询文档列表 - * - * @param knowledgeFilesDTO 查询条件 - * @param page 页码 - * @param limit 每页数量 - * @return 分页数据 - */ - PageData getPageList(KnowledgeFilesDTO knowledgeFilesDTO, Integer page, Integer limit); + /** + * 分页查询文档列表 + * + * @param knowledgeFilesDTO 查询条件 + * @param page 页码 + * @param limit 每页数量 + * @return 分页数据 + */ + PageData getPageList(KnowledgeFilesDTO knowledgeFilesDTO, Integer page, Integer limit); - /** - * 根据文档ID和知识库ID获取文档详情 - * - * @param documentId 文档ID - * @param datasetId 知识库ID - * @return 文档详情 - */ - KnowledgeFilesDTO getByDocumentId(String documentId, String datasetId); + /** + * 根据文档ID和知识库ID获取文档详情 + * + * @param documentId 文档ID + * @param datasetId 知识库ID + * @return 文档详情 + */ + KnowledgeFilesDTO getByDocumentId(String documentId, String datasetId); - /** - * 上传文档到知识库 - * - * @param datasetId 知识库ID - * @param file 上传的文件 - * @param name 文档名称 - * @param metaFields 元数据字段 - * @param chunkMethod 分块方法 - * @param parserConfig 解析器配置 - * @return 上传的文档信息 - */ - KnowledgeFilesDTO uploadDocument(String datasetId, MultipartFile file, String name, - Map metaFields, String chunkMethod, - Map parserConfig); + /** + * 上传文档到知识库 + * + * @param datasetId 知识库ID + * @param file 上传的文件 + * @param name 文档名称 + * @param metaFields 元数据字段 + * @param chunkMethod 分块方法 + * @param parserConfig 解析器配置 + * @return 上传的文档信息 + */ + KnowledgeFilesDTO uploadDocument(String datasetId, MultipartFile file, String name, + Map metaFields, String chunkMethod, + Map parserConfig); - /** - * 根据文档ID和知识库ID删除文档 - * - * @param documentId 文档ID - * @param datasetId 知识库ID - */ - void deleteByDocumentId(String documentId, String datasetId); + /** + * 根据文档ID和知识库ID删除文档 + * + * @param documentId 文档ID + * @param datasetId 知识库ID + */ + void deleteByDocumentId(String documentId, String datasetId); + /** + * 获取RAG配置信息 + * + * @param ragModelId RAG模型配置ID + * @return RAG配置信息 + */ + Map getRAGConfig(String ragModelId); - /** - * 获取RAG配置信息 - * - * @param ragModelId RAG模型配置ID - * @return RAG配置信息 - */ - Map getRAGConfig(String ragModelId); - - /** - * 获取默认RAG配置信息 - * - * @return 默认RAG配置信息 - */ - Map getDefaultRAGConfig(); + /** + * 获取默认RAG配置信息 + * + * @return 默认RAG配置信息 + */ + Map getDefaultRAGConfig(); - /** - * 解析文档(切块) - * - * @param datasetId 知识库ID - * @param documentIds 文档ID列表 - * @return 解析结果 - */ - boolean parseDocuments(String datasetId, List documentIds); + /** + * 解析文档(切块) + * + * @param datasetId 知识库ID + * @param documentIds 文档ID列表 + * @return 解析结果 + */ + boolean parseDocuments(String datasetId, List documentIds); - /** - * 添加切片到指定文档 - * - * @param datasetId 知识库ID - * @param documentId 文档ID - * @param content 切片内容 - * @param importantKeywords 重要关键词列表 - * @param questions 问题列表 - * @return 添加的切片信息 - */ - Map addChunk(String datasetId, String documentId, String content, - List importantKeywords, List questions); + /** + * 添加切片到指定文档 + * + * @param datasetId 知识库ID + * @param documentId 文档ID + * @param content 切片内容 + * @param importantKeywords 重要关键词列表 + * @param questions 问题列表 + * @return 添加的切片信息 + */ + Map addChunk(String datasetId, String documentId, String content, + List importantKeywords, List questions); - /** - * 列出指定文档的切片 - * - * @param datasetId 知识库ID - * @param documentId 文档ID - * @param keywords 关键词过滤 - * @param page 页码 - * @param pageSize 每页数量 - * @param chunkId 切片ID - * @return 切片列表信息 - */ - Map listChunks(String datasetId, String documentId, String keywords, - Integer page, Integer pageSize, String chunkId); + /** + * 列出指定文档的切片 + * + * @param datasetId 知识库ID + * @param documentId 文档ID + * @param keywords 关键词过滤 + * @param page 页码 + * @param pageSize 每页数量 + * @param chunkId 切片ID + * @return 切片列表信息 + */ + Map listChunks(String datasetId, String documentId, String keywords, + Integer page, Integer pageSize, String chunkId); - /** - * 召回测试 - 从指定数据集或文档中检索相关切片 - * - * @param question 用户查询或查询关键词 - * @param datasetIds 数据集ID列表 - * @param documentIds 文档ID列表 - * @param page 页码 - * @param pageSize 每页数量 - * @param similarityThreshold 最小相似度阈值 - * @param vectorSimilarityWeight 向量相似度权重 - * @param topK 参与向量余弦计算的切片数量 - * @param rerankId 重排模型ID - * @param keyword 是否启用关键词匹配 - * @param highlight 是否启用高亮显示 - * @param crossLanguages 跨语言翻译列表 - * @param metadataCondition 元数据过滤条件 - * @return 召回测试结果 - */ - Map retrievalTest(String question, List datasetIds, List documentIds, - Integer page, Integer pageSize, Float similarityThreshold, - Float vectorSimilarityWeight, Integer topK, String rerankId, - Boolean keyword, Boolean highlight, List crossLanguages, - Map metadataCondition); + /** + * 召回测试 - 从指定数据集或文档中检索相关切片 + * + * @param question 用户查询或查询关键词 + * @param datasetIds 数据集ID列表 + * @param documentIds 文档ID列表 + * @param page 页码 + * @param pageSize 每页数量 + * @param similarityThreshold 最小相似度阈值 + * @param vectorSimilarityWeight 向量相似度权重 + * @param topK 参与向量余弦计算的切片数量 + * @param rerankId 重排模型ID + * @param keyword 是否启用关键词匹配 + * @param highlight 是否启用高亮显示 + * @param crossLanguages 跨语言翻译列表 + * @param metadataCondition 元数据过滤条件 + * @return 召回测试结果 + */ + Map retrievalTest(String question, List datasetIds, List documentIds, + Integer page, Integer pageSize, Float similarityThreshold, + Float vectorSimilarityWeight, Integer topK, String rerankId, + Boolean keyword, Boolean highlight, List crossLanguages, + Map metadataCondition); } \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/knowledge/service/impl/KnowledgeBaseServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/knowledge/service/impl/KnowledgeBaseServiceImpl.java index 018c7027..4448f4b3 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/knowledge/service/impl/KnowledgeBaseServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/knowledge/service/impl/KnowledgeBaseServiceImpl.java @@ -37,15 +37,14 @@ import xiaozhi.modules.model.service.ModelConfigService; @Service @AllArgsConstructor @Slf4j -public class KnowledgeBaseServiceImpl extends BaseServiceImpl implements KnowledgeBaseService { +public class KnowledgeBaseServiceImpl extends BaseServiceImpl + implements KnowledgeBaseService { private final KnowledgeBaseDao knowledgeBaseDao; private final ModelConfigService modelConfigService; private final ModelConfigDao modelConfigDao; private RestTemplate restTemplate = new RestTemplate(); - - @Override public PageData getPageList(KnowledgeBaseDTO knowledgeBaseDTO, String page, String limit) { long curPage = Long.parseLong(page); @@ -53,11 +52,11 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl pageInfo = new Page<>(curPage, pageSize); QueryWrapper queryWrapper = new QueryWrapper<>(); - + // 添加查询条件 if (knowledgeBaseDTO != null) { queryWrapper.like(StringUtils.isNotBlank(knowledgeBaseDTO.getName()), "name", knowledgeBaseDTO.getName()) - .eq(knowledgeBaseDTO.getStatus() != null, "status", knowledgeBaseDTO.getStatus()); + .eq(knowledgeBaseDTO.getStatus() != null, "status", knowledgeBaseDTO.getStatus()); } // 添加排序规则:按创建时间降序 @@ -67,12 +66,13 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl pageData = getPageData(knowledgeBaseEntityIPage, KnowledgeBaseDTO.class); - + // 为每个知识库获取文档数量 if (pageData != null && pageData.getList() != null) { for (KnowledgeBaseDTO knowledgeBase : pageData.getList()) { try { - Integer documentCount = getDocumentCountFromRAGFlow(knowledgeBase.getDatasetId(), knowledgeBase.getRagModelId()); + Integer documentCount = getDocumentCountFromRAGFlow(knowledgeBase.getDatasetId(), + knowledgeBase.getRagModelId()); knowledgeBase.setDocumentCount(documentCount); } catch (Exception e) { log.warn("获取知识库 {} 的文档数量失败: {}", knowledgeBase.getDatasetId(), e.getMessage()); @@ -109,19 +109,17 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl ragConfig = getValidatedRAGConfig(knowledgeBaseDTO.getRagModelId()); datasetId = createDatasetInRAGFlow( - knowledgeBaseDTO.getName(), - knowledgeBaseDTO.getDescription(), - ragConfig - ); + knowledgeBaseDTO.getName(), + knowledgeBaseDTO.getDescription(), + ragConfig); } catch (Exception e) { // 如果RAG API调用失败,直接抛出异常,无需回滚(因为还没有插入本地数据库) throw e; } - + // 验证数据集ID是否已存在 KnowledgeBaseEntity existingEntity = knowledgeBaseDao.selectOne( - new QueryWrapper().eq("dataset_id", datasetId) - ); + new QueryWrapper().eq("dataset_id", datasetId)); if (existingEntity != null) { // 如果datasetId已存在,删除RAGFlow中的数据集并抛出异常 try { @@ -132,7 +130,7 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl() - .eq("dataset_id", knowledgeBaseDTO.getDatasetId()) - .ne("id", knowledgeBaseDTO.getId()) - ); + new QueryWrapper() + .eq("dataset_id", knowledgeBaseDTO.getDatasetId()) + .ne("id", knowledgeBaseDTO.getId())); if (conflictEntity != null) { throw new RenException(ErrorCode.DB_RECORD_EXISTS); } @@ -173,11 +170,10 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl ragConfig = getValidatedRAGConfig(knowledgeBaseDTO.getRagModelId()); updateDatasetInRAGFlow( - knowledgeBaseDTO.getDatasetId(), - knowledgeBaseDTO.getName(), - knowledgeBaseDTO.getDescription(), - ragConfig - ); + knowledgeBaseDTO.getDatasetId(), + knowledgeBaseDTO.getName(), + knowledgeBaseDTO.getDescription(), + ragConfig); } catch (Exception e) { // 如果RAG API调用失败,回滚本地数据库操作 knowledgeBaseDao.updateById(existingEntity); @@ -203,8 +199,8 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl 0 ? "成功" : "失败"); } - + log.info("=== 删除操作结束 ==="); } @@ -240,8 +236,7 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl().eq("dataset_id", datasetId) - ); + new QueryWrapper().eq("dataset_id", datasetId)); if (entity == null) { throw new RenException(ErrorCode.Knowledge_Base_RECORD_NOT_EXISTS); @@ -260,16 +255,15 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl().eq("dataset_id", datasetId) - ); + new QueryWrapper().eq("dataset_id", datasetId)); if (entity == null) { log.warn("记录不存在,datasetId: {}", datasetId); throw new RenException(ErrorCode.Knowledge_Base_RECORD_NOT_EXISTS); } - log.info("找到记录: ID={}, datasetId={}, ragModelId={}", - entity.getId(), entity.getDatasetId(), entity.getRagModelId()); + log.info("找到记录: ID={}, datasetId={}, ragModelId={}", + entity.getId(), entity.getDatasetId(), entity.getRagModelId()); // 先删除本地数据库记录 int deleteCount = knowledgeBaseDao.deleteById(entity.getId()); @@ -288,62 +282,62 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl getRAGConfig(String ragModelId) { if (StringUtils.isBlank(ragModelId)) { throw new RenException(ErrorCode.PARAMS_GET_ERROR); } - + // 从缓存获取模型配置 ModelConfigEntity modelConfig = modelConfigService.getModelByIdFromCache(ragModelId); if (modelConfig == null || modelConfig.getConfigJson() == null) { throw new RenException(ErrorCode.RAG_CONFIG_NOT_FOUND); } - + // 验证是否为RAG类型配置 if (!Constant.RAG_CONFIG_TYPE.equals(modelConfig.getModelType().toUpperCase())) { throw new RenException(ErrorCode.RAG_CONFIG_TYPE_ERROR); } - + Map config = modelConfig.getConfigJson(); - + // 验证必要的配置参数 validateRagConfig(config); - + // 返回配置信息 return config; } - + @Override public Map getDefaultRAGConfig() { // 获取默认RAG模型配置 QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("model_type", Constant.RAG_CONFIG_TYPE) - .eq("is_default", 1) - .eq("is_enabled", 1); + .eq("is_default", 1) + .eq("is_enabled", 1); List modelConfigs = modelConfigDao.selectList(queryWrapper); if (modelConfigs == null || modelConfigs.isEmpty()) { throw new RenException(ErrorCode.RAG_DEFAULT_CONFIG_NOT_FOUND); } - + ModelConfigEntity defaultConfig = modelConfigs.get(0); if (defaultConfig.getConfigJson() == null) { throw new RenException(ErrorCode.RAG_CONFIG_NOT_FOUND); } - + Map config = defaultConfig.getConfigJson(); - + // 验证必要的配置参数 validateRagConfig(config); - + return config; } - + /** * 验证RAG配置中是否包含必要的参数 */ @@ -351,17 +345,17 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl requestBody = new HashMap<>(); requestBody.put("name", name); @@ -385,26 +379,26 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl> requestEntity = new HttpEntity<>(requestBody, headers); - + // 发送POST请求 log.info("发送POST请求到RAGFlow API..."); ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class); - + log.info("RAGFlow API响应状态码: {}", response.getStatusCode()); log.debug("RAGFlow API响应内容: {}", response.getBody()); - + if (!response.getStatusCode().is2xxSuccessful()) { log.error("RAGFlow API调用失败,状态码: {}, 响应内容: {}", response.getStatusCode(), response.getBody()); throw new RenException(ErrorCode.RAG_API_CREATE_FAILED); } - + // 解析响应体,提取datasetId String responseBody = response.getBody(); if (StringUtils.isNotBlank(responseBody)) { @@ -412,9 +406,9 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl responseMap = objectMapper.readValue(responseBody, Map.class); - + log.debug("RAGFlow API响应解析结果: {}", responseMap); - + // 首先检查响应码 Integer code = (Integer) responseMap.get("code"); if (code != null && code == 0) { @@ -423,7 +417,7 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl dataMap = (Map) dataObj; datasetId = (String) dataMap.get("id"); - + if (StringUtils.isBlank(datasetId)) { // 如果id字段为空,尝试其他可能的字段名 datasetId = (String) dataMap.get("dataset_id"); @@ -435,7 +429,7 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl ragConfig) { + private void updateDatasetInRAGFlow(String datasetId, String name, String description, + Map ragConfig) { try { String baseUrl = (String) ragConfig.get("base_url"); String apiKey = (String) ragConfig.get("api_key"); - + log.info("开始调用RAGFlow API更新数据集,datasetId: {}, name: {}", datasetId, name); log.debug("RAGFlow配置 - baseUrl: {}, apiKey: {}", baseUrl, StringUtils.isBlank(apiKey) ? "未配置" : "已配置"); - + // 构建请求URL String url = baseUrl + "/api/v1/datasets/" + datasetId; log.debug("请求URL: {}", url); - + // 构建请求体 Map requestBody = new HashMap<>(); requestBody.put("dataset_id", datasetId); @@ -492,36 +489,38 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl> requestEntity = new HttpEntity<>(requestBody, headers); - + // 发送PUT请求 log.info("发送PUT请求到RAGFlow API..."); ResponseEntity response = restTemplate.exchange(url, HttpMethod.PUT, requestEntity, String.class); - + log.info("RAGFlow API响应状态码: {}", response.getStatusCode()); log.debug("RAGFlow API响应内容: {}", response.getBody()); - + if (!response.getStatusCode().is2xxSuccessful()) { log.error("RAGFlow API调用失败,状态码: {}, 响应内容: {}", response.getStatusCode(), response.getBody()); throw new RenException(ErrorCode.RAG_API_UPDATE_FAILED); } - + log.info("RAGFlow数据集更新成功,datasetId: {}", datasetId); - + } catch (HttpClientErrorException e) { - log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}", - e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); - throw new RenException(ErrorCode.RAG_API_UPDATE_FAILED, "更新RAGFlow数据集失败: " + e.getMessage() + ", 响应: " + e.getResponseBodyAsString()); + log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}", + e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); + throw new RenException(ErrorCode.RAG_API_UPDATE_FAILED, + "更新RAGFlow数据集失败: " + e.getMessage() + ", 响应: " + e.getResponseBodyAsString()); } catch (HttpServerErrorException e) { - log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}", - e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); - throw new RenException(ErrorCode.RAG_API_UPDATE_FAILED, "更新RAGFlow数据集失败: " + e.getMessage() + ", 响应: " + e.getResponseBodyAsString()); + log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}", + e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); + throw new RenException(ErrorCode.RAG_API_UPDATE_FAILED, + "更新RAGFlow数据集失败: " + e.getMessage() + ", 响应: " + e.getResponseBodyAsString()); } catch (ResourceAccessException e) { log.error("RAGFlow API调用失败 - 网络连接错误: {}", e.getMessage(), e); throw new RenException(ErrorCode.RAG_API_UPDATE_FAILED, "更新RAGFlow数据集失败: 网络连接错误 - " + e.getMessage()); @@ -530,7 +529,7 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl requestBody = new HashMap<>(); requestBody.put("ids", List.of(datasetId)); log.debug("请求体: {}", requestBody); - + // 设置请求头 HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.set("Authorization", "Bearer " + apiKey); - + HttpEntity> requestEntity = new HttpEntity<>(requestBody, headers); - + // 发送DELETE请求 log.info("发送DELETE请求到RAGFlow API..."); - ResponseEntity response = restTemplate.exchange(url, HttpMethod.DELETE, requestEntity, String.class); - + ResponseEntity response = restTemplate.exchange(url, HttpMethod.DELETE, requestEntity, + String.class); + log.info("RAGFlow API响应状态码: {}", response.getStatusCode()); log.debug("RAGFlow API响应内容: {}", response.getBody()); - + if (!response.getStatusCode().is2xxSuccessful()) { log.error("RAGFlow API调用失败,状态码: {}, 响应内容: {}", response.getStatusCode(), response.getBody()); throw new RenException(ErrorCode.RAG_API_DELETE_FAILED); } - + log.info("RAGFlow数据集删除成功,datasetId: {}", datasetId); - + } catch (HttpClientErrorException e) { - log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}", - e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); - throw new RenException(ErrorCode.RAG_API_DELETE_FAILED, "删除RAGFlow数据集失败: " + e.getMessage() + ", 响应: " + e.getResponseBodyAsString()); + log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}", + e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); + throw new RenException(ErrorCode.RAG_API_DELETE_FAILED, + "删除RAGFlow数据集失败: " + e.getMessage() + ", 响应: " + e.getResponseBodyAsString()); } catch (HttpServerErrorException e) { - log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}", - e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); - throw new RenException(ErrorCode.RAG_API_DELETE_FAILED, "删除RAGFlow数据集失败: " + e.getMessage() + ", 响应: " + e.getResponseBodyAsString()); + log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}", + e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); + throw new RenException(ErrorCode.RAG_API_DELETE_FAILED, + "删除RAGFlow数据集失败: " + e.getMessage() + ", 响应: " + e.getResponseBodyAsString()); } catch (ResourceAccessException e) { log.error("RAGFlow API调用失败 - 网络连接错误: {}", e.getMessage(), e); throw new RenException(ErrorCode.RAG_API_DELETE_FAILED, "删除RAGFlow数据集失败: 网络连接错误 - " + e.getMessage()); @@ -588,7 +590,7 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl ragConfig = getValidatedRAGConfig(ragModelId); String baseUrl = (String) ragConfig.get("base_url"); @@ -646,7 +648,7 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl responseMap = objectMapper.readValue(responseBody, Map.class); Integer code = (Integer) responseMap.get("code"); - + if (code != null && code == 0) { Object dataObj = responseMap.get("data"); if (dataObj instanceof Map) { @@ -669,11 +671,11 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl getPageList(KnowledgeFilesDTO knowledgeFilesDTO, Integer page, Integer limit) { try { - + log.info("=== 开始获取文档列表 ==="); - log.info("查询条件: datasetId={}, name={}, status={}, page={}, limit={}", + log.info("查询条件: datasetId={}, name={}, status={}, page={}, limit={}", knowledgeFilesDTO != null ? knowledgeFilesDTO.getDatasetId() : null, knowledgeFilesDTO != null ? knowledgeFilesDTO.getName() : null, knowledgeFilesDTO != null ? knowledgeFilesDTO.getStatus() : null, @@ -65,11 +65,11 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { } String url = baseUrl + "/api/v1/datasets/" + datasetId + "/documents"; - + // 添加查询参数 StringBuilder urlBuilder = new StringBuilder(url); List params = new ArrayList<>(); - + if (knowledgeFilesDTO != null && StringUtils.isNotBlank(knowledgeFilesDTO.getName())) { params.add("keywords=" + knowledgeFilesDTO.getName()); } @@ -79,11 +79,11 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { if (limit > 0) { params.add("page_size=" + limit); } - + if (!params.isEmpty()) { urlBuilder.append("?").append(String.join("&", params)); } - + url = urlBuilder.toString(); log.debug("请求URL: {}", url); @@ -111,7 +111,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { // 解析响应 Map responseMap = objectMapper.readValue(responseBody, Map.class); Integer code = (Integer) responseMap.get("code"); - + if (code != null && code == 0) { Object dataObj = responseMap.get("data"); return parseDocumentListResponse(dataObj, page, limit); @@ -124,12 +124,12 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { log.error("解析RAGFlow API响应失败: {}", e.getMessage(), e); throw new RenException(ErrorCode.RAG_API_QUERY_FAILED, "解析RAGFlow响应失败: " + e.getMessage()); } catch (HttpClientErrorException e) { - log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}", - e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); + log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}", + e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); throw new RenException(ErrorCode.RAG_API_QUERY_FAILED, "获取RAGFlow文档列表失败: " + e.getMessage()); } catch (HttpServerErrorException e) { - log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}", - e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); + log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}", + e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); throw new RenException(ErrorCode.RAG_API_QUERY_FAILED, "获取RAGFlow文档列表失败: " + e.getMessage()); } catch (ResourceAccessException e) { log.error("RAGFlow API调用失败 - 网络连接错误: {}", e.getMessage(), e); @@ -152,13 +152,13 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { if (dataObj instanceof Map) { Map dataMap = (Map) dataObj; - + // 获取文档列表 - 支持多种可能的字段名 Object documentsObj = null; - + // 支持多种可能的文档列表字段名 - String[] possibleDocumentFields = {"docs", "documents", "items", "list", "data"}; - + String[] possibleDocumentFields = { "docs", "documents", "items", "list", "data" }; + for (String fieldName : possibleDocumentFields) { if (dataMap.containsKey(fieldName) && dataMap.get(fieldName) instanceof List) { documentsObj = dataMap.get(fieldName); @@ -166,7 +166,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { break; } } - + // 如果标准字段不存在,尝试自动检测 if (documentsObj == null) { for (Map.Entry entry : dataMap.entrySet()) { @@ -180,10 +180,10 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { } } } - + if (documentsObj instanceof List) { List> documentList = (List>) documentsObj; - + for (Map docMap : documentList) { KnowledgeFilesDTO dto = convertRAGDocumentToDTO(docMap); if (dto != null) { @@ -191,11 +191,11 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { } } } - + // 解析总数 - 支持多种可能的字段名 Object totalObj = null; - String[] possibleTotalFields = {"total", "totalCount", "total_count", "count"}; - + String[] possibleTotalFields = { "total", "totalCount", "total_count", "count" }; + for (String fieldName : possibleTotalFields) { if (dataMap.containsKey(fieldName)) { totalObj = dataMap.get(fieldName); @@ -203,7 +203,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { break; } } - + if (totalObj instanceof Integer) { totalCount = ((Integer) totalObj).longValue(); } else if (totalObj instanceof Long) { @@ -234,19 +234,20 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { */ private KnowledgeFilesDTO convertRAGDocumentToDTO(Map docMap) { try { - if (docMap == null) return null; + if (docMap == null) + return null; KnowledgeFilesDTO dto = new KnowledgeFilesDTO(); - + // 设置基本字段 - 支持多种可能的字段名 dto.setId(getStringValueFromMultipleKeys(docMap, "id", "document_id", "doc_id")); // 使用RAGFlow的文档ID作为本地ID dto.setDocumentId(getStringValueFromMultipleKeys(docMap, "id", "document_id", "doc_id")); // RAGFlow文档ID dto.setName(getStringValueFromMultipleKeys(docMap, "name", "filename", "file_name", "title")); dto.setDatasetId(getStringValueFromMultipleKeys(docMap, "dataset_id", "dataset", "knowledge_base_id")); - + // 设置文件信息 - 支持多种可能的字段名 dto.setFileType(getStringValueFromMultipleKeys(docMap, "file_type", "type", "format", "extension")); - + // 文件大小 - 支持多种可能的字段名 Object sizeObj = getValueFromMultipleKeys(docMap, "size", "file_size", "size_bytes"); if (sizeObj instanceof Integer) { @@ -260,7 +261,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { log.warn("无法解析文件大小: {}", sizeObj); } } - + // 设置状态 - 支持多种可能的字段名 Object statusObj = getValueFromMultipleKeys(docMap, "status", "state", "processing_status"); if (statusObj instanceof String) { @@ -268,22 +269,24 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { } else if (statusObj instanceof Integer) { dto.setStatus((Integer) statusObj); } - + // 设置元数据和配置 - 支持多种可能的字段名 Object metaFieldsObj = getValueFromMultipleKeys(docMap, "meta_fields", "metadata", "meta", "properties"); if (metaFieldsObj instanceof Map) { dto.setMetaFields((Map) metaFieldsObj); } - - Object parserConfigObj = getValueFromMultipleKeys(docMap, "parser_config", "parser", "parse_config", "config"); + + Object parserConfigObj = getValueFromMultipleKeys(docMap, "parser_config", "parser", "parse_config", + "config"); if (parserConfigObj instanceof Map) { dto.setParserConfig((Map) parserConfigObj); } - + dto.setChunkMethod(getStringValueFromMultipleKeys(docMap, "chunk_method", "chunking", "chunk_strategy")); - + // 设置时间信息 - 支持多种可能的字段名 - Object createTimeObj = getValueFromMultipleKeys(docMap, "create_time", "created_at", "creation_time", "created"); + Object createTimeObj = getValueFromMultipleKeys(docMap, "create_time", "created_at", "creation_time", + "created"); if (createTimeObj instanceof Long) { dto.setCreatedAt(new Date((Long) createTimeObj)); } else if (createTimeObj instanceof String) { @@ -295,8 +298,9 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { log.warn("无法解析创建时间: {}", createTimeObj); } } - - Object updateTimeObj = getValueFromMultipleKeys(docMap, "update_time", "updated_at", "modified_time", "modified"); + + Object updateTimeObj = getValueFromMultipleKeys(docMap, "update_time", "updated_at", "modified_time", + "modified"); if (updateTimeObj instanceof Long) { dto.setUpdatedAt(new Date((Long) updateTimeObj)); } else if (updateTimeObj instanceof String) { @@ -308,7 +312,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { } return dto; - + } catch (Exception e) { log.error("转换RAGFlow文档数据失败: {}", e.getMessage(), e); return null; @@ -319,8 +323,9 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { * 转换RAGFlow状态到本地状态 */ private Integer convertRAGStatusToLocal(String ragStatus) { - if (ragStatus == null) return 0; - + if (ragStatus == null) + return 0; + switch (ragStatus.toLowerCase()) { case "pending": case "processing": @@ -405,7 +410,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { // 解析响应 Map responseMap = objectMapper.readValue(responseBody, Map.class); Integer code = (Integer) responseMap.get("code"); - + if (code != null && code == 0) { Object dataObj = responseMap.get("data"); if (dataObj instanceof Map) { @@ -429,12 +434,12 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { log.warn("文档不存在,documentId: {}, datasetId: {}", documentId, datasetId); throw new RenException(ErrorCode.Knowledge_Base_RECORD_NOT_EXISTS); } - log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}", - e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); + log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}", + e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); throw new RenException(ErrorCode.RAG_API_QUERY_FAILED, "获取RAGFlow文档失败: " + e.getMessage()); } catch (HttpServerErrorException e) { - log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}", - e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); + log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}", + e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); throw new RenException(ErrorCode.RAG_API_QUERY_FAILED, "获取RAGFlow文档失败: " + e.getMessage()); } catch (ResourceAccessException e) { log.error("RAGFlow API调用失败 - 网络连接错误: {}", e.getMessage(), e); @@ -448,9 +453,9 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { } @Override - public KnowledgeFilesDTO uploadDocument(String datasetId, MultipartFile file, String name, - Map metaFields, String chunkMethod, - Map parserConfig) { + public KnowledgeFilesDTO uploadDocument(String datasetId, MultipartFile file, String name, + Map metaFields, String chunkMethod, + Map parserConfig) { if (StringUtils.isBlank(datasetId) || file == null || file.isEmpty()) { throw new RenException(ErrorCode.PARAMS_GET_ERROR); } @@ -464,16 +469,16 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { String fileName = file.getOriginalFilename(); String fileType = getFileType(fileName); long fileSize = file.getSize(); - - log.info("文件信息 - 文件名: {}, 文件类型: {}, 文件大小: {} bytes", + + log.info("文件信息 - 文件名: {}, 文件类型: {}, 文件大小: {} bytes", fileName, fileType, fileSize); - + // 检查文件基本信息 if (StringUtils.isBlank(fileName)) { log.error("文件名为空"); throw new RenException(ErrorCode.PARAMS_GET_ERROR, "文件名不能为空"); } - + if (fileSize == 0) { log.error("文件大小为0"); throw new RenException(ErrorCode.PARAMS_GET_ERROR, "文件内容为空"); @@ -482,7 +487,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { log.info("2. 开始流式上传到RAGFlow"); // 直接调用RAGFlow API上传文档 - 使用流式上传 String documentId = uploadDocumentToRAGFlow(datasetId, file, name, metaFields, chunkMethod, parserConfig); - + log.info("文档上传成功,documentId: {}", documentId); // 返回上传的文档信息 @@ -496,7 +501,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { result.setStatus(1); // 上传成功,设置为处理中状态 return result; - + } catch (Exception e) { log.error("文档上传失败: {}", e.getMessage()); log.error("文档上传失败详细异常: ", e); @@ -509,7 +514,6 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { } } - @Override public void deleteByDocumentId(String documentId, String datasetId) { if (StringUtils.isBlank(documentId) || StringUtils.isBlank(datasetId)) { @@ -542,46 +546,46 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { log.warn("文件名为空,返回unknown类型"); return "unknown"; } - + try { int lastDotIndex = fileName.lastIndexOf('.'); if (lastDotIndex > 0 && lastDotIndex < fileName.length() - 1) { String extension = fileName.substring(lastDotIndex + 1).toLowerCase(); - + // 支持RAGFlow四种文档格式类型 - String[] documentTypes = {"pdf", "doc", "docx", "txt", "md", "mdx"}; - String[] spreadsheetTypes = {"csv", "xls", "xlsx"}; - String[] imageTypes = {"jpeg", "jpg", "png", "tif", "gif"}; - String[] presentationTypes = {"ppt", "pptx"}; - + String[] documentTypes = { "pdf", "doc", "docx", "txt", "md", "mdx" }; + String[] spreadsheetTypes = { "csv", "xls", "xlsx" }; + String[] imageTypes = { "jpeg", "jpg", "png", "tif", "gif" }; + String[] presentationTypes = { "ppt", "pptx" }; + // 检查文档类型 for (String type : documentTypes) { if (type.equals(extension)) { return "document"; } } - + // 检查表格类型 for (String type : spreadsheetTypes) { if (type.equals(extension)) { return "spreadsheet"; } } - + // 检查图片类型 for (String type : imageTypes) { if (type.equals(extension)) { return "image"; } } - + // 检查幻灯片类型 for (String type : presentationTypes) { if (type.equals(extension)) { return "presentation"; } } - + // 返回原始扩展名作为文件类型 return extension; } @@ -597,53 +601,53 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { if (StringUtils.isBlank(ragModelId)) { throw new RenException(ErrorCode.PARAMS_GET_ERROR); } - + // 从缓存获取模型配置 ModelConfigEntity modelConfig = modelConfigService.getModelByIdFromCache(ragModelId); if (modelConfig == null || modelConfig.getConfigJson() == null) { throw new RenException(ErrorCode.RAG_CONFIG_NOT_FOUND); } - + // 验证是否为RAG类型配置 if (!Constant.RAG_CONFIG_TYPE.equals(modelConfig.getModelType().toUpperCase())) { throw new RenException(ErrorCode.RAG_CONFIG_TYPE_ERROR); } - + Map config = modelConfig.getConfigJson(); - + // 验证必要的配置参数 validateRagConfig(config); - + // 返回配置信息 return config; } - + @Override public Map getDefaultRAGConfig() { // 获取默认RAG模型配置 QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("model_type", Constant.RAG_CONFIG_TYPE) - .eq("is_default", 1) - .eq("is_enabled", 1); + .eq("is_default", 1) + .eq("is_enabled", 1); List modelConfigs = modelConfigDao.selectList(queryWrapper); if (modelConfigs == null || modelConfigs.isEmpty()) { throw new RenException(ErrorCode.RAG_DEFAULT_CONFIG_NOT_FOUND); } - + ModelConfigEntity defaultConfig = modelConfigs.get(0); if (defaultConfig.getConfigJson() == null) { throw new RenException(ErrorCode.RAG_CONFIG_NOT_FOUND); } - + Map config = defaultConfig.getConfigJson(); - + // 验证必要的配置参数 validateRagConfig(config); - + return config; } - + /** * 验证RAG配置中是否包含必要的参数 */ @@ -651,11 +655,11 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { if (config == null) { throw new RenException(ErrorCode.RAG_CONFIG_NOT_FOUND); } - + // 从配置中提取必要的参数 String baseUrl = (String) config.get("base_url"); String apiKey = (String) config.get("api_key"); - + // 验证base_url是否存在且非空 if (StringUtils.isBlank(baseUrl)) { throw new RenException(ErrorCode.RAG_CONFIG_MISSING_PARAMS); @@ -665,38 +669,38 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { /** * 调用RAGFlow API上传文档 - 流式上传版本 */ - private String uploadDocumentToRAGFlow(String datasetId, MultipartFile file, String name, - Map metaFields, String chunkMethod, - Map parserConfig) { + private String uploadDocumentToRAGFlow(String datasetId, MultipartFile file, String name, + Map metaFields, String chunkMethod, + Map parserConfig) { try { // 获取RAG配置 Map ragConfig = getDefaultRAGConfig(); String baseUrl = (String) ragConfig.get("base_url"); String apiKey = (String) ragConfig.get("api_key"); - + log.info("开始调用RAGFlow API流式上传文档,datasetId: {}, 文件名: {}", datasetId, file.getOriginalFilename()); log.debug("RAGFlow配置 - baseUrl: {}, apiKey: {}", baseUrl, StringUtils.isBlank(apiKey) ? "未配置" : "已配置"); - + // 构建请求URL String url = baseUrl + "/api/v1/datasets/" + datasetId + "/documents"; log.debug("请求URL: {}", url); - + // 构建multipart/form-data请求 HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA); headers.set("Authorization", "Bearer " + apiKey); - + // 创建多部分请求体 - 使用MultipartFileResource进行流式上传 MultiValueMap body = new LinkedMultiValueMap<>(); body.add("file", new MultipartFileResource(file, file.getOriginalFilename())); - + // 添加其他参数 if (StringUtils.isNotBlank(name)) { body.add("name", name); } else { body.add("name", file.getOriginalFilename()); } - + if (metaFields != null && !metaFields.isEmpty()) { try { body.add("meta_fields", objectMapper.writeValueAsString(metaFields)); @@ -704,11 +708,11 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { log.warn("序列化meta_fields失败: {}", e.getMessage()); } } - + if (StringUtils.isNotBlank(chunkMethod)) { body.add("chunk_method", chunkMethod); } - + if (parserConfig != null && !parserConfig.isEmpty()) { try { body.add("parser_config", objectMapper.writeValueAsString(parserConfig)); @@ -716,49 +720,49 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { log.warn("序列化parser_config失败: {}", e.getMessage()); } } - + log.debug("multipart请求体参数数量: {}", body.size()); log.debug("multipart请求体参数: {}", body.keySet()); - + HttpEntity> requestEntity = new HttpEntity<>(body, headers); - + // 发送POST请求 log.info("发送multipart/form-data POST请求到RAGFlow API..."); ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class); - + log.info("RAGFlow API响应状态码: {}", response.getStatusCode()); log.debug("RAGFlow API响应内容: {}", response.getBody()); - + String responseBody = response.getBody(); String documentId = null; - + if (response.getStatusCode().is2xxSuccessful()) { try { Map responseMap = objectMapper.readValue(responseBody, Map.class); - + log.debug("RAGFlow API响应解析结果: {}", responseMap); - + // 首先检查响应码 Integer code = (Integer) responseMap.get("code"); if (code != null && code == 0) { // 响应码为0表示成功,从data字段中获取documentId Object dataObj = responseMap.get("data"); - + // 增强的documentId提取逻辑 documentId = extractDocumentIdFromResponse(dataObj); - + // 如果从data字段无法提取,尝试从根级别提取 if (StringUtils.isBlank(documentId)) { documentId = extractDocumentIdFromRoot(responseMap); } - + log.info("文档上传成功,documentId: {}", documentId); } else { // 如果响应码不为0,说明API调用失败 log.error("RAGFlow API调用失败,响应码: {}, 响应内容: {}", code, responseBody); throw new RenException(ErrorCode.RAG_API_CREATE_FAILED, "RAGFlow API调用失败,响应码: " + code); } - + log.info("从RAGFlow API响应中解析出documentId: {}", documentId); log.debug("完整响应内容: {}", responseBody); } catch (Exception e) { @@ -769,23 +773,25 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { log.error("RAGFlow API调用失败,状态码: {}, 响应内容: {}", response.getStatusCode(), responseBody); throw new RenException(ErrorCode.RAG_API_CREATE_FAILED); } - + if (StringUtils.isBlank(documentId)) { log.error("无法从RAGFlow API响应中获取documentId,响应内容: {}", responseBody); throw new RenException(ErrorCode.RAG_API_CREATE_FAILED, "RAGFlow API响应中未包含documentId"); } - + log.info("RAGFlow文档上传成功,documentId: {},文档已开始自动解析切片", documentId); return documentId; - + } catch (HttpClientErrorException e) { - log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}", - e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); - throw new RenException(ErrorCode.RAG_API_CREATE_FAILED, "上传RAGFlow文档失败: " + e.getMessage() + ", 响应: " + e.getResponseBodyAsString()); + log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}", + e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); + throw new RenException(ErrorCode.RAG_API_CREATE_FAILED, + "上传RAGFlow文档失败: " + e.getMessage() + ", 响应: " + e.getResponseBodyAsString()); } catch (HttpServerErrorException e) { - log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}", - e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); - throw new RenException(ErrorCode.RAG_API_CREATE_FAILED, "上传RAGFlow文档失败: " + e.getMessage() + ", 响应: " + e.getResponseBodyAsString()); + log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}", + e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); + throw new RenException(ErrorCode.RAG_API_CREATE_FAILED, + "上传RAGFlow文档失败: " + e.getMessage() + ", 响应: " + e.getResponseBodyAsString()); } catch (ResourceAccessException e) { log.error("RAGFlow API调用失败 - 网络连接错误: {}", e.getMessage(), e); throw new RenException(ErrorCode.RAG_API_CREATE_FAILED, "上传RAGFlow文档失败: 网络连接错误 - " + e.getMessage()); @@ -794,13 +800,13 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { throw new RenException(ErrorCode.RAG_API_CREATE_FAILED, "上传RAGFlow文档失败: " + e.getMessage()); } } - + /** * 从响应数据中提取documentId */ private String extractDocumentIdFromResponse(Object dataObj) { String documentId = null; - + if (dataObj instanceof List) { // data是一个数组,取第一个元素的id字段 List> dataList = (List>) dataObj; @@ -813,67 +819,69 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { Map dataMap = (Map) dataObj; documentId = extractDocumentIdFromMap(dataMap); } - + return documentId; } - + /** * 从Map中提取documentId,支持多种可能的字段名 */ private String extractDocumentIdFromMap(Map map) { - if (map == null) return null; - + if (map == null) + return null; + // 尝试多种可能的字段名 - String[] possibleFieldNames = {"id", "document_id", "documentId", "doc_id", "documentId"}; - + String[] possibleFieldNames = { "id", "document_id", "documentId", "doc_id", "documentId" }; + for (String fieldName : possibleFieldNames) { Object value = map.get(fieldName); if (value != null && value instanceof String && StringUtils.isNotBlank((String) value)) { return (String) value; } } - + return null; } - + /** * 从根级别响应中提取documentId */ private String extractDocumentIdFromRoot(Map responseMap) { - if (responseMap == null) return null; - + if (responseMap == null) + return null; + // 尝试从根级别提取 - String[] possibleFieldNames = {"id", "document_id", "documentId", "doc_id", "documentId"}; - + String[] possibleFieldNames = { "id", "document_id", "documentId", "doc_id", "documentId" }; + for (String fieldName : possibleFieldNames) { Object value = responseMap.get(fieldName); if (value != null && value instanceof String && StringUtils.isNotBlank((String) value)) { return (String) value; } } - + return null; } /** * 调用RAGFlow API更新文档配置 */ - private void updateDocumentInRAGFlow(String documentId, String name, Map metaFields, - String chunkMethod, Map parserConfig) { + private void updateDocumentInRAGFlow(String documentId, String name, Map metaFields, + String chunkMethod, Map parserConfig) { try { // 获取RAG配置 Map ragConfig = getDefaultRAGConfig(); String baseUrl = (String) ragConfig.get("base_url"); String apiKey = (String) ragConfig.get("api_key"); - + log.info("开始调用RAGFlow API更新文档配置,documentId: {}, name: {}", documentId, name); log.debug("RAGFlow配置 - baseUrl: {}, apiKey: {}", baseUrl, StringUtils.isBlank(apiKey) ? "未配置" : "已配置"); - + // 构建请求URL - 根据RAGFlow API规范,更新文档需要datasetId,但这里假设documentId足够 // 如果更新失败,可能需要调整URL格式 String url = baseUrl + "/api/v1/documents/" + documentId; log.debug("请求URL: {}", url); - + // 构建请求体 Map requestBody = new HashMap<>(); requestBody.put("document_id", documentId); @@ -889,38 +897,40 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { if (parserConfig != null && !parserConfig.isEmpty()) { requestBody.put("parser_config", parserConfig); } - + log.debug("请求体: {}", requestBody); - + // 设置请求头 HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.set("Authorization", "Bearer " + apiKey); - + HttpEntity> requestEntity = new HttpEntity<>(requestBody, headers); - + // 发送PUT请求 log.info("发送PUT请求到RAGFlow API..."); ResponseEntity response = restTemplate.exchange(url, HttpMethod.PUT, requestEntity, String.class); - + log.info("RAGFlow API响应状态码: {}", response.getStatusCode()); log.debug("RAGFlow API响应内容: {}", response.getBody()); - + if (!response.getStatusCode().is2xxSuccessful()) { log.error("RAGFlow API调用失败,状态码: {}, 响应内容: {}", response.getStatusCode(), response.getBody()); throw new RenException(ErrorCode.RAG_API_UPDATE_FAILED); } - + log.info("RAGFlow文档配置更新成功,documentId: {}", documentId); - + } catch (HttpClientErrorException e) { - log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}", - e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); - throw new RenException(ErrorCode.RAG_API_UPDATE_FAILED, "更新RAGFlow文档配置失败: " + e.getMessage() + ", 响应: " + e.getResponseBodyAsString()); + log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}", + e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); + throw new RenException(ErrorCode.RAG_API_UPDATE_FAILED, + "更新RAGFlow文档配置失败: " + e.getMessage() + ", 响应: " + e.getResponseBodyAsString()); } catch (HttpServerErrorException e) { - log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}", - e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); - throw new RenException(ErrorCode.RAG_API_UPDATE_FAILED, "更新RAGFlow文档配置失败: " + e.getMessage() + ", 响应: " + e.getResponseBodyAsString()); + log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}", + e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); + throw new RenException(ErrorCode.RAG_API_UPDATE_FAILED, + "更新RAGFlow文档配置失败: " + e.getMessage() + ", 响应: " + e.getResponseBodyAsString()); } catch (ResourceAccessException e) { log.error("RAGFlow API调用失败 - 网络连接错误: {}", e.getMessage(), e); throw new RenException(ErrorCode.RAG_API_UPDATE_FAILED, "更新RAGFlow文档配置失败: 网络连接错误 - " + e.getMessage()); @@ -939,42 +949,43 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { Map ragConfig = getDefaultRAGConfig(); String baseUrl = (String) ragConfig.get("base_url"); String apiKey = (String) ragConfig.get("api_key"); - + log.info("开始调用RAGFlow API删除文档,documentId: {}, datasetId: {}", documentId, datasetId); log.debug("RAGFlow配置 - baseUrl: {}, apiKey: {}", baseUrl, StringUtils.isBlank(apiKey) ? "未配置" : "已配置"); - + // 构建请求URL - 根据RAGFlow API文档,使用正确的路径参数名称 String url = baseUrl + "/api/v1/datasets/" + datasetId + "/documents"; log.debug("请求URL: {}", url); - + // 构建请求体 - 严格按照API文档格式 Map requestBody = new HashMap<>(); requestBody.put("ids", Arrays.asList(documentId)); // 使用Arrays.asList确保序列化正确 log.debug("请求体: {}", requestBody); - + // 设置请求头 HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.set("Authorization", "Bearer " + apiKey); - + HttpEntity> requestEntity = new HttpEntity<>(requestBody, headers); - + // 发送DELETE请求 log.info("发送DELETE请求到RAGFlow API..."); - ResponseEntity response = restTemplate.exchange(url, HttpMethod.DELETE, requestEntity, String.class); - + ResponseEntity response = restTemplate.exchange(url, HttpMethod.DELETE, requestEntity, + String.class); + log.info("RAGFlow API响应状态码: {}", response.getStatusCode()); log.debug("RAGFlow API响应内容: {}", response.getBody()); - + String responseBody = response.getBody(); - + if (response.getStatusCode().is2xxSuccessful()) { // 验证响应格式 if (responseBody != null) { try { Map responseMap = objectMapper.readValue(responseBody, Map.class); Integer code = (Integer) responseMap.get("code"); - + if (code != null && code == 0) { log.info("RAGFlow文档删除成功,documentId: {}", documentId); return; @@ -996,15 +1007,17 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { log.error("RAGFlow API调用失败,状态码: {}, 响应内容: {}", response.getStatusCode(), responseBody); throw new RenException(ErrorCode.RAG_API_DELETE_FAILED); } - + } catch (HttpClientErrorException e) { - log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}", - e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); - throw new RenException(ErrorCode.RAG_API_DELETE_FAILED, "删除RAGFlow文档失败: " + e.getMessage() + ", 响应: " + e.getResponseBodyAsString()); + log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}", + e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); + throw new RenException(ErrorCode.RAG_API_DELETE_FAILED, + "删除RAGFlow文档失败: " + e.getMessage() + ", 响应: " + e.getResponseBodyAsString()); } catch (HttpServerErrorException e) { - log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}", - e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); - throw new RenException(ErrorCode.RAG_API_DELETE_FAILED, "删除RAGFlow文档失败: " + e.getMessage() + ", 响应: " + e.getResponseBodyAsString()); + log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}", + e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); + throw new RenException(ErrorCode.RAG_API_DELETE_FAILED, + "删除RAGFlow文档失败: " + e.getMessage() + ", 响应: " + e.getResponseBodyAsString()); } catch (ResourceAccessException e) { log.error("RAGFlow API调用失败 - 网络连接错误: {}", e.getMessage(), e); throw new RenException(ErrorCode.RAG_API_DELETE_FAILED, "删除RAGFlow文档失败: 网络连接错误 - " + e.getMessage()); @@ -1020,32 +1033,32 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { private static class MultipartFileResource extends AbstractResource { private final MultipartFile multipartFile; private final String filename; - + public MultipartFileResource(MultipartFile multipartFile, String filename) { this.multipartFile = multipartFile; this.filename = filename; } - + @Override public String getFilename() { return this.filename; } - + @Override public InputStream getInputStream() throws IOException { return this.multipartFile.getInputStream(); } - + @Override public long contentLength() throws IOException { return this.multipartFile.getSize(); } - + @Override public boolean exists() { return true; } - + @Override public String getDescription() { return "MultipartFile resource for " + this.filename; @@ -1100,7 +1113,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { // 解析响应 Map responseMap = objectMapper.readValue(responseBody, Map.class); Integer code = (Integer) responseMap.get("code"); - + if (code != null && code == 0) { log.info("文档解析成功,datasetId: {}, documentIds: {}", datasetId, documentIds); return true; @@ -1114,12 +1127,12 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { log.error("解析RAGFlow API响应失败: {}", e.getMessage(), e); throw new RenException(ErrorCode.RAG_API_PARSE_FAILED, "解析RAGFlow响应失败: " + e.getMessage()); } catch (HttpClientErrorException e) { - log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}", - e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); + log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}", + e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); throw new RenException(ErrorCode.RAG_API_PARSE_FAILED, "解析RAGFlow文档失败: " + e.getMessage()); } catch (HttpServerErrorException e) { - log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}", - e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); + log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}", + e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); throw new RenException(ErrorCode.RAG_API_PARSE_FAILED, "解析RAGFlow文档失败: " + e.getMessage()); } catch (ResourceAccessException e) { log.error("RAGFlow API调用失败 - 网络连接错误: {}", e.getMessage(), e); @@ -1133,8 +1146,8 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { } @Override - public Map addChunk(String datasetId, String documentId, String content, - List importantKeywords, List questions) { + public Map addChunk(String datasetId, String documentId, String content, + List importantKeywords, List questions) { if (StringUtils.isBlank(datasetId) || StringUtils.isBlank(documentId) || StringUtils.isBlank(content)) { throw new RenException(ErrorCode.PARAMS_GET_ERROR, "datasetId、documentId和content不能为空"); } @@ -1155,15 +1168,15 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { // 构建请求体 Map requestBody = new HashMap<>(); requestBody.put("content", content); - + if (importantKeywords != null && !importantKeywords.isEmpty()) { requestBody.put("important_keywords", importantKeywords); } - + if (questions != null && !questions.isEmpty()) { requestBody.put("questions", questions); } - + log.debug("请求体: {}", requestBody); // 设置请求头 @@ -1190,7 +1203,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { // 解析响应 Map responseMap = objectMapper.readValue(responseBody, Map.class); Integer code = (Integer) responseMap.get("code"); - + if (code != null && code == 0) { log.info("切片添加成功,datasetId: {}, documentId: {}", datasetId, documentId); return responseMap; @@ -1204,12 +1217,12 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { log.error("解析RAGFlow API响应失败: {}", e.getMessage(), e); throw new RenException(ErrorCode.RAG_API_OPERATION_FAILED, "解析RAGFlow响应失败: " + e.getMessage()); } catch (HttpClientErrorException e) { - log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}", - e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); + log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}", + e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); throw new RenException(ErrorCode.RAG_API_OPERATION_FAILED, "添加切片失败: " + e.getMessage()); } catch (HttpServerErrorException e) { - log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}", - e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); + log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}", + e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); throw new RenException(ErrorCode.RAG_API_OPERATION_FAILED, "添加切片失败: " + e.getMessage()); } catch (ResourceAccessException e) { log.error("RAGFlow API调用失败 - 网络连接错误: {}", e.getMessage(), e); @@ -1223,14 +1236,14 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { } @Override - public Map listChunks(String datasetId, String documentId, String keywords, - Integer page, Integer pageSize, String chunkId) { + public Map listChunks(String datasetId, String documentId, String keywords, + Integer page, Integer pageSize, String chunkId) { if (StringUtils.isBlank(datasetId) || StringUtils.isBlank(documentId)) { throw new RenException(ErrorCode.PARAMS_GET_ERROR, "datasetId和documentId不能为空"); } log.info("=== 开始列出切片 ==="); - log.info("datasetId: {}, documentId: {}, keywords: {}, page: {}, pageSize: {}, chunkId: {}", + log.info("datasetId: {}, documentId: {}, keywords: {}, page: {}, pageSize: {}, chunkId: {}", datasetId, documentId, keywords, page, pageSize, chunkId); try { @@ -1242,31 +1255,31 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { // 构建请求URL - 根据RAGFlow API文档,列出切片的接口 StringBuilder urlBuilder = new StringBuilder(); urlBuilder.append(baseUrl).append("/api/v1/datasets/").append(datasetId) - .append("/documents/").append(documentId).append("/chunks"); - + .append("/documents/").append(documentId).append("/chunks"); + // 添加查询参数 List params = new ArrayList<>(); - + if (StringUtils.isNotBlank(keywords)) { params.add("keywords=" + keywords); } - + if (page != null && page > 0) { params.add("page=" + page); } - + if (pageSize != null && pageSize > 0) { params.add("page_size=" + pageSize); } - + if (StringUtils.isNotBlank(chunkId)) { params.add("id=" + chunkId); } - + if (!params.isEmpty()) { urlBuilder.append("?").append(String.join("&", params)); } - + String url = urlBuilder.toString(); log.debug("请求URL: {}", url); @@ -1294,10 +1307,10 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { // 解析响应 Map responseMap = objectMapper.readValue(responseBody, Map.class); Integer code = (Integer) responseMap.get("code"); - + if (code != null && code == 0) { log.info("切片列表获取成功,datasetId: {}, documentId: {}", datasetId, documentId); - + // 解析切片数据并格式化返回 return parseChunkListResponse(responseMap); } else { @@ -1310,12 +1323,12 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { log.error("解析RAGFlow API响应失败: {}", e.getMessage(), e); throw new RenException(ErrorCode.RAG_API_OPERATION_FAILED, "解析RAGFlow响应失败: " + e.getMessage()); } catch (HttpClientErrorException e) { - log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}", - e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); + log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}", + e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); throw new RenException(ErrorCode.RAG_API_OPERATION_FAILED, "列出切片失败: " + e.getMessage()); } catch (HttpServerErrorException e) { - log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}", - e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); + log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}", + e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); throw new RenException(ErrorCode.RAG_API_OPERATION_FAILED, "列出切片失败: " + e.getMessage()); } catch (ResourceAccessException e) { log.error("RAGFlow API调用失败 - 网络连接错误: {}", e.getMessage(), e); @@ -1341,13 +1354,13 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { Object dataObj = responseMap.get("data"); if (dataObj instanceof Map) { Map dataMap = (Map) dataObj; - + // 解析切片列表 - 支持多种可能的字段名 Object chunksObj = null; - + // 支持多种可能的切片列表字段名 - String[] possibleChunkFields = {"chunks", "items", "list", "data", "docs"}; - + String[] possibleChunkFields = { "chunks", "items", "list", "data", "docs" }; + for (String fieldName : possibleChunkFields) { if (dataMap.containsKey(fieldName) && dataMap.get(fieldName) instanceof List) { chunksObj = dataMap.get(fieldName); @@ -1355,7 +1368,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { break; } } - + // 如果标准字段不存在,尝试自动检测 if (chunksObj == null) { for (Map.Entry entry : dataMap.entrySet()) { @@ -1369,10 +1382,10 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { } } } - + if (chunksObj instanceof List) { List> rawChunkList = (List>) chunksObj; - + for (Map chunkMap : rawChunkList) { Map formattedChunk = formatChunkData(chunkMap); if (formattedChunk != null) { @@ -1380,11 +1393,11 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { } } } - + // 解析总数 - 支持多种可能的字段名 Object totalObj = null; - String[] possibleTotalFields = {"total", "totalCount", "total_count", "count"}; - + String[] possibleTotalFields = { "total", "totalCount", "total_count", "count" }; + for (String fieldName : possibleTotalFields) { if (dataMap.containsKey(fieldName)) { totalObj = dataMap.get(fieldName); @@ -1392,7 +1405,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { break; } } - + if (totalObj instanceof Integer) { totalCount = ((Integer) totalObj).longValue(); } else if (totalObj instanceof Long) { @@ -1404,18 +1417,18 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { log.warn("无法解析总数字段: {}", totalObj); } } - + // 如果没有找到总数,使用切片列表的大小 if (totalCount == 0 && !chunkList.isEmpty()) { totalCount = chunkList.size(); } } else { log.warn("RAGFlow API响应缺少data字段,尝试直接解析响应"); - + // 如果没有data字段,尝试直接解析响应 Object chunksObj = null; - String[] possibleChunkFields = {"chunks", "items", "list", "data", "docs"}; - + String[] possibleChunkFields = { "chunks", "items", "list", "data", "docs" }; + for (String fieldName : possibleChunkFields) { if (responseMap.containsKey(fieldName) && responseMap.get(fieldName) instanceof List) { chunksObj = responseMap.get(fieldName); @@ -1423,10 +1436,10 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { break; } } - + if (chunksObj instanceof List) { List> rawChunkList = (List>) chunksObj; - + for (Map chunkMap : rawChunkList) { Map formattedChunk = formatChunkData(chunkMap); if (formattedChunk != null) { @@ -1434,7 +1447,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { } } } - + // 解析总数 Object totalObj = responseMap.get("total"); if (totalObj instanceof Integer) { @@ -1442,19 +1455,19 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { } else if (totalObj instanceof Long) { totalCount = (Long) totalObj; } - + if (totalCount == 0 && !chunkList.isEmpty()) { totalCount = chunkList.size(); } } - + } catch (Exception e) { log.error("解析切片列表响应失败: {}", e.getMessage(), e); } - + result.put("list", chunkList); result.put("total", totalCount); - + log.debug("解析后的切片列表: {} 条记录", chunkList.size()); return result; } @@ -1466,9 +1479,9 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { if (chunkMap == null || chunkMap.isEmpty()) { return null; } - + Map formattedChunk = new HashMap<>(); - + try { // 提取切片ID - 支持多种可能的字段名 String chunkId = extractChunkId(chunkMap); @@ -1477,28 +1490,28 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { return null; } formattedChunk.put("id", chunkId); - + // 提取切片内容 - 支持多种可能的字段名 String content = extractChunkContent(chunkMap); formattedChunk.put("content", content != null ? content : ""); - + // 提取重要关键词 - 支持多种可能的字段名 List importantKeywords = extractImportantKeywords(chunkMap); formattedChunk.put("important_keywords", importantKeywords); - + // 提取问题列表 - 支持多种可能的字段名 List questions = extractQuestions(chunkMap); formattedChunk.put("questions", questions); - + // 提取创建时间 - 支持多种可能的字段名 String createTime = extractCreateTime(chunkMap); formattedChunk.put("create_time", createTime != null ? createTime : ""); - + } catch (Exception e) { log.error("格式化切片数据失败: {}", e.getMessage(), e); return null; } - + return formattedChunk; } @@ -1506,15 +1519,15 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { * 提取切片ID */ private String extractChunkId(Map chunkMap) { - String[] possibleIdFields = {"id", "chunk_id", "chunkId", "chunkId"}; - + String[] possibleIdFields = { "id", "chunk_id", "chunkId", "chunkId" }; + for (String fieldName : possibleIdFields) { Object value = chunkMap.get(fieldName); if (value != null && value instanceof String && StringUtils.isNotBlank((String) value)) { return (String) value; } } - + return null; } @@ -1522,15 +1535,15 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { * 提取切片内容 */ private String extractChunkContent(Map chunkMap) { - String[] possibleContentFields = {"content", "text", "chunk_content", "chunkContent"}; - + String[] possibleContentFields = { "content", "text", "chunk_content", "chunkContent" }; + for (String fieldName : possibleContentFields) { Object value = chunkMap.get(fieldName); if (value != null && value instanceof String && StringUtils.isNotBlank((String) value)) { return (String) value; } } - + return null; } @@ -1538,8 +1551,8 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { * 提取重要关键词 */ private List extractImportantKeywords(Map chunkMap) { - String[] possibleKeywordFields = {"important_keywords", "keywords", "importantKeywords", "key_words"}; - + String[] possibleKeywordFields = { "important_keywords", "keywords", "importantKeywords", "key_words" }; + for (String fieldName : possibleKeywordFields) { Object value = chunkMap.get(fieldName); if (value instanceof List) { @@ -1564,7 +1577,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { return keywords; } } - + return new ArrayList<>(); } @@ -1572,8 +1585,8 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { * 提取问题列表 */ private List extractQuestions(Map chunkMap) { - String[] possibleQuestionFields = {"questions", "question_list", "questionList", "qas"}; - + String[] possibleQuestionFields = { "questions", "question_list", "questionList", "qas" }; + for (String fieldName : possibleQuestionFields) { Object value = chunkMap.get(fieldName); if (value instanceof List) { @@ -1598,7 +1611,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { return questions; } } - + return new ArrayList<>(); } @@ -1606,8 +1619,8 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { * 提取创建时间 */ private String extractCreateTime(Map chunkMap) { - String[] possibleTimeFields = {"create_time", "created_at", "createTime", "timestamp"}; - + String[] possibleTimeFields = { "create_time", "created_at", "createTime", "timestamp" }; + for (String fieldName : possibleTimeFields) { Object value = chunkMap.get(fieldName); if (value != null) { @@ -1619,19 +1632,19 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { } } } - + return null; } @Override - public Map retrievalTest(String question, List datasetIds, List documentIds, - Integer page, Integer pageSize, Float similarityThreshold, - Float vectorSimilarityWeight, Integer topK, String rerankId, - Boolean keyword, Boolean highlight, List crossLanguages, - Map metadataCondition) { - + public Map retrievalTest(String question, List datasetIds, List documentIds, + Integer page, Integer pageSize, Float similarityThreshold, + Float vectorSimilarityWeight, Integer topK, String rerankId, + Boolean keyword, Boolean highlight, List crossLanguages, + Map metadataCondition) { + log.info("=== 开始召回测试 ==="); - log.info("问题: {}, 数据集ID: {}, 文档ID: {}, 页码: {}, 每页数量: {}", + log.info("问题: {}, 数据集ID: {}, 文档ID: {}, 页码: {}, 每页数量: {}", question, datasetIds, documentIds, page, pageSize); try { @@ -1647,51 +1660,51 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { // 构建请求体 Map requestBody = new HashMap<>(); requestBody.put("question", question); - + if (datasetIds != null && !datasetIds.isEmpty()) { requestBody.put("dataset_ids", datasetIds); } - + if (documentIds != null && !documentIds.isEmpty()) { requestBody.put("document_ids", documentIds); } - + if (page != null && page > 0) { requestBody.put("page", page); } - + if (pageSize != null && pageSize > 0) { requestBody.put("page_size", pageSize); } - + if (similarityThreshold != null) { requestBody.put("similarity_threshold", similarityThreshold); } - + if (vectorSimilarityWeight != null) { requestBody.put("vector_similarity_weight", vectorSimilarityWeight); } - + if (topK != null && topK > 0) { requestBody.put("top_k", topK); } - + if (rerankId != null) { requestBody.put("rerank_id", rerankId); } - + if (keyword != null) { requestBody.put("keyword", keyword); } - + if (highlight != null) { requestBody.put("highlight", highlight); } - + if (crossLanguages != null && !crossLanguages.isEmpty()) { requestBody.put("cross_languages", crossLanguages); } - + if (metadataCondition != null) { requestBody.put("metadata_condition", metadataCondition); } @@ -1722,7 +1735,7 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { // 解析响应 Map responseMap = objectMapper.readValue(responseBody, Map.class); Integer code = (Integer) responseMap.get("code"); - + if (code != null && code == 0) { Object dataObj = responseMap.get("data"); if (dataObj instanceof Map) { @@ -1743,12 +1756,12 @@ public class KnowledgeFilesServiceImpl implements KnowledgeFilesService { log.error("解析RAGFlow API响应失败: {}", e.getMessage(), e); throw new RenException(ErrorCode.RAG_API_QUERY_FAILED, "解析RAGFlow响应失败: " + e.getMessage()); } catch (HttpClientErrorException e) { - log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}", - e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); + log.error("RAGFlow API调用失败 - HTTP错误: {}, 状态码: {}, 响应内容: {}", + e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); throw new RenException(ErrorCode.RAG_API_QUERY_FAILED, "召回测试失败: " + e.getMessage()); } catch (HttpServerErrorException e) { - log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}", - e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); + log.error("RAGFlow API调用失败 - 服务器错误: {}, 状态码: {}, 响应内容: {}", + e.getMessage(), e.getStatusCode(), e.getResponseBodyAsString(), e); throw new RenException(ErrorCode.RAG_API_QUERY_FAILED, "召回测试失败: " + e.getMessage()); } catch (ResourceAccessException e) { log.error("RAGFlow API调用失败 - 网络连接错误: {}", e.getMessage(), e); diff --git a/main/manager-web/src/apis/module/knowledgeBase.js b/main/manager-web/src/apis/module/knowledgeBase.js index 1e0bf728..72af7339 100644 --- a/main/manager-web/src/apis/module/knowledgeBase.js +++ b/main/manager-web/src/apis/module/knowledgeBase.js @@ -8,6 +8,54 @@ function getAuthToken() { return localStorage.getItem('token') || ''; } +/** + * 通用API请求包装器 + * @param {Object} config - 请求配置 + * @param {string} config.url - 请求URL + * @param {string} config.method - 请求方法 + * @param {Object} [config.data] - 请求数据 + * @param {Object} [config.headers] - 额外请求头 + * @param {Function} config.callback - 成功回调 + * @param {Function} [config.errorCallback] - 错误回调 + * @param {string} [config.errorMessage] - 错误消息 + * @param {Function} [config.retryFunction] - 重试函数 + */ +function makeApiRequest(config) { + const token = getAuthToken(); + const { url, method, data, headers, callback, errorCallback, errorMessage, retryFunction } = config; + + const requestBuilder = RequestService.sendRequest() + .url(url) + .method(method) + .header({ + 'Authorization': `Bearer ${token}`, + ...headers + }); + + if (data) { + requestBuilder.data(data); + } + + requestBuilder + .success((res) => { + RequestService.clearRequestTime(); + callback(res); + }) + .fail((err) => { + console.error(errorMessage || '操作失败', err); + if (errorCallback) { + errorCallback(err); + } + }) + .networkFail(() => { + if (retryFunction) { + RequestService.reAjaxFun(() => { + retryFunction(); + }); + } + }).send(); +} + /** * 知识库管理相关API */ @@ -19,33 +67,20 @@ export default { * @param {Function} errorCallback - 错误回调 */ getKnowledgeBaseList(params, callback, errorCallback) { - const token = getAuthToken(); const queryParams = new URLSearchParams({ page: params.page, page_size: params.page_size, name: params.name || '' }).toString(); - RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/datasets?${queryParams}`) - .method('GET') - .header({ 'Authorization': `Bearer ${token}` }) - .success((res) => { - RequestService.clearRequestTime(); - callback(res); - }) - .fail((err) => { - console.error('获取知识库列表失败:', err); - if (errorCallback) { - errorCallback(err); - } - }) - .networkFail(() => { - const self = this; - RequestService.reAjaxFun(() => { - self.getKnowledgeBaseList(params, callback, errorCallback); - }); - }).send(); + makeApiRequest({ + url: `${getServiceUrl()}/api/v1/datasets?${queryParams}`, + method: 'GET', + callback: callback, + errorCallback: errorCallback, + errorMessage: '获取知识库列表失败', + retryFunction: () => this.getKnowledgeBaseList(params, callback, errorCallback) + }); }, /** @@ -56,20 +91,18 @@ export default { */ createKnowledgeBase(data, callback, errorCallback) { console.log('createKnowledgeBase called with data:', data); - const token = getAuthToken(); - console.log('Token exists:', !!token); console.log('API URL:', `${getServiceUrl()}/api/v1/datasets`); - RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/datasets`) - .method('POST') - .data(data) - .header({ 'Authorization': `Bearer ${token}` }) - .success((res) => { + + makeApiRequest({ + url: `${getServiceUrl()}/api/v1/datasets`, + method: 'POST', + data: data, + headers: { 'Content-Type': 'application/json' }, + callback: (res) => { console.log('createKnowledgeBase success response:', res); - RequestService.clearRequestTime(); callback(res); - }) - .fail((err) => { + }, + errorCallback: (err) => { console.error('创建知识库失败:', err); if (err.response) { console.error('Error response data:', err.response.data); @@ -78,14 +111,10 @@ export default { if (errorCallback) { errorCallback(err); } - }) - .networkFail(() => { - console.log('Network failure, retrying...'); - const self = this; - RequestService.reAjaxFun(() => { - self.createKnowledgeBase(data, callback, errorCallback); - }); - }).send(); + }, + errorMessage: '创建知识库失败', + retryFunction: () => this.createKnowledgeBase(data, callback, errorCallback) + }); }, /** @@ -97,30 +126,18 @@ export default { */ updateKnowledgeBase(datasetId, data, callback, errorCallback) { console.log('updateKnowledgeBase called with datasetId:', datasetId, 'data:', data); - const token = getAuthToken(); - console.log('Token exists:', !!token); console.log('API URL:', `${getServiceUrl()}/api/v1/datasets/${datasetId}`); - RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/datasets/${datasetId}`) - .method('PUT') - .data(data) - .header({ 'Authorization': `Bearer ${token}` }) - .success((res) => { - RequestService.clearRequestTime(); - callback(res); - }) - .fail((err) => { - console.error('更新知识库失败:', err); - if (errorCallback) { - errorCallback(err); - } - }) - .networkFail(() => { - const self = this; - RequestService.reAjaxFun(() => { - self.updateKnowledgeBase(datasetId, data, callback, errorCallback); - }); - }).send(); + + makeApiRequest({ + url: `${getServiceUrl()}/api/v1/datasets/${datasetId}`, + method: 'PUT', + data: data, + headers: { 'Content-Type': 'application/json' }, + callback: callback, + errorCallback: errorCallback, + errorMessage: '更新知识库失败', + retryFunction: () => this.updateKnowledgeBase(datasetId, data, callback, errorCallback) + }); }, /** @@ -131,29 +148,16 @@ export default { */ deleteKnowledgeBase(datasetId, callback, errorCallback) { console.log('deleteKnowledgeBase called with datasetId:', datasetId); - const token = getAuthToken(); - console.log('Token exists:', !!token); console.log('API URL:', `${getServiceUrl()}/api/v1/datasets/${datasetId}`); - RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/datasets/${datasetId}`) - .method('DELETE') - .header({ 'Authorization': `Bearer ${token}` }) - .success((res) => { - RequestService.clearRequestTime(); - callback(res); - }) - .fail((err) => { - console.error('删除知识库失败:', err); - if (errorCallback) { - errorCallback(err); - } - }) - .networkFail(() => { - const self = this; - RequestService.reAjaxFun(() => { - self.deleteKnowledgeBase(datasetId, callback, errorCallback); - }); - }).send(); + + makeApiRequest({ + url: `${getServiceUrl()}/api/v1/datasets/${datasetId}`, + method: 'DELETE', + callback: callback, + errorCallback: errorCallback, + errorMessage: '删除知识库失败', + retryFunction: () => this.deleteKnowledgeBase(datasetId, callback, errorCallback) + }); }, /** @@ -163,29 +167,17 @@ export default { * @param {Function} errorCallback - 错误回调 */ deleteKnowledgeBases(ids, callback, errorCallback) { - const token = getAuthToken(); // 确保ids是正确格式的字符串 const idsStr = Array.isArray(ids) ? ids.join(',') : ids; - RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/datasets/batch?ids=${idsStr}`) - .method('DELETE') - .header({ 'Authorization': `Bearer ${token}` }) - .success((res) => { - RequestService.clearRequestTime(); - callback(res); - }) - .fail((err) => { - console.error('批量删除知识库失败:', err); - if (errorCallback) { - errorCallback(err); - } - }) - .networkFail(() => { - const self = this; - RequestService.reAjaxFun(() => { - self.deleteKnowledgeBases(ids, callback, errorCallback); - }); - }).send(); + + makeApiRequest({ + url: `${getServiceUrl()}/api/v1/datasets/batch?ids=${idsStr}`, + method: 'DELETE', + callback: callback, + errorCallback: errorCallback, + errorMessage: '批量删除知识库失败', + retryFunction: () => this.deleteKnowledgeBases(ids, callback, errorCallback) + }); }, /** @@ -196,33 +188,20 @@ export default { * @param {Function} errorCallback - 错误回调 */ getDocumentList(datasetId, params, callback, errorCallback) { - const token = getAuthToken(); const queryParams = new URLSearchParams({ page: params.page, page_size: params.page_size, name: params.name || '' }).toString(); - RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/datasets/${datasetId}/documents?${queryParams}`) - .method('GET') - .header({ 'Authorization': `Bearer ${token}` }) - .success((res) => { - RequestService.clearRequestTime(); - callback(res); - }) - .fail((err) => { - console.error('获取文档列表失败:', err); - if (errorCallback) { - errorCallback(err); - } - }) - .networkFail(() => { - const self = this; - RequestService.reAjaxFun(() => { - self.getDocumentList(datasetId, params, callback, errorCallback); - }); - }).send(); + makeApiRequest({ + url: `${getServiceUrl()}/api/v1/datasets/${datasetId}/documents?${queryParams}`, + method: 'GET', + callback: callback, + errorCallback: errorCallback, + errorMessage: '获取文档列表失败', + retryFunction: () => this.getDocumentList(datasetId, params, callback, errorCallback) + }); }, /** @@ -233,31 +212,16 @@ export default { * @param {Function} errorCallback - 错误回调 */ uploadDocument(datasetId, formData, callback, errorCallback) { - const token = getAuthToken(); - RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/datasets/${datasetId}/documents`) - .method('POST') - .data(formData) - .header({ - 'Authorization': `Bearer ${token}`, - 'Content-Type': 'multipart/form-data' - }) - .success((res) => { - RequestService.clearRequestTime(); - callback(res); - }) - .fail((err) => { - console.error('上传文档失败:', err); - if (errorCallback) { - errorCallback(err); - } - }) - .networkFail(() => { - const self = this; - RequestService.reAjaxFun(() => { - self.uploadDocument(datasetId, formData, callback, errorCallback); - }); - }).send(); + makeApiRequest({ + url: `${getServiceUrl()}/api/v1/datasets/${datasetId}/documents`, + method: 'POST', + data: formData, + headers: { 'Content-Type': 'multipart/form-data' }, + callback: callback, + errorCallback: errorCallback, + errorMessage: '上传文档失败', + retryFunction: () => this.uploadDocument(datasetId, formData, callback, errorCallback) + }); }, /** @@ -268,35 +232,20 @@ export default { * @param {Function} errorCallback - 错误回调 */ parseDocument(datasetId, documentId, callback, errorCallback) { - const token = getAuthToken(); const requestBody = { document_ids: [documentId] }; - - RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/datasets/${datasetId}/chunks`) - .method('POST') - .data(requestBody) - .header({ - 'Authorization': `Bearer ${token}`, - 'Content-Type': 'application/json' - }) - .success((res) => { - RequestService.clearRequestTime(); - callback(res); - }) - .fail((err) => { - console.error('解析文档失败:', err); - if (errorCallback) { - errorCallback(err); - } - }) - .networkFail(() => { - const self = this; - RequestService.reAjaxFun(() => { - self.parseDocument(datasetId, documentId, callback, errorCallback); - }); - }).send(); + + makeApiRequest({ + url: `${getServiceUrl()}/api/v1/datasets/${datasetId}/chunks`, + method: 'POST', + data: requestBody, + headers: { 'Content-Type': 'application/json' }, + callback: callback, + errorCallback: errorCallback, + errorMessage: '解析文档失败', + retryFunction: () => this.parseDocument(datasetId, documentId, callback, errorCallback) + }); }, /** @@ -307,27 +256,14 @@ export default { * @param {Function} errorCallback - 错误回调 */ deleteDocument(datasetId, documentId, callback, errorCallback) { - const token = getAuthToken(); - RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/datasets/${datasetId}/documents/${documentId}`) - .method('DELETE') - .header({ 'Authorization': `Bearer ${token}` }) - .success((res) => { - RequestService.clearRequestTime(); - callback(res); - }) - .fail((err) => { - console.error('删除文档失败:', err); - if (errorCallback) { - errorCallback(err); - } - }) - .networkFail(() => { - const self = this; - RequestService.reAjaxFun(() => { - self.deleteDocument(datasetId, documentId, callback, errorCallback); - }); - }).send(); + makeApiRequest({ + url: `${getServiceUrl()}/api/v1/datasets/${datasetId}/documents/${documentId}`, + method: 'DELETE', + callback: callback, + errorCallback: errorCallback, + errorMessage: '删除文档失败', + retryFunction: () => this.deleteDocument(datasetId, documentId, callback, errorCallback) + }); }, /** @@ -339,8 +275,7 @@ export default { * @param {Function} errorCallback - 错误回调 */ listChunks(datasetId, documentId, params, callback, errorCallback) { - const token = getAuthToken(); - const queryParams = new URLSearchParams({ + let queryParams = new URLSearchParams({ page: params.page || 1, page_size: params.page_size || 10 }).toString(); @@ -350,26 +285,14 @@ export default { queryParams += `&keywords=${encodeURIComponent(params.keywords)}`; } - RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/datasets/${datasetId}/documents/${documentId}/chunks?${queryParams}`) - .method('GET') - .header({ 'Authorization': `Bearer ${token}` }) - .success((res) => { - RequestService.clearRequestTime(); - callback(res); - }) - .fail((err) => { - console.error('获取切片列表失败:', err); - if (errorCallback) { - errorCallback(err); - } - }) - .networkFail(() => { - const self = this; - RequestService.reAjaxFun(() => { - self.listChunks(datasetId, documentId, params, callback, errorCallback); - }); - }).send(); + makeApiRequest({ + url: `${getServiceUrl()}/api/v1/datasets/${datasetId}/documents/${documentId}/chunks?${queryParams}`, + method: 'GET', + callback: callback, + errorCallback: errorCallback, + errorMessage: '获取切片列表失败', + retryFunction: () => this.listChunks(datasetId, documentId, params, callback, errorCallback) + }); }, /** @@ -381,28 +304,16 @@ export default { * @param {Function} errorCallback - 错误回调 */ addChunk(datasetId, documentId, data, callback, errorCallback) { - const token = getAuthToken(); - RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/datasets/${datasetId}/documents/${documentId}/chunks`) - .method('POST') - .data(data) - .header({ 'Authorization': `Bearer ${token}` }) - .success((res) => { - RequestService.clearRequestTime(); - callback(res); - }) - .fail((err) => { - console.error('添加切片失败:', err); - if (errorCallback) { - errorCallback(err); - } - }) - .networkFail(() => { - const self = this; - RequestService.reAjaxFun(() => { - self.addChunk(datasetId, documentId, data, callback, errorCallback); - }); - }).send(); + makeApiRequest({ + url: `${getServiceUrl()}/api/v1/datasets/${datasetId}/documents/${documentId}/chunks`, + method: 'POST', + data: data, + headers: { 'Content-Type': 'application/json' }, + callback: callback, + errorCallback: errorCallback, + errorMessage: '添加切片失败', + retryFunction: () => this.addChunk(datasetId, documentId, data, callback, errorCallback) + }); }, /** @@ -413,28 +324,16 @@ export default { * @param {Function} errorCallback - 错误回调 */ retrievalTest(datasetId, data, callback, errorCallback) { - const token = getAuthToken(); - RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/datasets/${datasetId}/retrieval-test`) - .method('POST') - .data(data) - .header({ 'Authorization': `Bearer ${token}` }) - .success((res) => { - RequestService.clearRequestTime(); - callback(res); - }) - .fail((err) => { - console.error('召回测试失败:', err); - if (errorCallback) { - errorCallback(err); - } - }) - .networkFail(() => { - const self = this; - RequestService.reAjaxFun(() => { - self.retrievalTest(datasetId, data, callback, errorCallback); - }); - }).send(); + makeApiRequest({ + url: `${getServiceUrl()}/api/v1/datasets/${datasetId}/retrieval-test`, + method: 'POST', + data: data, + headers: { 'Content-Type': 'application/json' }, + callback: callback, + errorCallback: errorCallback, + errorMessage: '召回测试失败', + retryFunction: () => this.retrievalTest(datasetId, data, callback, errorCallback) + }); } }; \ No newline at end of file diff --git a/main/manager-web/src/i18n/en.js b/main/manager-web/src/i18n/en.js index 9773105f..4326bf30 100644 --- a/main/manager-web/src/i18n/en.js +++ b/main/manager-web/src/i18n/en.js @@ -1206,7 +1206,7 @@ export default { 'knowledgeFileUpload.documentNamePlaceholder': 'Please enter document name', 'knowledgeFileUpload.file': 'File', 'knowledgeFileUpload.clickToUpload': 'Click to upload', - 'knowledgeFileUpload.uploadTip': 'Only pdf, doc, docx, txt files are supported, and file size should not exceed 10MB', + 'knowledgeFileUpload.uploadTip': 'Supported file types: PDF, DOC, DOCX, TXT, MD, CSV, XLS, XLSX, PPT, PPTX. Maximum 32 files per upload, each file size up to 10MB', 'knowledgeFileUpload.dragOrClick': 'Drag file here, or click to upload', 'knowledgeFileUpload.cancel': 'Cancel', 'knowledgeFileUpload.confirm': 'Confirm', diff --git a/main/manager-web/src/i18n/zh_CN.js b/main/manager-web/src/i18n/zh_CN.js index 0a2bcd9c..51c77f2b 100644 --- a/main/manager-web/src/i18n/zh_CN.js +++ b/main/manager-web/src/i18n/zh_CN.js @@ -1206,7 +1206,7 @@ export default { 'knowledgeFileUpload.documentNamePlaceholder': '请输入文档名称', 'knowledgeFileUpload.file': '文件', 'knowledgeFileUpload.clickToUpload': '点击上传', - 'knowledgeFileUpload.uploadTip': '只能上传pdf、doc、docx、txt文件,且不超过10MB', + 'knowledgeFileUpload.uploadTip': '支持的文档类型:PDF、DOC、DOCX、TXT、MD、CSV、XLS、XLSX、PPT、PPTX,单次批量上传文件数不超过 32 个', 'knowledgeFileUpload.dragOrClick': '将文件拖到此处,或点击上传', 'knowledgeFileUpload.cancel': '取消', 'knowledgeFileUpload.confirm': '确定', diff --git a/main/manager-web/src/i18n/zh_TW.js b/main/manager-web/src/i18n/zh_TW.js index fe21f386..d1c609e8 100644 --- a/main/manager-web/src/i18n/zh_TW.js +++ b/main/manager-web/src/i18n/zh_TW.js @@ -1206,7 +1206,7 @@ export default { 'knowledgeFileUpload.documentNamePlaceholder': '請輸入文檔名稱', 'knowledgeFileUpload.file': '文件', 'knowledgeFileUpload.clickToUpload': '點擊上傳', - 'knowledgeFileUpload.uploadTip': '只能上傳pdf、doc、docx、txt文件,且不超過10MB', + 'knowledgeFileUpload.uploadTip': '支持的文件類型:PDF、DOC、DOCX、TXT、MD、CSV、XLS、XLSX、PPT、PPTX,单次批量上傳文件數不超過 32 個,每個文件大小不超過 10MB', 'knowledgeFileUpload.dragOrClick': '將文件拖到此處,或點擊上傳', 'knowledgeFileUpload.cancel': '取消', 'knowledgeFileUpload.confirm': '確定', diff --git a/main/manager-web/src/views/KnowledgeBaseManagement.vue b/main/manager-web/src/views/KnowledgeBaseManagement.vue index b9df8119..d39d1f03 100644 --- a/main/manager-web/src/views/KnowledgeBaseManagement.vue +++ b/main/manager-web/src/views/KnowledgeBaseManagement.vue @@ -15,7 +15,7 @@
-
+