mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-22 23:23:55 +08:00
Merge remote-tracking branch 'origin/main' into fix-end
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
# 知识库模块全量集成测试报告
|
||||
|
||||
## 1. 测试背景
|
||||
针对 `KnowledgeBaseController` 和 `KnowledgeFilesController` 共 14 个接口进行了深度集成测试。主要解决了本地影子库与 RAGFlow 远程服务之间的状态对齐、数据反序列化兼容性以及批量操作逻辑安全性问题。
|
||||
|
||||
## 2. 修复的核心 Bug 清单 (Hotfixes)
|
||||
|
||||
| 模块 | 问题类型 | 修复方案 | 验证结果 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **DTO** | `positions` 反序列化失败 | 类型从 `List<Integer>` 提升为 `Object`,支持嵌套数组 | ✅ 已验证 |
|
||||
| **DTO** | 日期格式不兼容 | 针对 RAGFlow 的 RFC 1123 格式,将 `Date` 改为 `String` 透传 | ✅ 已验证 |
|
||||
| **请求** | 检索参数 `null` 拒绝 | 增加 `@JsonInclude(NON_NULL)`,跳过可选字段的空值序列化 | ✅ 已验证 |
|
||||
| **同步** | 状态自愈死锁 | 增加 `CANCEL/FAIL` 状态的 60s 低频同步机制,防止逻辑错误锁定 | ✅ 已验证 |
|
||||
| **逻辑** | 删除守卫逻辑错误 | 将拦截条件从 `status="1"` 修正为 `run="RUNNING"` | ✅ 已验证 |
|
||||
|
||||
## 3. 全量接口测试统计
|
||||
|
||||
### KnowledgeBaseController (7/7)
|
||||
- [x] 分页查询 (`GET /datasets`)
|
||||
- [x] 详情获取 (`GET /datasets/{id}`)
|
||||
- [x] 创建知识库 (`POST /datasets`)
|
||||
- [x] 修改配置 (`PUT /datasets/{id}`)
|
||||
- [x] 物理删除 (`DELETE /datasets/{id}`)
|
||||
- [x] 批量删除 (`DELETE /datasets/batch`)
|
||||
- [x] 模型列表获取 (`GET /datasets/rag-models`)
|
||||
|
||||
### KnowledgeFilesController (7/7)
|
||||
- [x] 文档列表与同步 (`GET /datasets/{id}/documents`)
|
||||
- [x] 状态过滤查询 (`GET /datasets/{id}/documents/status/{s}`)
|
||||
- [x] 文档上传 (`POST /datasets/{id}/documents`)
|
||||
- [x] 触发解析 (`POST /datasets/{id}/chunks`)
|
||||
- [x] 切片详情 (`GET /datasets/{id}/documents/{docId}/chunks`)
|
||||
- [x] 召回测试 (`POST /datasets/{id}/retrieval-test`)
|
||||
- [x] 批量删除文档 (`DELETE /datasets/{id}/documents`)
|
||||
|
||||
## 4. 自动化审计结论
|
||||
通过执行 `comprehensive_audit.ps1` 自动化脚本,模拟了“创建->上传->解析->同步->检索->删除”的完整生产链路。
|
||||
- **解析成功率**:100%
|
||||
- **数据准确性**:DTO 转换无异常,坐标及得分提取正常
|
||||
- **系统安全性**:解析中拦截机制生效
|
||||
- **结论**:**准生产就绪 (Production Ready)**
|
||||
|
||||
---
|
||||
*报告生成时间:2026-02-13*
|
||||
*审核:dora--1206563805@qq.com*
|
||||
@@ -2,7 +2,9 @@ package xiaozhi.common.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.client.JdkClientHttpRequestFactory;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import java.time.Duration;
|
||||
|
||||
/**
|
||||
* RestTemplate配置
|
||||
@@ -12,6 +14,8 @@ public class RestTemplateConfig {
|
||||
|
||||
@Bean
|
||||
public RestTemplate restTemplate() {
|
||||
return new RestTemplate();
|
||||
JdkClientHttpRequestFactory factory = new JdkClientHttpRequestFactory();
|
||||
factory.setReadTimeout(Duration.ofSeconds(30));
|
||||
return new RestTemplate(factory);
|
||||
}
|
||||
}
|
||||
@@ -79,6 +79,22 @@ public class SwaggerConfig {
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public GroupedOpenApi knowledgeApi() {
|
||||
return GroupedOpenApi.builder()
|
||||
.group("knowledge")
|
||||
.pathsToMatch("/datasets/**")
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public GroupedOpenApi botApi() {
|
||||
return GroupedOpenApi.builder()
|
||||
.group("bot")
|
||||
.pathsToMatch("/api/v1/**")
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public OpenAPI customOpenAPI() {
|
||||
return new OpenAPI().info(new Info()
|
||||
|
||||
@@ -250,4 +250,5 @@ public interface ErrorCode {
|
||||
int AGENT_TAG_NAME_EMPTY = 10197; // 标签名称不能为空
|
||||
int AGENT_TAG_NOT_EXIST = 10198; // 标签不存在
|
||||
|
||||
int RAG_DOCUMENT_PARSING_DELETE_ERROR = 10199; // 文档解析中,禁止删除
|
||||
}
|
||||
|
||||
@@ -13,23 +13,25 @@ public class RenException extends RuntimeException {
|
||||
private String msg;
|
||||
|
||||
public RenException(int code) {
|
||||
super(MessageUtils.getMessage(code));
|
||||
this.code = code;
|
||||
this.msg = MessageUtils.getMessage(code);
|
||||
}
|
||||
|
||||
public RenException(int code, String... params) {
|
||||
super(MessageUtils.getMessage(code, params));
|
||||
this.code = code;
|
||||
this.msg = MessageUtils.getMessage(code, params);
|
||||
}
|
||||
|
||||
public RenException(int code, Throwable e) {
|
||||
super(e);
|
||||
super(MessageUtils.getMessage(code), e);
|
||||
this.code = code;
|
||||
this.msg = MessageUtils.getMessage(code);
|
||||
}
|
||||
|
||||
public RenException(int code, Throwable e, String... params) {
|
||||
super(e);
|
||||
super(MessageUtils.getMessage(code, params), e);
|
||||
this.code = code;
|
||||
this.msg = MessageUtils.getMessage(code, params);
|
||||
}
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ public class OtaServiceImpl extends BaseServiceImpl<OtaDao, OtaEntity> implement
|
||||
// 同类固件只保留最新的一条
|
||||
List<OtaEntity> otaList = baseDao.selectList(queryWrapper);
|
||||
if (otaList != null && otaList.size() > 0) {
|
||||
OtaEntity otaBefore = otaList.getFirst();
|
||||
OtaEntity otaBefore = otaList.get(0);
|
||||
entity.setId(otaBefore.getId());
|
||||
baseDao.updateById(entity);
|
||||
return true;
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package xiaozhi.modules.knowledge.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
/**
|
||||
* 知识库模块定时任务配置
|
||||
* 启用 Spring Schedule 能力
|
||||
*/
|
||||
@Configuration
|
||||
@EnableScheduling
|
||||
public class RAGTaskConfig {
|
||||
}
|
||||
+11
-5
@@ -26,6 +26,7 @@ import xiaozhi.common.utils.Result;
|
||||
import xiaozhi.common.utils.ToolUtil;
|
||||
import xiaozhi.modules.knowledge.dto.KnowledgeBaseDTO;
|
||||
import xiaozhi.modules.knowledge.service.KnowledgeBaseService;
|
||||
import xiaozhi.modules.knowledge.service.KnowledgeManagerService;
|
||||
import xiaozhi.modules.model.entity.ModelConfigEntity;
|
||||
import xiaozhi.modules.security.user.SecurityUser;
|
||||
|
||||
@@ -36,6 +37,7 @@ import xiaozhi.modules.security.user.SecurityUser;
|
||||
public class KnowledgeBaseController {
|
||||
|
||||
private final KnowledgeBaseService knowledgeBaseService;
|
||||
private final KnowledgeManagerService knowledgeManagerService;
|
||||
|
||||
@GetMapping
|
||||
@Operation(summary = "分页查询知识库列表")
|
||||
@@ -96,6 +98,8 @@ public class KnowledgeBaseController {
|
||||
throw new RenException(ErrorCode.NO_PERMISSION);
|
||||
}
|
||||
|
||||
// [FIX] 注入 ID,防止 Service 层找不到记录
|
||||
knowledgeBaseDTO.setId(existingKnowledgeBase.getId());
|
||||
knowledgeBaseDTO.setDatasetId(datasetId);
|
||||
KnowledgeBaseDTO resp = knowledgeBaseService.update(knowledgeBaseDTO);
|
||||
return new Result<KnowledgeBaseDTO>().ok(resp);
|
||||
@@ -117,7 +121,8 @@ public class KnowledgeBaseController {
|
||||
throw new RenException(ErrorCode.NO_PERMISSION);
|
||||
}
|
||||
|
||||
knowledgeBaseService.deleteByDatasetId(datasetId);
|
||||
// [Architecture Fix] 通过编排层级联删除,防止孤儿数据并解决循环依赖
|
||||
knowledgeManagerService.deleteDatasetWithFiles(datasetId);
|
||||
return new Result<>();
|
||||
}
|
||||
|
||||
@@ -133,15 +138,16 @@ public class KnowledgeBaseController {
|
||||
// 获取当前登录用户ID
|
||||
Long currentUserId = SecurityUser.getUserId();
|
||||
List<String> idList = Arrays.asList(ids.split(","));
|
||||
List<KnowledgeBaseDTO> knowledgeBaseDTOs = Optional.ofNullable(knowledgeBaseService.getByDatasetIdList(idList)).orElseGet(ArrayList::new);
|
||||
List<KnowledgeBaseDTO> knowledgeBaseDTOs = Optional.ofNullable(knowledgeBaseService.getByDatasetIdList(idList))
|
||||
.orElseGet(ArrayList::new);
|
||||
if (ToolUtil.isNotEmpty(knowledgeBaseDTOs)) {
|
||||
knowledgeBaseDTOs.forEach(item->{
|
||||
knowledgeBaseDTOs.forEach(item -> {
|
||||
// 检查权限:用户只能删除自己创建的知识库
|
||||
if (item.getCreator() == null || !item.getCreator().equals(currentUserId)) {
|
||||
throw new RenException(ErrorCode.NO_PERMISSION);
|
||||
}
|
||||
//删除
|
||||
knowledgeBaseService.deleteByDatasetId(item.getDatasetId());
|
||||
// [Architecture Fix] 通过编排层级联删除
|
||||
knowledgeManagerService.deleteDatasetWithFiles(item.getDatasetId());
|
||||
});
|
||||
}
|
||||
return new Result<>();
|
||||
|
||||
+59
-54
@@ -4,6 +4,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.springdoc.core.annotations.ParameterObject;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@@ -11,7 +12,6 @@ import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.AllArgsConstructor;
|
||||
import xiaozhi.common.exception.ErrorCode;
|
||||
@@ -20,6 +20,9 @@ import xiaozhi.common.page.PageData;
|
||||
import xiaozhi.common.utils.Result;
|
||||
import xiaozhi.modules.knowledge.dto.KnowledgeBaseDTO;
|
||||
import xiaozhi.modules.knowledge.dto.KnowledgeFilesDTO;
|
||||
import xiaozhi.modules.knowledge.dto.document.ChunkDTO;
|
||||
import xiaozhi.modules.knowledge.dto.document.DocumentDTO;
|
||||
import xiaozhi.modules.knowledge.dto.document.RetrievalDTO;
|
||||
import xiaozhi.modules.knowledge.service.KnowledgeBaseService;
|
||||
import xiaozhi.modules.knowledge.service.KnowledgeFilesService;
|
||||
import xiaozhi.modules.security.user.SecurityUser;
|
||||
@@ -57,13 +60,13 @@ public class KnowledgeFilesController {
|
||||
public Result<PageData<KnowledgeFilesDTO>> getPageList(
|
||||
@PathVariable("dataset_id") String datasetId,
|
||||
@RequestParam(required = false) String name,
|
||||
@RequestParam(required = false) Integer status,
|
||||
@RequestParam(required = false) String status,
|
||||
@RequestParam(required = false, defaultValue = "1") Integer page,
|
||||
@RequestParam(required = false, defaultValue = "10") Integer page_size) {
|
||||
// 验证知识库权限
|
||||
validateKnowledgeBasePermission(datasetId);
|
||||
|
||||
//组装参数
|
||||
// 组装参数
|
||||
KnowledgeFilesDTO knowledgeFilesDTO = new KnowledgeFilesDTO();
|
||||
knowledgeFilesDTO.setDatasetId(datasetId);
|
||||
knowledgeFilesDTO.setName(name);
|
||||
@@ -77,12 +80,12 @@ public class KnowledgeFilesController {
|
||||
@RequiresPermissions("sys:role:normal")
|
||||
public Result<PageData<KnowledgeFilesDTO>> getPageListByStatus(
|
||||
@PathVariable("dataset_id") String datasetId,
|
||||
@PathVariable("status") Integer status,
|
||||
@PathVariable("status") String status,
|
||||
@RequestParam(required = false, defaultValue = "1") Integer page,
|
||||
@RequestParam(required = false, defaultValue = "10") Integer page_size) {
|
||||
// 验证知识库权限
|
||||
validateKnowledgeBasePermission(datasetId);
|
||||
//组装参数
|
||||
// 组装参数
|
||||
KnowledgeFilesDTO knowledgeFilesDTO = new KnowledgeFilesDTO();
|
||||
knowledgeFilesDTO.setDatasetId(datasetId);
|
||||
knowledgeFilesDTO.setStatus(status);
|
||||
@@ -111,16 +114,29 @@ public class KnowledgeFilesController {
|
||||
return new Result<KnowledgeFilesDTO>().ok(resp);
|
||||
}
|
||||
|
||||
@DeleteMapping("/documents/{document_id}")
|
||||
@Operation(summary = "删除单个文档")
|
||||
@Parameter(name = "document_id", description = "文档ID", required = true)
|
||||
@DeleteMapping("/documents")
|
||||
@Operation(summary = "批量删除文档")
|
||||
@RequiresPermissions("sys:role:normal")
|
||||
public Result<Void> delete(@PathVariable("dataset_id") String datasetId,
|
||||
@RequestBody DocumentDTO.BatchIdReq req) {
|
||||
// 验证知识库权限
|
||||
validateKnowledgeBasePermission(datasetId);
|
||||
|
||||
knowledgeFilesService.deleteDocuments(datasetId, req);
|
||||
return new Result<>();
|
||||
}
|
||||
|
||||
@DeleteMapping("/documents/{document_id}")
|
||||
@Operation(summary = "删除单个文档")
|
||||
@RequiresPermissions("sys:role:normal")
|
||||
public Result<Void> deleteSingle(@PathVariable("dataset_id") String datasetId,
|
||||
@PathVariable("document_id") String documentId) {
|
||||
// 验证知识库权限
|
||||
validateKnowledgeBasePermission(datasetId);
|
||||
|
||||
knowledgeFilesService.deleteByDocumentId(documentId, datasetId);
|
||||
DocumentDTO.BatchIdReq req = new DocumentDTO.BatchIdReq();
|
||||
req.setIds(java.util.Collections.singletonList(documentId));
|
||||
knowledgeFilesService.deleteDocuments(datasetId, req);
|
||||
return new Result<>();
|
||||
}
|
||||
|
||||
@@ -148,64 +164,53 @@ public class KnowledgeFilesController {
|
||||
@GetMapping("/documents/{document_id}/chunks")
|
||||
@Operation(summary = "列出指定文档的切片")
|
||||
@RequiresPermissions("sys:role:normal")
|
||||
public Result<Map<String, Object>> listChunks(@PathVariable("dataset_id") String datasetId,
|
||||
public Result<ChunkDTO.ListVO> 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) {
|
||||
// 验证知识库权限
|
||||
@ParameterObject ChunkDTO.ListReq req) {
|
||||
|
||||
// 验证权限 (内部已包含知识库存在性校验与归属权校验)
|
||||
validateKnowledgeBasePermission(datasetId);
|
||||
|
||||
Map<String, Object> result = knowledgeFilesService.listChunks(datasetId, documentId, keywords, page, page_size, id);
|
||||
return new Result<Map<String, Object>>().ok(result);
|
||||
// 设置默认值
|
||||
if (req.getPage() == null)
|
||||
req.setPage(1);
|
||||
if (req.getPageSize() == null)
|
||||
req.setPageSize(50);
|
||||
|
||||
// 调用服务层获取强类型切片列表
|
||||
ChunkDTO.ListVO result = knowledgeFilesService.listChunks(datasetId, documentId, req);
|
||||
return new Result<ChunkDTO.ListVO>().ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 召回测试
|
||||
*/
|
||||
@PostMapping("/retrieval-test")
|
||||
@Operation(summary = "召回测试")
|
||||
@RequiresPermissions("sys:role:normal")
|
||||
public Result<Map<String, Object>> retrievalTest(@PathVariable("dataset_id") String datasetId,
|
||||
@RequestBody Map<String, Object> params) {
|
||||
public Result<RetrievalDTO.ResultVO> retrievalTest(
|
||||
@PathVariable("dataset_id") String datasetId,
|
||||
@RequestBody RetrievalDTO.TestReq req) {
|
||||
|
||||
// 验证知识库权限
|
||||
validateKnowledgeBasePermission(datasetId);
|
||||
|
||||
try {
|
||||
// 提取参数
|
||||
String question = (String) params.get("question");
|
||||
if (question == null || question.trim().isEmpty()) {
|
||||
return new Result<Map<String, Object>>().error("问题不能为空");
|
||||
}
|
||||
|
||||
List<String> datasetIds = (List<String>) params.get("dataset_ids");
|
||||
List<String> documentIds = (List<String>) params.get("document_ids");
|
||||
Integer page = (Integer) params.get("page");
|
||||
Integer pageSize = (Integer) params.get("page_size");
|
||||
Float similarityThreshold = (Float) params.get("similarity_threshold");
|
||||
Float vectorSimilarityWeight = (Float) params.get("vector_similarity_weight");
|
||||
Integer topK = (Integer) params.get("top_k");
|
||||
String rerankId = (String) params.get("rerank_id");
|
||||
Boolean keyword = (Boolean) params.get("keyword");
|
||||
Boolean highlight = (Boolean) params.get("highlight");
|
||||
List<String> crossLanguages = (List<String>) params.get("cross_languages");
|
||||
Map<String, Object> metadataCondition = (Map<String, Object>) params.get("metadata_condition");
|
||||
|
||||
// 如果未指定数据集ID,使用当前数据集
|
||||
if (datasetIds == null || datasetIds.isEmpty()) {
|
||||
datasetIds = java.util.Arrays.asList(datasetId);
|
||||
}
|
||||
|
||||
Map<String, Object> result = knowledgeFilesService.retrievalTest(
|
||||
question, datasetIds, documentIds, page, pageSize, similarityThreshold,
|
||||
vectorSimilarityWeight, topK, rerankId, keyword, highlight, crossLanguages, metadataCondition);
|
||||
|
||||
return new Result<Map<String, Object>>().ok(result);
|
||||
} catch (Exception e) {
|
||||
return new Result<Map<String, Object>>().error("召回测试失败: " + e.getMessage());
|
||||
// 业务下沉逻辑:如果未指定知识库ID,则设为当前路径中的 datasetId
|
||||
if (req.getDatasetIds() == null || req.getDatasetIds().isEmpty()) {
|
||||
req.setDatasetIds(java.util.Arrays.asList(datasetId));
|
||||
}
|
||||
|
||||
// [Reinforce] 强管控分页参数,防止 RAGFlow 端出现 Negative Slicing 报错
|
||||
if (req.getPage() == null || req.getPage() < 1) {
|
||||
req.setPage(1);
|
||||
}
|
||||
if (req.getPageSize() == null || req.getPageSize() < 1) {
|
||||
req.setPageSize(100);
|
||||
}
|
||||
|
||||
// 调用检索服务,返回强类型聚合对象
|
||||
RetrievalDTO.ResultVO result = knowledgeFilesService.retrievalTest(req);
|
||||
return new Result<RetrievalDTO.ResultVO>().ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析JSON字符串为Map对象
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package xiaozhi.modules.knowledge.dao;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import xiaozhi.common.dao.BaseDao;
|
||||
import xiaozhi.modules.knowledge.entity.DocumentEntity;
|
||||
|
||||
/**
|
||||
* 文档 DAO
|
||||
*/
|
||||
@Mapper
|
||||
public interface DocumentDao extends BaseDao<DocumentEntity> {
|
||||
}
|
||||
@@ -19,4 +19,17 @@ public interface KnowledgeBaseDao extends BaseDao<KnowledgeBaseEntity> {
|
||||
*/
|
||||
void deletePluginMappingByKnowledgeBaseId(@Param("knowledgeBaseId") String knowledgeBaseId);
|
||||
|
||||
/**
|
||||
* 通用维度原子更新知识库统计信息
|
||||
*
|
||||
* @param datasetId 数据集ID
|
||||
* @param docDelta 文档数增量
|
||||
* @param chunkDelta 分块数增量
|
||||
* @param tokenDelta Token数增量
|
||||
*/
|
||||
void updateStatsAfterChange(@Param("datasetId") String datasetId,
|
||||
@Param("docDelta") Integer docDelta,
|
||||
@Param("chunkDelta") Long chunkDelta,
|
||||
@Param("tokenDelta") Long tokenDelta);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
# RAGFlow API Interface Classification
|
||||
|
||||
## 1. External APIs (三方接入体系)
|
||||
**Path Prefix:** `/api/v1`
|
||||
**Authentication:** API Key (`@token_required`)
|
||||
**Primary Use:** External system integration, SDK usage.
|
||||
|
||||
| Interface Type | Python File Path | Class/Function Name | URL Pattern | Notes |
|
||||
|---|---|---|---|---|
|
||||
| **External** | `api/apps/sdk/session.py` | `agent_bot_completions` | `/api/v1/agentbots/<agent_id>/completions` | Agent Bot completion |
|
||||
| **External** | `api/apps/sdk/session.py` | `begin_inputs` | `/api/v1/agentbots/<agent_id>/inputs` | Get Agent Bot inputs |
|
||||
| **External** | `api/apps/sdk/agents.py` | `list_agents` | `/api/v1/agents` | List Agents |
|
||||
| **External** | `api/apps/sdk/agents.py` | `create_agent` | `/api/v1/agents` | Create Agent |
|
||||
| **External** | `api/apps/sdk/agents.py` | `update_agent` | `/api/v1/agents/<agent_id>` | Update Agent |
|
||||
| **External** | `api/apps/sdk/agents.py` | `delete_agent` | `/api/v1/agents/<agent_id>` | Delete Agent |
|
||||
| **External** | `api/apps/sdk/session.py` | `agent_completions` | `/api/v1/agents/<agent_id>/completions` | Agent completion |
|
||||
| **External** | `api/apps/sdk/session.py` | `create_agent_session` | `/api/v1/agents/<agent_id>/sessions` | Create Agent Session |
|
||||
| **External** | `api/apps/sdk/session.py` | `list_agent_session` | `/api/v1/agents/<agent_id>/sessions` | List Agent Sessions |
|
||||
| **External** | `api/apps/sdk/session.py` | `delete_agent_session` | `/api/v1/agents/<agent_id>/sessions` | Delete Agent Session |
|
||||
| **External** | `api/apps/sdk/session.py` | `agents_completion_openai_compatibility` | `/api/v1/agents_openai/<agent_id>/chat/completions` | OpenAI compatible Agent completion |
|
||||
| **External** | `api/apps/sdk/session.py` | `chatbot_completions` | `/api/v1/chatbots/<dialog_id>/completions` | Chatbot completion |
|
||||
| **External** | `api/apps/sdk/session.py` | `chatbots_inputs` | `/api/v1/chatbots/<dialog_id>/info` | Chatbot info |
|
||||
| **External** | `api/apps/sdk/chat.py` | `create` | `/api/v1/chats` | Create Chat |
|
||||
| **External** | `api/apps/sdk/chat.py` | `delete_chats` | `/api/v1/chats` | Delete Chat |
|
||||
| **External** | `api/apps/sdk/chat.py` | `list_chat` | `/api/v1/chats` | List Chats |
|
||||
| **External** | `api/apps/sdk/chat.py` | `update` | `/api/v1/chats/<chat_id>` | Update Chat |
|
||||
| **External** | `api/apps/sdk/session.py` | `chat_completion` | `/api/v1/chats/<chat_id>/completions` | Chat completion |
|
||||
| **External** | `api/apps/sdk/session.py` | `create` | `/api/v1/chats/<chat_id>/sessions` | Create Chat Session |
|
||||
| **External** | `api/apps/sdk/session.py` | `list_session` | `/api/v1/chats/<chat_id>/sessions` | List Chat Sessions |
|
||||
| **External** | `api/apps/sdk/session.py` | `delete` | `/api/v1/chats/<chat_id>/sessions` | Delete Chat Session |
|
||||
| **External** | `api/apps/sdk/session.py` | `update` | `/api/v1/chats/<chat_id>/sessions/<session_id>` | Update Chat Session |
|
||||
| **External** | `api/apps/sdk/session.py` | `chat_completion_openai_like` | `/api/v1/chats_openai/<chat_id>/chat/completions` | OpenAI compatible Chat completion |
|
||||
| **External** | `api/apps/sdk/dataset.py` | `create` | `/api/v1/datasets` | Create Dataset |
|
||||
| **External** | `api/apps/sdk/dataset.py` | `delete` | `/api/v1/datasets` | Delete Dataset |
|
||||
| **External** | `api/apps/sdk/dataset.py` | `list_datasets` | `/api/v1/datasets` | List Datasets |
|
||||
| **External** | `api/apps/sdk/dataset.py` | `update` | `/api/v1/datasets/<dataset_id>` | Update Dataset |
|
||||
| **External** | `api/apps/sdk/doc.py` | `parse` | `/api/v1/datasets/<dataset_id>/chunks` | Parse Document Chunks |
|
||||
| **External** | `api/apps/sdk/doc.py` | `stop_parsing` | `/api/v1/datasets/<dataset_id>/chunks` | Stop Parsing |
|
||||
| **External** | `api/apps/sdk/doc.py` | `upload` | `/api/v1/datasets/<dataset_id>/documents` | Upload Document |
|
||||
| **External** | `api/apps/sdk/doc.py` | `list_docs` | `/api/v1/datasets/<dataset_id>/documents` | List Documents |
|
||||
| **External** | `api/apps/sdk/doc.py` | `delete` | `/api/v1/datasets/<dataset_id>/documents` | Delete Document |
|
||||
| **External** | `api/apps/sdk/doc.py` | `update_doc` | `/api/v1/datasets/<dataset_id>/documents/<document_id>` | Update Document |
|
||||
| **External** | `api/apps/sdk/doc.py` | `download` | `/api/v1/datasets/<dataset_id>/documents/<document_id>` | Download Document |
|
||||
| **External** | `api/apps/sdk/doc.py` | `list_chunks` | `/api/v1/datasets/<dataset_id>/documents/<document_id>/chunks` | List Chunks |
|
||||
| **External** | `api/apps/sdk/doc.py` | `add_chunk` | `/api/v1/datasets/<dataset_id>/documents/<document_id>/chunks` | Add Chunk |
|
||||
| **External** | `api/apps/sdk/doc.py` | `update_chunk` | `/api/v1/datasets/<dataset_id>/documents/<document_id>/chunks/<chunk_id>` | Update Chunk |
|
||||
| **External** | `api/apps/sdk/dataset.py` | `knowledge_graph` | `/api/v1/datasets/<dataset_id>/knowledge_graph` | Knowledge Graph |
|
||||
| **External** | `api/apps/sdk/dataset.py` | `delete_knowledge_graph` | `/api/v1/datasets/<dataset_id>/knowledge_graph` | Delete Knowledge Graph |
|
||||
| **External** | `api/apps/sdk/doc.py` | `metadata_summary` | `/api/v1/datasets/<dataset_id>/metadata/summary` | Metadata Summary |
|
||||
| **External** | `api/apps/sdk/doc.py` | `metadata_batch_update` | `/api/v1/datasets/<dataset_id>/metadata/update` | Batch Update Metadata |
|
||||
| **External** | `api/apps/sdk/dataset.py` | `run_graphrag` | `/api/v1/datasets/<dataset_id>/run_graphrag` | Run GraphRAG |
|
||||
| **External** | `api/apps/sdk/dataset.py` | `run_raptor` | `/api/v1/datasets/<dataset_id>/run_raptor` | Run Raptor |
|
||||
| **External** | `api/apps/sdk/dataset.py` | `trace_graphrag` | `/api/v1/datasets/<dataset_id>/trace_graphrag` | Trace GraphRAG |
|
||||
| **External** | `api/apps/sdk/dataset.py` | `trace_raptor` | `/api/v1/datasets/<dataset_id>/trace_raptor` | Trace Raptor |
|
||||
| **External** | `api/apps/sdk/dify_retrieval.py` | `retrieval` | `/api/v1/dify/retrieval` | Dify Retrieval |
|
||||
| **External** | `api/apps/sdk/files.py` | `get_all_parent_folders` | `/api/v1/file/all_parent_folder` | Get All Parent Folders |
|
||||
| **External** | `api/apps/sdk/files.py` | `convert` | `/api/v1/file/convert` | File Convert |
|
||||
| **External** | `api/apps/sdk/files.py` | `create` | `/api/v1/file/create` | File Create |
|
||||
| **External** | `api/apps/sdk/files.py` | `download_attachment` | `/api/v1/file/download/<attachment_id>` | Download Attachment |
|
||||
| **External** | `api/apps/sdk/files.py` | `get` | `/api/v1/file/get/<file_id>` | Get File |
|
||||
| **External** | `api/apps/sdk/files.py` | `list_files` | `/api/v1/file/list` | List Files |
|
||||
| **External** | `api/apps/sdk/files.py` | `move` | `/api/v1/file/mv` | Move File |
|
||||
| **External** | `api/apps/sdk/files.py` | `get_parent_folder` | `/api/v1/file/parent_folder` | Get Parent Folder |
|
||||
| **External** | `api/apps/sdk/files.py` | `rename` | `/api/v1/file/rename` | Rename File |
|
||||
| **External** | `api/apps/sdk/files.py` | `rm` | `/api/v1/file/rm` | Remove File |
|
||||
| **External** | `api/apps/sdk/files.py` | `get_root_folder` | `/api/v1/file/root_folder` | Get Root Folder |
|
||||
| **External** | `api/apps/sdk/files.py` | `upload` | `/api/v1/file/upload` | Upload File |
|
||||
| **External** | `api/apps/sdk/doc.py` | `retrieval_test` | `/api/v1/retrieval` | Retrieval Test |
|
||||
| **External** | `api/apps/sdk/session.py` | `ask_about_embedded` | `/api/v1/searchbots/ask` | Searchbot Ask |
|
||||
| **External** | `api/apps/sdk/session.py` | `detail_share_embedded` | `/api/v1/searchbots/detail` | Searchbot Detail |
|
||||
| **External** | `api/apps/sdk/session.py` | `mindmap` | `/api/v1/searchbots/mindmap` | Searchbot Mindmap |
|
||||
| **External** | `api/apps/sdk/session.py` | `related_questions_embedded` | `/api/v1/searchbots/related_questions` | Searchbot Related Questions |
|
||||
| **External** | `api/apps/sdk/session.py` | `retrieval_test_embedded` | `/api/v1/searchbots/retrieval_test` | Searchbot Retrieval Test |
|
||||
| **External** | `api/apps/sdk/session.py` | `ask_about` | `/api/v1/sessions/ask` | Session Ask |
|
||||
| **External** | `api/apps/sdk/session.py` | `related_questions` | `/api/v1/sessions/related_questions` | Session Related Questions |
|
||||
| **External** | `api/apps/sdk/agents.py` | `webhook` | `/api/v1/webhook_test/<agent_id>` | Webhook Test |
|
||||
| **External** | `api/apps/sdk/agents.py` | `webhook_trace` | `/api/v1/webhook_trace/<agent_id>` | Webhook Trace |
|
||||
| **External** | `api/apps/sdk/doc.py` | `rm_chunk` | `/api/v1datasets/<dataset_id>/documents/<document_id>/chunks` | Remove Chunk |
|
||||
|
||||
|
||||
## 2. Internal APIs (内部前端体系)
|
||||
**Path Prefix:** `/v1/<app_name>` matches file `api/apps/<app_name>_app.py`
|
||||
**Authentication:** Session/Cookie (`@login_required`)
|
||||
**Primary Use:** RAGFlow Web Frontend.
|
||||
|
||||
**Selected Core Interfaces:**
|
||||
|
||||
| Interface Type | Python File Path | Class/Function Name | URL Pattern | Notes |
|
||||
|---|---|---|---|---|
|
||||
| Internal | `api/apps/user_app.py` | `login` | `/v1/user/login` | User Login (Frontend) |
|
||||
| Internal | `api/apps/user_app.py` | `log_out` | `/v1/user/logout` | User Logout |
|
||||
| Internal | `api/apps/user_app.py` | `user_add` | `/v1/user/register` | User Registration |
|
||||
| Internal | `api/apps/user_app.py` | `user_profile` | `/v1/user/info` | User Profile Info |
|
||||
| Internal | `api/apps/api_app.py` | `new_token` | `/v1/api/new_token` | Generate new API Token |
|
||||
| Internal | `api/apps/conversation_app.py` | `set_conversation` | `/v1/conversation/set` | Create/Update Conversation |
|
||||
| Internal | `api/apps/conversation_app.py` | `completion` | `/v1/conversation/completion` | Chat Conversation Completion |
|
||||
| Internal | `api/apps/kb_app.py` | `list_kbs` | `/v1/kb/list` | List Knowledge Bases |
|
||||
| Internal | `api/apps/kb_app.py` | `create` | `/v1/kb/create` | Create Knowledge Base |
|
||||
| Internal | `api/apps/document_app.py` | `upload` | `/v1/document/upload` | Upload Document to KB |
|
||||
| Internal | `api/apps/document_app.py` | `parse` | `/v1/document/parse` | Parse Document |
|
||||
|
||||
*(For a complete list of all 200+ internal APIs, please refer to the `api_endpoints.txt` file or the full scan results)*
|
||||
+279
@@ -0,0 +1,279 @@
|
||||
# RAGFlow Agent 与 Dify 兼容接口详解 (Agent & Dify Compatibility)
|
||||
|
||||
## 1. Dify 兼容检索 - `retrieval`
|
||||
**接口描述**: 模拟 Dify API 格式的知识库检索接口。此接口主要用于让现有的 Dify 客户端或系统能够方便地接入 RAGFlow 的知识库检索能力。它支持文本检索、混合检索以及通过元数据过滤文档。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/dify/retrieval`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| knowledge_id | string | 是 | - | **知识库 ID**。 |
|
||||
| query | string | 是 | - | **查询文本**。用户输入的检索问题。 |
|
||||
| use_kg | boolean | 否 | false | **使用知识图谱**。是否结合知识图谱进行检索。 |
|
||||
| retrieval_setting | object | 否 | {} | **检索配置**。包含相似度阈值和 Top-K。 |
|
||||
| metadata_condition | object | 否 | {} | **元数据过滤条件**。用于筛选特定文档。 |
|
||||
|
||||
#### 参数详情 (Detail Objects)
|
||||
**retrieval_setting**:
|
||||
```json
|
||||
{
|
||||
"score_threshold": 0.5, // 相似度阈值 (default: 0.0)
|
||||
"top_k": 5 // 返回数量 (default: 1024)
|
||||
}
|
||||
```
|
||||
|
||||
**metadata_condition**:
|
||||
```json
|
||||
{
|
||||
"logic": "and", // 逻辑关系 (and/or)
|
||||
"conditions": [
|
||||
{
|
||||
"name": "author", // 字段名
|
||||
"comparison_operator": "eq",// 运算符 (eq, ne, gt, lt 等)
|
||||
"value": "Alice" // 字段值
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"records": [
|
||||
{
|
||||
"content": "RAGFlow 是一个基于深度文档理解的检索增强生成引擎...",
|
||||
"score": 0.92,
|
||||
"title": "RAGFlow_Introduction.pdf",
|
||||
"metadata": {
|
||||
"doc_id": "doc_uuid_123",
|
||||
"author": "Alice",
|
||||
"publish_year": "2024"
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": "DeepDOC 模型能够精准识别复杂的表格结构...",
|
||||
"score": 0.88,
|
||||
"title": "DeepDOC_Tech_Report.pdf",
|
||||
"metadata": {
|
||||
"doc_id": "doc_uuid_456",
|
||||
"author": "Bob"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 创建 Agent 会话 - `create_agent_session`
|
||||
**接口描述**: 创建一个新的 Agent 会话 (Session)。会话是用户与 Agent 交互的上下文容器,保存了历史对话记录和 DSL(领域特定语言)状态。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/agents/<agent_id>/sessions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| agent_id | string | 是 | **Agent ID**。 |
|
||||
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| user_id | string | 否 | **用户标识**。用于区分不同终端用户的会话。若不传,默认为当前 Tenant ID。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": "session_uuid_new_123",
|
||||
"agent_id": "agent_uuid_abc",
|
||||
"user_id": "user_123",
|
||||
"source": "agent",
|
||||
"dsl": { ... }, // 完整的 Agent DSL 定义
|
||||
"messages": [
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "你好!我是你的智能助手,有什么可以帮你的吗?" // Prologue (开场白)
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 获取 Agent 会话列表 - `list_agent_session`
|
||||
**接口描述**: 分页获取指定 Agent 下的会话列表。支持按 ID 或 User ID 过滤。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/agents/<agent_id>/sessions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| agent_id | string | 是 | **Agent ID**。 |
|
||||
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| page | int | 否 | 1 | **页码**。 |
|
||||
| page_size | int | 否 | 30 | **每页数量**。 |
|
||||
| orderby | string | 否 | "update_time" | **排序字段**。 |
|
||||
| desc | boolean | 否 | true | **是否降序**。 |
|
||||
| id | string | 否 | - | **会话 ID**。精确筛选。 |
|
||||
| user_id | string | 否 | - | **用户标识**。筛选特定用户的会话。 |
|
||||
| dsl | boolean | 否 | true | **包含 DSL**。是否在返回结果中包含完整的 DSL 结构 (数据量较大)。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": [
|
||||
{
|
||||
"id": "session_uuid_123",
|
||||
"agent_id": "agent_uuid_abc",
|
||||
"user_id": "user_123",
|
||||
"create_time": 1715000000000,
|
||||
"update_time": 1715000050000,
|
||||
"source": "agent",
|
||||
"messages": [
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "Hi there!"
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "What is RAG?"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 删除 Agent 会话 - `delete_agent_session`
|
||||
**接口描述**: 批量删除 Agent 会话。
|
||||
**请求方法**: `DELETE`
|
||||
**接口地址**: `/api/v1/agents/<agent_id>/sessions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| agent_id | string | 是 | **Agent ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| ids | array<string> | 否 | **会话 ID 列表**。若不传该参数,将尝试删除(或清空)该 Agent 下的所有会话(需谨慎)。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"ids": ["session_id_1", "session_id_2"]
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"success_count": 2,
|
||||
"errors": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Agent 对话 (流式) - `agent_completions`
|
||||
**接口描述**: 向 Agent 发送用户问题并获取回复。这是 Agent 交互的核心接口,支持 **Server-Sent Events (SSE)** 流式响应。Agent 会根据编排好的 DSL 流程执行(可能涉及多个节点、知识库检索、LLM 推理等),并实时推送执行过程和最终结果。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/agents/<agent_id>/completions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| agent_id | string | 是 | **Agent ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| session_id | string | 是 | - | **会话 ID**。必须是 `create_agent_session` 返回的 ID。 |
|
||||
| question | string | 是 | - | **用户问题**。 |
|
||||
| stream | boolean | 否 | true | **是否流式响应**。强烈建议设为 `true` 以获得更好的用户体验。 |
|
||||
| return_trace | boolean | 否 | false | **返回执行轨迹**。如果为 `true`,流式响应中将包含各个节点的执行过程数据 (Trace)。 |
|
||||
|
||||
### 响应参数 (Stream Response)
|
||||
**Content-Type**: `text/event-stream`
|
||||
|
||||
响应是一个 SSE 流,每一行以 `data:` 开头,包含一个 JSON 对象。
|
||||
|
||||
**Event Types**:
|
||||
- `message`: 普通文本消息片段。
|
||||
- `node_finished`: (当 `return_trace=true` 时) 节点执行完成事件,包含节点输出数据。
|
||||
- `message_end`: 消息结束。
|
||||
- `[DONE]`: 流结束标志。
|
||||
|
||||
#### Stream Chunk Examples:
|
||||
|
||||
**1. 文本生成片段 (message)**:
|
||||
```text
|
||||
data:{"code": 0, "message": "success", "data": {"content": "Hello", "reference": {}, "id": "msg_uuid_1"}, "event": "message"}
|
||||
|
||||
data:{"code": 0, "message": "success", "data": {"content": " world", "reference": {}, "id": "msg_uuid_1"}, "event": "message"}
|
||||
```
|
||||
|
||||
**2. 节点执行轨迹 (node_finished, return_trace=true)**:
|
||||
```text
|
||||
data:{"code": 0, "message": "success", "data": {"component_id": "retrieval_node_1", "content": "...", "trace": [...]}, "event": "node_finished"}
|
||||
```
|
||||
|
||||
**3. 最终结束 (DONE)**:
|
||||
```text
|
||||
data:[DONE]
|
||||
```
|
||||
|
||||
#### Non-Stream Response (stream=false)
|
||||
如果不使用流式响应,将等待 Agent 全流程执行完毕后一次性返回 JSON。
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"content": "Hello world! This is the final answer.",
|
||||
"reference": {
|
||||
"chunk_id_1": { ... } // 引用来源
|
||||
},
|
||||
"trace": [ ... ] // 如果 return_trace=true
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,233 @@
|
||||
## 1. 获取 Agent 列表 - `list_agents`
|
||||
**接口描述**: 分页查询当前租户下的所有 Agent 列表,支持按 ID 或标题筛选。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/agents`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
无
|
||||
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| page | int | 否 | 1 | 页码 |
|
||||
| page_size | int | 否 | 30 | 每页条数 |
|
||||
| orderby | string | 否 | update_time | 排序字段 (create_time, update_time, title) |
|
||||
| desc | boolean | 否 | True | 是否降序排列 (True: 降序, False: 升序) |
|
||||
| id | string | 否 | - | 按 Agent ID 精确筛选 |
|
||||
| title | string | 否 | - | 按 Agent 标题精确筛选 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": [
|
||||
{
|
||||
"id": "e0d34e2c-...",
|
||||
"title": "My Assistant",
|
||||
"description": "A helpful AI assistant",
|
||||
"dsl": { ... }, // Agent 的 DSL 流程定义
|
||||
"user_id": "tenant_123",
|
||||
"avatar": "", // 头像 Base64 或 URL
|
||||
"canvas_category": "Agent",
|
||||
"create_time": 1715623400000,
|
||||
"update_time": 1715624500000
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 创建 Agent - `create_agent`
|
||||
**接口描述**: 创建一个新的 Agent,必须包含标题和 DSL 定义。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/agents`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
无
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| title | string | 是 | - | Agent 的名称 (必须唯一) |
|
||||
| dsl | object | 是 | - | Agent 的流程定义 (节点、连线配置) |
|
||||
| description | string | 否 | - | Agent 的功能描述 |
|
||||
| avatar | string | 否 | - | Agent 头像 (Base64 字符串或 URL) |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 更新 Agent - `update_agent`
|
||||
**接口描述**: 更新指定 Agent 的配置信息,支持增量更新(仅传递需要修改的字段)。
|
||||
**请求方法**: `PUT`
|
||||
**接口地址**: `/api/v1/agents/<agent_id>`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| agent_id | string | 是 | 要更新的 Agent ID |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| title | string | 否 | - | 新的 Agent 名称 |
|
||||
| dsl | object | 否 | - | 新的 DSL 流程定义 |
|
||||
| description | string | 否 | - | 新的功能描述 |
|
||||
| avatar | string | 否 | - | 新的头像 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 删除 Agent - `delete_agent`
|
||||
**接口描述**: 根据 ID 删除指定的 Agent。此操作不可恢复。
|
||||
**请求方法**: `DELETE`
|
||||
**接口地址**: `/api/v1/agents/<agent_id>`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| agent_id | string | 是 | 要删除的 Agent ID |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
无
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Webhook 测试触发 - `webhook`
|
||||
**接口描述**: 用于测试 Agent 的 Webhook 触发功能。该接口模拟外部系统调用,触发 Agent 按照配置的 "Begin" 节点逻辑开始执行。支持同步等待结果或流式返回(取决于 Agent 配置)。
|
||||
**请求方法**: `POST` (支持 GET/PUT/DELETE 等,取决于 Canvas 配置)
|
||||
**接口地址**: `/api/v1/webhook_test/<agent_id>`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| agent_id | string | 是 | Agent 的唯一标识符 |
|
||||
|
||||
#### Query / Headers / Body Parameters
|
||||
**说明**: 此接口的参数完全动态,取决于 Agent 画布中 **"Begin" (开始)** 节点的 **Webhook** 配置。
|
||||
- 如果配置了 Query 参数验证,则需在 URL 中传递对应参数。
|
||||
- 如果配置了 Header 验证,则需传递对应 Header。
|
||||
- **Body**: 通常为 JSON 格式,包含 Agent 运行所需的变量(inputs)或上下文数据。
|
||||
|
||||
**Body Example (JSON)**:
|
||||
```json
|
||||
{
|
||||
"inputs": {
|
||||
"topic": "AI Trends",
|
||||
"style": "professional"
|
||||
},
|
||||
"query": "Start generation"
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json` (或 `text/event-stream`)
|
||||
|
||||
**即时响应模式 (Immediately)**:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"content": "生成的回答内容...",
|
||||
"usage": { ... }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**流式响应模式 (SSE)**:
|
||||
如果不使用 `webhook_test` 而是生产环境 `webhook` 且配置为 SSE,则返回流式数据。但在 `webhook_test` 接口中,通常配合 `webhook_trace` 进行异步调试。
|
||||
|
||||
---
|
||||
|
||||
## 6. Webhook 执行轨迹查询 - `webhook_trace`
|
||||
**接口描述**: 轮询查询 Agent 在 Webhook 测试触发后的执行日志和中间状态。采用长轮询或游标机制,实时获取执行进度。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/webhook_trace/<agent_id>`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| agent_id | string | 是 | Agent 的唯一标识符 |
|
||||
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| since_ts | float | 否 | 当前时间 | 起始时间戳。返回此时间之后的日志事件。首次调用可不传(获取当前时间作为游标)。 |
|
||||
| webhook_id | string | 否 | - | Webhook 会话 ID。用于锁定特定的某次执行记录。首次轮询时不传,接口会返回新生成的 ID。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"webhook_id": "YWdlbnxxxx...", // 当前追踪的会话 ID (加密串)
|
||||
"finished": false, // 执行是否已结束 (true/false)
|
||||
"next_since_ts": 1715629999.5, // 下一次轮询应使用的 since_ts
|
||||
"events": [ // 本次轮询获取到的新事件列表
|
||||
{
|
||||
"ts": 1715629998.1,
|
||||
"event": "message", // 事件类型: message, start_to_think, finished, error 等
|
||||
"data": {
|
||||
"content": "思考中...",
|
||||
"reference": []
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 💡 最佳实践 (调试流程)
|
||||
1. **初始化**: 调用 `GET /webhook_trace/<id>` (不带参数),获取 `next_since_ts` (记为 `T0`)。
|
||||
2. **触发**: 调用 `POST /webhook_test/<id>` 发送测试数据。
|
||||
3. **首帧捕获**: 循环调用 `GET /webhook_trace/<id>?since_ts=T0`,直到返回 `webhook_id` (记为 `WID`) 和第一批 `events`。
|
||||
4. **持续追踪**: 使用 `WID` 和响应中的 `next_since_ts` 持续轮询,直到 `data.finished == true`。
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
# RAGFlow 对话交互接口详解 (Chat Completion & OpenAI Compatibility)
|
||||
|
||||
## 5. 对话助手对话 (流式) - `chat_completion`
|
||||
**接口描述**: 发送问题给对话助手 (Assistant/Chat) 并获取回复。这是 RAGFlow 最核心的原生对话接口,支持 **Server-Sent Events (SSE)** 流式响应。它会根据助手绑定的知识库进行 RAG 检索生成。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/chats/<chat_id>/completions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| chat_id | string | 是 | **助手 ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| session_id | string | 是 | - | **会话 ID**。从 `create_chat_session` 获取。 |
|
||||
| question | string | 是 | - | **用户问题**。 |
|
||||
| stream | boolean | 否 | true | **是否流式响应**。 |
|
||||
| quote | boolean | 否 | false | **返回引用**。是否在响应中包含检索到的引用片段。 |
|
||||
| doc_ids | string | 否 | - | **限定文档 ID**。多个 ID 用逗号分隔,仅检索指定文档。 |
|
||||
| metadata_condition | object | 否 | {} | **元数据过滤**。用于限定检索范围。 |
|
||||
|
||||
### 响应参数 (Stream Response)
|
||||
**Content-Type**: `text/event-stream`
|
||||
|
||||
每一行数据以 `data:` 开头,包含一个 JSON 对象。
|
||||
|
||||
**Event Example**:
|
||||
```text
|
||||
data:{"code": 0, "message": "success", "data": {"answer": "Hello", "reference": {}}}
|
||||
|
||||
data:{"code": 0, "message": "success", "data": {"answer": " world!", "reference": {}}}
|
||||
|
||||
data:{"code": 0, "message": "success", "data": {"answer": "", "reference": {"chunk_1": {...}}}} // 引用数据
|
||||
```
|
||||
|
||||
### 响应参数 (Non-Stream Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"answer": "Hello world! This is the generated response.",
|
||||
"reference": {
|
||||
"chunk_id_1": {
|
||||
"content_with_weight": "Original text...",
|
||||
"doc_name": "manual.pdf"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. OpenAI 兼容对话 - `chat_completion_openai_like`
|
||||
**接口描述**: 提供与 **OpenAI API (`/v1/chat/completions`)** 完全兼容的接口。允许开发者使用 LangChain、OpenAI Python SDK 或其他支持 OpenAI 协议的工具直接调用 RAGFlow,实现无缝迁移。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/chats_openai/<chat_id>/chat/completions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| chat_id | string | 是 | **助手 ID**。在此上下文中充当 "Base URL" 的一部分。 |
|
||||
|
||||
#### Body Parameters (JSON - OpenAI Standard)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| messages | array | 是 | **消息列表**。包含 `role` (system/user/assistant) 和 `content`。 |
|
||||
| model | string | 是 | **模型名称**。可以是任意非空字符串 (RAGFlow 会使用助手预设的模型)。 |
|
||||
| stream | boolean | 否 | **是否流式**。默认为 `true`。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"model": "ragflow_default",
|
||||
"messages": [
|
||||
{"role": "system", "content": "You are a helpful assistant."},
|
||||
{"role": "user", "content": "Explain quantum physics."}
|
||||
],
|
||||
"stream": true
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Stream Response - OpenAI Format)
|
||||
**Content-Type**: `text/event-stream`
|
||||
|
||||
严格遵循 OpenAI Chunk 格式:
|
||||
|
||||
```text
|
||||
data: {"id": "chatcmpl-123", "object": "chat.completion.chunk", "created": 1715000000, "model": "model", "choices": [{"index": 0, "delta": {"role": "assistant", "content": ""}, "finish_reason": null}]}
|
||||
|
||||
data: {"id": "chatcmpl-123", "object": "chat.completion.chunk", "created": 1715000001, "model": "model", "choices": [{"index": 0, "delta": {"content": "Quantum"}, "finish_reason": null}]}
|
||||
|
||||
data: {"id": "chatcmpl-123", "object": "chat.completion.chunk", "created": 1715000002, "model": "model", "choices": [{"index": 0, "delta": {"content": " physics"}, "finish_reason": null}]}
|
||||
|
||||
data: [DONE]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 嵌入式 Chatbot 对话 - `chatbot_completions`
|
||||
**接口描述**: 专为 **嵌入式窗口 (Embed Window)** 设计的公开对话接口。它通常用于将 RAGFlow 助手作为客服窗口嵌入到第三方网站。与普通接口不同,它通过 `Authorization` Header 传递 **Beta Token** (即 API Key) 进行鉴权,且通常面向最终用户。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/chatbots/<dialog_id>/completions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dialog_id | string | 是 | **助手 ID** (Dialog ID)。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| question | string | 是 | - | **用户问题**。 |
|
||||
| stream | boolean | 否 | true | **是否流式**。 |
|
||||
| session_id | string | 否 | - | **会话 ID**。用于维持上下文。 |
|
||||
| quote | boolean | 否 | false | **返回引用**。 |
|
||||
|
||||
### 响应参数 (Stream Response)
|
||||
**Content-Type**: `text/event-stream`
|
||||
|
||||
与 `chat_completion` 类似,返回 RAGFlow 原生 SSE 格式。
|
||||
|
||||
```text
|
||||
data:{"code": 0, "message": "success", "data": {"answer": "Here is the answer...", "reference": {}}}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Chatbot 初始化信息 - `chatbots_inputs`
|
||||
**接口描述**: 获取嵌入式 Chatbot 的初始化配置信息。通常在前端组件加载时调用,用于展示助手的头像、名称、开场白 (Prologue) 等信息。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/chatbots/<dialog_id>/info`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dialog_id | string | 是 | **助手 ID**。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"title": "IT Support Bot", // 助手名称
|
||||
"avatar": "http://...", // 头像 URL
|
||||
"prologue": "Hi! How can I help?" // 开场白
|
||||
}
|
||||
}
|
||||
```
|
||||
+208
@@ -0,0 +1,208 @@
|
||||
# RAGFlow 聊天助手会话管理接口详解 (Chat Assistant Session Management)
|
||||
|
||||
## 1. 创建会话 - `create_chat_session`
|
||||
**接口描述**: 为指定的聊天助手 (Chat/Assistant) 创建一个新的会话。系统会自动加载该助手的开场白 (Prologue) 作为第一条消息。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/chats/<chat_id>/sessions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| chat_id | string | 是 | **助手 ID** (Assistant/Dialog ID)。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| name | string | 否 | "New session" | **会话名称**。 |
|
||||
| user_id | string | 否 | - | **用户标识**。用于区分不同终端用户的会话。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"name": "Consulting regarding RAG",
|
||||
"user_id": "client_001"
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": "session_uuid_123",
|
||||
"chat_id": "chat_uuid_abc",
|
||||
"name": "Consulting regarding RAG",
|
||||
"user_id": "client_001",
|
||||
"create_time": 1715000000000,
|
||||
"create_date": "2024-05-01 10:00:00",
|
||||
"update_time": 1715000000000,
|
||||
"update_date": "2024-05-01 10:00:00",
|
||||
"messages": [
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "Hi! I am your AI assistant. How can I help you today?" // 自动加载的开场白
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 获取会话列表 - `list_chat_session`
|
||||
**接口描述**: 分页获取指定助手下的会话列表。支持按名称或用户 ID 过滤。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/chats/<chat_id>/sessions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| chat_id | string | 是 | **助手 ID**。 |
|
||||
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| page | int | 否 | 1 | **页码**。 |
|
||||
| page_size | int | 否 | 30 | **每页数量**。 |
|
||||
| orderby | string | 否 | "create_time" | **排序字段**。 |
|
||||
| desc | boolean | 否 | true | **是否降序**。 |
|
||||
| name | string | 否 | - | **会话名称搜索**。 |
|
||||
| id | string | 否 | - | **会话 ID 精确筛选**。 |
|
||||
| user_id | string | 否 | - | **用户标识筛选**。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": [
|
||||
{
|
||||
"id": "session_uuid_123",
|
||||
"chat_id": "chat_uuid_abc",
|
||||
"name": "Consulting regarding RAG",
|
||||
"user_id": "client_001",
|
||||
"create_time": 1715000000000,
|
||||
"create_date": "2024-05-01 10:00:00",
|
||||
"update_time": 1715000050000,
|
||||
"update_date": "2024-05-01 10:00:50",
|
||||
"messages": [
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "Hi! I am your AI assistant. How can I help you today?"
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "What is RAGFlow?"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "session_uuid_456",
|
||||
"chat_id": "chat_uuid_abc",
|
||||
"name": "New session",
|
||||
"user_id": "client_002",
|
||||
"create_time": 1714900000000,
|
||||
"create_date": "2024-04-30 09:00:00",
|
||||
"update_time": 1714900000000,
|
||||
"update_date": "2024-04-30 09:00:00",
|
||||
"messages": [ ... ]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 更新会话 - `update_chat_session`
|
||||
**接口描述**: 更新会话信息。目前主要用于 **重命名** 会话。注意:不能通过此接口修改消息记录 (`messages`)。
|
||||
**请求方法**: `PUT`
|
||||
**接口地址**: `/api/v1/chats/<chat_id>/sessions/<session_id>`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| chat_id | string | 是 | **助手 ID**。 |
|
||||
| session_id | string | 是 | **会话 ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| name | string | 否 | **新的会话名称**。不可为空字符串。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"name": "RAG Technical Discussion"
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 删除会话 - `delete_chat_session`
|
||||
**接口描述**: 批量删除指定助手下的会话。
|
||||
**请求方法**: `DELETE`
|
||||
**接口地址**: `/api/v1/chats/<chat_id>/sessions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| chat_id | string | 是 | **助手 ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| ids | array<string> | 否 | **待删除的会话 ID 列表**。若不传该参数,将尝试删除该助手下的**所有会话**(请极其谨慎使用)。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"ids": ["session_uuid_123", "session_uuid_456"]
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": null // 若全部删除成功
|
||||
}
|
||||
```
|
||||
|
||||
**Response (部分成功时)**:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "Partially deleted 1 sessions with 1 errors",
|
||||
"data": {
|
||||
"success_count": 1,
|
||||
"errors": ["The chat doesn't own the session session_uuid_999"]
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,213 @@
|
||||
## 1. 创建助手应用 - `create`
|
||||
**接口描述**: 创建一个新的对话助手(Chat Assistant)。支持配置关联知识库、LLM 模型参数、提示词(Prompt)以及开场白等高级设置。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/chats`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
无
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| name | string | 是 | - | 助手应用名称 (租户内唯一) |
|
||||
| avatar | string | 否 | - | 助手头像 (URL 或 Base64 字符串) |
|
||||
| description | string | 否 | "A helpful Assistant" | 助手的功能描述 |
|
||||
| dataset_ids | array | 否 | [] | 关联的知识库 ID 列表 (必须是当前租户有权限访问的知识库) |
|
||||
| llm | object | 否 | - | LLM 模型生成配置 (如模型名称、温度等) |
|
||||
| prompt | object | 否 | - | 提示词引擎与检索配置 (包含 System Prompt, Opener, Rerank 等) |
|
||||
|
||||
**`llm` 对象详细结构**:
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| model_name | string | 是 | - | 模型名称 (例如: `deepseek-chat`, `gpt-4`, `qwen-turbo`) |
|
||||
| temperature | float | 否 | 0.1 | 温度系数 (0.0 ~ 1.0),越高越随机,越低越确定 |
|
||||
| top_p | float | 否 | 0.3 | 核采样概率阈值 |
|
||||
| max_tokens | int | 否 | 512 | 单次回答的最大 Token 数限制 |
|
||||
| presence_penalty | float | 否 | 0.4 | 话题新鲜度惩罚 (-2.0 ~ 2.0),正值鼓励讨论新话题 |
|
||||
| frequency_penalty | float | 否 | 0.7 | 频率惩罚 (-2.0 ~ 2.0),正值减少重复词汇 |
|
||||
|
||||
**`prompt` 对象详细结构**:
|
||||
*注意:此对象包含“提示词配置”与“检索策略配置”两部分。*
|
||||
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| prompt | string | 否 | (内置默认提示词) | **System Prompt (系统提示词)**。给大模型的角色指令,例如 "你是一个客服..."。可使用变量占位符 `{knowledge}`。 |
|
||||
| opener | string | 否 | "Hi! I'm your assistant..." | **开场白**。用户进入对话窗口时,助手自动发送的第一条欢迎语。 |
|
||||
| show_quote | boolean | 否 | true | **显示引用**。回答中是否标注来源文档 (e.g., [1])。 |
|
||||
| variables | array | 否 | `[{"key": "knowledge", "optional": false}]` | **变量列表**。定义用于填充 System Prompt 的变量。`knowledge` 为保留变量,代表检索到的知识片段。 |
|
||||
| rerank_model | string | 否 | - | **重排序模型 ID**。配置后会对检索结果进行二次精排 (如 `BAAI/bge-reranker-v2-m3`)。 |
|
||||
| keywords_similarity_weight | float | 否 | 0.7 | **关键字权重** (0.0 ~ 1.0)。控制混合检索的比例。更接近 1.0 侧重关键字匹配,更接近 0.0 侧重向量语义匹配。 |
|
||||
| similarity_threshold | float | 否 | 0.2 | **相似度阈值** (0.0 ~ 1.0)。低于此相似度的文档块将被过滤,不喂给大模型。 |
|
||||
| top_n | int | 否 | 6 | **Top N**。最终截取并输入给大模型的文档块数量。 |
|
||||
| empty_response | string | 否 | "Sorry! No relevant..." | **空结果回复**。当没有检索到相关知识库内容时的兜底回复。 |
|
||||
| tts | boolean | 否 | false | **启用 TTS**。是否将助手的文本回答自动转为语音播放。 |
|
||||
| refine_multiturn | boolean | 否 | true | **多轮对话优化**。是否根据历史上下文重写用户问题 (Query Rewrite) 以提高检索准确率。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": "e0d34e2c-1234-5678-9xxx-xxxxxxxxxxxx",
|
||||
"name": "企业知识库助手",
|
||||
"avatar": "http://example.com/avatar.png",
|
||||
"description": "用于回答员工内部问题的 AI",
|
||||
"dataset_ids": ["kb_123", "kb_456"],
|
||||
"llm": {
|
||||
"model_name": "deepseek-chat",
|
||||
"temperature": 0.1,
|
||||
"top_p": 0.3,
|
||||
"max_tokens": 512,
|
||||
"presence_penalty": 0.4,
|
||||
"frequency_penalty": 0.7
|
||||
},
|
||||
"prompt": {
|
||||
"prompt": "你是一个智能助手,请根据以下知识回答问题:\n{knowledge}",
|
||||
"opener": "你好!有什么可以帮你的?",
|
||||
"show_quote": true,
|
||||
"variables": [
|
||||
{ "key": "knowledge", "optional": false }
|
||||
],
|
||||
"rerank_model": "",
|
||||
"keywords_similarity_weight": 0.7,
|
||||
"similarity_threshold": 0.2,
|
||||
"top_n": 8,
|
||||
"empty_response": "抱歉,知识库中没有找到相关答案。",
|
||||
"tts": false,
|
||||
"refine_multiturn": true
|
||||
},
|
||||
"create_time": 1715623400000,
|
||||
"update_time": 1715624500000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 获取助手列表 - `list_chat`
|
||||
**接口描述**: 获取当前租户下的所有助手应用列表。支持分页、排序及按名称/ID筛选。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/chats`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
无
|
||||
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| page | int | 否 | 1 | 页码 |
|
||||
| page_size | int | 否 | 30 | 每页条数 |
|
||||
| orderby | string | 否 | create_time | 排序字段 (`create_time`, `update_time`) |
|
||||
| desc | boolean | 否 | true | 是否降序排列 (`true`: 降序, `false`: 升序) |
|
||||
| name | string | 否 | - | 按名称模糊搜索 (支持 partial match) |
|
||||
| id | string | 否 | - | 按 ID 精确筛选 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": [
|
||||
{
|
||||
"id": "e0d34e2c-...",
|
||||
"name": "客服机器人",
|
||||
"avatar": "http://...",
|
||||
"datasets": [
|
||||
{
|
||||
"id": "kb_1",
|
||||
"name": "产品手册",
|
||||
"avatar": "",
|
||||
"chunk_num": 100
|
||||
}
|
||||
],
|
||||
"llm": { ... }, // (结构同 create 接口响应)
|
||||
"prompt": { ... }, // (结构同 create 接口响应)
|
||||
"create_time": 1715623400000
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 更新助手配置 - `update`
|
||||
**接口描述**: 更新指定助手应用的配置信息。支持全量或增量更新部分字段。
|
||||
**请求方法**: `PUT`
|
||||
**接口地址**: `/api/v1/chats/<chat_id>`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| chat_id | string | 是 | 助手应用 ID |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
*(以下所有字段均为可选,仅传递需要修改的字段即可)*
|
||||
|
||||
| 参数名 | 类型 | 默认值 | 说明 |
|
||||
|---|---|---|---|
|
||||
| name | string | - | 新的助手名称 |
|
||||
| avatar | string | - | 新的头像 URL 或 Base64 |
|
||||
| dataset_ids | array | - | **全量替换**关联的知识库 ID 列表 |
|
||||
| llm | object | - | 更新 LLM 配置。需包含 `model_name`,其他字段覆盖更新。 |
|
||||
| prompt | object | - | 更新提示词配置。支持增量更新 (e.g. 只改 `opener`)。 |
|
||||
| show_quotation | boolean | - | 是否显示引用来源 (此字段直接位于根对象下,对应 prompt.show_quote) |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 批量删除助手 - `delete_chats`
|
||||
**接口描述**: 批量删除一个或多个助手应用。
|
||||
**请求方法**: `DELETE`
|
||||
**接口地址**: `/api/v1/chats`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
无
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| ids | array<string> | 是 | 要删除的助手应用 ID 列表。**⚠️ 注意:若列表为空或不传,虽然后端有全量删除逻辑,但在实际业务中应严谨传递 ID。** |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"ids": ["chat_id_1001", "chat_id_1002"]
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"success_count": 2, // 成功删除的数量
|
||||
"errors": [] // 失败原因列表 (如 ID 不存在)
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,420 @@
|
||||
## 1. 创建知识库 - `create`
|
||||
**接口描述**: 创建一个新的知识库(Dataset),用于存储和检索文档数据。支持配置嵌入模型(Embedding Model)、解析方法、权限范围等。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/datasets`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
无
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| name | string | 是 | - | **知识库名称**。在同一个租户(Tenant)内必须唯一。 |
|
||||
| avatar | string | 否 | "" | **知识库头像**。Base64 编码的图片字符串。 |
|
||||
| description | string | 否 | "" | **描述信息**。用于说明知识库的用途或内容概要。 |
|
||||
| embedding_model | string | 否 | (系统默认) | **嵌入模型名称** (例如 `BAAI/bge-large-zh-v1.5`)。若不传,则自动使用系统设置的默认 Embedding 模型。 |
|
||||
| permission | string | 否 | "me" | **可见权限**。`me`: 仅自己可见;`team`: 团队内所有成员可见。 |
|
||||
| chunk_method | string | 否 | "naive" | **默认分块解析方法**。当上传文件未指定解析方式时使用。可选值: `naive` (通用), `manual` (手动), `qa` (Q&A拆分), `table` (表格), `paper` (论文), `book` (书籍), `laws` (法律), `presentation` (PPT), `picture` (图片), `one` (单文档), `email` (邮件)。 |
|
||||
| parser_config | object | 否 | (见下文) | **解析器详细配置**。根据 `chunk_method` 的不同而变化。 |
|
||||
|
||||
**`parser_config` 默认配置参数 (Naive 通用模式)**:
|
||||
| 参数名 | 类型 | 默认值 | 说明 |
|
||||
|---|---|---|---|
|
||||
| chunk_token_num | int | 512 | **切片最大 Token 数**。超过该长度会被截断到下一块。 |
|
||||
| delimiter | string | "\\n" | **分段分隔符**。用于识别段落边界。 |
|
||||
| layout_recognize | string | "DeepDOC" | **布局识别模型**。用于处理复杂文档结构 (如 `DeepDOC` 或 `Simple`)。 |
|
||||
| html4excel | boolean | false | **Excel转HTML**。是否将 Excel 表格转为 HTML 格式进行解析。 |
|
||||
| auto_keywords | int | 0 | **自动关键词抽取**。0 表示不抽取;N>0 表示为每个切片抽取 N 个关键词。 |
|
||||
| auto_questions | int | 0 | **自动问题生成**。0 表示不生成;N>0 表示为每个切片生成 N 个相关问题。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": "kb_uuid_12345678",
|
||||
"name": "企业产品手册",
|
||||
"avatar": "",
|
||||
"tenant_id": "tenant_001",
|
||||
"description": "存放所有产品相关的说明文档",
|
||||
"embedding_model": "BAAI/bge-large-zh-v1.5",
|
||||
"permission": "me",
|
||||
"chunk_method": "naive",
|
||||
"parser_config": {
|
||||
"chunk_token_num": 512,
|
||||
"delimiter": "\n",
|
||||
"layout_recognize": "DeepDOC",
|
||||
"html4excel": false,
|
||||
"auto_keywords": 0,
|
||||
"auto_questions": 0
|
||||
},
|
||||
"chunk_count": 0,
|
||||
"document_count": 0,
|
||||
"create_time": 1715623400000,
|
||||
"update_time": 1715624500000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 删除知识库 - `delete`
|
||||
**接口描述**: 批量删除一个或多个知识库。删除知识库将连带删除其中的所有文档和索引数据,**不可恢复**。
|
||||
**请求方法**: `DELETE`
|
||||
**接口地址**: `/api/v1/datasets`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
无
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| ids | array<string> | 是 | **ID 列表**。指定要删除的知识库 ID。如果传递 `null`,则会**清空当前租户下所有**知识库(高危操作,请谨慎使用)。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"ids": ["kb_id_101", "kb_id_102"]
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "Successfully deleted 2 datasets, 0 failed...",
|
||||
"data": {
|
||||
"success_count": 2, // 成功删除的数量
|
||||
"errors": [] // 失败的 ID 及原因列表
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 获取知识库列表 - `list_datasets`
|
||||
**接口描述**: 获取当前用户(及团队)有权限访问的知识库列表。支持分页、排序和筛选。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/datasets`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
无
|
||||
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| page | int | 否 | 1 | **页码**。从 1 开始。 |
|
||||
| page_size | int | 否 | 30 | **每页条数**。 |
|
||||
| orderby | string | 否 | "create_time" | **排序字段**。可选值: `create_time` (创建时间), `update_time` (更新时间), `document_count` (文档数)。 |
|
||||
| desc | boolean | 否 | true | **是否降序**。`true`: 降序 (最新的在前); `false`: 升序。 |
|
||||
| name | string | 否 | - | **名称筛选**。支持模糊匹配。 |
|
||||
| id | string | 否 | - | **ID 筛选**。精确匹配知识库 ID。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": [
|
||||
{
|
||||
"id": "kb_uuid_123",
|
||||
"name": "HR 政策库",
|
||||
"document_count": 12, // 包含的文档数量
|
||||
"token_num": 10240, // 总 Token 数
|
||||
"chunk_count": 150, // 总切片数
|
||||
"create_time": 1715623400000,
|
||||
"permission": "team",
|
||||
"embedding_model": "BAAI/bge-large-zh-v1.5"
|
||||
}
|
||||
],
|
||||
"total": 1 // 匹配查询条件的总记录数 (用户分页计算)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 更新知识库配置 - `update`
|
||||
**接口描述**: 更新指定知识库的配置信息。注意:如果知识库内已有解析过的切片,通常不允许修改嵌入模型 (`embedding_model`)。
|
||||
**请求方法**: `PUT`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | 知识库 ID |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
*(以下所有字段均为可选,仅传递需要修改的字段即可)*
|
||||
|
||||
| 参数名 | 类型 | 默认值 | 说明 |
|
||||
|---|---|---|---|
|
||||
| name | string | - | **新名称**。需保持租户内唯一。 |
|
||||
| avatar | string | - | **新头像**。Base64 字符串。 |
|
||||
| description | string | - | **新描述**。 |
|
||||
| permission | string | - | **新权限**。`me` 或 `team`。 |
|
||||
| embedding_model | string | - | **嵌入模型**。**注意**: 仅当知识库为空(chunk_count=0)时才允许修改。 |
|
||||
| chunk_method | string | - | **默认解析方法**。修改后将应用于后续新上传的文件 (旧文件解析方式不变)。 |
|
||||
| parser_config | object | - | **解析器配置**。全量覆盖旧配置 (结构参考 create 接口)。 |
|
||||
| pagerank | int | 0 | **PageRank 权重**。仅在使用 Elasticsearch 引擎且需调整图谱权重时设置。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": "kb_uuid_...",
|
||||
"name": "新名称",
|
||||
"update_time": 1715629999000,
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 获取知识图谱数据 - `knowledge_graph`
|
||||
**接口描述**: 获取知识库构建的知识图谱数据,包含节点(Nodes)和边(Edges),用于前端可视化展示(如 ECharts 力导向图)。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/knowledge_graph`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | 知识库 ID |
|
||||
|
||||
#### Query Parameters
|
||||
无
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"graph": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node_1",
|
||||
"label": "人工智能", // 节点显示的文本
|
||||
"pagerank": 0.05, // PageRank 权重 (决定节点大小)
|
||||
"color": "#fcb", // 节点颜色
|
||||
"img": "" // 节点图标 (如有)
|
||||
},
|
||||
{
|
||||
"id": "node_2",
|
||||
"label": "机器学习",
|
||||
"pagerank": 0.03,
|
||||
"color": "#e2b"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"source": "node_1", // 起始节点 ID
|
||||
"target": "node_2", // 目标节点 ID
|
||||
"weight": 0.8, // 边权重 (决定连线粗细)
|
||||
"label": "includes" // 关系名称 (显示在连线上)
|
||||
}
|
||||
]
|
||||
},
|
||||
"mind_map": { // 思维导图结构的保留字段 (通常用于脑图展示)
|
||||
"root": {
|
||||
"id": "root_node",
|
||||
"children": [...]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 清空知识图谱数据 - `delete_knowledge_graph`
|
||||
**接口描述**: 删除指定知识库中已生成的知识图谱索引数据(包括所有实体节点和关系边)。
|
||||
**注意**: 此操作**不会**删除原始文档或普通的向量索引,仅仅是重置图谱结构。如果需要重新生成图谱,请再次调用 `chunk` 相关接口或使用 `run_graphrag`。
|
||||
**请求方法**: `DELETE`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/knowledge_graph`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | 知识库 ID |
|
||||
|
||||
#### Body Parameters
|
||||
无
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 运行/触发 GraphRAG 索引任务 - `run_graphrag`
|
||||
**接口描述**: 触发后台异步任务,对知识库中的文档进行 GraphRAG 索引构建。此过程会使用 LLM 抽取实体(Entities)和关系(Relationships),并构建全局社区摘要。
|
||||
**前提条件**: 知识库中必须包含已解析的文档。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/run_graphrag`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | 知识库 ID |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
*(Body 可为空 `{}`, 后续版本将扩展以下配置参数)*
|
||||
|
||||
| 参数名 | 类型 | 默认值 | 说明 |
|
||||
|---|---|---|---|
|
||||
| entity_types | array | ["organization", "person", "geo", "event"] | **(预留)** 指定要抽取的实体类型列表。 |
|
||||
| method | string | "light" | **(预留)** 构建模式: `light` (轻量级), `general` (标准), `complex` (深度)。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"graphrag_task_id": "task_uuid_12345678" // 异步任务 ID,用于后续追踪进度
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 运行/触发 RAPTOR 递归摘要任务 - `run_raptor`
|
||||
**接口描述**: 触发后台异步任务,对知识库中的文档运行 RAPTOR (Recursive Abstractive Processing for Tree-Organized Retrieval) 算法。
|
||||
**功能说明**: 该算法会递归地对文档块进行聚类和摘要,生成多层级的树状索引,显著提升对长文档和复杂问题的回答能力。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/run_raptor`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | 知识库 ID |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
*(Body 可为空 `{}`, 后续版本将扩展以下配置参数)*
|
||||
|
||||
| 参数名 | 类型 | 默认值 | 说明 |
|
||||
|---|---|---|---|
|
||||
| max_cluster | int | 64 | **(预留)** 最大聚类数。 |
|
||||
| prompt | string | (内置摘要提示词) | **(预留)** 用于生成摘要的 Prompt。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"raptor_task_id": "task_uuid_87654321" // 异步任务 ID
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 查询 GraphRAG 任务进度 - `trace_graphrag`
|
||||
**接口描述**: 查询指定知识库当前 **GraphRAG** 索引构建任务的实时状态。支持长轮询机制监测进度。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/trace_graphrag`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | 知识库 ID |
|
||||
|
||||
#### Query Parameters
|
||||
无
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": "task_uuid_12345678", // 任务 ID
|
||||
"doc_id": "doc_uuid_...", // 当前正在处理的文档 ID (如果是多文档任务)
|
||||
"from_page": 0, // 当前处理的起始页码
|
||||
"to_page": 10, // 当前处理的结束页码
|
||||
"progress": 0.45, // **总进度** (0.0 ~ 1.0)。0.0: 未开始/刚开始; 1.0: 完成; -1.0: 失败。
|
||||
"progress_msg": "Extracting entities from chunk 25...", // **当前状态描述**。用于前端展示 Loading 提示。
|
||||
"create_time": 1715623400000,
|
||||
"update_time": 1715624500000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 查询 RAPTOR 任务进度 - `trace_raptor`
|
||||
**接口描述**: 查询指定知识库当前 **RAPTOR** 递归摘要任务的实时状态。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/trace_raptor`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | 知识库 ID |
|
||||
|
||||
#### Query Parameters
|
||||
无
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": "task_uuid_87654321",
|
||||
"progress": 1.0, // 进度值。1.0 表示树构建完成。
|
||||
"progress_msg": "Tree construction completed.", // 状态消息。
|
||||
"create_time": 1715629000000
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,757 @@
|
||||
## 1. 上传文档 - `upload`
|
||||
**接口描述**: 向指定的知识库上传一个或多个文档文件。上传后,文档将立即被存入文件系统/对象存储,并在数据库中创建记录。默认解析状态为 `UNSTART` (未开始),解析配置将继承自 KnowledgeBase 的默认设置。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/documents`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
**Content-Type**: `multipart/form-data`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | **知识库 ID**。指定文档归属的知识库。 |
|
||||
|
||||
#### Form Data Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| file | file | 是 | **文件二进制流**。支持多文件上传 (Multiple Files)。<br>支持格式: PDF, DOCX, TXT, MD, CS, HTML, CSV, XLSX, PPTX 等。<br>单文件大小限制请参考系统配置 (默认通常为 10MB/100MB)。 |
|
||||
| parent_path | string | 否 | **父级目录路径**。类似于文件系统的文件夹结构,默认为 `/`。如果指定 (如 `/docs/v1/`),文档将在该虚拟路径下列出。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": [
|
||||
{
|
||||
"id": "e457f92e3c0411ef8d4c0242ac120003",
|
||||
"thumbnail": null,
|
||||
"dataset_id": "d1234567890abcdef1234567890abcde",
|
||||
"chunk_method": "naive",
|
||||
"pipeline_id": null,
|
||||
"parser_config": {
|
||||
"chunk_token_num": 512,
|
||||
"delimiter": "\\n",
|
||||
"layout_recognize": "DeepDOC",
|
||||
"html4excel": false,
|
||||
"auto_keywords": 0,
|
||||
"auto_questions": 0,
|
||||
"topn_tags": 3,
|
||||
"raptor": {
|
||||
"use_raptor": false
|
||||
},
|
||||
"graphrag": {
|
||||
"use_graphrag": false
|
||||
}
|
||||
},
|
||||
"source_type": "local",
|
||||
"type": "pdf",
|
||||
"created_by": "user_id_123",
|
||||
"name": "UserGuide_v2.pdf",
|
||||
"location": "UserGuide_v2.pdf",
|
||||
"size": 102400,
|
||||
"token_count": 0,
|
||||
"chunk_count": 0,
|
||||
"progress": 0.0,
|
||||
"progress_msg": "",
|
||||
"process_begin_at": null,
|
||||
"process_duration": 0.0,
|
||||
"meta_fields": {},
|
||||
"suffix": "pdf",
|
||||
"run": "UNSTART",
|
||||
"status": "1",
|
||||
"create_time": 1715623400123,
|
||||
"create_date": "2024-05-13 10:03:20",
|
||||
"update_time": 1715623400123,
|
||||
"update_date": "2024-05-13 10:03:20"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 获取文档列表 - `list_docs`
|
||||
**接口描述**: 查询知识库下的文档列表。支持分页检索、关键词搜索、状态筛选等功能。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/documents`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | **知识库 ID**。 |
|
||||
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| page | int | 否 | 1 | **页码**。从 1 开始计数。 |
|
||||
| page_size | int | 否 | 30 | **每页数量**。 |
|
||||
| orderby | string | 否 | "create_time" | **排序字段**。支持 `create_time` (创建时间), `name` (文件名), `size` (大小) 等。 |
|
||||
| desc | boolean | 否 | true | **是否降序**。`true` (最新/最大在前), `false` (最旧/最小在前)。 |
|
||||
| id | string | 否 | - | **精确筛选 ID**。仅返回指定 ID 的文档。 |
|
||||
| name | string | 否 | - | **精确筛选文件名**。仅返回指定名称的文档。 |
|
||||
| keywords | string | 否 | - | **模糊搜索**。匹配文档名称包含该关键词的记录。 |
|
||||
| suffix | array | 否 | - | **文件后缀筛选** (如 `pdf`, `docx`)。 |
|
||||
| run | array | 否 | - | **运行状态筛选**。可选值: `UNSTART`, `RUNNING`, `CANCEL`, `DONE`, `FAIL`。 |
|
||||
| create_time_from | int | 否 | 0 | **起始时间戳** (毫秒)。查询在此时间之后创建的文档。 |
|
||||
| create_time_to | int | 否 | 0 | **结束时间戳** (毫秒)。查询在此时间之前创建的文档。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"total": 128,
|
||||
"docs": [
|
||||
{
|
||||
"id": "e457f92e3c0411ef8d4c0242ac120003",
|
||||
"thumbnail": null,
|
||||
"dataset_id": "d1234567890abcdef1234567890abcde",
|
||||
"chunk_method": "naive",
|
||||
"pipeline_id": null,
|
||||
"parser_config": {
|
||||
"chunk_token_num": 512,
|
||||
"delimiter": "\\n",
|
||||
"layout_recognize": "DeepDOC",
|
||||
"html4excel": false,
|
||||
"auto_keywords": 0,
|
||||
"auto_questions": 0,
|
||||
"topn_tags": 3,
|
||||
"raptor": {
|
||||
"use_raptor": false
|
||||
},
|
||||
"graphrag": {
|
||||
"use_graphrag": false
|
||||
}
|
||||
},
|
||||
"source_type": "local",
|
||||
"type": "pdf",
|
||||
"created_by": "user_id_123",
|
||||
"name": "UserGuide_v2.pdf",
|
||||
"location": "UserGuide_v2.pdf",
|
||||
"size": 102400,
|
||||
"token_count": 45000,
|
||||
"chunk_count": 120,
|
||||
"progress": 1.0,
|
||||
"progress_msg": "Parsing finished",
|
||||
"process_begin_at": "2024-05-13 10:05:00",
|
||||
"process_duration": 45.2,
|
||||
"meta_fields": {
|
||||
"author": "RAGFlow Team",
|
||||
"version": "2.0"
|
||||
},
|
||||
"suffix": "pdf",
|
||||
"run": "DONE",
|
||||
"status": "1",
|
||||
"create_time": 1715623400123,
|
||||
"create_date": "2024-05-13 10:03:20",
|
||||
"update_time": 1715623450000,
|
||||
"update_date": "2024-05-13 10:05:45"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 更新文档信息 - `update_doc`
|
||||
**接口描述**: 更新文档的名称、状态或解析配置。
|
||||
**特别注意**: 如果修改了 `chunk_method` 或 `parser_config`,后端会自动将 `run` 状态重置为 `UNSTART`,并清除已有的 chunk 数据,等待重新解析。
|
||||
**请求方法**: `PUT`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/documents/<document_id>`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | **知识库 ID**。 |
|
||||
| document_id | string | 是 | **文档 ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
*(仅需传递要修改的字段)*
|
||||
|
||||
| 参数名 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| name | string | **新文档名称**。需包含文件后缀且不能改变原始文件类型 (如从 `.pdf` 改为 `.txt` 会导致错误)。 |
|
||||
| enabled | boolean | **启用/禁用**。`true`: 启用 (DEFAULT, 对应 status="1"); `false`: 禁用 (对应 status="0")。禁用后该文档不参与检索。 |
|
||||
| chunk_method | string | **解析方法**。可选值: `naive`, `manual`, `qa`, `table`, `paper`, `book`, `laws`, `presentation`, `picture`, `one`, `knowledge_graph`, `email`。 |
|
||||
| parser_config | object | **解析器详细配置**。应与 `chunk_method` 匹配。以下列出 `naive` (通用) 方法的完整配置参数。 |
|
||||
|
||||
**parser_config (Naive 模式全量参数)**:
|
||||
| 参数名 | 类型 | 默认值 | 说明 |
|
||||
|---|---|---|---|
|
||||
| chunk_token_num | int | 512 | **切片最大 Token 数**。 |
|
||||
| delimiter | string | "\\n" | **分段符**。支持转义字符。 |
|
||||
| layout_recognize | string | "DeepDOC" | **布局识别模型**。可选 `DeepDOC` 或 `Simple`。 |
|
||||
| html4excel | boolean | false | **Excel转HTML**。是否将 Excel 解析为 HTML 表格。 |
|
||||
| auto_keywords | int | 0 | **自动关键词数量**。0 表示不抽取。 |
|
||||
| auto_questions | int | 0 | **自动问题数量**。0 表示不生成。 |
|
||||
| topn_tags | int | 3 | **自动标签数量**。 |
|
||||
| raptor | object | `{ "use_raptor": false }` | **RAPTOR 配置**。设置 `use_raptor: true` 可开启递归摘要索引。 |
|
||||
| graphrag | object | `{ "use_graphrag": false }` | **GraphRAG 配置**。设置 `use_graphrag: true` 可开启图谱增强。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": "e457f92e3c0411ef8d4c0242ac120003",
|
||||
"thumbnail": null,
|
||||
"dataset_id": "d1234567890abcdef1234567890abcde",
|
||||
"chunk_method": "naive",
|
||||
"pipeline_id": null,
|
||||
"parser_config": {
|
||||
"chunk_token_num": 1024,
|
||||
"delimiter": "\\n",
|
||||
"layout_recognize": "DeepDOC",
|
||||
"html4excel": false,
|
||||
"auto_keywords": 0,
|
||||
"auto_questions": 0,
|
||||
"topn_tags": 3,
|
||||
"raptor": {
|
||||
"use_raptor": false
|
||||
},
|
||||
"graphrag": {
|
||||
"use_graphrag": false
|
||||
}
|
||||
},
|
||||
"source_type": "local",
|
||||
"type": "pdf",
|
||||
"created_by": "user_id_123",
|
||||
"name": "Renamed_Guide.pdf",
|
||||
"location": "UserGuide_v2.pdf",
|
||||
"size": 102400,
|
||||
"token_count": 45000,
|
||||
"chunk_count": 0,
|
||||
"progress": 0.0,
|
||||
"progress_msg": "",
|
||||
"process_begin_at": null,
|
||||
"process_duration": 0.0,
|
||||
"meta_fields": {},
|
||||
"suffix": "pdf",
|
||||
"run": "UNSTART",
|
||||
"status": "0",
|
||||
"create_time": 1715623400123,
|
||||
"create_date": "2024-05-13 10:03:20",
|
||||
"update_time": 1715629999000,
|
||||
"update_date": "2024-05-13 12:00:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 删除文档 - `delete`
|
||||
**接口描述**: 物理删除一个或多个文档。此操作不可恢复,将同时删除数据库记录、MinIO 中的源文件以及 Elasticsearch 中的所有相关切片索引。
|
||||
**请求方法**: `DELETE`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/documents`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | **知识库 ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| ids | array<string> | 是 | **文档 ID 列表**。必须指定要删除的文档 ID。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 下载/预览原始文件 - `download`
|
||||
**接口描述**: 获取文档的原始二进制文件流。响应头将会包含 `Content-Disposition` 字段,指示浏览器以附件形式下载。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/documents/<document_id>`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | **知识库 ID**。 |
|
||||
| document_id | string | 是 | **文档 ID**。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/octet-stream`
|
||||
**Content-Disposition**: `attachment; filename="UserGuide_v2.pdf"`
|
||||
|
||||
*(直接返回文件的二进制数据流)*
|
||||
|
||||
|
||||
## 6. 触发/重试文档解析 - `parse`
|
||||
**接口描述**: 手动触发文档的解析任务。通常在上传文件后、或修改了解析配置(如 `chunk_method`)后调用此接口。支持批量触发。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/chunks`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | **知识库 ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| document_ids | array<string> | 是 | **文档 ID 列表**。指定需要(重新)解析的文档 ID。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"document_ids": ["doc_id_1", "doc_id_2"]
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 停止文档解析 - `stop_parsing`
|
||||
**接口描述**: 停止当前正在进行的文档解析任务。
|
||||
**请求方法**: `DELETE`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/chunks`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | **知识库 ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| document_ids | array<string> | 是 | **文档 ID 列表**。指定要停止解析的任务。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 获取切片列表 - `list_chunks`
|
||||
**接口描述**: 获取指定文档已解析出的切片(Chunk)列表。支持分页和关键词搜索。返回结果包含文档的详细元数据和具体的切片内容。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/documents/<document_id>/chunks`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | **知识库 ID**。 |
|
||||
| document_id | string | 是 | **文档 ID**。 |
|
||||
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| page | int | 否 | 1 | **页码**。 |
|
||||
| page_size | int | 否 | 30 | **每页数量**。 |
|
||||
| keywords | string | 否 | - | **搜索关键词**。在切片内容中进行全文检索。 |
|
||||
| id | string | 否 | - | **精确切片 ID**。若指定,则只返回该 ID 对应的切片。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"total": 150,
|
||||
"chunks": [
|
||||
{
|
||||
"id": "e457f92e3c0411ef8d4c0242ac120003_0",
|
||||
"content": "RAGFlow 是一款基于深度文档理解的开源 RAG(检索增强生成)引擎。它旨在为各种规模的企业提供精简的 RAG 工作流。RAGFlow 结合了传统文档处理的稳健性与现代大语言模型(LLM)的生成能力,确保在处理复杂格式数据(如 PDF 表格、扫描件等)时依然能保持极高的召回率和准确性。",
|
||||
"document_id": "doc_uuid_123",
|
||||
"docnm_kwd": "RAGFlow_UserGuide_v2.pdf",
|
||||
"important_keywords": ["RAGFlow", "开源", "深度文档理解", "LLM"],
|
||||
"questions": ["什么是 RAGFlow?", "RAGFlow 的主要特点是什么?"],
|
||||
"image_id": "",
|
||||
"dataset_id": "kb_uuid_456",
|
||||
"available": true,
|
||||
"positions": [1]
|
||||
},
|
||||
{
|
||||
"id": "e457f92e3c0411ef8d4c0242ac120003_1",
|
||||
"content": "主要特性:\n1. **深度文档解析**:内置 DeepDOC 识别引擎,精准还原表格、段落结构。\n2. **多路召回**:支持关键词 + 向量的混合检索。\n3. **可视化编排**:提供基于 Graph 的工作流编排能力。",
|
||||
"document_id": "doc_uuid_123",
|
||||
"docnm_kwd": "RAGFlow_UserGuide_v2.pdf",
|
||||
"important_keywords": ["DeepDOC", "混合检索", "可视化编排"],
|
||||
"questions": [],
|
||||
"image_id": "img_uuid_789",
|
||||
"dataset_id": "kb_uuid_456",
|
||||
"available": true,
|
||||
"positions": [2]
|
||||
}
|
||||
],
|
||||
"doc": {
|
||||
"id": "doc_uuid_123",
|
||||
"name": "RAGFlow_UserGuide_v2.pdf",
|
||||
"chunk_count": 150,
|
||||
"token_count": 45000,
|
||||
"chunk_method": "naive",
|
||||
"run": "DONE",
|
||||
"status": "1",
|
||||
"progress": 1.0,
|
||||
"progress_msg": "Parsing finished",
|
||||
"process_begin_at": "2024-05-13 10:05:00",
|
||||
"process_duration": 45.2,
|
||||
"meta_fields": {
|
||||
"author": "RAGFlow Team",
|
||||
"version": "2.0"
|
||||
},
|
||||
"create_time": 1715623400123,
|
||||
"create_date": "2024-05-13 10:03:20",
|
||||
"update_time": 1715623450000,
|
||||
"update_date": "2024-05-13 10:05:45",
|
||||
"dataset_id": "kb_uuid_456"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 手动新增切片 - `add_chunk`
|
||||
**接口描述**: 向指定文档中手动添加一个新的切片。系统会自动计算该切片的向量嵌入 (Embedding)。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/documents/<document_id>/chunks`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | **知识库 ID**。 |
|
||||
| document_id | string | 是 | **文档 ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| content | string | 是 | **切片内容**。手动输入的文本内容。 |
|
||||
| important_keywords | array<string> | 否 | **重要关键词**。用于关键词检索增强。 |
|
||||
| questions | array<string> | 否 | **预设问题**。用于 Q&A 检索模式增强。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"chunk": {
|
||||
"id": "new_chunk_uuid_999",
|
||||
"content": "这是管理员手动添加的一条补充切片,用于修正文档中缺失的关键信息。",
|
||||
"document_id": "doc_uuid_123",
|
||||
"docnm_kwd": "RAGFlow_UserGuide_v2.pdf",
|
||||
"important_keywords": ["手动添加", "补充信息"],
|
||||
"questions": ["如何手动添加切片?"],
|
||||
"image_id": "",
|
||||
"dataset_id": "kb_uuid_456",
|
||||
"available": true,
|
||||
"positions": []
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 修改切片信息 - `update_chunk`
|
||||
**接口描述**: 修改已存在的切片内容、关键词、可用状态等。修改内容后,系统会自动重新计算向量。
|
||||
**请求方法**: `PUT`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/documents/<document_id>/chunks/<chunk_id>`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | **知识库 ID**。 |
|
||||
| document_id | string | 是 | **文档 ID**。 |
|
||||
| chunk_id | string | 是 | **切片 ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
*(以下字段均为可选,仅传递需修改的字段)*
|
||||
|
||||
| 参数名 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| content | string | **新的切片内容**。 |
|
||||
| important_keywords | array<string> | **更新关键词列表**。覆盖原有列表。 |
|
||||
| available | boolean | **启用/禁用**。`true`: 启用 (默认); `false`: 禁用 (检索时将忽略此切片)。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. 删除切片 - `rm_chunk`
|
||||
**接口描述**: 批量删除文档中的指定切片。
|
||||
**请求方法**: `DELETE`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/documents/<document_id>/chunks`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | **知识库 ID**。 |
|
||||
| document_id | string | 是 | **文档 ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| chunk_ids | array<string> | 是 | **切片 ID 列表**。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "deleted 2 chunks",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## 12. 获取元数据摘要 - `metadata_summary`
|
||||
**接口描述**: 获取知识库中所有文档的元数据摘要信息。通常用于前端展示知识库的数据分布概况,例如不同文件类型的数量统计、文件状态分布等。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/metadata/summary`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | **知识库 ID**。 |
|
||||
|
||||
#### Query Parameters
|
||||
无
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"summary": {
|
||||
"total_doc_count": 120,
|
||||
"total_token_count": 500000,
|
||||
"file_type_distribution": {
|
||||
"pdf": 80,
|
||||
"docx": 30,
|
||||
"txt": 10
|
||||
},
|
||||
"status_distribution": {
|
||||
"1": 118, // 正常启用
|
||||
"0": 2 // 禁用
|
||||
},
|
||||
"custom_metadata": {
|
||||
"author": {
|
||||
"Alice": 50,
|
||||
"Bob": 30
|
||||
},
|
||||
"department": {
|
||||
"HR": 20,
|
||||
"Engineering": 100
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 13. 批量更新元数据 - `metadata_batch_update`
|
||||
**接口描述**: 对知识库中的文档进行批量元数据修改。支持基于复杂的条件筛选文档,然后执行批量更新或删除元数据字段的操作。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/datasets/<dataset_id>/metadata/update`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| dataset_id | string | 是 | **知识库 ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| selector | object | 否 | **筛选器**。定义要更新哪些文档。如果不传,可能作用于全量文档(请谨慎)。 |
|
||||
| updates | array | 否 | **更新操作列表**。包含 `key` 和 `value`。 |
|
||||
| deletes | array | 否 | **删除操作列表**。包含 `key`。 |
|
||||
|
||||
**Request Example (复杂场景)**:
|
||||
```json
|
||||
{
|
||||
"selector": {
|
||||
"document_ids": ["doc_id_101", "doc_id_102"],
|
||||
"metadata_condition": {
|
||||
"logic": "and",
|
||||
"conditions": [
|
||||
{"key": "author", "value": "OldName", "operator": "eq"},
|
||||
{"key": "status", "value": "draft", "operator": "eq"}
|
||||
]
|
||||
}
|
||||
},
|
||||
"updates": [
|
||||
{"key": "author", "value": "Admin"},
|
||||
{"key": "reviewed_by", "value": "ManagerA"}
|
||||
],
|
||||
"deletes": [
|
||||
{"key": "temp_tag"},
|
||||
{"key": "draft_flag"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"updated": 2, // 实际更新成功的文档数量
|
||||
"matched_docs": 2 // 匹配到的文档数量
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 14. 检索测试 (Hit Test) - `retrieval_test`
|
||||
**接口描述**: 在指定的知识库中进行模拟检索测试。此接口用于验证分段(Chunk)质量、检索参数(相似度阈值、Top K)的效果,是调试 RAG 效果的核心工具。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/retrieval`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
**注意**: 即使是简单的查询,由于包含较多配置参数,本接口也设计为 `POST` 请求。
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
无
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| dataset_ids | array<string> | 是 | - | **目标知识库 ID 列表**。支持跨多个知识库检索。 |
|
||||
| question | string | 是 | - | **用户查询问题**。 |
|
||||
| similarity_threshold | float | 否 | 0.2 | **相似度阈值**。低于此分数的 Chunk 将被过滤。 |
|
||||
| vector_similarity_weight | float | 否 | 0.3 | **向量权重**。混合检索时,向量检索结果的权重 (0~1)。剩余权重归于关键词检索。 |
|
||||
| top_k | int | 否 | 1024 | **初筛数量**。向量检索返回的候选切片数量。 |
|
||||
| rerank_id | string | 否 | - | **重排模型 ID**。若指定,将对检索结果进行 Rerank 二次排序。 |
|
||||
| highlight | boolean | 否 | true | **高亮匹配**。是否在返回内容中高亮关键词。 |
|
||||
| keyword | boolean | 否 | false | **关键词增强**。是否使用 LLM 提取问题关键词以增强检索。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"total": 15,
|
||||
"chunks": [
|
||||
{
|
||||
"id": "e457f92e3c0411ef8d4c0242ac120003_12",
|
||||
"content": "RAGFlow 支持多种文档解析模式,其中 DeepDOC 模式特别适合处理包含大量表格和扫描件的 PDF 文档。它使用深度学习模型识别文档布局,精准提取表格内容。",
|
||||
"document_id": "doc_uuid_123",
|
||||
"dataset_id": "kb_uuid_456",
|
||||
"document_name": "RAGFlow_UserGuide_v2.pdf",
|
||||
"document_keyword": "RAGFlow_UserGuide_v2.pdf",
|
||||
"similarity": 0.88,
|
||||
"vector_similarity": 0.85,
|
||||
"term_similarity": 0.92,
|
||||
"index": 12,
|
||||
"highlight": "RAGFlow 支持多种<em>文档解析模式</em>,其中 <em>DeepDOC</em> 模式特别适合处理包含大量表格和扫描件的 PDF 文档。",
|
||||
"important_keywords": ["DeepDOC", "PDF"],
|
||||
"questions": ["DeepDOC 模式有什么用?"],
|
||||
"image_id": "",
|
||||
"positions": [12]
|
||||
},
|
||||
{
|
||||
"id": "e457f92e3c0411ef8d4c0242ac120003_15",
|
||||
"content": "如果文档主要由纯文本构成,建议使用 Naive 模式。该模式解析速度快,适合通用场景。",
|
||||
"document_id": "doc_uuid_123",
|
||||
"dataset_id": "kb_uuid_456",
|
||||
"document_name": "RAGFlow_UserGuide_v2.pdf",
|
||||
"document_keyword": "RAGFlow_UserGuide_v2.pdf",
|
||||
"similarity": 0.45,
|
||||
"vector_similarity": 0.40,
|
||||
"term_similarity": 0.50,
|
||||
"index": 15,
|
||||
"highlight": "如果文档主要由纯文本构成,建议使用 <em>Naive</em> 模式。",
|
||||
"important_keywords": ["Naive", "纯文本"],
|
||||
"questions": [],
|
||||
"image_id": "",
|
||||
"positions": [15]
|
||||
}
|
||||
],
|
||||
"doc_aggs": [
|
||||
{
|
||||
"doc_name": "RAGFlow_UserGuide_v2.pdf",
|
||||
"doc_id": "doc_uuid_123",
|
||||
"count": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,503 @@
|
||||
# RAGFlow 文件管理接口详解 (File Management API)
|
||||
|
||||
## 1. 上传文件 - `upload`
|
||||
**接口描述**: 上传一个或多个文件到指定文件夹。支持多文件上传 (Multipart)。上传成功后,文件将存储在 MinIO/S3 中,并返回文件元数据列表。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/file/upload`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
**Content-Type**: `multipart/form-data`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Form Data Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| file | file | 是 | **文件二进制流**。支持多文件上传。 |
|
||||
| parent_id | string | 否 | **父级目录 ID**。如果省略,默认上传到根目录 (root)。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": [
|
||||
{
|
||||
"id": "e457f92e3c0411ef8d4c0242ac120003",
|
||||
"parent_id": "root_folder_id_123",
|
||||
"tenant_id": "tenant_uuid_456",
|
||||
"created_by": "user_uuid_789",
|
||||
"type": "pdf",
|
||||
"name": "ProjectReport.pdf",
|
||||
"location": "ProjectReport.pdf",
|
||||
"size": 204800,
|
||||
"source_type": "",
|
||||
"create_time": 1715623400123,
|
||||
"create_date": "2024-05-13 10:03:20",
|
||||
"update_time": 1715623400123,
|
||||
"update_date": "2024-05-13 10:03:20"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 新建文件夹 - `create`
|
||||
**接口描述**: 在指定父目录下创建一个新的文件夹(逻辑目录)。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/file/create`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| name | string | 是 | **文件夹名称**。同一目录下不可重名。 |
|
||||
| parent_id | string | 否 | **父级目录 ID**。省略则默认为根目录。 |
|
||||
| type | string | 是 | **类型**。固定值为 `FOLDER` 创建文件夹。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"name": "Year2024_Reports",
|
||||
"parent_id": "root_folder_id_123",
|
||||
"type": "FOLDER"
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": "folder_uuid_abc",
|
||||
"parent_id": "root_folder_id_123",
|
||||
"tenant_id": "tenant_uuid_456",
|
||||
"created_by": "user_uuid_789",
|
||||
"name": "Year2024_Reports",
|
||||
"location": "",
|
||||
"size": 0,
|
||||
"type": "folder",
|
||||
"source_type": "",
|
||||
"create_time": 1715623500000,
|
||||
"create_date": "2024-05-13 10:05:00",
|
||||
"update_time": 1715623500000,
|
||||
"update_date": "2024-05-13 10:05:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 获取文件列表 - `list_files`
|
||||
**接口描述**: 分页获取指定文件夹下的文件和子文件夹列表。支持按名称模糊搜索。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/file/list`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| parent_id | string | 否 | (Root) | **父级目录 ID**。指定要查看的目录 ID。 |
|
||||
| keywords | string | 否 | - | **搜索关键词**。按文件名模糊搜索。 |
|
||||
| page | int | 否 | 1 | **页码**。 |
|
||||
| page_size | int | 否 | 15 | **每页数量**。 |
|
||||
| orderby | string | 否 | "create_time" | **排序字段**。 |
|
||||
| desc | boolean | 否 | true | **是否降序**。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"total": 25,
|
||||
"parent_folder": {
|
||||
"id": "root_folder_id_123",
|
||||
"parent_id": "",
|
||||
"tenant_id": "tenant_uuid_456",
|
||||
"created_by": "system",
|
||||
"name": "ROOT",
|
||||
"location": "",
|
||||
"size": 0,
|
||||
"type": "folder",
|
||||
"source_type": "",
|
||||
"create_time": 1710000000000,
|
||||
"create_date": "2024-03-01 00:00:00",
|
||||
"update_time": 1710000000000,
|
||||
"update_date": "2024-03-01 00:00:00"
|
||||
},
|
||||
"files": [
|
||||
{
|
||||
"id": "folder_uuid_abc",
|
||||
"parent_id": "root_folder_id_123",
|
||||
"tenant_id": "tenant_uuid_456",
|
||||
"created_by": "user_uuid_789",
|
||||
"name": "Year2024_Reports",
|
||||
"location": "",
|
||||
"size": 0,
|
||||
"type": "folder",
|
||||
"source_type": "",
|
||||
"create_time": 1715623500000,
|
||||
"create_date": "2024-05-13 10:05:00",
|
||||
"update_time": 1715623500000,
|
||||
"update_date": "2024-05-13 10:05:00"
|
||||
},
|
||||
{
|
||||
"id": "e457f92e3c0411ef8d4c0242ac120003",
|
||||
"parent_id": "root_folder_id_123",
|
||||
"tenant_id": "tenant_uuid_456",
|
||||
"created_by": "user_uuid_789",
|
||||
"name": "ProjectReport.pdf",
|
||||
"location": "ProjectReport.pdf",
|
||||
"size": 204800,
|
||||
"type": "pdf",
|
||||
"source_type": "",
|
||||
"create_time": 1715623400123,
|
||||
"create_date": "2024-05-13 10:03:20",
|
||||
"update_time": 1715623400123,
|
||||
"update_date": "2024-05-13 10:03:20"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 获取文件流 (下载) - `get`
|
||||
**接口描述**: 通过文件 ID 下载文件内容。不同于获取元数据,该接口直接返回文件的二进制流(Octet-stream 或 Image 等)。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/file/get/<file_id>`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| file_id | string | 是 | **文件 ID**。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/octet-stream` (或具体 MIME 类型如 `image/png`)
|
||||
|
||||
*(返回二进制文件流)*
|
||||
|
||||
---
|
||||
|
||||
## 5. 下载附件 - `download_attachment`
|
||||
**接口描述**: 这是一个通用的附件下载接口,通常用于系统内部引用或特定路径的下载。它使用 `attachment_id`(通常对应 MinIO 中的存储路径/Key)来检索文件。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/file/download/<attachment_id>`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| attachment_id | string | 是 | **附件 ID / 存储 Key**。通常对应底层存储的唯一标识符。 |
|
||||
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| ext | string | 否 | "markdown" | **文件扩展名**。用于设置响应头中的 Content-Type。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/octet-stream` (或根据 ext 参数推断)
|
||||
|
||||
*(返回二进制文件流)*
|
||||
|
||||
|
||||
## 6. 重命名文件/文件夹 - `rename`
|
||||
**接口描述**: 修改文件或文件夹的名称。对于文件,通常不允许修改扩展名(后缀)。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/file/rename`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| file_id | string | 是 | **目标文件/文件夹 ID**。 |
|
||||
| name | string | 是 | **新名称**。需符合文件命名规范,且同一目录下不可重名。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"file_id": "file_uuid_123",
|
||||
"name": "New_Report_Final.pdf"
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 移动文件/文件夹 - `move`
|
||||
**接口描述**: 批量移动文件或文件夹到指定的目录 (Move)。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/file/mv`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| src_file_ids | array<string> | 是 | **源文件/文件夹 ID 列表**。支持批量移动。 |
|
||||
| dest_file_id | string | 是 | **目标文件夹 ID**。必须是已存在的文件夹 ID。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"src_file_ids": ["file_id_1", "file_id_2"],
|
||||
"dest_file_id": "folder_id_target"
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 删除文件/文件夹 - `rm`
|
||||
**接口描述**: 批量删除文件或文件夹。如果是文件夹,将递归删除其下的所有内容。此操作不可恢复。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/file/rm`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| file_ids | array<string> | 是 | **待删除的文件/文件夹 ID 列表**。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"file_ids": ["file_uuid_to_delete_1", "folder_uuid_to_delete_2"]
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 文件转知识库文档 - `convert`
|
||||
**接口描述**: 将已上传的文件(File)导入到指定的知识库(Dataset)中,转换为文档(Document)并进行解析。这是一个“文件 -> 知识库”的桥接操作。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/file/convert`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| file_ids | array<string> | 是 | **源文件 ID 列表**。必须是已存在于文件管理系统中的 ID。 |
|
||||
| kb_ids | array<string> | 是 | **目标知识库 ID 列表**。文件将被同时导入到这些知识库中。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"file_ids": ["file_uuid_pdf_1", "file_uuid_txt_2"],
|
||||
"kb_ids": ["dataset_uuid_A"]
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": [
|
||||
{
|
||||
"id": "mapping_uuid_1",
|
||||
"file_id": "file_uuid_pdf_1",
|
||||
"document_id": "doc_uuid_created_in_kb_A",
|
||||
"create_time": 1715623600123,
|
||||
"create_date": "2024-05-13 10:06:40",
|
||||
"update_time": 1715623600123,
|
||||
"update_date": "2024-05-13 10:06:40"
|
||||
},
|
||||
{
|
||||
"id": "mapping_uuid_2",
|
||||
"file_id": "file_uuid_txt_2",
|
||||
"document_id": "doc_uuid_created_in_kb_A",
|
||||
"create_time": 1715623600124,
|
||||
"create_date": "2024-05-13 10:06:40",
|
||||
"update_time": 1715623600124,
|
||||
"update_date": "2024-05-13 10:06:40"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## 10. 获取根目录信息 - `get_root_folder`
|
||||
**接口描述**: 获取当前用户的根目录文件夹信息。每个用户(Tenant)都有且仅有一个系统自动创建的根目录。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/file/root_folder`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Query Parameters
|
||||
无
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"root_folder": {
|
||||
"id": "root_folder_id_123",
|
||||
"parent_id": "",
|
||||
"tenant_id": "tenant_uuid_456",
|
||||
"created_by": "system",
|
||||
"name": "ROOT",
|
||||
"location": "",
|
||||
"size": 0,
|
||||
"type": "folder",
|
||||
"source_type": "",
|
||||
"create_time": 1710000000000,
|
||||
"create_date": "2024-03-01 00:00:00",
|
||||
"update_time": 1710000000000,
|
||||
"update_date": "2024-03-01 00:00:00"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. 获取父目录信息 - `get_parent_folder`
|
||||
**接口描述**: 获取指定文件或文件夹的直接父级目录信息。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/file/parent_folder`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| file_id | string | 是 | **当前文件/文件夹 ID**。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"parent_folder": {
|
||||
"id": "root_folder_id_123",
|
||||
"parent_id": "",
|
||||
"tenant_id": "tenant_uuid_456",
|
||||
"created_by": "system",
|
||||
"name": "ROOT",
|
||||
"location": "",
|
||||
"size": 0,
|
||||
"type": "folder",
|
||||
"source_type": "",
|
||||
"create_time": 1710000000000,
|
||||
"create_date": "2024-03-01 00:00:00",
|
||||
"update_time": 1710000000000,
|
||||
"update_date": "2024-03-01 00:00:00"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. 获取完整路径 (面包屑) - `get_all_parent_folders`
|
||||
**接口描述**: 获取指定文件或文件夹的所有上级目录列表,形成完整的路径链。返回的列表顺序通常是从根目录到直接父目录(有序)。此接口常用于前端展示“面包屑导航” (Breadcrumbs)。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/file/all_parent_folder`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| file_id | string | 是 | **目标文件/文件夹 ID**。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"parent_folders": [
|
||||
{
|
||||
"id": "root_folder_id_123",
|
||||
"parent_id": "",
|
||||
"tenant_id": "tenant_uuid_456",
|
||||
"created_by": "system",
|
||||
"name": "ROOT",
|
||||
"location": "",
|
||||
"size": 0,
|
||||
"type": "folder",
|
||||
"source_type": "",
|
||||
"create_time": 1710000000000,
|
||||
"create_date": "2024-03-01 00:00:00",
|
||||
"update_time": 1710000000000,
|
||||
"update_date": "2024-03-01 00:00:00"
|
||||
},
|
||||
{
|
||||
"id": "folder_project_a_id",
|
||||
"parent_id": "root_folder_id_123",
|
||||
"tenant_id": "tenant_uuid_456",
|
||||
"created_by": "user_id_001",
|
||||
"name": "Project A Docs",
|
||||
"location": "",
|
||||
"size": 0,
|
||||
"type": "folder",
|
||||
"source_type": "",
|
||||
"create_time": 1715000000000,
|
||||
"create_date": "2024-05-01 09:00:00",
|
||||
"update_time": 1715000000000,
|
||||
"update_date": "2024-05-01 09:00:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
+228
@@ -0,0 +1,228 @@
|
||||
# RAGFlow 搜索机器人 & AgentBot 接口详解 (SearchBot & AgentBot)
|
||||
|
||||
## 1. 搜索机器人对话 - `ask_about_embedded`
|
||||
**接口描述**: 面向 **SearchBot (搜索机器人)** 的核心对话接口,通常用于嵌入式知识库问答场景。与普通 Chat 不同,它更侧重于从指定的 `kb_ids` 中直接检索答案,且鉴权使用 `Authorization: Bearer <Beta_Token>` (即 API Key)。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/searchbots/ask`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| question | string | 是 | - | **用户问题**。 |
|
||||
| kb_ids | array<string> | 是 | - | **知识库 ID 列表**。限定从哪些知识库中检索。 |
|
||||
| search_id | string | 否 | - | **搜索应用 ID**。如果指定,将使用该搜索应用的配置 (Search App Config)。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"question": "What is the refund policy?",
|
||||
"kb_ids": ["dataset_uuid_1", "dataset_uuid_2"],
|
||||
"search_id": "search_app_uuid_abc"
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Stream Response)
|
||||
**Content-Type**: `text/event-stream`
|
||||
|
||||
```text
|
||||
data:{"code": 0, "message": "", "data": {"answer": "According to the ", "reference": {}}}
|
||||
|
||||
data:{"code": 0, "message": "", "data": {"answer": "policy, refunds are processed within 7 days.", "reference": {"chunk_1": {"content_with_weight": "Refunds...", "doc_name": "policy.pdf"}}}}
|
||||
|
||||
data:{"code": 0, "message": "", "data": true} // 结束标志
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 获取思维导图 - `mindmap`
|
||||
**接口描述**: 根据用户的查询或对话上下文,生成用于前端展示的思维导图数据结构。这通常用于帮助用户梳理复杂的搜索结果或知识结构。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/searchbots/mindmap`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| question | string | 是 | **用户问题/主题**。 |
|
||||
| kb_ids | array<string> | 是 | **知识库 ID 列表**。 |
|
||||
| search_id | string | 否 | **搜索应用 ID**。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"root": {
|
||||
"text": "Refund Policy", // 根节点文本
|
||||
"children": [
|
||||
{
|
||||
"text": "Conditions",
|
||||
"children": [
|
||||
{ "text": "Product defect" },
|
||||
{ "text": "Shipping error" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": "Timeline",
|
||||
"children": [
|
||||
{ "text": "7-14 business days" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 获取相关推荐问题 - `related_questions_embedded`
|
||||
**接口描述**: 根据用户当前的问题,生成一组相关的推荐问题 (Suggest Questions)。常用于搜索结果页底部的“猜你想问”。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/searchbots/related_questions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| question | string | 是 | **用户当前问题**。 |
|
||||
| search_id | string | 否 | **搜索应用 ID**。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": [
|
||||
"How to apply for a refund online?",
|
||||
"What items are non-refundable?",
|
||||
"Contact customer support"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 获取 AgentBot 输入项 - `begin_inputs`
|
||||
**接口描述**: 获取 **AgentBot** (嵌入式 Agent) 的初始化信息,特别是前置输入项 (Prolog/Inputs)。这用于在用户开始对话前,展示一个表单让用户输入必要信息(如姓名、邮箱、API Key 等),这些信息会被传递给 Agent 的 `Begin` 节点。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/agentbots/<agent_id>/inputs`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| agent_id | string | 是 | **Agent ID**。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"title": "Booking Assistant",
|
||||
"avatar": "http://...",
|
||||
"prologue": "Welcome! Please tell me your details.",
|
||||
"inputs": { // `Begin` 节点定义的输入变量
|
||||
"user_name": {
|
||||
"type": "string",
|
||||
"description": "Your Name",
|
||||
"required": true
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
"description": "Contact Email",
|
||||
"required": false
|
||||
}
|
||||
},
|
||||
"mode": "chat"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. AgentBot 对话交互 - `agent_bot_completions`
|
||||
**接口描述**: 面向 **AgentBot** 的嵌入式对话接口。与 `agent_completions` 类似,但它专为无需登录的 C 端用户设计,通过 API Key 鉴权。它支持完整的 Agent 流程执行和流式响应。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/agentbots/<agent_id>/completions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| agent_id | string | 是 | **Agent ID**。 |
|
||||
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| session_id | string | 是 | **会话 ID**。 |
|
||||
| inputs | object | 否 | **前置输入值**。对应 `begin_inputs` 中定义的变量,如 `{"user_name": "Alice"}`。 |
|
||||
| query | string | 否 | **用户输入**。 |
|
||||
| stream | boolean | 否 | **是否流式**。默认 `true`。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"session_id": "session_uuid_123",
|
||||
"inputs": {
|
||||
"user_name": "Bob"
|
||||
},
|
||||
"query": "I want to book a room.",
|
||||
"stream": true
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Stream Response)
|
||||
**Content-Type**: `text/event-stream`
|
||||
|
||||
```text
|
||||
data:{"event": "message", "data": {"content": "Hello Bob, ", "reference": {}}}
|
||||
|
||||
data:{"event": "message", "data": {"content": "when do you want to check in?", "reference": {}}}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Agent OpenAI 兼容接口 - `agents_completion_openai_compatibility`
|
||||
**接口描述**: 专门针对 Agent 的 **OpenAI 兼容** 接口。这使得外部工具可以像调用 OpenAI Chat Completion 一样调用 RAGFlow 配置好的复杂 Agent。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/agents_openai/<agent_id>/chat/completions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Path Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| agent_id | string | 是 | **Agent ID**。 |
|
||||
|
||||
#### Body Parameters (OpenAI Standard)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| messages | array | 是 | 包含 `role`, `content` 的消息数组。 |
|
||||
| model | string | 是 | 占位符,任意字符串。 |
|
||||
| stream | boolean | 否 | 默认 `true`。 |
|
||||
|
||||
### 响应参数 (Stream Response - OpenAI Format)
|
||||
**Content-Type**: `text/event-stream`
|
||||
|
||||
```text
|
||||
data: {"id": "agent-chat-uuid", "object": "chat.completion.chunk", "created": 1715000000, "model": "ragflow_agent", "choices": [{"index": 0, "delta": {"role": "assistant", "content": ""}, "finish_reason": null}]}
|
||||
|
||||
data: {"id": "agent-chat-uuid", "object": "chat.completion.chunk", "created": 1715000001, "model": "ragflow_agent", "choices": [{"index": 0, "delta": {"content": "Processing your request..."}, "finish_reason": null}]}
|
||||
|
||||
data: [DONE]
|
||||
```
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
# RAGFlow SearchBot 补充与通用会话接口详解 (Session Extras)
|
||||
|
||||
## 1. 获取引用详情 - `detail_share_embedded`
|
||||
**接口描述**: 当用户点击 SearchBot 回复中的引用标号 (e.g., [1]) 时,调用此接口获取该引用的详细内容(包括原文片段、来源文档名等)。此接口通常用于前端展示“引用来源”侧边栏或弹窗。它使用 API Key (Beta Token) 进行鉴权。
|
||||
**请求方法**: `GET`
|
||||
**接口地址**: `/api/v1/searchbots/detail`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Query Parameters
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| search_id | string | 是 | **搜索应用/SearchBot ID**。此接口需要验证调用者是否有权访问该 SearchBot。 |
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": "search_app_uuid_123",
|
||||
"title": "IT Knowledge Base",
|
||||
"description": "Tech support search bot",
|
||||
"kb_ids": ["kb_uuid_1", "kb_uuid_2"],
|
||||
"search_config": {
|
||||
"top_k": 5,
|
||||
"similarity_threshold": 0.5
|
||||
},
|
||||
// 注意:此接口目前主要返回 Search App 的详情配置,
|
||||
// 前端通常使用 search_config 或其他信息来辅助展示引用。
|
||||
// 具体引用内容的文本通常已包含在 `ask` 接口的 `reference` 字段中。
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. SearchBot 检索测试 - `retrieval_test_embedded`
|
||||
**接口描述**: 面向 SearchBot 的**检索效果测试**接口。它不通过 LLM 生成答案,而是直接返回 RAG 检索到的文档片段 (`chunks`)。这用于调试 SearchBot 的检索参数(如相似度阈值、Top-K)是否合理。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/searchbots/retrieval_test`
|
||||
**鉴权方式**: Header `Authorization: Bearer <API_KEY>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| kb_id | string/array | 是 | - | **知识库 ID** (或列表)。支持单个 ID 字符串或 ID 列表。 |
|
||||
| question | string | 是 | - | **测试查询词**。 |
|
||||
| page | int | 否 | 1 | **页码**。 |
|
||||
| size | int | 否 | 30 | **每页数量**。 |
|
||||
| doc_ids | array<string> | 否 | - | **限定文档 ID**。仅在指定文档中检索。 |
|
||||
| similarity_threshold | float | 否 | 0.0 | **相似度阈值**。 |
|
||||
| top_k | int | 否 | 1024 | **Top-K 数量**。 |
|
||||
| highlight | boolean | 否 | false | **高亮匹配**。是否在返回内容中标记匹配关键词。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"kb_id": ["dataset_uuid_1"],
|
||||
"question": "refund policy",
|
||||
"top_k": 5,
|
||||
"highlight": true
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"total": 12, // 命中总是
|
||||
"chunks": [
|
||||
{
|
||||
"content_with_weight": "Refunds are processed within <em>7 days</em>...", // 支持高亮
|
||||
"doc_name": "policy.pdf",
|
||||
"doc_id": "doc_uuid_101",
|
||||
"similarity": 0.92,
|
||||
"img_id": ""
|
||||
},
|
||||
{
|
||||
"content_with_weight": "Product return guidelines...",
|
||||
"doc_name": "guidelines.docx",
|
||||
"doc_id": "doc_uuid_102",
|
||||
"similarity": 0.88
|
||||
}
|
||||
],
|
||||
"labels": [] // 如果启用了查询标签功能
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 通用会话问答 - `ask_about`
|
||||
**接口描述**: **内部/测试用**的通用会话问答接口。与 `ask_embedded` 不同,此接口通常用于 RAGFlow 控制台内部的“调试”或“预览”功能,鉴权依赖用户的登录 Token (User Token),且必须显式指定 `dataset_ids`。它不绑定特定的 Chat/Agent/SearchBot 配置。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/sessions/ask`
|
||||
**鉴权方式**: Header `Authorization: Bearer <USER_TOKEN>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| question | string | 是 | **用户问题**。 |
|
||||
| dataset_ids | array<string> | 是 | **知识库 ID 列表**。必须是当前用户有权访问的知识库。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"question": "Summary of report",
|
||||
"dataset_ids": ["dataset_uuid_internal_1"]
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Stream Response)
|
||||
**Content-Type**: `text/event-stream`
|
||||
|
||||
```text
|
||||
data:{"code": 0, "message": "", "data": {"answer": "Here is the summary:", "reference": {}}}
|
||||
|
||||
data:{"code": 0, "message": "", "data": {"answer": " The report indicates...", "reference": {}}}
|
||||
|
||||
data:{"code": 0, "message": "", "data": true} // 结束
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 通用相关问题 - `related_questions`
|
||||
**接口描述**: **内部/测试用**的通用相关问题推荐接口。根据用户的问题和行业背景,利用 LLM 生成推荐问题。通常用于内部测试台。
|
||||
**请求方法**: `POST`
|
||||
**接口地址**: `/api/v1/sessions/related_questions`
|
||||
**鉴权方式**: Header `Authorization: Bearer <USER_TOKEN>`
|
||||
|
||||
### 请求参数 (Request)
|
||||
#### Body Parameters (JSON)
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| question | string | 是 | - | **原始问题/关键词**。 |
|
||||
| industry | string | 否 | "" | **行业背景** (e.g., "Finance", "Healthcare")。帮助 LLM 生成更专业的推荐。 |
|
||||
|
||||
**Request Example**:
|
||||
```json
|
||||
{
|
||||
"question": "Data privacy",
|
||||
"industry": "IT"
|
||||
}
|
||||
```
|
||||
|
||||
### 响应参数 (Response)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": [
|
||||
"GDPR compliance checklist",
|
||||
"Data encryption standards",
|
||||
"User consent management"
|
||||
]
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,98 @@
|
||||
# RAGFlow External API Reference (Grouped by File)
|
||||
|
||||
## File: `api/apps/sdk/agents.py`
|
||||
| Function Name | URL Pattern | Notes |
|
||||
|---|---|---|
|
||||
| `list_agents` | `/api/v1/agents` | List Agents |
|
||||
| `create_agent` | `/api/v1/agents` | Create Agent |
|
||||
| `update_agent` | `/api/v1/agents/<agent_id>` | Update Agent |
|
||||
| `delete_agent` | `/api/v1/agents/<agent_id>` | Delete Agent |
|
||||
| `webhook` | `/api/v1/webhook_test/<agent_id>` | Webhook Test |
|
||||
| `webhook_trace` | `/api/v1/webhook_trace/<agent_id>` | Webhook Trace |
|
||||
|
||||
## File: `api/apps/sdk/chat.py`
|
||||
| Function Name | URL Pattern | Notes |
|
||||
|---|---|---|
|
||||
| `create` | `/api/v1/chats` | Create Chat |
|
||||
| `delete_chats` | `/api/v1/chats` | Delete Chat |
|
||||
| `list_chat` | `/api/v1/chats` | List Chats |
|
||||
| `update` | `/api/v1/chats/<chat_id>` | Update Chat |
|
||||
|
||||
## File: `api/apps/sdk/dataset.py`
|
||||
| Function Name | URL Pattern | Notes |
|
||||
|---|---|---|
|
||||
| `create` | `/api/v1/datasets` | Create Dataset |
|
||||
| `delete` | `/api/v1/datasets` | Delete Dataset |
|
||||
| `list_datasets` | `/api/v1/datasets` | List Datasets |
|
||||
| `update` | `/api/v1/datasets/<dataset_id>` | Update Dataset |
|
||||
| `knowledge_graph` | `/api/v1/datasets/<dataset_id>/knowledge_graph` | Knowledge Graph |
|
||||
| `delete_knowledge_graph` | `/api/v1/datasets/<dataset_id>/knowledge_graph` | Delete Knowledge Graph |
|
||||
| `run_graphrag` | `/api/v1/datasets/<dataset_id>/run_graphrag` | Run GraphRAG |
|
||||
| `run_raptor` | `/api/v1/datasets/<dataset_id>/run_raptor` | Run Raptor |
|
||||
| `trace_graphrag` | `/api/v1/datasets/<dataset_id>/trace_graphrag` | Trace GraphRAG |
|
||||
| `trace_raptor` | `/api/v1/datasets/<dataset_id>/trace_raptor` | Trace Raptor |
|
||||
|
||||
## File: `api/apps/sdk/dify_retrieval.py`
|
||||
| Function Name | URL Pattern | Notes |
|
||||
|---|---|---|
|
||||
| `retrieval` | `/api/v1/dify/retrieval` | Dify Retrieval |
|
||||
|
||||
## File: `api/apps/sdk/doc.py`
|
||||
| Function Name | URL Pattern | Notes |
|
||||
|---|---|---|
|
||||
| `parse` | `/api/v1/datasets/<dataset_id>/chunks` | Parse Document Chunks |
|
||||
| `stop_parsing` | `/api/v1/datasets/<dataset_id>/chunks` | Stop Parsing |
|
||||
| `upload` | `/api/v1/datasets/<dataset_id>/documents` | Upload Document |
|
||||
| `list_docs` | `/api/v1/datasets/<dataset_id>/documents` | List Documents |
|
||||
| `delete` | `/api/v1/datasets/<dataset_id>/documents` | Delete Document |
|
||||
| `update_doc` | `/api/v1/datasets/<dataset_id>/documents/<document_id>` | Update Document |
|
||||
| `download` | `/api/v1/datasets/<dataset_id>/documents/<document_id>` | Download Document |
|
||||
| `list_chunks` | `/api/v1/datasets/<dataset_id>/documents/<document_id>/chunks` | List Chunks |
|
||||
| `add_chunk` | `/api/v1/datasets/<dataset_id>/documents/<document_id>/chunks` | Add Chunk |
|
||||
| `update_chunk` | `/api/v1/datasets/<dataset_id>/documents/<document_id>/chunks/<chunk_id>` | Update Chunk |
|
||||
| `rm_chunk` | `/api/v1/datasets/<dataset_id>/documents/<document_id>/chunks` | Remove Chunk |
|
||||
| `metadata_summary` | `/api/v1/datasets/<dataset_id>/metadata/summary` | Metadata Summary |
|
||||
| `metadata_batch_update` | `/api/v1/datasets/<dataset_id>/metadata/update` | Batch Update Metadata |
|
||||
| `retrieval_test` | `/api/v1/retrieval` | Retrieval Test |
|
||||
|
||||
## File: `api/apps/sdk/files.py`
|
||||
| Function Name | URL Pattern | Notes |
|
||||
|---|---|---|
|
||||
| `get_all_parent_folders` | `/api/v1/file/all_parent_folder` | Get All Parent Folders |
|
||||
| `convert` | `/api/v1/file/convert` | File Convert |
|
||||
| `create` | `/api/v1/file/create` | File Create |
|
||||
| `download_attachment` | `/api/v1/file/download/<attachment_id>` | Download Attachment |
|
||||
| `get` | `/api/v1/file/get/<file_id>` | Get File |
|
||||
| `list_files` | `/api/v1/file/list` | List Files |
|
||||
| `move` | `/api/v1/file/mv` | Move File |
|
||||
| `get_parent_folder` | `/api/v1/file/parent_folder` | Get Parent Folder |
|
||||
| `rename` | `/api/v1/file/rename` | Rename File |
|
||||
| `rm` | `/api/v1/file/rm` | Remove File |
|
||||
| `get_root_folder` | `/api/v1/file/root_folder` | Get Root Folder |
|
||||
| `upload` | `/api/v1/file/upload` | Upload File |
|
||||
|
||||
## File: `api/apps/sdk/session.py`
|
||||
| Function Name | URL Pattern | Notes |
|
||||
|---|---|---|
|
||||
| `agent_bot_completions` | `/api/v1/agentbots/<agent_id>/completions` | Agent Bot completion |
|
||||
| `begin_inputs` | `/api/v1/agentbots/<agent_id>/inputs` | Get Agent Bot inputs |
|
||||
| `agent_completions` | `/api/v1/agents/<agent_id>/completions` | Agent completion |
|
||||
| `create_agent_session` | `/api/v1/agents/<agent_id>/sessions` | Create Agent Session |
|
||||
| `list_agent_session` | `/api/v1/agents/<agent_id>/sessions` | List Agent Sessions |
|
||||
| `delete_agent_session` | `/api/v1/agents/<agent_id>/sessions` | Delete Agent Session |
|
||||
| `agents_completion_openai_compatibility` | `/api/v1/agents_openai/<agent_id>/chat/completions` | OpenAI compatible Agent completion |
|
||||
| `chatbot_completions` | `/api/v1/chatbots/<dialog_id>/completions` | Chatbot completion |
|
||||
| `chatbots_inputs` | `/api/v1/chatbots/<dialog_id>/info` | Chatbot info |
|
||||
| `chat_completion` | `/api/v1/chats/<chat_id>/completions` | Chat completion |
|
||||
| `create` | `/api/v1/chats/<chat_id>/sessions` | Create Chat Session |
|
||||
| `list_session` | `/api/v1/chats/<chat_id>/sessions` | List Chat Sessions |
|
||||
| `delete` | `/api/v1/chats/<chat_id>/sessions` | Delete Chat Session |
|
||||
| `update` | `/api/v1/chats/<chat_id>/sessions/<session_id>` | Update Chat Session |
|
||||
| `chat_completion_openai_like` | `/api/v1/chats_openai/<chat_id>/chat/completions` | OpenAI compatible Chat completion |
|
||||
| `ask_about_embedded` | `/api/v1/searchbots/ask` | Searchbot Ask |
|
||||
| `detail_share_embedded` | `/api/v1/searchbots/detail` | Searchbot Detail |
|
||||
| `mindmap` | `/api/v1/searchbots/mindmap` | Searchbot Mindmap |
|
||||
| `related_questions_embedded` | `/api/v1/searchbots/related_questions` | Searchbot Related Questions |
|
||||
| `retrieval_test_embedded` | `/api/v1/searchbots/retrieval_test` | Searchbot Retrieval Test |
|
||||
| `ask_about` | `/api/v1/sessions/ask` | Session Ask |
|
||||
| `related_questions` | `/api/v1/sessions/related_questions` | Session Related Questions |
|
||||
@@ -0,0 +1,45 @@
|
||||
# RAGFlow API 接口文档索引 (Unofficial Detailed Guide)
|
||||
|
||||
本文档汇集了 RAGFlow 核心模块的 API 详解。所有文档均遵循 **Zero Omissions (无省略)** 原则,全字段展开并包含中文注释。
|
||||
|
||||
## 📚 1. 知识库与文档管理 (Knowledge & Documents)
|
||||
核心的数据管理模块,负责上传文件、解析文档与建立索引。
|
||||
|
||||
- **[知识库管理 (Dataset)](./RAGFlow_Dataset接口详解.md)**
|
||||
- 涵盖知识库的创建、列表查询、更新、删除等接口。
|
||||
- **[文档处理 (Document)](./RAGFlow_Document接口详解.md)**
|
||||
- 涵盖文档的上传 (Upload)、解析配置更新 (Update)、解析状态查询 (Run Status)。
|
||||
- **切片管理**: 解析后的 Chunk 列表查询、增删改查。
|
||||
- **检索测试**: 直接对知识库进行召回测试 (Retrieval Test)。
|
||||
- **[文件管理 (File)](./RAGFlow_File接口详解.md)**
|
||||
- 类似网盘的文件操作体系。
|
||||
- **CRUD**: 上传、下载、列表。
|
||||
- **目录**: 文件夹创建、面包屑导航 (`get_all_parent_folders`)。
|
||||
- **操作**: 移动、重命名、删除、导入知识库 (`convert`).
|
||||
|
||||
## 💬 2. 聊天助手 (Chat Assistant)
|
||||
RAGFlow 原生的对话助手体系,基于 Assistant (Dialog) 模型。
|
||||
|
||||
- **[会话管理 (Chat Session)](./RAGFlow_Chat_Session接口详解.md)**
|
||||
- 管理 `/chats/` 下的会话生命周期。
|
||||
- 创建会话、获取历史记录、重命名、批量删除。
|
||||
- **[对话交互 (Chat Completion)](./RAGFlow_Chat_Completion接口详解.md)**
|
||||
- **Core Chat**: 原生流式对话 (`/chats/<id>/completions`), 支持引用 (`quote`)。
|
||||
- **OpenAI Compatible**: 完美兼容 OpenAI `/v1/chat/completions` 协议。
|
||||
- **Embedded Bot**: 面向 C 端嵌入窗口的对话接口 (`/chatbots/`).
|
||||
|
||||
## 🤖 3. Agent 与 机器人 (Agent & Bots)
|
||||
基于 Graph (DAG) 编排的复杂应用与各类机器人扩展。
|
||||
|
||||
- **[Agent 与 Dify 兼容 (Agent & Dify)](./RAGFlow_Agent_Dify接口详解.md)**
|
||||
- **Agent Session**: Agent 的会话管理与流式对话 (`agent_completions`)。
|
||||
- **Dify Adapter**: 兼容 Dify 协议的检索接口 (`retrieval`).
|
||||
- **[SearchBot 与 AgentBot](./RAGFlow_SearchBot_AgentBot接口详解.md)**
|
||||
- **SearchBot**: 纯搜索机器人,支持思维导图 (`mindmap`)、相关问题 (`related_questions`).
|
||||
- **AgentBot**: 嵌入式 Agent,支持前置表单 (`begin_inputs`).
|
||||
- **Agent OpenAI**: Agent 的 OpenAI 兼容接口。
|
||||
|
||||
## 🛠️ 4. 其他 (Extras)
|
||||
- **[通用与补充接口 (Session Extras)](./RAGFlow_Session_Extra接口详解.md)**
|
||||
- **引用详情**: 获取 SearchBot 引用来源 (`detail_share_embedded`).
|
||||
- **通用问答**: 内部调试用的直接问答 (`ask_about`).
|
||||
@@ -0,0 +1,68 @@
|
||||
package xiaozhi.modules.knowledge.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 文档 DTO
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "知识库文档")
|
||||
public class DocumentDTO implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "本地ID")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "知识库ID")
|
||||
private String datasetId;
|
||||
|
||||
@Schema(description = "RAGFlow文档ID")
|
||||
private String documentId;
|
||||
|
||||
@Schema(description = "文档名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "文件大小")
|
||||
private Long size;
|
||||
|
||||
@Schema(description = "文件类型")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "分块方法")
|
||||
private String chunkMethod;
|
||||
|
||||
@Schema(description = "解析配置")
|
||||
private Map<String, Object> parserConfig;
|
||||
|
||||
@Schema(description = "处理状态 (1:解析中 3:成功 4:失败)")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "错误信息")
|
||||
private String error;
|
||||
|
||||
@Schema(description = "分块数量")
|
||||
private Integer chunkCount;
|
||||
|
||||
@Schema(description = "Token数量")
|
||||
private Long tokenCount;
|
||||
|
||||
@Schema(description = "是否启用")
|
||||
private Integer enabled;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private Date createdAt;
|
||||
|
||||
@Schema(description = "更新时间")
|
||||
private Date updatedAt;
|
||||
|
||||
@Schema(description = "上传进度 (虚拟字段)")
|
||||
private Double progress;
|
||||
|
||||
@Schema(description = "缩略图/预览图 (虚拟字段)")
|
||||
private String thumbnail;
|
||||
}
|
||||
@@ -26,9 +26,30 @@ public class KnowledgeBaseDTO implements Serializable {
|
||||
@Schema(description = "知识库名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "知识库头像(Base64)")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "知识库描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "嵌入模型名称")
|
||||
private String embeddingModel;
|
||||
|
||||
@Schema(description = "权限设置: me/team")
|
||||
private String permission;
|
||||
|
||||
@Schema(description = "分块方法")
|
||||
private String chunkMethod;
|
||||
|
||||
@Schema(description = "解析器配置(JSON String)")
|
||||
private String parserConfig;
|
||||
|
||||
@Schema(description = "分块总数")
|
||||
private Long chunkCount;
|
||||
|
||||
@Schema(description = "总Token数")
|
||||
private Long tokenNum;
|
||||
|
||||
@Schema(description = "状态(0:禁用 1:启用)")
|
||||
private Integer status;
|
||||
|
||||
|
||||
+27
-4
@@ -6,10 +6,12 @@ import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "知识库文档")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class KnowledgeFilesDTO implements Serializable {
|
||||
|
||||
@Serial
|
||||
@@ -35,7 +37,19 @@ public class KnowledgeFilesDTO implements Serializable {
|
||||
@Schema(description = "文件路径")
|
||||
private String filePath;
|
||||
|
||||
@Schema(description = "元数据字段")
|
||||
@Schema(description = "解析进度 (0.0 ~ 1.0)")
|
||||
private Double progress;
|
||||
|
||||
@Schema(description = "缩略图 (Base64 或 URL)")
|
||||
private String thumbnail;
|
||||
|
||||
@Schema(description = "解析耗时 (单位: 秒)")
|
||||
private Double processDuration;
|
||||
|
||||
@Schema(description = "来源类型 (local, s3, url 等)")
|
||||
private String sourceType;
|
||||
|
||||
@Schema(description = "元数据字段 (Map 格式)")
|
||||
private Map<String, Object> metaFields;
|
||||
|
||||
@Schema(description = "分块方法")
|
||||
@@ -44,10 +58,10 @@ public class KnowledgeFilesDTO implements Serializable {
|
||||
@Schema(description = "解析器配置")
|
||||
private Map<String, Object> parserConfig;
|
||||
|
||||
@Schema(description = "状态")
|
||||
private Integer status;
|
||||
@Schema(description = "可用状态 (1: 启用/正常, 0: 禁用/失效)")
|
||||
private String status;
|
||||
|
||||
@Schema(description = "文档解析状态")
|
||||
@Schema(description = "运行状态 (UNSTART/RUNNING/CANCEL/DONE/FAIL)")
|
||||
private String run;
|
||||
|
||||
@Schema(description = "创建者")
|
||||
@@ -62,6 +76,15 @@ public class KnowledgeFilesDTO implements Serializable {
|
||||
@Schema(description = "更新时间")
|
||||
private Date updatedAt;
|
||||
|
||||
@Schema(description = "分块数量")
|
||||
private Integer chunkCount;
|
||||
|
||||
@Schema(description = "Token数量")
|
||||
private Long tokenCount;
|
||||
|
||||
@Schema(description = "解析错误信息")
|
||||
private String error;
|
||||
|
||||
// 文档解析状态常量定义
|
||||
private static final Integer STATUS_UNSTART = 0;
|
||||
private static final Integer STATUS_RUNNING = 1;
|
||||
|
||||
@@ -0,0 +1,421 @@
|
||||
package xiaozhi.modules.knowledge.dto.agent;
|
||||
|
||||
import lombok.*;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.validation.constraints.*;
|
||||
|
||||
@Schema(description = "智能体 (Agent) 管理聚合 DTO")
|
||||
public class AgentDTO {
|
||||
|
||||
// ========== 1. Agent 管理 (CRUD) - 对应 RAGFlow_Agent接口详解 ==========
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "Agent 创建请求")
|
||||
public static class CreateReq implements Serializable {
|
||||
@Schema(description = "Agent 标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "My Agent")
|
||||
@NotBlank(message = "Agent 标题不能为空")
|
||||
@JsonProperty("title")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "DSL 定义 (画布 JSON)", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "DSL 定义不能为空")
|
||||
@JsonProperty("dsl")
|
||||
private Map<String, Object> dsl;
|
||||
|
||||
@Schema(description = "描述", example = "这是一个测试 Agent")
|
||||
@JsonProperty("description")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "头像 URL", example = "http://example.com/avatar.png")
|
||||
@JsonProperty("avatar")
|
||||
private String avatar;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "Agent 更新请求")
|
||||
public static class UpdateReq implements Serializable {
|
||||
@Schema(description = "Agent 标题", example = "Updated Agent")
|
||||
@JsonProperty("title")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "DSL 定义 (画布 JSON)")
|
||||
@JsonProperty("dsl")
|
||||
private Map<String, Object> dsl;
|
||||
|
||||
@Schema(description = "描述")
|
||||
@JsonProperty("description")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "头像 URL")
|
||||
@JsonProperty("avatar")
|
||||
private String avatar;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "Agent 列表请求")
|
||||
public static class ListReq implements Serializable {
|
||||
@Schema(description = "页码", defaultValue = "1")
|
||||
@JsonProperty("page")
|
||||
@Builder.Default
|
||||
private Integer page = 1;
|
||||
|
||||
@Schema(description = "每页大小", defaultValue = "10")
|
||||
@JsonProperty("page_size")
|
||||
@Builder.Default
|
||||
private Integer pageSize = 10;
|
||||
|
||||
@Schema(description = "排序字段", defaultValue = "update_time")
|
||||
@JsonProperty("orderby")
|
||||
@Builder.Default
|
||||
private String orderby = "update_time";
|
||||
|
||||
@Schema(description = "是否降序", defaultValue = "true")
|
||||
@JsonProperty("desc")
|
||||
@Builder.Default
|
||||
private Boolean desc = true;
|
||||
|
||||
@Schema(description = "Agent ID 过滤")
|
||||
@JsonProperty("id")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "标题模糊搜索")
|
||||
@JsonProperty("title")
|
||||
private String title;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "Agent 响应对象")
|
||||
public static class AgentVO implements Serializable {
|
||||
@Schema(description = "Agent ID")
|
||||
@JsonProperty("id")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "标题")
|
||||
@JsonProperty("title")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "描述")
|
||||
@JsonProperty("description")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "头像")
|
||||
@JsonProperty("avatar")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "DSL 定义")
|
||||
@JsonProperty("dsl")
|
||||
private Map<String, Object> dsl;
|
||||
|
||||
@Schema(description = "创建者 ID")
|
||||
@JsonProperty("user_id")
|
||||
private String userId;
|
||||
|
||||
@Schema(description = "画布分类")
|
||||
@JsonProperty("canvas_category")
|
||||
private String canvasCategory;
|
||||
|
||||
@Schema(description = "创建时间 (时间戳)")
|
||||
@JsonProperty("create_time")
|
||||
private Long createTime;
|
||||
|
||||
@Schema(description = "更新时间 (时间戳)")
|
||||
@JsonProperty("update_time")
|
||||
private Long updateTime;
|
||||
}
|
||||
|
||||
// ========== 2. Webhook 调试与追踪 - 对应 RAGFlow_Agent接口详解 ==========
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "Webhook 触发请求 (参数动态)")
|
||||
public static class WebhookTriggerReq implements Serializable {
|
||||
@Schema(description = "输入变量", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "输入变量不能为空")
|
||||
@JsonProperty("inputs")
|
||||
private Map<String, Object> inputs;
|
||||
|
||||
@Schema(description = "查询词", example = "Hello")
|
||||
@JsonProperty("query")
|
||||
private String query;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "Webhook 追踪请求")
|
||||
public static class WebhookTraceReq implements Serializable {
|
||||
@Schema(description = "时间戳游标", example = "1700000000.0")
|
||||
@JsonProperty("since_ts")
|
||||
private Double sinceTs;
|
||||
|
||||
@Schema(description = "Webhook ID")
|
||||
@JsonProperty("webhook_id")
|
||||
private String webhookId;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "Webhook 追踪响应")
|
||||
public static class WebhookTraceVO implements Serializable {
|
||||
@Schema(description = "Webhook ID")
|
||||
@JsonProperty("webhook_id")
|
||||
private String webhookId;
|
||||
|
||||
@Schema(description = "是否结束")
|
||||
@JsonProperty("finished")
|
||||
private Boolean finished;
|
||||
|
||||
@Schema(description = "下一次查询的时间戳游标")
|
||||
@JsonProperty("next_since_ts")
|
||||
private Double nextSinceTs;
|
||||
|
||||
@Schema(description = "事件列表")
|
||||
@JsonProperty("events")
|
||||
private List<TraceEvent> events;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "追踪事件项")
|
||||
public static class TraceEvent implements Serializable {
|
||||
@Schema(description = "时间戳")
|
||||
@JsonProperty("ts")
|
||||
private Double ts;
|
||||
|
||||
@Schema(description = "事件类型")
|
||||
@JsonProperty("event")
|
||||
private String event;
|
||||
|
||||
@Schema(description = "事件数据")
|
||||
@JsonProperty("data")
|
||||
private Object data;
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 3. Agent 会话 (Session) - 对应 RAGFlow_Agent_Dify接口详解 ==========
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "Session 创建请求")
|
||||
public static class SessionCreateReq implements Serializable {
|
||||
@Schema(description = "用户 ID")
|
||||
@JsonProperty("user_id")
|
||||
private String userId;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "Session 列表请求")
|
||||
public static class SessionListReq implements Serializable {
|
||||
@Schema(description = "页码", defaultValue = "1")
|
||||
@JsonProperty("page")
|
||||
@Builder.Default
|
||||
private Integer page = 1;
|
||||
|
||||
@Schema(description = "每页大小", defaultValue = "10")
|
||||
@JsonProperty("page_size")
|
||||
@Builder.Default
|
||||
private Integer pageSize = 10;
|
||||
|
||||
@Schema(description = "排序字段", defaultValue = "create_time")
|
||||
@JsonProperty("orderby")
|
||||
@Builder.Default
|
||||
private String orderby = "create_time";
|
||||
|
||||
@Schema(description = "是否降序", defaultValue = "true")
|
||||
@JsonProperty("desc")
|
||||
@Builder.Default
|
||||
private Boolean desc = true;
|
||||
|
||||
@Schema(description = "Session ID")
|
||||
@JsonProperty("id")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "用户 ID")
|
||||
@JsonProperty("user_id")
|
||||
private String userId;
|
||||
|
||||
@Schema(description = "是否返回 DSL")
|
||||
@JsonProperty("dsl")
|
||||
@Builder.Default
|
||||
private Boolean dsl = false;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "Session 批量删除请求")
|
||||
public static class SessionBatchDeleteReq implements Serializable {
|
||||
@Schema(description = "会话 ID 列表", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@JsonProperty("ids")
|
||||
@NotEmpty(message = "ID列表不能为空")
|
||||
private List<String> ids;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "Session 响应对象")
|
||||
public static class SessionVO implements Serializable {
|
||||
@Schema(description = "Session ID")
|
||||
@JsonProperty("id")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "Agent ID")
|
||||
@JsonProperty("agent_id")
|
||||
private String agentId;
|
||||
|
||||
@Schema(description = "用户 ID")
|
||||
@JsonProperty("user_id")
|
||||
private String userId;
|
||||
|
||||
@Schema(description = "来源")
|
||||
@JsonProperty("source")
|
||||
private String source;
|
||||
|
||||
@Schema(description = "DSL 定义")
|
||||
@JsonProperty("dsl")
|
||||
private Map<String, Object> dsl;
|
||||
|
||||
@Schema(description = "消息列表")
|
||||
@JsonProperty("messages")
|
||||
private List<Map<String, Object>> messages;
|
||||
}
|
||||
|
||||
// ========== 4. Agent 对话 (Completion) - 对应 RAGFlow_Agent_Dify接口详解 ==========
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "Completion 对话请求")
|
||||
public static class CompletionReq implements Serializable {
|
||||
@Schema(description = "会话 ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "会话 ID 不能为空")
|
||||
@JsonProperty("session_id")
|
||||
private String sessionId;
|
||||
|
||||
@Schema(description = "用户问题")
|
||||
@JsonProperty("question")
|
||||
private String question;
|
||||
|
||||
@Schema(description = "是否流式返回", defaultValue = "true")
|
||||
@JsonProperty("stream")
|
||||
@Builder.Default
|
||||
private Boolean stream = true;
|
||||
|
||||
@Schema(description = "是否返回追踪信息", defaultValue = "false")
|
||||
@JsonProperty("return_trace")
|
||||
@Builder.Default
|
||||
private Boolean returnTrace = false;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "Completion 对话响应")
|
||||
public static class CompletionVO implements Serializable {
|
||||
@Schema(description = "会话 ID")
|
||||
@JsonProperty("id")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "回复内容")
|
||||
@JsonProperty("content")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "引用来源")
|
||||
@JsonProperty("reference")
|
||||
private Map<String, Object> reference;
|
||||
|
||||
@Schema(description = "追踪信息")
|
||||
@JsonProperty("trace")
|
||||
private List<Object> trace;
|
||||
}
|
||||
|
||||
// ========== 5. Dify 兼容检索 - 对应 RAGFlow_Agent_Dify接口详解 ==========
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "Dify 兼容检索请求")
|
||||
public static class DifyRetrievalReq implements Serializable {
|
||||
@Schema(description = "知识库 ID")
|
||||
@JsonProperty("knowledge_id")
|
||||
private String knowledgeId;
|
||||
|
||||
@Schema(description = "查询词")
|
||||
@JsonProperty("query")
|
||||
private String query;
|
||||
|
||||
@Schema(description = "检索设置")
|
||||
@JsonProperty("retrieval_setting")
|
||||
private Map<String, Object> retrievalSetting;
|
||||
|
||||
@Schema(description = "元数据过滤条件")
|
||||
@JsonProperty("metadata_condition")
|
||||
private Map<String, Object> metadataCondition;
|
||||
|
||||
@Schema(description = "是否使用知识图谱")
|
||||
@JsonProperty("use_kg")
|
||||
private Boolean useKg;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "Dify 兼容检索响应")
|
||||
public static class DifyRetrievalVO implements Serializable {
|
||||
@Schema(description = "检索结果列表")
|
||||
@JsonProperty("records")
|
||||
private List<Record> records;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "检索记录")
|
||||
public static class Record implements Serializable {
|
||||
@Schema(description = "内容")
|
||||
@JsonProperty("content")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "相似度分数")
|
||||
@JsonProperty("score")
|
||||
private Double score;
|
||||
|
||||
@Schema(description = "标题")
|
||||
@JsonProperty("title")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "元数据")
|
||||
@JsonProperty("metadata")
|
||||
private Map<String, Object> metadata;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package xiaozhi.modules.knowledge.dto.bot;
|
||||
|
||||
import lombok.*;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.validation.constraints.*;
|
||||
|
||||
@Schema(description = "外部机器人 (Bot) 聚合 DTO")
|
||||
public class BotDTO {
|
||||
|
||||
// ========== 1. SearchBot (检索机器人) ==========
|
||||
|
||||
// 对应 /api/v1/searchbots/ask
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "SearchBot 提问请求")
|
||||
public static class SearchAskReq implements Serializable {
|
||||
@Schema(description = "用户问题", requiredMode = Schema.RequiredMode.REQUIRED, example = "What is RAG?")
|
||||
@NotBlank(message = "问题不能为空")
|
||||
@JsonProperty("question")
|
||||
private String question;
|
||||
|
||||
@Schema(description = "是否返回引用", defaultValue = "false")
|
||||
@JsonProperty("quote")
|
||||
@Builder.Default
|
||||
private Boolean quote = false;
|
||||
|
||||
@Schema(description = "是否流式返回", defaultValue = "true")
|
||||
@JsonProperty("stream")
|
||||
@Builder.Default
|
||||
private Boolean stream = true;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "SearchBot 提问响应")
|
||||
public static class SearchAskVO implements Serializable {
|
||||
@Schema(description = "回答内容")
|
||||
@JsonProperty("answer")
|
||||
private String answer;
|
||||
|
||||
@Schema(description = "引用来源 (Value 结构通常对应 RetrievalDTO.HitVO)")
|
||||
@JsonProperty("reference")
|
||||
private Map<String, Object> reference;
|
||||
}
|
||||
|
||||
// 对应 /api/v1/searchbots/related_questions
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "相关问题请求")
|
||||
public static class RelatedQuestionReq implements Serializable {
|
||||
@Schema(description = "用户问题", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "问题不能为空")
|
||||
@JsonProperty("question")
|
||||
private String question;
|
||||
}
|
||||
|
||||
// 对应 /api/v1/searchbots/mindmap
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "思维导图请求")
|
||||
public static class MindMapReq implements Serializable {
|
||||
@Schema(description = "用户问题", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "问题不能为空")
|
||||
@JsonProperty("question")
|
||||
private String question;
|
||||
}
|
||||
|
||||
// ========== 2. AgentBot (嵌入式 Agent) ==========
|
||||
|
||||
// 对应 /api/v1/agentbots/{id}/inputs
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "AgentBot 输入参数请求")
|
||||
public static class AgentInputsReq implements Serializable {
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "AgentBot 输入参数定义响应")
|
||||
public static class AgentInputsVO implements Serializable {
|
||||
@Schema(description = "表单变量定义列表")
|
||||
@JsonProperty("variables")
|
||||
private List<Map<String, Object>> variables;
|
||||
}
|
||||
|
||||
// 对应 /api/v1/agentbots/{id}/completions
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "AgentBot 对话请求")
|
||||
public static class AgentCompletionReq implements Serializable {
|
||||
@Schema(description = "输入参数值")
|
||||
@JsonProperty("inputs")
|
||||
private Map<String, Object> inputs;
|
||||
|
||||
@Schema(description = "用户查询", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "查询内容不能为空")
|
||||
@JsonProperty("question")
|
||||
private String question;
|
||||
|
||||
@Schema(description = "是否流式返回", defaultValue = "true")
|
||||
@JsonProperty("stream")
|
||||
@Builder.Default
|
||||
private Boolean stream = true;
|
||||
|
||||
@Schema(description = "会话 ID")
|
||||
@JsonProperty("session_id")
|
||||
private String sessionId;
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package xiaozhi.modules.knowledge.dto.chat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 聊天对话请求 DTO (OpenAI 兼容格式)
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "聊天对话请求")
|
||||
public class ChatCompletionRequest implements Serializable {
|
||||
|
||||
@Schema(description = "模型标识 (对应 agent_id 或 bot_id)", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@JsonProperty("model")
|
||||
private String model;
|
||||
|
||||
@Schema(description = "对话消息列表", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@JsonProperty("messages")
|
||||
private List<Message> messages;
|
||||
|
||||
@Schema(description = "是否流式返回", defaultValue = "false")
|
||||
@JsonProperty("stream")
|
||||
private Boolean stream = false;
|
||||
|
||||
@Schema(description = "温度系数 (0-1)", defaultValue = "0.7")
|
||||
@JsonProperty("temperature")
|
||||
private Double temperature;
|
||||
|
||||
@Schema(description = "Session ID (可选,用于延续会话)")
|
||||
@JsonProperty("session_id")
|
||||
private String sessionId;
|
||||
|
||||
@Schema(description = "其他RAGFlow特定参数 (可选)")
|
||||
private Map<String, Object> extra;
|
||||
|
||||
@Data
|
||||
public static class Message implements Serializable {
|
||||
@Schema(description = "角色 (system, user, assistant)", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String role;
|
||||
|
||||
@Schema(description = "内容", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String content;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,523 @@
|
||||
package xiaozhi.modules.knowledge.dto.chat;
|
||||
|
||||
import lombok.*;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.validation.constraints.*;
|
||||
|
||||
/**
|
||||
* 对话管理聚合 DTO
|
||||
* <p>
|
||||
* 容器类,内含对话助手、会话和消息的所有请求/响应对象。
|
||||
* </p>
|
||||
*/
|
||||
@Schema(description = "对话管理聚合 DTO")
|
||||
public class ChatDTO {
|
||||
|
||||
// ========== 1. 对话助手 (Assistant/Bot) 相关 ==========
|
||||
|
||||
/**
|
||||
* 提示词配置
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "提示词配置")
|
||||
public static class PromptConfig implements Serializable {
|
||||
|
||||
@Schema(description = "系统提示词", example = "你是一个专业的客服助手...")
|
||||
@JsonProperty("prompt")
|
||||
private String systemPrompt;
|
||||
|
||||
@Schema(description = "开场白", example = "您好,我是您的智能助手,请问有什么可以帮您?")
|
||||
private String opener;
|
||||
|
||||
@Schema(description = "空结果回复", example = "抱歉,我没有找到相关信息。")
|
||||
@JsonProperty("empty_response")
|
||||
private String emptyResponse;
|
||||
|
||||
@Schema(description = "是否展示引用", example = "true")
|
||||
@JsonProperty("show_quote")
|
||||
private Boolean quote;
|
||||
|
||||
@Schema(description = "是否启用 TTS", example = "false")
|
||||
private Boolean tts;
|
||||
|
||||
@Schema(description = "相似度阈值 (0.0 - 1.0)", example = "0.2")
|
||||
@JsonProperty("similarity_threshold")
|
||||
private Float similarityThreshold;
|
||||
|
||||
@Schema(description = "关键词相似度权重 (0.0 - 1.0)", example = "0.7")
|
||||
@JsonProperty("keywords_similarity_weight")
|
||||
private Float vectorSimilarityWeight;
|
||||
|
||||
@Schema(description = "检索 Top N", example = "6")
|
||||
@JsonProperty("top_n")
|
||||
private Integer topK;
|
||||
|
||||
@Schema(description = "Rerank 模型", example = "rerank_model_001")
|
||||
@JsonProperty("rerank_model")
|
||||
private String rerankId;
|
||||
|
||||
@Schema(description = "是否启用多轮对话优化", example = "false")
|
||||
@JsonProperty("refine_multiturn")
|
||||
private Boolean refineMultigraph;
|
||||
|
||||
@Schema(description = "变量列表")
|
||||
private List<Map<String, Object>> variables;
|
||||
}
|
||||
|
||||
/**
|
||||
* LLM 配置
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "LLM 模型配置")
|
||||
public static class LLMConfig implements Serializable {
|
||||
|
||||
@NotBlank(message = "模型名称不能为空")
|
||||
@Schema(description = "模型名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "gpt-4")
|
||||
@JsonProperty("model_name")
|
||||
private String modelName;
|
||||
|
||||
@Schema(description = "温度参数 (0.0 - 2.0)", example = "0.7")
|
||||
private Float temperature;
|
||||
|
||||
@Schema(description = "Top P 采样", example = "0.9")
|
||||
@JsonProperty("top_p")
|
||||
private Float topP;
|
||||
|
||||
@Schema(description = "最大 Token 数", example = "4096")
|
||||
@JsonProperty("max_tokens")
|
||||
private Integer maxTokens;
|
||||
|
||||
@Schema(description = "存在惩罚", example = "0.0")
|
||||
@JsonProperty("presence_penalty")
|
||||
private Float presencePenalty;
|
||||
|
||||
@Schema(description = "频率惩罚", example = "0.0")
|
||||
@JsonProperty("frequency_penalty")
|
||||
private Float frequencyPenalty;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建助手请求
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "创建助手请求")
|
||||
public static class AssistantCreateReq implements Serializable {
|
||||
|
||||
@NotBlank(message = "助手名称不能为空")
|
||||
@Schema(description = "助手名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "智能客服助手")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "助手头像 (Base64 编码)", example = "")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "关联的知识库 ID 列表", example = "[\"kb_001\", \"kb_002\"]")
|
||||
@JsonProperty("dataset_ids")
|
||||
private List<String> datasetIds;
|
||||
|
||||
@Schema(description = "助手描述", example = "这是一个智能客服助手")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "LLM 模型配置")
|
||||
@JsonProperty("llm")
|
||||
private LLMConfig llm;
|
||||
|
||||
@Schema(description = "提示词配置")
|
||||
@JsonProperty("prompt")
|
||||
private PromptConfig promptConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新助手请求
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "更新助手请求")
|
||||
public static class AssistantUpdateReq implements Serializable {
|
||||
|
||||
@Schema(description = "助手名称", example = "智能客服助手 V2")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "助手头像 (Base64 编码)", example = "")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "关联的知识库 ID 列表", example = "[\"kb_001\", \"kb_002\"]")
|
||||
@JsonProperty("dataset_ids")
|
||||
private List<String> datasetIds;
|
||||
|
||||
@Schema(description = "助手描述", example = "这是一个智能客服助手")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "LLM 模型配置")
|
||||
@JsonProperty("llm")
|
||||
private LLMConfig llm;
|
||||
|
||||
@Schema(description = "提示词配置")
|
||||
@JsonProperty("prompt")
|
||||
private PromptConfig promptConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询助手列表请求
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "查询助手列表请求")
|
||||
public static class AssistantListReq implements Serializable {
|
||||
|
||||
@Schema(description = "页码 (从 1 开始)", example = "1")
|
||||
private Integer page;
|
||||
|
||||
@Schema(description = "每页数量", example = "30")
|
||||
@JsonProperty("page_size")
|
||||
private Integer pageSize;
|
||||
|
||||
@Schema(description = "按名称过滤 (模糊匹配)", example = "客服")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "排序字段: create_time / update_time", example = "create_time")
|
||||
private String orderby;
|
||||
|
||||
@Schema(description = "是否降序", example = "true")
|
||||
private Boolean desc;
|
||||
|
||||
@Schema(description = "按 ID 精确筛选", example = "assistant_001")
|
||||
private String id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 助手详情 VO
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "助手详情 VO")
|
||||
public static class AssistantVO implements Serializable {
|
||||
|
||||
@Schema(description = "助手 ID", example = "assistant_001")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "租户 ID", example = "tenant_001")
|
||||
@JsonProperty("tenant_id")
|
||||
private String tenantId;
|
||||
|
||||
@Schema(description = "助手名称", example = "智能客服助手")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "助手头像", example = "")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "关联的知识库 ID 列表")
|
||||
@JsonProperty("dataset_ids")
|
||||
private List<String> datasetIds;
|
||||
|
||||
@Schema(description = "关联的知识库列表 (详情)")
|
||||
private List<SimpleDatasetVO> datasets;
|
||||
|
||||
@Schema(description = "助手描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "LLM 模型配置")
|
||||
@JsonProperty("llm")
|
||||
private LLMConfig llm;
|
||||
|
||||
@Schema(description = "提示词配置")
|
||||
@JsonProperty("prompt")
|
||||
private PromptConfig promptConfig;
|
||||
|
||||
@Schema(description = "创建时间 (时间戳)", example = "1700000000000")
|
||||
@JsonProperty("create_time")
|
||||
private Long createTime;
|
||||
|
||||
@Schema(description = "更新时间 (时间戳)", example = "1700000001000")
|
||||
@JsonProperty("update_time")
|
||||
private Long updateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除助手请求
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "删除助手请求")
|
||||
public static class AssistantDeleteReq implements Serializable {
|
||||
|
||||
@Schema(description = "要删除的助手 ID 列表", example = "[\"assistant_001\", \"assistant_002\"]")
|
||||
private List<String> ids;
|
||||
}
|
||||
|
||||
// ========== 2. 会话 (Session) 相关 ==========
|
||||
|
||||
/**
|
||||
* 创建会话请求
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "创建会话请求")
|
||||
public static class SessionCreateReq implements Serializable {
|
||||
|
||||
@Schema(description = "会话名称", example = "技术咨询会话")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "用户 ID", example = "user_001")
|
||||
@JsonProperty("user_id")
|
||||
private String userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新会话请求
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "更新会话请求")
|
||||
public static class SessionUpdateReq implements Serializable {
|
||||
|
||||
@Schema(description = "会话名称", example = "技术咨询会话 - 更新")
|
||||
private String name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询会话列表请求
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "查询会话列表请求")
|
||||
public static class SessionListReq implements Serializable {
|
||||
|
||||
@Schema(description = "助手 ID", example = "assistant_001")
|
||||
@JsonProperty("assistant_id")
|
||||
private String assistantId;
|
||||
|
||||
@Schema(description = "页码 (从 1 开始)", example = "1")
|
||||
private Integer page;
|
||||
|
||||
@Schema(description = "每页数量", example = "30")
|
||||
@JsonProperty("page_size")
|
||||
private Integer pageSize;
|
||||
|
||||
@Schema(description = "按名称过滤", example = "技术")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "排序字段", example = "create_time")
|
||||
private String orderby;
|
||||
|
||||
@Schema(description = "是否降序", example = "true")
|
||||
private Boolean desc;
|
||||
|
||||
@Schema(description = "会话 ID 精确筛选", example = "session_001")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "用户标识筛选", example = "user_001")
|
||||
@JsonProperty("user_id")
|
||||
private String userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 会话详情 VO
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "会话详情 VO")
|
||||
public static class SessionVO implements Serializable {
|
||||
|
||||
@Schema(description = "会话 ID", example = "session_001")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "助手 ID", example = "assistant_001")
|
||||
@JsonProperty("chat_id")
|
||||
private String chatId;
|
||||
|
||||
@Schema(description = "助手 ID (兼容旧版)", example = "assistant_001")
|
||||
@JsonProperty("assistant_id")
|
||||
private String assistantId;
|
||||
|
||||
@Schema(description = "会话名称", example = "技术咨询会话")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "创建时间 (时间戳)", example = "1700000000000")
|
||||
@JsonProperty("create_time")
|
||||
private Long createTime;
|
||||
|
||||
@Schema(description = "更新时间 (时间戳)", example = "1700000001000")
|
||||
@JsonProperty("update_time")
|
||||
private Long updateTime;
|
||||
|
||||
@Schema(description = "创建日期", example = "2024-05-01 10:00:00")
|
||||
@JsonProperty("create_date")
|
||||
private String createDate;
|
||||
|
||||
@Schema(description = "更新日期", example = "2024-05-01 10:00:00")
|
||||
@JsonProperty("update_date")
|
||||
private String updateDate;
|
||||
|
||||
@Schema(description = "用户 ID", example = "user_001")
|
||||
@JsonProperty("user_id")
|
||||
private String userId;
|
||||
|
||||
@Schema(description = "对话历史消息列表")
|
||||
private List<Map<String, Object>> messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除会话请求
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "删除会话请求")
|
||||
public static class SessionDeleteReq implements Serializable {
|
||||
|
||||
@Schema(description = "要删除的会话 ID 列表", example = "[\"session_001\", \"session_002\"]")
|
||||
private List<String> ids;
|
||||
}
|
||||
|
||||
// ========== 3. 消息/对话 (Completion) 相关 ==========
|
||||
|
||||
/**
|
||||
* 发送消息请求
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "发送消息请求")
|
||||
public static class CompletionReq implements Serializable {
|
||||
|
||||
@NotBlank(message = "问题内容不能为空")
|
||||
@Schema(description = "用户问题", requiredMode = Schema.RequiredMode.REQUIRED, example = "请介绍一下你们的产品")
|
||||
private String question;
|
||||
|
||||
@Schema(description = "是否使用流式响应 (SSE)", example = "true")
|
||||
@Builder.Default
|
||||
private Boolean stream = true;
|
||||
|
||||
@NotBlank(message = "会话 ID 不能为空")
|
||||
@Schema(description = "会话 ID (可选,不传则创建新会话)", example = "session_001")
|
||||
@JsonProperty("session_id")
|
||||
private String sessionId;
|
||||
|
||||
@Schema(description = "是否展示引用", example = "true")
|
||||
private Boolean quote;
|
||||
|
||||
@Schema(description = "指定检索的文档 ID 列表 (逗号分隔)", example = "doc_001,doc_002")
|
||||
@JsonProperty("doc_ids")
|
||||
private String docIds;
|
||||
|
||||
@Schema(description = "元数据过滤条件")
|
||||
@JsonProperty("metadata_condition")
|
||||
private Map<String, Object> metadataCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息响应 VO
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "消息响应 VO")
|
||||
public static class CompletionVO implements Serializable {
|
||||
|
||||
@Schema(description = "AI 回答内容")
|
||||
private String answer;
|
||||
|
||||
@Schema(description = "引用信息")
|
||||
private Reference reference;
|
||||
|
||||
@Schema(description = "会话 ID", example = "session_001")
|
||||
@JsonProperty("session_id")
|
||||
private String sessionId;
|
||||
|
||||
@Schema(description = "任务 ID (用于流式响应追踪)", example = "task_001")
|
||||
@JsonProperty("task_id")
|
||||
private String taskId;
|
||||
|
||||
/**
|
||||
* 引用信息 (检索命中结果)
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "引用信息")
|
||||
public static class Reference implements Serializable {
|
||||
|
||||
@Schema(description = "命中的文档块列表")
|
||||
private List<xiaozhi.modules.knowledge.dto.document.RetrievalDTO.HitVO> chunks;
|
||||
|
||||
@Schema(description = "文档聚合信息")
|
||||
@JsonProperty("doc_aggs")
|
||||
private List<DocAgg> docAggs;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文档聚合信息
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "文档聚合信息")
|
||||
public static class DocAgg implements Serializable {
|
||||
|
||||
@Schema(description = "文档 ID", example = "doc_001")
|
||||
@JsonProperty("doc_id")
|
||||
private String docId;
|
||||
|
||||
@Schema(description = "文档名称", example = "产品手册.pdf")
|
||||
@JsonProperty("doc_name")
|
||||
private String docName;
|
||||
|
||||
@Schema(description = "命中次数", example = "3")
|
||||
private Integer count;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 简易知识库 VO (用于 Assistant 列表)
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "简易知识库 VO")
|
||||
public static class SimpleDatasetVO implements Serializable {
|
||||
@Schema(description = "知识库 ID")
|
||||
private String id;
|
||||
@Schema(description = "知识库名称")
|
||||
private String name;
|
||||
@Schema(description = "头像")
|
||||
private String avatar;
|
||||
@Schema(description = "分块数量")
|
||||
@JsonProperty("chunk_num")
|
||||
private Integer chunkNum;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package xiaozhi.modules.knowledge.dto.common;
|
||||
|
||||
import lombok.*;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.validation.constraints.*;
|
||||
|
||||
@Schema(description = "通用扩展功能 DTO")
|
||||
public class CommonDTO {
|
||||
|
||||
// ========== 1. 引用详情 (detail_share_embedded) ==========
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "引用详情请求")
|
||||
public static class ReferenceDetailReq implements Serializable {
|
||||
@Schema(description = "切片 ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "切片 ID 不能为空")
|
||||
@JsonProperty("chunk_id")
|
||||
private String chunkId;
|
||||
|
||||
@Schema(description = "知识库 ID")
|
||||
@JsonProperty("knowledge_id")
|
||||
private String knowledgeId;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "引用详情响应")
|
||||
public static class ReferenceDetailVO implements Serializable {
|
||||
@Schema(description = "切片 ID")
|
||||
@JsonProperty("chunk_id")
|
||||
private String chunkId;
|
||||
|
||||
@Schema(description = "完整内容")
|
||||
@JsonProperty("content_with_weight")
|
||||
private String contentWithWeight;
|
||||
|
||||
@Schema(description = "文档名称")
|
||||
@JsonProperty("doc_name")
|
||||
private String docName;
|
||||
|
||||
@Schema(description = "图片 ID 列表")
|
||||
@JsonProperty("img_id")
|
||||
private String imageId; // 注意:RAGFlow 有时返回 String 有时返回 List,需根据实际情况确认,暂定 String 用于 ID
|
||||
|
||||
@Schema(description = "文档 ID")
|
||||
@JsonProperty("doc_id")
|
||||
private String docId;
|
||||
}
|
||||
|
||||
// ========== 2. 通用问答 (ask_about) - 调试用 ==========
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "通用问答请求 (调试用)")
|
||||
public static class AskAboutReq implements Serializable {
|
||||
@Schema(description = "用户问题", requiredMode = Schema.RequiredMode.REQUIRED, example = "What is this dataset about?")
|
||||
@NotBlank(message = "问题不能为空")
|
||||
@JsonProperty("question")
|
||||
private String question;
|
||||
|
||||
@Schema(description = "数据集 ID 列表", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty(message = "数据集列表不能为空")
|
||||
@JsonProperty("dataset_ids")
|
||||
private List<String> datasetIds;
|
||||
}
|
||||
|
||||
// 响应通常复用 String 或者简单的 Map 结构,视具体实现而定,暂不定义专用 VO
|
||||
}
|
||||
@@ -0,0 +1,447 @@
|
||||
package xiaozhi.modules.knowledge.dto.dataset;
|
||||
|
||||
import lombok.*;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import jakarta.validation.constraints.*;
|
||||
|
||||
/**
|
||||
* 知识库管理聚合 DTO
|
||||
* <p>
|
||||
* 容器类,内含知识库模块所有请求/响应对象的静态内部类定义。
|
||||
* </p>
|
||||
*/
|
||||
@Schema(description = "知识库管理聚合 DTO")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class DatasetDTO {
|
||||
|
||||
// ========== 通用内部类 ==========
|
||||
|
||||
/**
|
||||
* 解析器配置
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "解析器配置")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class ParserConfig implements Serializable {
|
||||
|
||||
@Schema(description = "分块 token 数量", example = "128")
|
||||
@JsonProperty("chunk_token_num")
|
||||
private Integer chunkTokenNum;
|
||||
|
||||
@Schema(description = "分隔符", example = "\\n!?;。;!?")
|
||||
private String delimiter;
|
||||
|
||||
@Schema(description = "布局识别模型: DeepDOC / Simple", example = "DeepDOC")
|
||||
@JsonProperty("layout_recognize")
|
||||
private String layoutRecognize;
|
||||
|
||||
@Schema(description = "是否将 Excel 转为 HTML", example = "false")
|
||||
private Boolean html4excel;
|
||||
|
||||
@Schema(description = "自动生成关键词数量 (0 表示关闭)", example = "0")
|
||||
@JsonProperty("auto_keywords")
|
||||
private Integer autoKeywords;
|
||||
|
||||
@Schema(description = "自动生成问题数量 (0 表示关闭)", example = "0")
|
||||
@JsonProperty("auto_questions")
|
||||
private Integer autoQuestions;
|
||||
}
|
||||
|
||||
// ========== 请求类 ==========
|
||||
|
||||
/**
|
||||
* 创建知识库请求 (映射接口 1: create)
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "创建知识库请求")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class CreateReq implements Serializable {
|
||||
|
||||
@NotBlank(message = "知识库名称不能为空")
|
||||
@Schema(description = "知识库名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "my_dataset")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "知识库头像 (Base64 编码)", example = "")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "知识库描述", example = "用于存储产品文档")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "嵌入模型名称", example = "BAAI/bge-large-zh-v1.5")
|
||||
@JsonProperty("embedding_model")
|
||||
private String embeddingModel;
|
||||
|
||||
@Schema(description = "权限设置: me / team", example = "me")
|
||||
private String permission;
|
||||
|
||||
@Schema(description = "分块方法: naive / manual / qa / table / paper / book / laws / presentation / picture / one / knowledge_graph / email", example = "naive")
|
||||
@JsonProperty("chunk_method")
|
||||
private String chunkMethod;
|
||||
|
||||
@Schema(description = "解析器配置")
|
||||
@JsonProperty("parser_config")
|
||||
private ParserConfig parserConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新知识库请求 (映射接口 4: update)
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "更新知识库请求")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class UpdateReq implements Serializable {
|
||||
|
||||
@Schema(description = "知识库名称", example = "updated_dataset")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "知识库头像 (Base64 编码)", example = "")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "知识库描述", example = "更新后的描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "权限设置: me / team", example = "team")
|
||||
private String permission;
|
||||
|
||||
@Schema(description = "嵌入模型名称", example = "BAAI/bge-large-zh-v1.5")
|
||||
@JsonProperty("embedding_model")
|
||||
private String embeddingModel;
|
||||
|
||||
@Schema(description = "分块方法: naive / manual / qa / table / paper / book / laws / presentation / picture / one / knowledge_graph / email", example = "naive")
|
||||
@JsonProperty("chunk_method")
|
||||
private String chunkMethod;
|
||||
|
||||
@Schema(description = "解析器配置")
|
||||
@JsonProperty("parser_config")
|
||||
private ParserConfig parserConfig;
|
||||
|
||||
@Schema(description = "PageRank 权重 (0-100)", example = "50")
|
||||
private Integer pagerank;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询知识库列表请求 (映射接口 3: list_datasets)
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "查询知识库列表请求")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class ListReq implements Serializable {
|
||||
|
||||
@Schema(description = "页码 (从 1 开始)", example = "1")
|
||||
private Integer page;
|
||||
|
||||
@Schema(description = "每页数量", example = "30")
|
||||
@JsonProperty("page_size")
|
||||
private Integer pageSize;
|
||||
|
||||
@Schema(description = "排序字段: create_time / update_time", example = "create_time")
|
||||
private String orderby;
|
||||
|
||||
@Schema(description = "是否降序", example = "true")
|
||||
private Boolean desc;
|
||||
|
||||
@Schema(description = "按名称过滤 (模糊匹配)", example = "my_dataset")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "按知识库 ID 过滤", example = "abc123")
|
||||
private String id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除知识库请求 (映射接口 2: delete)
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "批量删除知识库请求")
|
||||
public static class BatchIdReq implements Serializable {
|
||||
|
||||
@NotNull(message = "知识库 ID 列表不能为空")
|
||||
@Size(min = 1, message = "至少需要一个知识库 ID")
|
||||
@Schema(description = "知识库 ID 列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "[\"id1\", \"id2\"]")
|
||||
private List<String> ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行 GraphRAG 请求
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "运行 GraphRAG 请求")
|
||||
public static class RunGraphRagReq implements Serializable {
|
||||
|
||||
@Schema(description = "实体类型列表", example = "[\"person\", \"organization\"]")
|
||||
@JsonProperty("entity_types")
|
||||
private List<String> entityTypes;
|
||||
|
||||
@Schema(description = "构建方法: light / fast / full", example = "light")
|
||||
private String method;
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行 RAPTOR 请求
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "运行 RAPTOR 请求")
|
||||
public static class RunRaptorReq implements Serializable {
|
||||
|
||||
@Schema(description = "最大聚类数", example = "64")
|
||||
@JsonProperty("max_cluster")
|
||||
private Integer maxCluster;
|
||||
|
||||
@Schema(description = "自定义提示词", example = "请总结以下内容...")
|
||||
private String prompt;
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步任务 ID 响应 VO (映射接口 7/8: run_graphrag/run_raptor)
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "异步任务 ID 响应")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class TaskIdVO implements Serializable {
|
||||
|
||||
@Schema(description = "GraphRAG 任务 ID", example = "task_uuid_12345678")
|
||||
@JsonProperty("graphrag_task_id")
|
||||
private String graphragTaskId;
|
||||
|
||||
@Schema(description = "RAPTOR 任务 ID", example = "task_uuid_87654321")
|
||||
@JsonProperty("raptor_task_id")
|
||||
private String raptorTaskId;
|
||||
}
|
||||
|
||||
// ========== 响应类 ==========
|
||||
|
||||
/**
|
||||
* 知识库详情 VO (映射接口 1/3 的返回数据项)
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "知识库详情 VO")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class InfoVO implements Serializable {
|
||||
|
||||
@Schema(description = "知识库 ID", example = "abc123")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "知识库名称", example = "my_dataset")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "知识库头像 (Base64 编码)", example = "")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "租户 ID", example = "tenant_001")
|
||||
@JsonProperty("tenant_id")
|
||||
private String tenantId;
|
||||
|
||||
@Schema(description = "知识库描述", example = "用于存储产品文档")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "嵌入模型名称", example = "BAAI/bge-large-zh-v1.5")
|
||||
@JsonProperty("embedding_model")
|
||||
private String embeddingModel;
|
||||
|
||||
@Schema(description = "权限设置: me / team", example = "me")
|
||||
private String permission;
|
||||
|
||||
@Schema(description = "分块方法", example = "naive")
|
||||
@JsonProperty("chunk_method")
|
||||
private String chunkMethod;
|
||||
|
||||
@Schema(description = "解析器配置")
|
||||
@JsonProperty("parser_config")
|
||||
private ParserConfig parserConfig;
|
||||
|
||||
@Schema(description = "分块总数", example = "1024")
|
||||
@JsonProperty("chunk_count")
|
||||
private Long chunkCount;
|
||||
|
||||
@Schema(description = "文档总数", example = "50")
|
||||
@JsonProperty("document_count")
|
||||
private Long documentCount;
|
||||
|
||||
@Schema(description = "创建时间 (时间戳)", example = "1700000000000")
|
||||
@JsonProperty("create_time")
|
||||
private Long createTime;
|
||||
|
||||
@Schema(description = "更新时间 (时间戳)", example = "1700000001000")
|
||||
@JsonProperty("update_time")
|
||||
private Long updateTime;
|
||||
|
||||
@Schema(description = "总 Token 数", example = "102400")
|
||||
@JsonProperty("token_num")
|
||||
private Long tokenNum;
|
||||
|
||||
@Schema(description = "创建日期 (格式: yyyy-MM-dd HH:mm:ss)")
|
||||
@JsonProperty("create_date")
|
||||
private String createDate;
|
||||
|
||||
@Schema(description = "最后更新日期 (格式: yyyy-MM-dd HH:mm:ss)")
|
||||
@JsonProperty("update_date")
|
||||
private String updateDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量操作响应 VO
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "批量操作响应 VO")
|
||||
public static class BatchOperationVO implements Serializable {
|
||||
|
||||
@Schema(description = "成功操作数量", example = "5")
|
||||
@JsonProperty("success_count")
|
||||
private Integer successCount;
|
||||
|
||||
@Schema(description = "错误列表")
|
||||
private List<Object> errors;
|
||||
}
|
||||
|
||||
// ========== 知识图谱相关 ==========
|
||||
|
||||
/**
|
||||
* 知识图谱数据 VO (映射接口 5: knowledge_graph)
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "知识图谱数据 VO")
|
||||
public static class GraphVO implements Serializable {
|
||||
|
||||
@Schema(description = "图谱节点列表")
|
||||
private List<Node> nodes;
|
||||
|
||||
@Schema(description = "图谱边列表")
|
||||
private List<Edge> edges;
|
||||
|
||||
@Schema(description = "思维导图数据")
|
||||
@JsonProperty("mind_map")
|
||||
private Map<String, Object> mindMap;
|
||||
|
||||
/**
|
||||
* 图谱节点
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "图谱节点")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class Node implements Serializable {
|
||||
|
||||
@Schema(description = "节点 ID", example = "node_001")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "节点标签", example = "产品")
|
||||
private String label;
|
||||
|
||||
@Schema(description = "PageRank 值", example = "0.85")
|
||||
private Double pagerank;
|
||||
|
||||
@Schema(description = "节点颜色", example = "#FF5733")
|
||||
private String color;
|
||||
|
||||
@Schema(description = "节点图片 URL", example = "https://example.com/icon.png")
|
||||
private String img;
|
||||
}
|
||||
|
||||
/**
|
||||
* 图谱边
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "图谱边")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class Edge implements Serializable {
|
||||
|
||||
@Schema(description = "源节点 ID", example = "node_001")
|
||||
private String source;
|
||||
|
||||
@Schema(description = "目标节点 ID", example = "node_002")
|
||||
private String target;
|
||||
|
||||
@Schema(description = "边权重", example = "0.75")
|
||||
private Double weight;
|
||||
|
||||
@Schema(description = "边标签 (关系描述)", example = "属于")
|
||||
private String label;
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 异步任务追踪 (GraphRAG/RAPTOR) ==========
|
||||
|
||||
/**
|
||||
* 异步任务追踪 VO (映射接口 9/10: 任务进度返回)
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "异步任务追踪 VO")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class TaskTraceVO implements Serializable {
|
||||
|
||||
@Schema(description = "任务 ID", example = "task_001")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "文档 ID", example = "doc_001")
|
||||
@JsonProperty("doc_id")
|
||||
private String docId;
|
||||
|
||||
@Schema(description = "起始页码", example = "1")
|
||||
@JsonProperty("from_page")
|
||||
private Integer fromPage;
|
||||
|
||||
@Schema(description = "结束页码", example = "10")
|
||||
@JsonProperty("to_page")
|
||||
private Integer toPage;
|
||||
|
||||
@Schema(description = "进度百分比 (0.0 - 1.0)", example = "0.75")
|
||||
private Double progress;
|
||||
|
||||
@Schema(description = "进度消息", example = "正在处理第 5 页...")
|
||||
@JsonProperty("progress_msg")
|
||||
private String progressMsg;
|
||||
|
||||
@Schema(description = "创建时间 (时间戳)", example = "1700000000000")
|
||||
@JsonProperty("create_time")
|
||||
private Long createTime;
|
||||
|
||||
@Schema(description = "更新时间 (时间戳)", example = "1700000001000")
|
||||
@JsonProperty("update_time")
|
||||
private Long updateTime;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
package xiaozhi.modules.knowledge.dto.document;
|
||||
|
||||
import lombok.*;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import jakarta.validation.constraints.*;
|
||||
|
||||
/**
|
||||
* 切片管理聚合 DTO
|
||||
*/
|
||||
@Schema(description = "切片管理聚合 DTO")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class ChunkDTO {
|
||||
|
||||
/**
|
||||
* 新增切片请求参数
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "新增切片请求参数")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class AddReq implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "切片内容", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "切片内容不能为空")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "重要关键词列表")
|
||||
@JsonProperty("important_keywords")
|
||||
private List<String> importantKeywords;
|
||||
|
||||
@Schema(description = "预设问题列表")
|
||||
private List<String> questions;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新切片请求参数
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "更新切片请求参数")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class UpdateReq implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "新的切片内容")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "更新关键词列表 (覆盖原有列表)")
|
||||
@JsonProperty("important_keywords")
|
||||
private List<String> importantKeywords;
|
||||
|
||||
@Schema(description = "启用/禁用 (true: 启用, false: 禁用)")
|
||||
private Boolean available;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取切片列表请求参数
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "获取切片列表请求参数")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class ListReq implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "页码 (默认 1)")
|
||||
private Integer page;
|
||||
|
||||
@Schema(description = "每页数量 (默认 30)")
|
||||
@JsonProperty("page_size")
|
||||
private Integer pageSize;
|
||||
|
||||
@Schema(description = "搜索关键词 (全文检索)")
|
||||
private String keywords;
|
||||
|
||||
@Schema(description = "精确切片 ID")
|
||||
private String id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除切片请求参数
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "批量删除切片请求参数")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class RemoveReq implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "切片 ID 列表", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@JsonProperty("chunk_ids")
|
||||
@NotEmpty(message = "切片ID列表不能为空")
|
||||
private List<String> chunkIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文档切片信息 VO
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "文档切片信息")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class InfoVO implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "切片 ID (通常为 document_id + 索引)", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String id;
|
||||
|
||||
@Schema(description = "切片文本内容 (全文检索的主要对象)", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String content;
|
||||
|
||||
@Schema(description = "所属文档 ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@JsonProperty("document_id")
|
||||
private String documentId;
|
||||
|
||||
@Schema(description = "文档名称 / 关键词")
|
||||
@JsonProperty("docnm_kwd")
|
||||
private String docnmKwd;
|
||||
|
||||
@Schema(description = "重要关键词列表 (用于关键词增强检索)")
|
||||
@JsonProperty("important_keywords")
|
||||
private List<String> importantKeywords;
|
||||
|
||||
@Schema(description = "预设问题列表 (用于 Q&A 模式增强)")
|
||||
private List<String> questions;
|
||||
|
||||
@Schema(description = "关联的图片 ID")
|
||||
@JsonProperty("image_id")
|
||||
private String imageId;
|
||||
|
||||
@Schema(description = "所属知识库 ID")
|
||||
@JsonProperty("dataset_id")
|
||||
private String datasetId;
|
||||
|
||||
@Schema(description = "切片是否可用 (true: 参与检索, false: 被禁用)")
|
||||
private Boolean available;
|
||||
|
||||
@Schema(description = "切片在原文中的位置索引列表 (RAGFlow返回嵌套数组, 如 [[start, end, filename]])")
|
||||
private List<List<Object>> positions;
|
||||
|
||||
@Schema(description = "Token ID 列表")
|
||||
@JsonProperty("token")
|
||||
private List<Integer> token;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分片列表聚合响应
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "分片列表聚合响应")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class ListVO implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "切片信息列表")
|
||||
private List<InfoVO> chunks;
|
||||
|
||||
@Schema(description = "关联的文档详细信息")
|
||||
private DocumentDTO.InfoVO doc;
|
||||
|
||||
@Schema(description = "总记录数")
|
||||
private Long total;
|
||||
}
|
||||
}
|
||||
+407
@@ -0,0 +1,407 @@
|
||||
package xiaozhi.modules.knowledge.dto.document;
|
||||
|
||||
import lombok.*;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonAlias;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import jakarta.validation.constraints.*;
|
||||
|
||||
/**
|
||||
* 文档管理聚合 DTO
|
||||
*/
|
||||
@Schema(description = "文档管理聚合 DTO")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class DocumentDTO {
|
||||
|
||||
/**
|
||||
* 上传文档请求参数
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "上传文档请求参数")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class UploadReq implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "知识库 ID (必须指定归属)", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@JsonProperty("dataset_id")
|
||||
@NotBlank(message = "知识库ID不能为空")
|
||||
private String datasetId;
|
||||
|
||||
@Schema(description = "文件名 (如果指定,则覆盖原始文件名)")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "分块方法")
|
||||
@JsonProperty("chunk_method")
|
||||
private DocumentDTO.InfoVO.ChunkMethod chunkMethod;
|
||||
|
||||
@Schema(description = "解析参数配置")
|
||||
@JsonProperty("parser_config")
|
||||
private DocumentDTO.InfoVO.ParserConfig parserConfig;
|
||||
|
||||
@Schema(description = "虚拟文件夹路径 (默认为 /)")
|
||||
@JsonProperty("parent_path")
|
||||
private String parentPath;
|
||||
|
||||
@Schema(description = "元数据字段")
|
||||
@JsonProperty("meta")
|
||||
private Map<String, Object> metaFields;
|
||||
|
||||
@Schema(description = "文件二进制流 (支持 PDF, DOCX, TXT, MD 等多种格式)", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "上传文件不能为空")
|
||||
private org.springframework.web.multipart.MultipartFile file;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新文档请求参数
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "更新文档请求参数")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class UpdateReq implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "新文档名称 (必须包含文件后缀,且不能更改原始类型)")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "启用/禁用状态 (true: 启用, false: 禁用; 禁用后不参与检索)")
|
||||
private Boolean enabled;
|
||||
|
||||
@Schema(description = "新解析方法 (修改此项会重置解析状态)")
|
||||
@JsonProperty("chunk_method")
|
||||
private InfoVO.ChunkMethod chunkMethod;
|
||||
|
||||
@Schema(description = "新解析器详细配置 (应与 chunk_method 配套使用)")
|
||||
@JsonProperty("parser_config")
|
||||
private InfoVO.ParserConfig parserConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文档列表请求参数
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "获取文档列表请求参数")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class ListReq implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "页码 (默认: 1)")
|
||||
private Integer page;
|
||||
|
||||
@Schema(description = "每页数量 (默认: 30)")
|
||||
@JsonProperty("page_size")
|
||||
private Integer pageSize;
|
||||
|
||||
@Schema(description = "排序字段 (可选: create_time, name, size; 默认: create_time)")
|
||||
private String orderby;
|
||||
|
||||
@Schema(description = "是否降序排列 (true: 最新/最大在前; false: 最旧/最小在前; 默认: true)")
|
||||
private Boolean desc;
|
||||
|
||||
@Schema(description = "精确筛选: 文档 ID")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "精确筛选: 文档完整名称 (含后缀)")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "模糊搜索: 文档名称关键词")
|
||||
private String keywords;
|
||||
|
||||
@Schema(description = "筛选: 文件后缀列表 (如 ['pdf', 'docx'])")
|
||||
private List<String> suffix;
|
||||
|
||||
@Schema(description = "筛选: 运行状态列表")
|
||||
private List<InfoVO.RunStatus> run;
|
||||
|
||||
@Schema(description = "筛选: 起始创建时间 (时间戳, 毫秒)")
|
||||
@JsonProperty("create_time_from")
|
||||
private Long createTimeFrom;
|
||||
|
||||
@Schema(description = "筛选: 结束创建时间 (时间戳, 毫秒)")
|
||||
@JsonProperty("create_time_to")
|
||||
private Long createTimeTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量文档操作请求参数 (用于删除、解析等)
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "批量文档操作请求参数")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class BatchIdReq implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "文档 ID 列表", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@JsonProperty("ids") // 为了兼容性,也可以考虑支持 document_ids,但这里统一叫 ids
|
||||
@JsonAlias("document_ids")
|
||||
@NotEmpty(message = "文档ID列表不能为空")
|
||||
private List<String> ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* 知识库文档信息 VO
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "知识库文档信息")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class InfoVO implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "文档 ID (唯一标识)", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String id;
|
||||
|
||||
@Schema(description = "文档缩略图 URL (Base64 或 链接)")
|
||||
private String thumbnail;
|
||||
|
||||
@Schema(description = "所属知识库 ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@JsonProperty("dataset_id")
|
||||
private String datasetId;
|
||||
|
||||
@Schema(description = "文档解析方法 (决定了文档如何被切片)")
|
||||
@JsonProperty("chunk_method")
|
||||
private ChunkMethod chunkMethod;
|
||||
|
||||
@Schema(description = "关联的 ETL Pipeline ID (如有)")
|
||||
@JsonProperty("pipeline_id")
|
||||
private String pipelineId;
|
||||
|
||||
@Schema(description = "文档解析器的详细配置")
|
||||
@JsonProperty("parser_config")
|
||||
private ParserConfig parserConfig;
|
||||
|
||||
@Schema(description = "来源类型 (如 local, s3, url 等)")
|
||||
@JsonProperty("source_type")
|
||||
private String sourceType;
|
||||
|
||||
@Schema(description = "文档文件类型 (如 pdf, docx, txt)", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String type;
|
||||
|
||||
@Schema(description = "创建者用户 ID")
|
||||
@JsonProperty("created_by")
|
||||
private String createdBy;
|
||||
|
||||
@Schema(description = "文档名称 (包含扩展名)", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String name;
|
||||
|
||||
@Schema(description = "文件存储路径或位置标识")
|
||||
private String location;
|
||||
|
||||
@Schema(description = "文件大小 (单位: Bytes)")
|
||||
private Long size;
|
||||
|
||||
@Schema(description = "包含的 Token 总数 (解析后统计)")
|
||||
@JsonProperty("token_count")
|
||||
private Long tokenCount;
|
||||
|
||||
@Schema(description = "包含的切片 (Chunk) 总数")
|
||||
@JsonProperty("chunk_count")
|
||||
private Long chunkCount;
|
||||
|
||||
@Schema(description = "解析进度 (0.0 ~ 1.0, 1.0 表示完成)")
|
||||
private Double progress;
|
||||
|
||||
@Schema(description = "当前进度描述或错误信息")
|
||||
@JsonProperty("progress_msg")
|
||||
private String progressMsg;
|
||||
|
||||
@Schema(description = "开始处理的时间戳 (RAGFlow返回RFC1123格式)")
|
||||
@JsonProperty("process_begin_at")
|
||||
private String processBeginAt;
|
||||
|
||||
@Schema(description = "处理总耗时 (单位: 秒)")
|
||||
@JsonProperty("process_duration")
|
||||
private Double processDuration;
|
||||
|
||||
@Schema(description = "自定义元数据字段 (Key-Value 键值对)")
|
||||
@JsonProperty("meta_fields")
|
||||
private Map<String, Object> metaFields;
|
||||
|
||||
@Schema(description = "文件后缀名 (不含点)")
|
||||
private String suffix;
|
||||
|
||||
@Schema(description = "文档解析运行状态")
|
||||
private RunStatus run;
|
||||
|
||||
@Schema(description = "文档可用状态 (1: 启用/正常, 0: 禁用/失效)", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String status;
|
||||
|
||||
@Schema(description = "创建时间 (时间戳, 毫秒)", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@JsonProperty("create_time")
|
||||
private Long createTime;
|
||||
|
||||
@Schema(description = "创建日期 (RAGFlow返回RFC1123格式)")
|
||||
@JsonProperty("create_date")
|
||||
private String createDate;
|
||||
|
||||
@Schema(description = "最后更新时间 (时间戳, 毫秒)")
|
||||
@JsonProperty("update_time")
|
||||
private Long updateTime;
|
||||
|
||||
@Schema(description = "最后更新日期 (RAGFlow返回RFC1123格式)")
|
||||
@JsonProperty("update_date")
|
||||
private String updateDate;
|
||||
|
||||
/**
|
||||
* 解析方法枚举 (ChunkMethod)
|
||||
*/
|
||||
public enum ChunkMethod {
|
||||
@Schema(description = "通用模式: 适用于大多数纯文本或混合文档")
|
||||
@JsonProperty("naive")
|
||||
NAIVE,
|
||||
@Schema(description = "手动模式: 允许用户手动编辑切片")
|
||||
@JsonProperty("manual")
|
||||
MANUAL,
|
||||
@Schema(description = "问答模式: 专门优化 Q&A 格式的文档")
|
||||
@JsonProperty("qa")
|
||||
QA,
|
||||
@Schema(description = "表格模式: 专门优化 Excel 或 CSV 等表格数据")
|
||||
@JsonProperty("table")
|
||||
TABLE,
|
||||
@Schema(description = "论文模式: 针对学术论文排版优化")
|
||||
@JsonProperty("paper")
|
||||
PAPER,
|
||||
@Schema(description = "书籍模式: 针对书籍章节结构优化")
|
||||
@JsonProperty("book")
|
||||
BOOK,
|
||||
@Schema(description = "法律法规模式: 针对法律条文结构优化")
|
||||
@JsonProperty("laws")
|
||||
LAWS,
|
||||
@Schema(description = "演示文稿模式: 针对 PPT 等演示文件优化")
|
||||
@JsonProperty("presentation")
|
||||
PRESENTATION,
|
||||
@Schema(description = "图片模式: 针对图片内容进行 OCR 和描述")
|
||||
@JsonProperty("picture")
|
||||
PICTURE,
|
||||
@Schema(description = "整体模式: 将整个文档作为一个切片")
|
||||
@JsonProperty("one")
|
||||
ONE,
|
||||
@Schema(description = "知识图谱模式: 提取实体关系构建图谱")
|
||||
@JsonProperty("knowledge_graph")
|
||||
KNOWLEDGE_GRAPH,
|
||||
@Schema(description = "邮件模式: 针对邮件格式优化")
|
||||
@JsonProperty("email")
|
||||
EMAIL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行状态枚举 (RunStatus)
|
||||
*/
|
||||
public enum RunStatus {
|
||||
@Schema(description = "未开始: 等待解析队列")
|
||||
@JsonProperty("UNSTART")
|
||||
UNSTART,
|
||||
@Schema(description = "进行中: 正在解析或索引")
|
||||
@JsonProperty("RUNNING")
|
||||
RUNNING,
|
||||
@Schema(description = "已取消: 用户手动取消")
|
||||
@JsonProperty("CANCEL")
|
||||
CANCEL,
|
||||
@Schema(description = "已完成: 解析成功")
|
||||
@JsonProperty("DONE")
|
||||
DONE,
|
||||
@Schema(description = "失败: 解析过程中出错")
|
||||
@JsonProperty("FAIL")
|
||||
FAIL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 布局识别模型枚举
|
||||
*/
|
||||
public enum LayoutRecognize {
|
||||
@Schema(description = "深度文档理解模型: 适合复杂排版")
|
||||
@JsonProperty("DeepDOC")
|
||||
DeepDOC,
|
||||
@Schema(description = "简单规则模型: 适合纯文本")
|
||||
@JsonProperty("Simple")
|
||||
Simple;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "文档解析器参数配置")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class ParserConfig implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "切片最大 Token 数 (建议值: 512, 1024, 2048)")
|
||||
@JsonProperty("chunk_token_num")
|
||||
private Integer chunkTokenNum;
|
||||
|
||||
@Schema(description = "分段分隔符 (支持转义字符, 如 \\n)")
|
||||
private String delimiter;
|
||||
|
||||
@Schema(description = "布局识别模型 (DeepDOC/Simple)")
|
||||
@JsonProperty("layout_recognize")
|
||||
private LayoutRecognize layoutRecognize;
|
||||
|
||||
@Schema(description = "是否将 Excel 转换为 HTML 表格")
|
||||
@JsonProperty("html4excel")
|
||||
private Boolean html4excel;
|
||||
|
||||
@Schema(description = "自动提取关键词数量 (0 表示不提取)")
|
||||
@JsonProperty("auto_keywords")
|
||||
private Integer autoKeywords;
|
||||
|
||||
@Schema(description = "自动生成问题数量 (0 表示不生成)")
|
||||
@JsonProperty("auto_questions")
|
||||
private Integer autoQuestions;
|
||||
|
||||
@Schema(description = "自动生成标签数量")
|
||||
@JsonProperty("topn_tags")
|
||||
private Integer topnTags;
|
||||
|
||||
@Schema(description = "RAPTOR 高级索引配置")
|
||||
private RaptorConfig raptor;
|
||||
|
||||
@Schema(description = "GraphRAG 知识图谱配置")
|
||||
@JsonProperty("graphrag")
|
||||
private GraphRagConfig graphRag;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "RAPTOR (递归摘要索引) 配置")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class RaptorConfig implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Schema(description = "是否启用 RAPTOR 索引")
|
||||
@JsonProperty("use_raptor")
|
||||
private Boolean useRaptor;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "GraphRAG (图增强检索) 配置")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class GraphRagConfig implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Schema(description = "是否启用 GraphRAG 索引")
|
||||
@JsonProperty("use_graphrag")
|
||||
private Boolean useGraphRag;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+307
@@ -0,0 +1,307 @@
|
||||
package xiaozhi.modules.knowledge.dto.document;
|
||||
|
||||
import lombok.*;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import jakarta.validation.constraints.*;
|
||||
|
||||
/**
|
||||
* 检索与元数据管理聚合 DTO
|
||||
*/
|
||||
@Schema(description = "检索与元数据管理聚合 DTO")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class RetrievalDTO {
|
||||
|
||||
/**
|
||||
* 文档聚合信息 (VO)
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "文档聚合信息")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class DocAggVO implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "文档名称")
|
||||
@JsonProperty("doc_name")
|
||||
private String docName;
|
||||
|
||||
@Schema(description = "文档 ID")
|
||||
@JsonProperty("doc_id")
|
||||
private String docId;
|
||||
|
||||
@Schema(description = "数量")
|
||||
private Integer count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检索测试请求参数
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "检索测试请求参数")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public static class TestReq implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "知识库 ID 列表", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@JsonProperty("dataset_ids")
|
||||
@NotEmpty(message = "知识库ID列表不能为空")
|
||||
private List<String> datasetIds;
|
||||
|
||||
@Schema(description = "文档 ID 列表 (可选,用于限定检索范围)")
|
||||
@JsonProperty("document_ids")
|
||||
private List<String> documentIds;
|
||||
|
||||
@Schema(description = "检索问题", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "检索问题不能为空")
|
||||
private String question;
|
||||
|
||||
@Schema(description = "页码 (默认 1)")
|
||||
private Integer page;
|
||||
|
||||
@Schema(description = "每页数量 (默认 10)")
|
||||
@JsonProperty("page_size")
|
||||
private Integer pageSize;
|
||||
|
||||
@Schema(description = "相似度阈值 (默认 0.2)")
|
||||
@JsonProperty("similarity_threshold")
|
||||
private Float similarityThreshold;
|
||||
|
||||
@Schema(description = "向量相似度权重 (默认 0.3)")
|
||||
@JsonProperty("vector_similarity_weight")
|
||||
private Float vectorSimilarityWeight;
|
||||
|
||||
@Schema(description = "返回 Top K 切片 (默认 1024)")
|
||||
@JsonProperty("top_k")
|
||||
private Integer topK;
|
||||
|
||||
@Schema(description = "重排序模型 ID")
|
||||
@JsonProperty("rerank_id")
|
||||
private String rerankId;
|
||||
|
||||
@Schema(description = "是否高亮关键词")
|
||||
private Boolean highlight;
|
||||
|
||||
@Schema(description = "是否启用关键词检索")
|
||||
private Boolean keyword;
|
||||
|
||||
@Schema(description = "跨语言翻译列表 (可选)")
|
||||
@JsonProperty("cross_languages")
|
||||
private List<String> crossLanguages;
|
||||
|
||||
@Schema(description = "元数据过滤条件 (JSON 对象)")
|
||||
@JsonProperty("metadata_condition")
|
||||
private Map<String, Object> metadataCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检索命中结果 (VO)
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "检索命中切片详情")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class HitVO implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "切片 ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String id;
|
||||
|
||||
@Schema(description = "切片内容", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String content;
|
||||
|
||||
@Schema(description = "所属文档 ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@JsonProperty("document_id")
|
||||
private String documentId;
|
||||
|
||||
@Schema(description = "所属知识库 ID")
|
||||
@JsonProperty("dataset_id")
|
||||
private String datasetId;
|
||||
|
||||
@Schema(description = "文档名称")
|
||||
@JsonProperty("document_name")
|
||||
private String documentName;
|
||||
|
||||
@Schema(description = "文档关键词")
|
||||
@JsonProperty("document_keyword")
|
||||
private String documentKeyword;
|
||||
|
||||
@Schema(description = "综合相似度", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Float similarity;
|
||||
|
||||
@Schema(description = "向量相似度")
|
||||
@JsonProperty("vector_similarity")
|
||||
private Float vectorSimilarity;
|
||||
|
||||
@Schema(description = "关键词相似度")
|
||||
@JsonProperty("term_similarity")
|
||||
private Float termSimilarity;
|
||||
|
||||
@Schema(description = "索引位置")
|
||||
private Integer index;
|
||||
|
||||
@Schema(description = "高亮内容")
|
||||
private String highlight;
|
||||
|
||||
@Schema(description = "重要关键词列表")
|
||||
@JsonProperty("important_keywords")
|
||||
private List<String> importantKeywords;
|
||||
|
||||
@Schema(description = "预设问题列表")
|
||||
private List<String> questions;
|
||||
|
||||
@Schema(description = "图片 ID")
|
||||
@JsonProperty("image_id")
|
||||
private String imageId;
|
||||
|
||||
@Schema(description = "位置索引 (RAGFlow返回嵌套数组, 如 [[start, end, filename]])")
|
||||
private Object positions;
|
||||
}
|
||||
|
||||
/**
|
||||
* 知识库元数据摘要 (VO)
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "知识库元数据摘要信息")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class MetaSummaryVO implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "文档总数", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@JsonProperty("total_doc_count")
|
||||
private Long totalDocCount;
|
||||
|
||||
@Schema(description = "Token 总数", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@JsonProperty("total_token_count")
|
||||
private Long totalTokenCount;
|
||||
|
||||
@Schema(description = "文件类型分布 (key: 文件后缀, value: 数量)")
|
||||
@JsonProperty("file_type_distribution")
|
||||
private Map<String, Long> fileTypeDistribution;
|
||||
|
||||
@Schema(description = "文状态分布 (key: 状态码, value: 数量)")
|
||||
@JsonProperty("status_distribution")
|
||||
private Map<String, Long> statusDistribution;
|
||||
|
||||
@Schema(description = "自定义元数据统计 (key: 字段名, value: 数量/值)")
|
||||
@JsonProperty("custom_metadata")
|
||||
private Map<String, Object> customMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更新元数据请求参数
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "批量更新元数据请求参数")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class MetaBatchReq implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "筛选器: 用于指定要更新的文档范围 (默认全部)")
|
||||
private Selector selector;
|
||||
|
||||
@Schema(description = "新增或更新的元数据列表")
|
||||
private List<UpdateItem> updates;
|
||||
|
||||
@Schema(description = "需要删除的元数据键列表")
|
||||
private List<DeleteItem> deletes;
|
||||
|
||||
/**
|
||||
* 文档筛选器
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "元数据更新筛选器")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class Selector implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "指定文档 ID 列表")
|
||||
@JsonProperty("document_ids")
|
||||
private List<String> documentIds;
|
||||
|
||||
@Schema(description = "元数据条件匹配 (key: 字段名, value: 匹配值)")
|
||||
@JsonProperty("metadata_condition")
|
||||
private Map<String, Object> metadataCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新项
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "元数据更新项")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class UpdateItem implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "元数据键名", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String key;
|
||||
|
||||
@Schema(description = "元数据值", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Object value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除项
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "元数据删除项")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class DeleteItem implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "需删除的元数据键名", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String key;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 召回测试结果聚合响应
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "召回测试结果聚合响应")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class ResultVO implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "检索命中的切片列表")
|
||||
private List<HitVO> chunks;
|
||||
|
||||
@Schema(description = "文档分布统计")
|
||||
@JsonProperty("doc_aggs")
|
||||
private List<DocAggVO> docAggs;
|
||||
|
||||
@Schema(description = "总命中记录数")
|
||||
private Long total;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,363 @@
|
||||
package xiaozhi.modules.knowledge.dto.file;
|
||||
|
||||
import lombok.*;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.validation.constraints.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* 文件管理聚合 DTO
|
||||
* <p>
|
||||
* 容器类,内含文件模块所有请求/响应对象的静态内部类定义。
|
||||
* </p>
|
||||
*/
|
||||
@Schema(description = "文件管理聚合 DTO")
|
||||
public class FileDTO {
|
||||
|
||||
// ========== 请求类 ==========
|
||||
|
||||
/**
|
||||
* 文件上传请求 (对应接口 1: upload)
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "文件上传请求")
|
||||
public static class UploadReq implements Serializable {
|
||||
|
||||
@NotNull(message = "文件不能为空")
|
||||
@Schema(description = "上传的文件", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private MultipartFile file;
|
||||
|
||||
@Schema(description = "父文件夹 ID (为空则上传到根目录)", example = "folder_001")
|
||||
@JsonProperty("parent_id")
|
||||
private String parentId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新建文件夹请求 (对应接口 2: create)
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "新建文件夹请求")
|
||||
public static class CreateReq implements Serializable {
|
||||
|
||||
@NotBlank(message = "文件夹名称不能为空")
|
||||
@Schema(description = "文件夹名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "新建文件夹")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "父文件夹 ID (为空则创建在根目录)", example = "folder_001")
|
||||
@JsonProperty("parent_id")
|
||||
private String parentId;
|
||||
|
||||
@NotBlank(message = "类型不能为空")
|
||||
@Schema(description = "类型: FOLDER", requiredMode = Schema.RequiredMode.REQUIRED, example = "FOLDER")
|
||||
@Builder.Default
|
||||
private String type = "FOLDER";
|
||||
}
|
||||
|
||||
/**
|
||||
* 重命名请求 (对应接口 6: rename)
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "重命名请求")
|
||||
public static class RenameReq implements Serializable {
|
||||
|
||||
@NotBlank(message = "文件 ID 不能为空")
|
||||
@Schema(description = "文件/文件夹 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "file_001")
|
||||
@JsonProperty("file_id")
|
||||
private String fileId;
|
||||
|
||||
@NotBlank(message = "新名称不能为空")
|
||||
@Schema(description = "新名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "重命名后的文件")
|
||||
private String name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移动请求 (对应接口 7: move)
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "移动请求")
|
||||
public static class MoveReq implements Serializable {
|
||||
|
||||
@NotEmpty(message = "源文件 ID 列表不能为空")
|
||||
@Schema(description = "源文件/文件夹 ID 列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "[\"file_001\", \"file_002\"]")
|
||||
@JsonProperty("src_file_ids")
|
||||
private List<String> srcFileIds;
|
||||
|
||||
@NotBlank(message = "目标文件夹 ID 不能为空")
|
||||
@Schema(description = "目标文件夹 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "folder_002")
|
||||
@JsonProperty("dest_file_id")
|
||||
private String destFileId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除请求 (对应接口 8: rm)
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "批量删除请求")
|
||||
public static class RemoveReq implements Serializable {
|
||||
|
||||
@NotEmpty(message = "文件 ID 列表不能为空")
|
||||
@Schema(description = "文件/文件夹 ID 列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "[\"file_001\", \"file_002\"]")
|
||||
@JsonProperty("file_ids")
|
||||
private List<String> fileIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入知识库请求 (对应接口 9: convert)
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "导入知识库请求")
|
||||
public static class ConvertReq implements Serializable {
|
||||
|
||||
@NotEmpty(message = "文件 ID 列表不能为空")
|
||||
@Schema(description = "文件 ID 列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "[\"file_001\", \"file_002\"]")
|
||||
@JsonProperty("file_ids")
|
||||
private List<String> fileIds;
|
||||
|
||||
@NotEmpty(message = "知识库 ID 列表不能为空")
|
||||
@Schema(description = "目标知识库 ID 列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "[\"kb_001\"]")
|
||||
@JsonProperty("kb_ids")
|
||||
private List<String> kbIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表查询请求 (对应接口 3: list_files)
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "列表查询请求")
|
||||
public static class ListReq implements Serializable {
|
||||
|
||||
@Schema(description = "父文件夹 ID (为空则查询根目录)", example = "folder_001")
|
||||
@JsonProperty("parent_id")
|
||||
private String parentId;
|
||||
|
||||
@Schema(description = "关键词搜索", example = "文档")
|
||||
private String keywords;
|
||||
|
||||
@Schema(description = "页码 (从 1 开始)", example = "1")
|
||||
private Integer page;
|
||||
|
||||
@Schema(description = "每页数量", example = "30")
|
||||
@JsonProperty("page_size")
|
||||
private Integer pageSize;
|
||||
|
||||
@Schema(description = "排序字段: create_time / update_time / name / size", example = "create_time")
|
||||
private String orderby;
|
||||
|
||||
@Schema(description = "是否降序", example = "true")
|
||||
private Boolean desc;
|
||||
}
|
||||
|
||||
// ========== 响应类 ==========
|
||||
|
||||
/**
|
||||
* 文件/文件夹基础信息 VO
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "文件/文件夹基础信息")
|
||||
public static class InfoVO implements Serializable {
|
||||
|
||||
@Schema(description = "文件/文件夹 ID", example = "file_001")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "父文件夹 ID", example = "folder_001")
|
||||
@JsonProperty("parent_id")
|
||||
private String parentId;
|
||||
|
||||
@Schema(description = "租户 ID", example = "tenant_001")
|
||||
@JsonProperty("tenant_id")
|
||||
private String tenantId;
|
||||
|
||||
@Schema(description = "创建者 ID", example = "user_001")
|
||||
@JsonProperty("created_by")
|
||||
private String createdBy;
|
||||
|
||||
@Schema(description = "类型: FOLDER / FILE", example = "FOLDER")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "名称", example = "我的文件夹")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "路径位置", example = "/root/folder")
|
||||
private String location;
|
||||
|
||||
@Schema(description = "文件大小 (字节)", example = "1024")
|
||||
private Long size;
|
||||
|
||||
@Schema(description = "来源类型", example = "local")
|
||||
@JsonProperty("source_type")
|
||||
private String sourceType;
|
||||
|
||||
@Schema(description = "创建时间 (时间戳)", example = "1700000000000")
|
||||
@JsonProperty("create_time")
|
||||
private Long createTime;
|
||||
|
||||
@Schema(description = "创建日期 (格式化)", example = "2024-01-15 10:30:00")
|
||||
@JsonProperty("create_date")
|
||||
private String createDate;
|
||||
|
||||
@Schema(description = "更新时间 (时间戳)", example = "1700000001000")
|
||||
@JsonProperty("update_time")
|
||||
private Long updateTime;
|
||||
|
||||
@Schema(description = "更新日期 (格式化)", example = "2024-01-15 11:00:00")
|
||||
@JsonProperty("update_date")
|
||||
private String updateDate;
|
||||
|
||||
@Schema(description = "文件扩展名", example = "pdf")
|
||||
private String extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表响应 VO (对应接口 3: list_files)
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "文件列表响应")
|
||||
public static class ListVO implements Serializable {
|
||||
|
||||
@Schema(description = "总记录数", example = "100")
|
||||
private Long total;
|
||||
|
||||
@Schema(description = "当前父文件夹信息")
|
||||
@JsonProperty("parent_folder")
|
||||
private InfoVO parentFolder;
|
||||
|
||||
@Schema(description = "文件/文件夹列表")
|
||||
private List<InfoVO> files;
|
||||
|
||||
@Schema(description = "面包屑导航路径")
|
||||
private List<InfoVO> breadcrumb;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换结果项 VO (对应接口 9: convert)
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "文件转换结果项")
|
||||
public static class ConvertVO implements Serializable {
|
||||
|
||||
@Schema(description = "转换记录 ID", example = "convert_001")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "源文件 ID", example = "file_001")
|
||||
@JsonProperty("file_id")
|
||||
private String fileId;
|
||||
|
||||
@Schema(description = "目标文档 ID", example = "doc_001")
|
||||
@JsonProperty("document_id")
|
||||
private String documentId;
|
||||
|
||||
@Schema(description = "创建时间 (时间戳)", example = "1700000000000")
|
||||
@JsonProperty("create_time")
|
||||
private Long createTime;
|
||||
|
||||
@Schema(description = "创建日期 (格式化)", example = "2024-01-15 10:30:00")
|
||||
@JsonProperty("create_date")
|
||||
private String createDate;
|
||||
|
||||
@Schema(description = "更新时间 (时间戳)", example = "1700000001000")
|
||||
@JsonProperty("update_time")
|
||||
private Long updateTime;
|
||||
|
||||
@Schema(description = "更新日期 (格式化)", example = "2024-01-15 11:00:00")
|
||||
@JsonProperty("update_date")
|
||||
private String updateDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换状态 VO (对应接口 10: get_convert_status)
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "文件转换状态")
|
||||
public static class ConvertStatusVO implements Serializable {
|
||||
|
||||
@Schema(description = "转换状态: pending / processing / completed / failed", example = "completed")
|
||||
private String status;
|
||||
|
||||
@Schema(description = "转换进度 (0.0 - 1.0)", example = "1.0")
|
||||
private Float progress;
|
||||
|
||||
@Schema(description = "状态消息", example = "转换完成")
|
||||
private String message;
|
||||
}
|
||||
|
||||
/**
|
||||
* 面包屑 VO (对应接口 12: all_parent_folder)
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "面包屑导航 (所有父文件夹)")
|
||||
public static class BreadcrumbVO implements Serializable {
|
||||
|
||||
@Schema(description = "父文件夹列表 (从根到当前的路径)")
|
||||
@JsonProperty("parent_folders")
|
||||
private List<InfoVO> parentFolders;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根目录信息 VO (对应接口 10: get_root_folder)
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "根目录信息")
|
||||
public static class RootFolderVO implements Serializable {
|
||||
|
||||
@Schema(description = "根文件夹信息")
|
||||
@JsonProperty("root_folder")
|
||||
private InfoVO rootFolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 父目录信息 VO (对应接口 11: get_parent_folder)
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Schema(description = "父目录信息")
|
||||
public static class ParentFolderVO implements Serializable {
|
||||
|
||||
@Schema(description = "父文件夹信息")
|
||||
@JsonProperty("parent_folder")
|
||||
private InfoVO parentFolder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package xiaozhi.modules.knowledge.entity;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 文档表 (Shadow DB for RAGFlow Documents)
|
||||
* 对应表名: ai_knowledge_document
|
||||
*/
|
||||
@Data
|
||||
@TableName(value = "ai_rag_knowledge_document", autoResultMap = true)
|
||||
@Schema(description = "知识库文档表")
|
||||
public class DocumentEntity implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(type = IdType.ASSIGN_UUID)
|
||||
@Schema(description = "本地唯一ID")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "知识库ID (关联 ai_rag_dataset.dataset_id)")
|
||||
private String datasetId;
|
||||
|
||||
@Schema(description = "RAGFlow文档ID (远程ID)")
|
||||
private String documentId;
|
||||
|
||||
@Schema(description = "文档名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "文件大小(Bytes)")
|
||||
private Long size;
|
||||
|
||||
@Schema(description = "文件类型(pdf/doc/txt等)")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "分块方法")
|
||||
private String chunkMethod;
|
||||
|
||||
@Schema(description = "解析配置(JSON String)")
|
||||
private String parserConfig;
|
||||
|
||||
@Schema(description = "可用状态 (1: 启用/正常, 0: 禁用/失效)")
|
||||
private String status;
|
||||
|
||||
@Schema(description = "运行状态 (UNSTART/RUNNING/CANCEL/DONE/FAIL)")
|
||||
private String run;
|
||||
|
||||
@Schema(description = "解析进度 (0.0 ~ 1.0)")
|
||||
private Double progress;
|
||||
|
||||
@Schema(description = "缩略图 (Base64 或 URL)")
|
||||
private String thumbnail;
|
||||
|
||||
@Schema(description = "解析耗时 (单位: 秒)")
|
||||
private Double processDuration;
|
||||
|
||||
@Schema(description = "自定义元数据 (JSON 格式)")
|
||||
private String metaFields;
|
||||
|
||||
@Schema(description = "来源类型 (local, s3, url 等)")
|
||||
private String sourceType;
|
||||
|
||||
@Schema(description = "解析错误信息")
|
||||
private String error;
|
||||
|
||||
@Schema(description = "分块数量")
|
||||
private Integer chunkCount;
|
||||
|
||||
@Schema(description = "Token数量")
|
||||
private Long tokenCount;
|
||||
|
||||
@Schema(description = "是否启用 (0:禁用 1:启用)")
|
||||
private Integer enabled;
|
||||
|
||||
@Schema(description = "创建者")
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Long creator;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Date createdAt;
|
||||
|
||||
@Schema(description = "更新时间")
|
||||
@TableField(fill = FieldFill.UPDATE)
|
||||
private Date updatedAt;
|
||||
|
||||
@Schema(description = "最新同步时间")
|
||||
private Date lastSyncAt;
|
||||
}
|
||||
+29
-1
@@ -23,15 +23,43 @@ public class KnowledgeBaseEntity {
|
||||
@Schema(description = "知识库ID")
|
||||
private String datasetId;
|
||||
|
||||
@Schema(description = "RAG模型配置ID")
|
||||
// @Deprecated
|
||||
@Schema(description = "RAG模型配置ID (连接RAGFlow的凭证指针)")
|
||||
private String ragModelId;
|
||||
|
||||
@Schema(description = "租户ID")
|
||||
private String tenantId;
|
||||
|
||||
@Schema(description = "知识库名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "知识库头像(Base64)")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "知识库描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "嵌入模型名称")
|
||||
private String embeddingModel;
|
||||
|
||||
@Schema(description = "权限设置: me/team")
|
||||
private String permission;
|
||||
|
||||
@Schema(description = "分块方法")
|
||||
private String chunkMethod;
|
||||
|
||||
@Schema(description = "解析器配置(JSON String)")
|
||||
private String parserConfig;
|
||||
|
||||
@Schema(description = "分块总数")
|
||||
private Long chunkCount;
|
||||
|
||||
@Schema(description = "文档总数")
|
||||
private Long documentCount;
|
||||
|
||||
@Schema(description = "总Token数")
|
||||
private Long tokenNum;
|
||||
|
||||
@Schema(description = "状态(0:禁用 1:启用)")
|
||||
private Integer status;
|
||||
|
||||
|
||||
+64
-49
@@ -3,10 +3,14 @@ package xiaozhi.modules.knowledge.rag;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import xiaozhi.modules.knowledge.dto.dataset.DatasetDTO;
|
||||
|
||||
import xiaozhi.common.page.PageData;
|
||||
import xiaozhi.modules.knowledge.dto.KnowledgeFilesDTO;
|
||||
import xiaozhi.modules.knowledge.dto.document.DocumentDTO;
|
||||
import xiaozhi.modules.knowledge.dto.document.ChunkDTO;
|
||||
import xiaozhi.modules.knowledge.dto.document.RetrievalDTO;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* 知识库API适配器抽象基类
|
||||
@@ -46,35 +50,24 @@ public abstract class KnowledgeBaseAdapter {
|
||||
* @return 分页数据
|
||||
*/
|
||||
public abstract PageData<KnowledgeFilesDTO> getDocumentList(String datasetId,
|
||||
Map<String, Object> queryParams,
|
||||
Integer page,
|
||||
Integer limit);
|
||||
DocumentDTO.ListReq req);
|
||||
|
||||
/**
|
||||
* 根据文档ID获取文档详情
|
||||
*
|
||||
* @param datasetId 知识库ID
|
||||
* @return 文档详情
|
||||
* @param datasetId 知识库ID
|
||||
* @param documentId 文档ID
|
||||
* @return 文档详情 (强类型 InfoVO)
|
||||
*/
|
||||
public abstract KnowledgeFilesDTO getDocumentById(String datasetId, String documentId);
|
||||
public abstract DocumentDTO.InfoVO getDocumentById(String datasetId, String documentId);
|
||||
|
||||
/**
|
||||
* 上传文档到知识库
|
||||
*
|
||||
* @param datasetId 知识库ID
|
||||
* @param file 上传的文件
|
||||
* @param name 文档名称
|
||||
* @param metaFields 元数据字段
|
||||
* @param chunkMethod 分块方法
|
||||
* @param parserConfig 解析器配置
|
||||
* @param req 上传请求参数
|
||||
* @return 上传的文档信息
|
||||
*/
|
||||
public abstract KnowledgeFilesDTO uploadDocument(String datasetId,
|
||||
MultipartFile file,
|
||||
String name,
|
||||
Map<String, Object> metaFields,
|
||||
String chunkMethod,
|
||||
Map<String, Object> parserConfig);
|
||||
public abstract KnowledgeFilesDTO uploadDocument(DocumentDTO.UploadReq req);
|
||||
|
||||
/**
|
||||
* 根据状态分页查询文档列表
|
||||
@@ -91,12 +84,12 @@ public abstract class KnowledgeBaseAdapter {
|
||||
Integer limit);
|
||||
|
||||
/**
|
||||
* 删除文档
|
||||
* 删除文档 (支持批量删除)
|
||||
*
|
||||
* @param datasetId 知识库ID
|
||||
* @param documentId 文档ID
|
||||
* @param datasetId 知识库ID
|
||||
* @param req 包含文档ID列表的请求对象
|
||||
*/
|
||||
public abstract void deleteDocument(String datasetId, String documentId);
|
||||
public abstract void deleteDocument(String datasetId, DocumentDTO.BatchIdReq req);
|
||||
|
||||
/**
|
||||
* 解析文档(切块)
|
||||
@@ -112,32 +105,21 @@ public abstract class KnowledgeBaseAdapter {
|
||||
*
|
||||
* @param datasetId 知识库ID
|
||||
* @param documentId 文档ID
|
||||
* @param keywords 关键词过滤
|
||||
* @param page 页码
|
||||
* @param pageSize 每页数量
|
||||
* @param chunkId 切片ID
|
||||
* @return 切片列表信息
|
||||
* @param req 列表请求参数 (分页、关键词等)
|
||||
* @return 切片列表VO
|
||||
*/
|
||||
public abstract Map<String, Object> listChunks(String datasetId,
|
||||
public abstract ChunkDTO.ListVO listChunks(String datasetId,
|
||||
String documentId,
|
||||
String keywords,
|
||||
Integer page,
|
||||
Integer pageSize,
|
||||
String chunkId);
|
||||
ChunkDTO.ListReq req);
|
||||
|
||||
/**
|
||||
* 召回测试 - 从知识库中检索相关切片
|
||||
*
|
||||
* @param question 用户查询
|
||||
* @param datasetIds 数据集ID列表
|
||||
* @param documentIds 文档ID列表
|
||||
* @param retrievalParams 检索参数
|
||||
* @param req 检索测试请求参数
|
||||
* @return 召回测试结果
|
||||
*/
|
||||
public abstract Map<String, Object> retrievalTest(String question,
|
||||
List<String> datasetIds,
|
||||
List<String> documentIds,
|
||||
Map<String, Object> retrievalParams);
|
||||
public abstract RetrievalDTO.ResultVO retrievalTest(
|
||||
RetrievalDTO.TestReq req);
|
||||
|
||||
/**
|
||||
* 测试连接
|
||||
@@ -170,25 +152,27 @@ public abstract class KnowledgeBaseAdapter {
|
||||
/**
|
||||
* 创建数据集
|
||||
*
|
||||
* @param createParams 创建参数
|
||||
* @return 数据集ID
|
||||
* @param req 创建参数
|
||||
* @return 数据集详情
|
||||
*/
|
||||
public abstract String createDataset(Map<String, Object> createParams);
|
||||
public abstract DatasetDTO.InfoVO createDataset(DatasetDTO.CreateReq req);
|
||||
|
||||
/**
|
||||
* 更新数据集
|
||||
*
|
||||
* @param datasetId 数据集ID
|
||||
* @param updateParams 更新参数
|
||||
* @param datasetId 数据集ID
|
||||
* @param req 更新参数
|
||||
* @return 数据集详情
|
||||
*/
|
||||
public abstract void updateDataset(String datasetId, Map<String, Object> updateParams);
|
||||
public abstract DatasetDTO.InfoVO updateDataset(String datasetId, DatasetDTO.UpdateReq req);
|
||||
|
||||
/**
|
||||
* 删除数据集
|
||||
*
|
||||
* @param datasetId 数据集ID
|
||||
* @param req 删除请求参数(包含ID列表)
|
||||
* @return 批量操作结果
|
||||
*/
|
||||
public abstract void deleteDataset(String datasetId);
|
||||
public abstract DatasetDTO.BatchOperationVO deleteDataset(DatasetDTO.BatchIdReq req);
|
||||
|
||||
/**
|
||||
* 获取数据集的文档数量
|
||||
@@ -197,4 +181,35 @@ public abstract class KnowledgeBaseAdapter {
|
||||
* @return 文档数量
|
||||
*/
|
||||
public abstract Integer getDocumentCount(String datasetId);
|
||||
|
||||
/**
|
||||
* 发送流式请求 (SSE)
|
||||
*
|
||||
* @param endpoint API端点
|
||||
* @param body 请求体
|
||||
* @param onData 数据回调
|
||||
*/
|
||||
public abstract void postStream(String endpoint, Object body, Consumer<String> onData);
|
||||
|
||||
/**
|
||||
* SearchBot 提问
|
||||
*
|
||||
* @param config RAG配置
|
||||
* @param body 请求体
|
||||
* @param onData 数据回调
|
||||
* @return 响应对象
|
||||
*/
|
||||
public abstract Object postSearchBotAsk(Map<String, Object> config, Object body,
|
||||
Consumer<String> onData);
|
||||
|
||||
/**
|
||||
* AgentBot 对话
|
||||
*
|
||||
* @param config RAG配置
|
||||
* @param agentId Agent ID
|
||||
* @param body 请求体
|
||||
* @param onData 数据回调
|
||||
*/
|
||||
public abstract void postAgentBotCompletion(Map<String, Object> config, String agentId, Object body,
|
||||
Consumer<String> onData);
|
||||
}
|
||||
+10
-1
@@ -22,6 +22,9 @@ public class KnowledgeBaseAdapterFactory {
|
||||
// 适配器实例缓存
|
||||
private static final Map<String, KnowledgeBaseAdapter> adapterCache = new ConcurrentHashMap<>();
|
||||
|
||||
// 最大缓存实例数,防止内存泄露 (Issue 9)
|
||||
private static final int MAX_CACHE_SIZE = 50;
|
||||
|
||||
static {
|
||||
// 注册内置适配器类型
|
||||
registerAdapter("ragflow", xiaozhi.modules.knowledge.rag.impl.RAGFlowAdapter.class);
|
||||
@@ -61,7 +64,13 @@ public class KnowledgeBaseAdapterFactory {
|
||||
// 创建新的适配器实例
|
||||
KnowledgeBaseAdapter adapter = createAdapter(adapterType, config);
|
||||
|
||||
// 缓存适配器实例
|
||||
// 缓存适配器实例 (带容量限制检查)
|
||||
if (adapterCache.size() >= MAX_CACHE_SIZE) {
|
||||
log.warn("适配器缓存已达上限 ({}),执行内存保护性清除", MAX_CACHE_SIZE);
|
||||
// 简单处理:直接清空,生产环境下建议使用 LRU
|
||||
adapterCache.clear();
|
||||
}
|
||||
|
||||
adapterCache.put(cacheKey, adapter);
|
||||
log.info("创建并缓存适配器实例: {}", cacheKey);
|
||||
|
||||
|
||||
@@ -0,0 +1,278 @@
|
||||
package xiaozhi.modules.knowledge.rag;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.TimeZone;
|
||||
import java.util.Locale;
|
||||
import java.net.URLEncoder;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.net.URI;
|
||||
import java.io.OutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import xiaozhi.common.exception.ErrorCode;
|
||||
import xiaozhi.common.exception.RenException;
|
||||
|
||||
/**
|
||||
* RAGFlow HTTP Client
|
||||
* 统一处理HTTP通信、鉴权、超时与错误解析
|
||||
*/
|
||||
@Slf4j
|
||||
public class RAGFlowClient {
|
||||
|
||||
private final String baseUrl;
|
||||
private final String apiKey;
|
||||
private final RestTemplate restTemplate;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
// 默认超时时间 (秒)
|
||||
private static final int DEFAULT_TIMEOUT = 30;
|
||||
|
||||
public RAGFlowClient(String baseUrl, String apiKey) {
|
||||
this(baseUrl, apiKey, DEFAULT_TIMEOUT);
|
||||
}
|
||||
|
||||
public RAGFlowClient(String baseUrl, String apiKey, int timeoutSeconds) {
|
||||
this.baseUrl = baseUrl.endsWith("/") ? baseUrl.substring(0, baseUrl.length() - 1) : baseUrl;
|
||||
this.apiKey = apiKey;
|
||||
this.objectMapper = new ObjectMapper();
|
||||
// [Reinforce] 兼容 RAGFlow 返回的 RFC 1123 日期格式 (如: Tue, 10 Feb 2026 10:27:35 GMT)
|
||||
this.objectMapper
|
||||
.setDateFormat(new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US));
|
||||
this.objectMapper.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
|
||||
// 优先从 Spring 上下文中获取池化的 RestTemplate Bean (Issue 3: 连接池化)
|
||||
RestTemplate pooledTemplate = null;
|
||||
try {
|
||||
pooledTemplate = xiaozhi.common.utils.SpringContextUtils.getBean(RestTemplate.class);
|
||||
} catch (Exception e) {
|
||||
log.warn("无法从 SpringContext 获取池化 RestTemplate,将退化为简单连接模式: {}", e.getMessage());
|
||||
}
|
||||
|
||||
if (false) { // Force new RestTemplate for debugging
|
||||
this.restTemplate = pooledTemplate;
|
||||
log.debug("RAGFlowClient 已成功挂载全局池化 RestTemplate");
|
||||
} else {
|
||||
// 兜底方案:配置超时并创建简单 RestTemplate
|
||||
log.info("RAGFlowClient 初始化: 使用独立 RestTemplate (Debug Mode)");
|
||||
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
|
||||
factory.setConnectTimeout(timeoutSeconds * 1000);
|
||||
factory.setReadTimeout(timeoutSeconds * 1000);
|
||||
this.restTemplate = new RestTemplate(factory);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 GET 请求
|
||||
*/
|
||||
public Map<String, Object> get(String endpoint, Map<String, Object> queryParams) {
|
||||
String url = buildUrl(endpoint, queryParams);
|
||||
log.debug("GET {}", url);
|
||||
return execute(url, HttpMethod.GET, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 POST 请求 (JSON)
|
||||
*/
|
||||
public Map<String, Object> post(String endpoint, Object body) {
|
||||
String url = buildUrl(endpoint, null);
|
||||
log.info("RAGFlow Client POST Request: URL={}, BodyType={}", url,
|
||||
body != null ? body.getClass().getName() : "null");
|
||||
try {
|
||||
return execute(url, HttpMethod.POST, body);
|
||||
} catch (Exception e) {
|
||||
log.error("RAGFlow Client POST Failed: URL={}", url, e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 DELETE 请求
|
||||
*/
|
||||
public Map<String, Object> delete(String endpoint, Object body) {
|
||||
String url = buildUrl(endpoint, null);
|
||||
log.debug("DELETE {}", url);
|
||||
return execute(url, HttpMethod.DELETE, body);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 PUT 请求
|
||||
*/
|
||||
public Map<String, Object> put(String endpoint, Object body) {
|
||||
String url = buildUrl(endpoint, null);
|
||||
log.debug("PUT {}", url);
|
||||
return execute(url, HttpMethod.PUT, body);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 Multipart 请求 (文件上传)
|
||||
*/
|
||||
public Map<String, Object> postMultipart(String endpoint, MultiValueMap<String, Object> parts) {
|
||||
String url = buildUrl(endpoint, null);
|
||||
log.debug("POST MULTIPART {}", url);
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
|
||||
headers.setBearerAuth(apiKey);
|
||||
// 为了防止中文文件名乱码,某些环境可能需要设置 Charset,但在 Multipart 中通常由 Part header 控制
|
||||
|
||||
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(parts, headers);
|
||||
|
||||
return doExecute(url, HttpMethod.POST, requestEntity);
|
||||
}
|
||||
|
||||
private Map<String, Object> execute(String url, HttpMethod method, Object body) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.setBearerAuth(apiKey);
|
||||
// 强制 UTF-8
|
||||
headers.setAcceptCharset(Collections.singletonList(StandardCharsets.UTF_8));
|
||||
|
||||
HttpEntity<Object> requestEntity = new HttpEntity<>(body, headers);
|
||||
return doExecute(url, method, requestEntity);
|
||||
}
|
||||
|
||||
private Map<String, Object> doExecute(String url, HttpMethod method, HttpEntity<?> requestEntity) {
|
||||
try {
|
||||
ResponseEntity<String> response = restTemplate.exchange(url, method, requestEntity, String.class);
|
||||
|
||||
if (!response.getStatusCode().is2xxSuccessful()) {
|
||||
log.error("RAGFlow API Error Status: {}", response.getStatusCode());
|
||||
throw new RenException(ErrorCode.RAG_API_ERROR, "HTTP " + response.getStatusCode());
|
||||
}
|
||||
|
||||
String responseBody = response.getBody();
|
||||
if (responseBody == null) {
|
||||
throw new RenException(ErrorCode.RAG_API_ERROR, "Empty Response");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = objectMapper.readValue(responseBody, Map.class);
|
||||
|
||||
Integer code = (Integer) map.get("code");
|
||||
if (code != null && code != 0) {
|
||||
String msg = (String) map.get("message");
|
||||
log.error("RAGFlow Business Error: code={}, msg={}", code, msg);
|
||||
throw new RenException(ErrorCode.RAG_API_ERROR, msg != null ? msg : "Unknown RAGFlow Error");
|
||||
}
|
||||
|
||||
// 返回 data 字段,如果 data 不存在则返回整个 map (视具体情况,通常 RAGFlow 返回 code=0, data=...)
|
||||
// 兼容性处理:如果 external caller 需要 check code,这里已经 check 过了。
|
||||
// 统一返回 wrap 了 code 的 map 还是只返回 data?
|
||||
// 根据分析报告,旧逻辑 check code==0 后取 data.
|
||||
// 这里我们返回整个 Map,让 Adapter 决定怎么取,或者我们直接在这里剥离?
|
||||
// 建议:为了灵活性,返回全量 Map,但在 Client 层做 code!=0 的抛错。
|
||||
return map;
|
||||
|
||||
} catch (RenException re) {
|
||||
throw re;
|
||||
} catch (Exception e) {
|
||||
log.error("RAGFlow Client Execute Error! URL: {}, Method: {}, Body Type: {}", url, method,
|
||||
requestEntity.getBody() != null ? requestEntity.getBody().getClass().getName() : "null");
|
||||
log.error("Full exception stack trace: ", e);
|
||||
throw new RenException(ErrorCode.RAG_API_ERROR, "Request Failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private String buildUrl(String endpoint, Map<String, Object> queryParams) {
|
||||
StringBuilder sb = new StringBuilder(baseUrl);
|
||||
if (!endpoint.startsWith("/")) {
|
||||
sb.append("/");
|
||||
}
|
||||
sb.append(endpoint);
|
||||
|
||||
if (queryParams != null && !queryParams.isEmpty()) {
|
||||
sb.append("?");
|
||||
queryParams.forEach((k, v) -> {
|
||||
if (v != null) {
|
||||
try {
|
||||
sb.append(k).append("=")
|
||||
.append(URLEncoder.encode(v.toString(),
|
||||
StandardCharsets.UTF_8.name()))
|
||||
.append("&");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
log.warn("参数编码失败: k={}, v={}", k, v);
|
||||
sb.append(k).append("=").append(v).append("&");
|
||||
}
|
||||
}
|
||||
});
|
||||
// 移除最后一个 &
|
||||
sb.setLength(sb.length() - 1);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送流式 POST 请求 (SSE)
|
||||
* 使用 Java 21 HttpClient 实现
|
||||
*
|
||||
* @param endpoint API端点
|
||||
* @param body 请求体
|
||||
* @param onData 数据回调(每收到一行数据调用一次)
|
||||
*/
|
||||
public void postStream(String endpoint, Object body, Consumer<String> onData) {
|
||||
try {
|
||||
String url = buildUrl(endpoint, null);
|
||||
log.debug("POST STREAM {}", url);
|
||||
|
||||
String jsonBody = objectMapper.writeValueAsString(body);
|
||||
|
||||
HttpClient httpClient = HttpClient.newBuilder()
|
||||
.connectTimeout(Duration.ofSeconds(DEFAULT_TIMEOUT))
|
||||
.build();
|
||||
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(url))
|
||||
.header("Content-Type", "application/json")
|
||||
.header("Authorization", "Bearer " + apiKey)
|
||||
.POST(HttpRequest.BodyPublishers.ofString(jsonBody, StandardCharsets.UTF_8))
|
||||
.build();
|
||||
|
||||
// 发送请求并处理流式响应
|
||||
httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream())
|
||||
.body()
|
||||
.transferTo(new OutputStream() {
|
||||
private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
if (b == '\n') {
|
||||
String line = buffer.toString(StandardCharsets.UTF_8);
|
||||
if (!line.trim().isEmpty()) {
|
||||
onData.accept(line);
|
||||
}
|
||||
buffer.reset();
|
||||
} else {
|
||||
buffer.write(b);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("RAGFlow Stream Request Error", e);
|
||||
throw new RenException(ErrorCode.RAG_API_ERROR, "Stream Request Failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
+455
-892
File diff suppressed because it is too large
Load Diff
+10
@@ -93,4 +93,14 @@ public interface KnowledgeBaseService extends BaseService<KnowledgeBaseEntity> {
|
||||
* @return RAG模型列表
|
||||
*/
|
||||
List<ModelConfigEntity> getRAGModels();
|
||||
|
||||
/**
|
||||
* 更新知识库统计信息 (用于被文件服务回调)
|
||||
*
|
||||
* @param datasetId 知识库ID
|
||||
* @param docDelta 文档数增量
|
||||
* @param chunkDelta 分块数增量
|
||||
* @param tokenDelta Token数增量
|
||||
*/
|
||||
void updateStatistics(String datasetId, Integer docDelta, Long chunkDelta, Long tokenDelta);
|
||||
}
|
||||
+42
-31
@@ -7,6 +7,9 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import xiaozhi.common.page.PageData;
|
||||
import xiaozhi.modules.knowledge.dto.KnowledgeFilesDTO;
|
||||
import xiaozhi.modules.knowledge.dto.document.ChunkDTO;
|
||||
import xiaozhi.modules.knowledge.dto.document.RetrievalDTO;
|
||||
import xiaozhi.modules.knowledge.dto.document.DocumentDTO;
|
||||
|
||||
/**
|
||||
* 知识库文档服务接口
|
||||
@@ -28,9 +31,9 @@ public interface KnowledgeFilesService {
|
||||
*
|
||||
* @param documentId 文档ID
|
||||
* @param datasetId 知识库ID
|
||||
* @return 文档详情
|
||||
* @return 文档详情 (强类型 InfoVO)
|
||||
*/
|
||||
KnowledgeFilesDTO getByDocumentId(String documentId, String datasetId);
|
||||
DocumentDTO.InfoVO getByDocumentId(String documentId, String datasetId);
|
||||
|
||||
/**
|
||||
* 上传文档到知识库
|
||||
@@ -48,12 +51,12 @@ public interface KnowledgeFilesService {
|
||||
Map<String, Object> parserConfig);
|
||||
|
||||
/**
|
||||
* 根据文档ID和知识库ID删除文档
|
||||
* 批量删除文档
|
||||
*
|
||||
* @param documentId 文档ID
|
||||
* @param datasetId 知识库ID
|
||||
* @param datasetId 知识库ID
|
||||
* @param req 删除请求参数 (含文档ID列表)
|
||||
*/
|
||||
void deleteByDocumentId(String documentId, String datasetId);
|
||||
void deleteDocuments(String datasetId, DocumentDTO.BatchIdReq req);
|
||||
|
||||
/**
|
||||
* 获取RAG配置信息
|
||||
@@ -77,36 +80,44 @@ public interface KnowledgeFilesService {
|
||||
*
|
||||
* @param datasetId 知识库ID
|
||||
* @param documentId 文档ID
|
||||
* @param keywords 关键词过滤
|
||||
* @param page 页码
|
||||
* @param pageSize 每页数量
|
||||
* @param chunkId 切片ID
|
||||
* @param req 切片列表请求参数
|
||||
* @return 切片列表信息
|
||||
*/
|
||||
Map<String, Object> listChunks(String datasetId, String documentId, String keywords,
|
||||
Integer page, Integer pageSize, String chunkId);
|
||||
ChunkDTO.ListVO listChunks(String datasetId, String documentId, ChunkDTO.ListReq req);
|
||||
|
||||
/**
|
||||
* 召回测试 - 从指定数据集或文档中检索相关切片
|
||||
* 召回测试
|
||||
*
|
||||
* @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 元数据过滤条件
|
||||
* @param req 检索测试请求参数
|
||||
* @return 召回测试结果
|
||||
*/
|
||||
Map<String, Object> retrievalTest(String question, List<String> datasetIds, List<String> documentIds,
|
||||
Integer page, Integer pageSize, Float similarityThreshold,
|
||||
Float vectorSimilarityWeight, Integer topK, String rerankId,
|
||||
Boolean keyword, Boolean highlight, List<String> crossLanguages,
|
||||
Map<String, Object> metadataCondition);
|
||||
RetrievalDTO.ResultVO retrievalTest(RetrievalDTO.TestReq req);
|
||||
|
||||
/**
|
||||
* 保存文档影子记录
|
||||
*/
|
||||
void saveDocumentShadow(String datasetId, KnowledgeFilesDTO result, String originalName, String chunkMethod,
|
||||
Map<String, Object> parserConfig);
|
||||
|
||||
/**
|
||||
* 批量删除文档影子记录并同步统计数据
|
||||
*
|
||||
* @param documentIds 文档ID列表
|
||||
* @param datasetId 数据集ID
|
||||
* @param chunkDelta 待扣减的总分块数
|
||||
* @param tokenDelta 待扣减的总Token数
|
||||
*/
|
||||
void deleteDocumentShadows(List<String> documentIds, String datasetId, Long chunkDelta, Long tokenDelta);
|
||||
|
||||
/**
|
||||
* 根据数据集ID清理所有关联文档 (级联删除专用)
|
||||
*
|
||||
* @param datasetId 数据集ID
|
||||
*/
|
||||
void deleteDocumentsByDatasetId(String datasetId);
|
||||
|
||||
/**
|
||||
* 同步所有处于 RUNNING 状态的文档 (供定时任务调用)
|
||||
*/
|
||||
void syncRunningDocuments();
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package xiaozhi.modules.knowledge.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 知识库模块领域编排服务
|
||||
* 用于处理跨 KnowledgeBase 和 KnowledgeFiles 的复杂业务流程,彻底解决 Service 间的循环依赖问题。
|
||||
*/
|
||||
public interface KnowledgeManagerService {
|
||||
|
||||
/**
|
||||
* 级联删除知识库及其下属所有文档 (包括本地 DB 和 RAGFlow 远程数据)
|
||||
*
|
||||
* @param datasetId 知识库 ID
|
||||
*/
|
||||
void deleteDatasetWithFiles(String datasetId);
|
||||
|
||||
/**
|
||||
* 批量级联删除知识库
|
||||
*
|
||||
* @param datasetIds 知识库 ID 列表
|
||||
*/
|
||||
void batchDeleteDatasetsWithFiles(List<String> datasetIds);
|
||||
}
|
||||
+283
-513
@@ -1,19 +1,14 @@
|
||||
package xiaozhi.modules.knowledge.service.impl;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import xiaozhi.common.constant.Constant;
|
||||
import xiaozhi.common.exception.ErrorCode;
|
||||
import xiaozhi.common.exception.RenException;
|
||||
@@ -22,10 +17,10 @@ import xiaozhi.common.redis.RedisKeys;
|
||||
import xiaozhi.common.redis.RedisUtils;
|
||||
import xiaozhi.common.service.impl.BaseServiceImpl;
|
||||
import xiaozhi.common.utils.ConvertUtils;
|
||||
import xiaozhi.common.utils.MessageUtils;
|
||||
import xiaozhi.common.utils.ToolUtil;
|
||||
import xiaozhi.common.utils.JsonUtils;
|
||||
import xiaozhi.modules.knowledge.dao.KnowledgeBaseDao;
|
||||
import xiaozhi.modules.knowledge.dto.KnowledgeBaseDTO;
|
||||
import xiaozhi.modules.knowledge.dto.dataset.DatasetDTO;
|
||||
import xiaozhi.modules.knowledge.entity.KnowledgeBaseEntity;
|
||||
import xiaozhi.modules.knowledge.rag.KnowledgeBaseAdapter;
|
||||
import xiaozhi.modules.knowledge.rag.KnowledgeBaseAdapterFactory;
|
||||
@@ -35,6 +30,15 @@ import xiaozhi.modules.model.entity.ModelConfigEntity;
|
||||
import xiaozhi.modules.model.service.ModelConfigService;
|
||||
import xiaozhi.modules.security.user.SecurityUser;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 知识库服务实现类 (Refactored)
|
||||
* 集成 RAGFlow Adapter 与 Shadow DB 模式
|
||||
*/
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
@Slf4j
|
||||
@@ -46,200 +50,50 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl<KnowledgeBaseDao,
|
||||
private final ModelConfigDao modelConfigDao;
|
||||
private final RedisUtils redisUtils;
|
||||
|
||||
@Override
|
||||
public KnowledgeBaseEntity selectById(Serializable datasetId) {
|
||||
if (datasetId == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 先从Redis获取缓存
|
||||
String key = RedisKeys.getKnowledgeBaseCacheKey(datasetId.toString());
|
||||
KnowledgeBaseEntity cachedEntity = (KnowledgeBaseEntity) redisUtils.get(key);
|
||||
if (cachedEntity != null) {
|
||||
return cachedEntity;
|
||||
}
|
||||
|
||||
// 如果缓存中没有,则从数据库获取
|
||||
KnowledgeBaseEntity entity = knowledgeBaseDao.selectById(datasetId);
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 存入Redis缓存
|
||||
redisUtils.set(key, entity);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageData<KnowledgeBaseDTO> getPageList(KnowledgeBaseDTO knowledgeBaseDTO, Integer page, Integer limit) {
|
||||
long curPage = page;
|
||||
long pageSize = limit;
|
||||
Page<KnowledgeBaseEntity> pageInfo = new Page<>(curPage, pageSize);
|
||||
|
||||
Page<KnowledgeBaseEntity> pageInfo = new Page<>(page, limit);
|
||||
QueryWrapper<KnowledgeBaseEntity> queryWrapper = new QueryWrapper<>();
|
||||
|
||||
// 添加查询条件
|
||||
if (knowledgeBaseDTO != null) {
|
||||
queryWrapper.like(StringUtils.isNotBlank(knowledgeBaseDTO.getName()), "name", knowledgeBaseDTO.getName());
|
||||
queryWrapper.eq(knowledgeBaseDTO.getStatus() != null, "status", knowledgeBaseDTO.getStatus());
|
||||
queryWrapper.eq("creator", knowledgeBaseDTO.getCreator());
|
||||
}
|
||||
|
||||
// 添加排序规则:按创建时间降序
|
||||
queryWrapper.orderByDesc("created_at");
|
||||
|
||||
IPage<KnowledgeBaseEntity> knowledgeBaseEntityIPage = knowledgeBaseDao.selectPage(pageInfo, queryWrapper);
|
||||
IPage<KnowledgeBaseEntity> iPage = knowledgeBaseDao.selectPage(pageInfo, queryWrapper);
|
||||
PageData<KnowledgeBaseDTO> pageData = getPageData(iPage, KnowledgeBaseDTO.class);
|
||||
|
||||
// 获取分页数据
|
||||
PageData<KnowledgeBaseDTO> pageData = getPageData(knowledgeBaseEntityIPage, KnowledgeBaseDTO.class);
|
||||
|
||||
// 为每个知识库获取文档数量
|
||||
// Enrich with Document Count from RAG (Optional / Lazy)
|
||||
if (pageData != null && pageData.getList() != null) {
|
||||
for (KnowledgeBaseDTO knowledgeBase : pageData.getList()) {
|
||||
try {
|
||||
Integer documentCount = getDocumentCountFromRAG(knowledgeBase.getDatasetId(),
|
||||
knowledgeBase.getRagModelId());
|
||||
knowledgeBase.setDocumentCount(documentCount);
|
||||
} catch (Exception e) {
|
||||
// 构建详细的错误信息,包含异常类型和消息
|
||||
String baseErrorMessage = e.getClass().getSimpleName() + " - 获取知识库文档数量失败";
|
||||
String errorMessage = baseErrorMessage + (e.getMessage() != null ? ": " + e.getMessage() : "");
|
||||
log.warn("知识库 {} {}", knowledgeBase.getDatasetId(), errorMessage);
|
||||
knowledgeBase.setDocumentCount(0); // 设置默认值
|
||||
}
|
||||
for (KnowledgeBaseDTO dto : pageData.getList()) {
|
||||
enrichDocumentCount(dto);
|
||||
}
|
||||
}
|
||||
|
||||
return pageData;
|
||||
}
|
||||
|
||||
private void enrichDocumentCount(KnowledgeBaseDTO dto) {
|
||||
try {
|
||||
if (StringUtils.isNotBlank(dto.getDatasetId()) && StringUtils.isNotBlank(dto.getRagModelId())) {
|
||||
KnowledgeBaseAdapter adapter = getAdapterByModelId(dto.getRagModelId());
|
||||
if (adapter != null) {
|
||||
dto.setDocumentCount(adapter.getDocumentCount(dto.getDatasetId()));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("无法获取知识库 {} 的文档计数: {}", dto.getName(), e.getMessage());
|
||||
dto.setDocumentCount(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public KnowledgeBaseDTO getById(String id) {
|
||||
if (StringUtils.isBlank(id)) {
|
||||
throw new RenException(ErrorCode.IDENTIFIER_NOT_NULL);
|
||||
}
|
||||
|
||||
KnowledgeBaseEntity entity = knowledgeBaseDao.selectById(id);
|
||||
if (entity == null) {
|
||||
throw new RenException(ErrorCode.Knowledge_Base_RECORD_NOT_EXISTS);
|
||||
}
|
||||
|
||||
return ConvertUtils.sourceToTarget(entity, KnowledgeBaseDTO.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KnowledgeBaseDTO save(KnowledgeBaseDTO knowledgeBaseDTO) {
|
||||
if (knowledgeBaseDTO == null) {
|
||||
throw new RenException(ErrorCode.PARAMS_GET_ERROR);
|
||||
}
|
||||
|
||||
// 检查是否存在同名知识库
|
||||
checkDuplicateKnowledgeBaseName(knowledgeBaseDTO, null);
|
||||
|
||||
String datasetId = null;
|
||||
// 调用RAG API创建数据集
|
||||
try {
|
||||
Map<String, Object> ragConfig = getValidatedRAGConfig(knowledgeBaseDTO.getRagModelId());
|
||||
datasetId = createDatasetInRAG(
|
||||
knowledgeBaseDTO.getName(),
|
||||
knowledgeBaseDTO.getDescription(),
|
||||
ragConfig);
|
||||
} catch (Exception e) {
|
||||
// 如果RAG API调用失败,直接抛出异常
|
||||
throw e;
|
||||
}
|
||||
|
||||
// 验证数据集ID是否已存在
|
||||
KnowledgeBaseEntity existingEntity = knowledgeBaseDao.selectOne(
|
||||
new QueryWrapper<KnowledgeBaseEntity>().eq("dataset_id", datasetId));
|
||||
if (existingEntity != null) {
|
||||
// 如果datasetId已存在,删除RAG中的数据集并抛出异常
|
||||
try {
|
||||
Map<String, Object> ragConfig = getValidatedRAGConfig(knowledgeBaseDTO.getRagModelId());
|
||||
deleteDatasetInRAG(datasetId, ragConfig);
|
||||
} catch (Exception deleteException) {
|
||||
// 提供更详细的错误信息,包括异常类型和消息
|
||||
String errorMessage = "删除重复datasetId的RAG数据集失败: " + deleteException.getClass().getSimpleName();
|
||||
if (deleteException.getMessage() != null) {
|
||||
errorMessage += " - " + deleteException.getMessage();
|
||||
}
|
||||
log.warn(errorMessage, deleteException);
|
||||
}
|
||||
throw new RenException(ErrorCode.DB_RECORD_EXISTS);
|
||||
}
|
||||
|
||||
// 创建本地实体并保存
|
||||
KnowledgeBaseEntity entity = ConvertUtils.sourceToTarget(knowledgeBaseDTO, KnowledgeBaseEntity.class);
|
||||
entity.setDatasetId(datasetId);
|
||||
knowledgeBaseDao.insert(entity);
|
||||
|
||||
return ConvertUtils.sourceToTarget(entity, KnowledgeBaseDTO.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KnowledgeBaseDTO update(KnowledgeBaseDTO knowledgeBaseDTO) {
|
||||
if (knowledgeBaseDTO == null || StringUtils.isBlank(knowledgeBaseDTO.getId())) {
|
||||
throw new RenException(ErrorCode.IDENTIFIER_NOT_NULL);
|
||||
}
|
||||
|
||||
// 检查记录是否存在
|
||||
KnowledgeBaseEntity existingEntity = knowledgeBaseDao.selectById(knowledgeBaseDTO.getId());
|
||||
if (existingEntity == null) {
|
||||
throw new RenException(ErrorCode.Knowledge_Base_RECORD_NOT_EXISTS);
|
||||
}
|
||||
|
||||
// 检查是否存在同名知识库(排除当前记录)
|
||||
checkDuplicateKnowledgeBaseName(knowledgeBaseDTO, knowledgeBaseDTO.getId());
|
||||
|
||||
// 验证数据集ID是否与其他记录冲突
|
||||
if (StringUtils.isNotBlank(knowledgeBaseDTO.getDatasetId())) {
|
||||
KnowledgeBaseEntity conflictEntity = knowledgeBaseDao.selectOne(
|
||||
new QueryWrapper<KnowledgeBaseEntity>()
|
||||
.eq("dataset_id", knowledgeBaseDTO.getDatasetId())
|
||||
.ne("id", knowledgeBaseDTO.getId()));
|
||||
if (conflictEntity != null) {
|
||||
throw new RenException(ErrorCode.DB_RECORD_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
boolean needRagValidation = StringUtils.isNotBlank(knowledgeBaseDTO.getDatasetId())
|
||||
&& StringUtils.isNotBlank(knowledgeBaseDTO.getRagModelId());
|
||||
|
||||
if (needRagValidation) {
|
||||
try {
|
||||
// 先校验RAG配置
|
||||
Map<String, Object> ragConfig = getValidatedRAGConfig(knowledgeBaseDTO.getRagModelId());
|
||||
|
||||
// 调用RAG API更新数据集
|
||||
updateDatasetInRAG(
|
||||
knowledgeBaseDTO.getDatasetId(),
|
||||
knowledgeBaseDTO.getName(),
|
||||
knowledgeBaseDTO.getDescription(),
|
||||
ragConfig);
|
||||
|
||||
log.info("RAG API更新成功,datasetId: {}", knowledgeBaseDTO.getDatasetId());
|
||||
} catch (Exception e) {
|
||||
// 提供更详细的错误信息,包括异常类型和消息
|
||||
String errorMessage = "更新RAG数据集失败: " + e.getClass().getSimpleName();
|
||||
if (e.getMessage() != null) {
|
||||
errorMessage += " - " + e.getMessage();
|
||||
}
|
||||
log.error(errorMessage, e);
|
||||
throw e;
|
||||
}
|
||||
} else {
|
||||
log.warn("datasetId或ragModelId为空,跳过RAG更新");
|
||||
}
|
||||
|
||||
KnowledgeBaseEntity entity = ConvertUtils.sourceToTarget(knowledgeBaseDTO, KnowledgeBaseEntity.class);
|
||||
knowledgeBaseDao.updateById(entity);
|
||||
|
||||
// 删除缓存
|
||||
if (entity.getDatasetId() != null) {
|
||||
redisUtils.delete(RedisKeys.getKnowledgeBaseCacheKey(entity.getId()));
|
||||
}
|
||||
|
||||
return ConvertUtils.sourceToTarget(entity, KnowledgeBaseDTO.class);
|
||||
}
|
||||
|
||||
@@ -248,400 +102,316 @@ public class KnowledgeBaseServiceImpl extends BaseServiceImpl<KnowledgeBaseDao,
|
||||
if (StringUtils.isBlank(datasetId)) {
|
||||
throw new RenException(ErrorCode.PARAMS_GET_ERROR);
|
||||
}
|
||||
|
||||
KnowledgeBaseEntity entity = knowledgeBaseDao.selectOne(
|
||||
new QueryWrapper<KnowledgeBaseEntity>().eq("dataset_id", datasetId));
|
||||
|
||||
// [Production Fix] 兼容性查找:优先通过 dataset_id 找,找不到通过主键 id 找,确保前端传哪种 UUID 都能命中
|
||||
KnowledgeBaseEntity entity = knowledgeBaseDao
|
||||
.selectOne(new QueryWrapper<KnowledgeBaseEntity>()
|
||||
.eq("dataset_id", datasetId)
|
||||
.or()
|
||||
.eq("id", datasetId));
|
||||
if (entity == null) {
|
||||
throw new RenException(ErrorCode.Knowledge_Base_RECORD_NOT_EXISTS);
|
||||
}
|
||||
return ConvertUtils.sourceToTarget(entity, KnowledgeBaseDTO.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public KnowledgeBaseDTO save(KnowledgeBaseDTO dto) {
|
||||
// 1. Validation
|
||||
checkDuplicateName(dto.getName(), null);
|
||||
KnowledgeBaseAdapter adapter = null;
|
||||
|
||||
// 2. RAG Creation
|
||||
String datasetId = null;
|
||||
try {
|
||||
// 若未指定 RAG 模型,自动使用系统默认
|
||||
if (StringUtils.isBlank(dto.getRagModelId())) {
|
||||
List<ModelConfigEntity> models = getRAGModels();
|
||||
if (models != null && !models.isEmpty()) {
|
||||
dto.setRagModelId(models.get(0).getId());
|
||||
} else {
|
||||
throw new RenException(ErrorCode.RAG_CONFIG_NOT_FOUND, "未指定且无可用默认 RAG 模型");
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Object> ragConfig = getValidatedRAGConfig(dto.getRagModelId());
|
||||
adapter = KnowledgeBaseAdapterFactory.getAdapter((String) ragConfig.get("type"),
|
||||
ragConfig);
|
||||
|
||||
DatasetDTO.CreateReq createReq = ConvertUtils.sourceToTarget(dto, DatasetDTO.CreateReq.class);
|
||||
createReq.setName(SecurityUser.getUser().getUsername() + "_" + dto.getName());
|
||||
|
||||
DatasetDTO.InfoVO ragResponse = adapter.createDataset(createReq);
|
||||
if (ragResponse == null || StringUtils.isBlank(ragResponse.getId())) {
|
||||
throw new RenException(ErrorCode.RAG_API_ERROR, "RAG创建返回无效: 缺失ID");
|
||||
}
|
||||
datasetId = ragResponse.getId();
|
||||
|
||||
// 3. Local Save (Shadow)
|
||||
KnowledgeBaseEntity entity = ConvertUtils.sourceToTarget(dto, KnowledgeBaseEntity.class);
|
||||
|
||||
// [Production Fix] 统一本地 ID 与 RAGFlow ID,防止前端调用 /delete 或 /update 时因 ID 混淆(本地
|
||||
// UUID vs RAG UUID)导致 10163 错误
|
||||
entity.setId(datasetId);
|
||||
entity.setDatasetId(datasetId);
|
||||
entity.setStatus(1); // Default Enabled
|
||||
|
||||
// ✅ FULL PERSISTENCE: 严格全量回写 (User Requirement)
|
||||
// 使用强类型 DTO 属性获取,不再从 Map 中手动解析 Key
|
||||
entity.setTenantId(ragResponse.getTenantId());
|
||||
entity.setChunkMethod(ragResponse.getChunkMethod());
|
||||
entity.setEmbeddingModel(ragResponse.getEmbeddingModel());
|
||||
entity.setPermission(ragResponse.getPermission());
|
||||
|
||||
if (StringUtils.isBlank(entity.getAvatar())) {
|
||||
entity.setAvatar(ragResponse.getAvatar());
|
||||
}
|
||||
|
||||
// Parse Config (JSON)
|
||||
if (ragResponse.getParserConfig() != null) {
|
||||
entity.setParserConfig(JsonUtils.toJsonString(ragResponse.getParserConfig()));
|
||||
}
|
||||
|
||||
// Numeric fields
|
||||
entity.setChunkCount(ragResponse.getChunkCount() != null ? ragResponse.getChunkCount() : 0L);
|
||||
entity.setDocumentCount(ragResponse.getDocumentCount() != null ? ragResponse.getDocumentCount() : 0L);
|
||||
entity.setTokenNum(ragResponse.getTokenNum() != null ? ragResponse.getTokenNum() : 0L);
|
||||
|
||||
// 清空 creator/updater,让 FieldMetaObjectHandler 从 SecurityUser 自动填充
|
||||
// ConvertUtils 会把 DTO 中的 creator=0 拷贝过来,导致 strictInsertFill 跳过填充
|
||||
entity.setCreator(null);
|
||||
entity.setUpdater(null);
|
||||
|
||||
knowledgeBaseDao.insert(entity);
|
||||
return ConvertUtils.sourceToTarget(entity, KnowledgeBaseDTO.class);
|
||||
} catch (Exception e) {
|
||||
log.error("RAG创建或本地保存失败", e);
|
||||
// 如果datasetId已生成但在保存本地时失败,尝试回滚RAG (Best Effort)
|
||||
if (StringUtils.isNotBlank(datasetId)) {
|
||||
try {
|
||||
if (adapter != null)
|
||||
adapter.deleteDataset(
|
||||
DatasetDTO.BatchIdReq.builder().ids(Collections.singletonList(datasetId)).build());
|
||||
} catch (Exception rollbackEx) {
|
||||
log.error("RAG回滚失败: {}", datasetId, rollbackEx);
|
||||
}
|
||||
}
|
||||
if (e instanceof RenException) {
|
||||
throw (RenException) e;
|
||||
}
|
||||
throw new RenException(ErrorCode.RAG_API_ERROR, "创建知识库失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@SuppressWarnings("deprecation")
|
||||
public KnowledgeBaseDTO update(KnowledgeBaseDTO dto) {
|
||||
log.info("Update Service Called: ID={}, DatasetID={}", dto.getId(), dto.getDatasetId());
|
||||
KnowledgeBaseEntity entity = knowledgeBaseDao.selectById(dto.getId());
|
||||
if (entity == null) {
|
||||
log.error("Update failed: Entity not found for ID={}", dto.getId());
|
||||
throw new RenException(ErrorCode.Knowledge_Base_RECORD_NOT_EXISTS);
|
||||
}
|
||||
|
||||
checkDuplicateName(dto.getName(), dto.getId());
|
||||
|
||||
// 验证数据集ID是否与其他记录冲突
|
||||
if (StringUtils.isNotBlank(dto.getDatasetId())) {
|
||||
KnowledgeBaseEntity conflictEntity = knowledgeBaseDao.selectOne(
|
||||
new QueryWrapper<KnowledgeBaseEntity>()
|
||||
.eq("dataset_id", dto.getDatasetId())
|
||||
.ne("id", dto.getId()));
|
||||
if (conflictEntity != null) {
|
||||
throw new RenException(ErrorCode.DB_RECORD_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
// RAG Update if needed
|
||||
if (StringUtils.isNotBlank(entity.getDatasetId()) && StringUtils.isNotBlank(dto.getRagModelId())) {
|
||||
try {
|
||||
// 🤖 AUTO-FILL: 若 DTO 未传 ragModelId (极少情况),尝试复用 Entity 中的
|
||||
if (StringUtils.isBlank(dto.getRagModelId())) {
|
||||
dto.setRagModelId(entity.getRagModelId());
|
||||
}
|
||||
|
||||
// [FIX] 智能补全:如果 DTO 里的关键字段为空,则使用 Entity 里的旧值
|
||||
// 确保发给 RAGFlow 的请求包含所有必填项 (Partial Update Support)
|
||||
if (StringUtils.isBlank(dto.getPermission())) {
|
||||
dto.setPermission(entity.getPermission());
|
||||
}
|
||||
if (StringUtils.isBlank(dto.getChunkMethod())) {
|
||||
dto.setChunkMethod(entity.getChunkMethod());
|
||||
}
|
||||
|
||||
KnowledgeBaseAdapter adapter = getAdapterByModelId(dto.getRagModelId());
|
||||
if (adapter != null) {
|
||||
DatasetDTO.UpdateReq updateReq = ConvertUtils.sourceToTarget(dto, DatasetDTO.UpdateReq.class);
|
||||
|
||||
// 1. 必填/核心字段前缀处理
|
||||
if (StringUtils.isNotBlank(dto.getName())) {
|
||||
updateReq.setName(SecurityUser.getUser().getUsername() + "_" + dto.getName());
|
||||
}
|
||||
|
||||
// 2. 解析器配置支持 (如果 DTO 里有字符串形式的配置,尝试转换,但优先建议 DTO 化)
|
||||
if (StringUtils.isNotBlank(dto.getParserConfig())) {
|
||||
try {
|
||||
DatasetDTO.ParserConfig parserConfig = JsonUtils.parseObject(dto.getParserConfig(),
|
||||
DatasetDTO.ParserConfig.class);
|
||||
updateReq.setParserConfig(parserConfig);
|
||||
} catch (Exception e) {
|
||||
log.warn("解析 parser_config 失败,跳过同步", e);
|
||||
}
|
||||
}
|
||||
|
||||
adapter.updateDataset(entity.getDatasetId(), updateReq);
|
||||
log.info("RAG更新成功: {}", entity.getDatasetId());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("RAG更新失败", e);
|
||||
// 恢复事务一致性:RAG失败则整体回滚
|
||||
if (e instanceof RenException) {
|
||||
throw (RenException) e;
|
||||
}
|
||||
throw new RenException(ErrorCode.RAG_API_ERROR, "RAG更新失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
BeanUtils.copyProperties(dto, entity);
|
||||
knowledgeBaseDao.updateById(entity);
|
||||
|
||||
// Clean cache
|
||||
redisUtils.delete(RedisKeys.getKnowledgeBaseCacheKey(entity.getId()));
|
||||
|
||||
return ConvertUtils.sourceToTarget(entity, KnowledgeBaseDTO.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据知识库ID集合查询知识库
|
||||
* @param datasetIdList 知识库ID集合
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public List<KnowledgeBaseDTO> getByDatasetIdList(List<String> datasetIdList) {
|
||||
//判断参数
|
||||
if (ToolUtil.isEmpty(datasetIdList)) {
|
||||
throw new RenException(ErrorCode.PARAMS_GET_ERROR);
|
||||
}
|
||||
//批量查询
|
||||
List<KnowledgeBaseEntity> entityList = knowledgeBaseDao.selectList(
|
||||
new QueryWrapper<KnowledgeBaseEntity>().in("dataset_id", datasetIdList));
|
||||
if (ToolUtil.isEmpty(entityList)) {
|
||||
throw new RenException(ErrorCode.Knowledge_Base_RECORD_NOT_EXISTS);
|
||||
}
|
||||
return ConvertUtils.sourceToTarget(entityList, KnowledgeBaseDTO.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteByDatasetId(String datasetId) {
|
||||
if (StringUtils.isBlank(datasetId)) {
|
||||
throw new RenException(ErrorCode.PARAMS_GET_ERROR);
|
||||
}
|
||||
|
||||
log.info("=== 开始通过datasetId删除操作 ===");
|
||||
log.info("删除datasetId: {}", datasetId);
|
||||
|
||||
KnowledgeBaseEntity entity = knowledgeBaseDao.selectOne(
|
||||
new QueryWrapper<KnowledgeBaseEntity>().eq("dataset_id", datasetId));
|
||||
KnowledgeBaseEntity entity = knowledgeBaseDao
|
||||
.selectOne(new QueryWrapper<KnowledgeBaseEntity>().eq("dataset_id", datasetId));
|
||||
|
||||
// 1. 恢复 404 校验:找不到记录抛异常
|
||||
if (entity == null) {
|
||||
log.warn("记录不存在,datasetId: {}", datasetId);
|
||||
throw new RenException(ErrorCode.Knowledge_Base_RECORD_NOT_EXISTS);
|
||||
}
|
||||
redisUtils.delete(RedisKeys.getKnowledgeBaseCacheKey(entity.getId()));
|
||||
|
||||
log.info("找到记录: ID={}, datasetId={}, ragModelId={}",
|
||||
entity.getId(), entity.getDatasetId(), entity.getRagModelId());
|
||||
|
||||
// 先调用RAG API删除数据集
|
||||
// 2. RAG Delete (Strict Mode)
|
||||
// 恢复严格一致性:RAG 删除失败则抛出异常,触发事务回滚,不允许已删除本地但保留远程的脏数据
|
||||
boolean apiDeleteSuccess = false;
|
||||
if (StringUtils.isNotBlank(entity.getDatasetId()) && StringUtils.isNotBlank(entity.getRagModelId())) {
|
||||
if (StringUtils.isNotBlank(entity.getRagModelId()) && StringUtils.isNotBlank(entity.getDatasetId())) {
|
||||
try {
|
||||
log.info("开始调用RAG API删除数据集");
|
||||
// 在删除前进行RAG配置校验
|
||||
Map<String, Object> ragConfig = getValidatedRAGConfig(entity.getRagModelId());
|
||||
deleteDatasetInRAG(entity.getDatasetId(), ragConfig);
|
||||
log.info("RAG API删除调用完成");
|
||||
KnowledgeBaseAdapter adapter = getAdapterByModelId(entity.getRagModelId());
|
||||
if (adapter != null) {
|
||||
adapter.deleteDataset(
|
||||
DatasetDTO.BatchIdReq.builder().ids(Collections.singletonList(datasetId)).build());
|
||||
}
|
||||
apiDeleteSuccess = true;
|
||||
} catch (Exception e) {
|
||||
// 提供更详细的错误信息,包括异常类型和消息
|
||||
String errorMessage = "删除RAG数据集失败: " + e.getClass().getSimpleName();
|
||||
if (e.getMessage() != null) {
|
||||
errorMessage += " - " + e.getMessage();
|
||||
log.error("RAG删除失败,触发回滚", e);
|
||||
if (e instanceof RenException) {
|
||||
throw (RenException) e;
|
||||
}
|
||||
log.error(errorMessage, e);
|
||||
throw e;
|
||||
throw new RenException(ErrorCode.RAG_API_ERROR, "RAG删除失败: " + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
log.warn("datasetId或ragModelId为空,跳过RAG删除");
|
||||
apiDeleteSuccess = true; // 没有RAG数据集,视为成功
|
||||
}
|
||||
|
||||
// API删除成功后再删除本地记录
|
||||
// 3. Local Delete (Safe Order)
|
||||
// 恢复正确顺序:先删子表 (Plugin Mapping),再删主表 (Entity)
|
||||
if (apiDeleteSuccess) {
|
||||
log.info("开始删除ai_agent_plugin_mapping表中与知识库ID '{}' 相关的映射记录", entity.getId());
|
||||
|
||||
// 先删除相关的插件映射记录
|
||||
log.info("开始删除关联数据, entityId: {}", entity.getId());
|
||||
knowledgeBaseDao.deletePluginMappingByKnowledgeBaseId(entity.getId());
|
||||
log.info("插件映射记录删除完成");
|
||||
|
||||
int deleteCount = knowledgeBaseDao.deleteById(entity.getId());
|
||||
log.info("本地数据库删除结果: {}", deleteCount > 0 ? "成功" : "失败");
|
||||
redisUtils.delete(RedisKeys.getKnowledgeBaseCacheKey(entity.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
log.info("=== 通过datasetId删除操作结束 ===");
|
||||
@Override
|
||||
public List<KnowledgeBaseDTO> getByDatasetIdList(List<String> datasetIdList) {
|
||||
if (datasetIdList == null || datasetIdList.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// [Production Fix] 批量兼容性查找
|
||||
QueryWrapper<KnowledgeBaseEntity> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.in("dataset_id", datasetIdList).or().in("id", datasetIdList);
|
||||
List<KnowledgeBaseEntity> list = knowledgeBaseDao.selectList(queryWrapper);
|
||||
return ConvertUtils.sourceToTarget(list, KnowledgeBaseDTO.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> 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<String, Object> config = modelConfig.getConfigJson();
|
||||
|
||||
// 验证必要的配置参数
|
||||
validateRagConfig(config);
|
||||
|
||||
// 返回配置信息
|
||||
return config;
|
||||
return getValidatedRAGConfig(ragModelId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getRAGConfigByDatasetId(String datasetId) {
|
||||
if (StringUtils.isBlank(datasetId)) {
|
||||
throw new RenException(ErrorCode.RAG_DATASET_ID_NOT_NULL);
|
||||
}
|
||||
|
||||
// 根据datasetId查询知识库信息
|
||||
KnowledgeBaseDTO knowledgeBase = getByDatasetId(datasetId);
|
||||
if (knowledgeBase == null) {
|
||||
log.warn("未找到datasetId为{}的知识库", datasetId);
|
||||
throw new RenException(ErrorCode.Knowledge_Base_RECORD_NOT_EXISTS);
|
||||
}
|
||||
|
||||
// 如果知识库指定了ragModelId,使用该配置
|
||||
String ragModelId = knowledgeBase.getRagModelId();
|
||||
if (StringUtils.isBlank(ragModelId)) {
|
||||
log.warn("知识库datasetId为{}未配置ragModelId", datasetId);
|
||||
KnowledgeBaseEntity entity = knowledgeBaseDao
|
||||
.selectOne(new QueryWrapper<KnowledgeBaseEntity>().eq("dataset_id", datasetId));
|
||||
if (entity == null || StringUtils.isBlank(entity.getRagModelId())) {
|
||||
throw new RenException(ErrorCode.RAG_CONFIG_NOT_FOUND);
|
||||
}
|
||||
return getRAGConfig(entity.getRagModelId());
|
||||
}
|
||||
|
||||
// 获取并返回RAG配置
|
||||
return getRAGConfig(ragModelId);
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateStatistics(String datasetId, Integer docDelta, Long chunkDelta, Long tokenDelta) {
|
||||
log.info("递增更新知识库统计: datasetId={}, docs={}, chunks={}, tokens={}", datasetId, docDelta, chunkDelta, tokenDelta);
|
||||
knowledgeBaseDao.updateStatsAfterChange(datasetId, docDelta, chunkDelta, tokenDelta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ModelConfigEntity> getRAGModels() {
|
||||
// 查询RAG类型的模型配置
|
||||
QueryWrapper<ModelConfigEntity> queryWrapper = new QueryWrapper<ModelConfigEntity>()
|
||||
.select("id", "model_name")
|
||||
return modelConfigDao.selectList(new QueryWrapper<ModelConfigEntity>()
|
||||
.select("id", "model_name", "config_json") // Explicitly select needed fields
|
||||
.eq("model_type", Constant.RAG_CONFIG_TYPE)
|
||||
.eq("is_enabled", 1)
|
||||
.orderByDesc("is_default")
|
||||
.orderByDesc("create_date");
|
||||
|
||||
List<ModelConfigEntity> modelConfigs = modelConfigDao.selectList(queryWrapper);
|
||||
return modelConfigs;
|
||||
.orderByDesc("create_date"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证RAG配置中是否包含必要的参数
|
||||
*/
|
||||
private void validateRagConfig(Map<String, Object> config) {
|
||||
if (config == null) {
|
||||
// --- Helpers ---
|
||||
|
||||
private void checkDuplicateName(String name, String excludeId) {
|
||||
if (StringUtils.isBlank(name))
|
||||
return;
|
||||
QueryWrapper<KnowledgeBaseEntity> qw = new QueryWrapper<>();
|
||||
qw.eq("name", name).eq("creator", SecurityUser.getUserId());
|
||||
if (excludeId != null)
|
||||
qw.ne("id", excludeId);
|
||||
if (knowledgeBaseDao.selectCount(qw) > 0) {
|
||||
throw new RenException(ErrorCode.KNOWLEDGE_BASE_NAME_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
private KnowledgeBaseAdapter getAdapterByModelId(String modelId) {
|
||||
Map<String, Object> config = getValidatedRAGConfig(modelId);
|
||||
return KnowledgeBaseAdapterFactory.getAdapter((String) config.get("type"), config);
|
||||
}
|
||||
|
||||
private Map<String, Object> getValidatedRAGConfig(String modelId) {
|
||||
ModelConfigEntity configEntity = modelConfigService.getModelByIdFromCache(modelId);
|
||||
if (configEntity == null || configEntity.getConfigJson() == 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_API_ERROR_URL_NULL);
|
||||
}
|
||||
|
||||
// 验证api_key是否存在且非空
|
||||
if (StringUtils.isBlank(apiKey)) {
|
||||
throw new RenException(ErrorCode.RAG_API_ERROR_API_KEY_NULL);
|
||||
}
|
||||
|
||||
// 检查api_key是否包含占位符
|
||||
if (apiKey.contains("你")) {
|
||||
throw new RenException(ErrorCode.RAG_API_ERROR_API_KEY_INVALID);
|
||||
}
|
||||
|
||||
// 验证base_url格式
|
||||
if (!baseUrl.startsWith("http://") && !baseUrl.startsWith("https://")) {
|
||||
throw new RenException(ErrorCode.RAG_API_ERROR_URL_INVALID);
|
||||
Map<String, Object> config = new HashMap<>(configEntity.getConfigJson());
|
||||
if (!config.containsKey("type")) {
|
||||
config.put("type", "ragflow");
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从RAG配置中提取适配器类型
|
||||
*
|
||||
* @param config RAG配置
|
||||
* @return 适配器类型
|
||||
*/
|
||||
private String extractAdapterType(Map<String, Object> config) {
|
||||
if (config == null) {
|
||||
throw new RenException(ErrorCode.RAG_CONFIG_NOT_FOUND);
|
||||
}
|
||||
|
||||
// 从配置中提取适配器类型
|
||||
String adapterType = (String) config.get("type");
|
||||
|
||||
// 验证适配器类型是否存在且非空
|
||||
if (StringUtils.isBlank(adapterType)) {
|
||||
throw new RenException(ErrorCode.RAG_ADAPTER_TYPE_NOT_FOUND);
|
||||
}
|
||||
|
||||
// 验证适配器类型是否已注册
|
||||
if (!KnowledgeBaseAdapterFactory.isAdapterTypeRegistered(adapterType)) {
|
||||
throw new RenException(ErrorCode.RAG_ADAPTER_TYPE_NOT_SUPPORTED,
|
||||
"不支持的适配器类型: " + adapterType);
|
||||
}
|
||||
|
||||
return adapterType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用适配器创建数据集
|
||||
*/
|
||||
private String createDatasetInRAG(String name, String description, Map<String, Object> ragConfig) {
|
||||
log.info("开始使用适配器创建数据集, name: {}", name);
|
||||
|
||||
try {
|
||||
// 从RAG配置中提取适配器类型
|
||||
String adapterType = extractAdapterType(ragConfig);
|
||||
|
||||
// 使用适配器工厂获取适配器实例
|
||||
KnowledgeBaseAdapter adapter = KnowledgeBaseAdapterFactory.getAdapter(adapterType, ragConfig);
|
||||
|
||||
// 构建数据集创建参数
|
||||
Map<String, Object> createParams = new HashMap<>();
|
||||
String username = SecurityUser.getUser().getUsername();
|
||||
createParams.put("name", username + "_" + name);
|
||||
if (StringUtils.isNotBlank(description)) {
|
||||
createParams.put("description", description);
|
||||
}
|
||||
|
||||
// 调用适配器的创建数据集方法
|
||||
String datasetId = adapter.createDataset(createParams);
|
||||
|
||||
log.info("数据集创建成功,datasetId: {}", datasetId);
|
||||
return datasetId;
|
||||
|
||||
} catch (Exception e) {
|
||||
// 直接传递底层适配器的详细错误信息
|
||||
log.error("创建数据集失败", e);
|
||||
if (e instanceof RenException) {
|
||||
throw (RenException) e;
|
||||
}
|
||||
throw new RenException(ErrorCode.RAG_API_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用适配器更新数据集
|
||||
*/
|
||||
private void updateDatasetInRAG(String datasetId, String name, String description,
|
||||
Map<String, Object> ragConfig) {
|
||||
log.info("开始使用适配器更新数据集,datasetId: {}, name: {}", datasetId, name);
|
||||
|
||||
try {
|
||||
// 从RAG配置中提取适配器类型
|
||||
String adapterType = extractAdapterType(ragConfig);
|
||||
|
||||
// 使用适配器工厂获取适配器实例
|
||||
KnowledgeBaseAdapter adapter = KnowledgeBaseAdapterFactory.getAdapter(adapterType, ragConfig);
|
||||
|
||||
// 构建数据集更新参数
|
||||
Map<String, Object> updateParams = new HashMap<>();
|
||||
String username = SecurityUser.getUser().getUsername();
|
||||
updateParams.put("name", username + "_" + name);
|
||||
if (StringUtils.isNotBlank(description)) {
|
||||
updateParams.put("description", description);
|
||||
}
|
||||
|
||||
// 调用适配器的更新数据集方法
|
||||
adapter.updateDataset(datasetId, updateParams);
|
||||
|
||||
log.info("数据集更新成功,datasetId: {}", datasetId);
|
||||
|
||||
} catch (Exception e) {
|
||||
// 直接传递底层适配器的详细错误信息
|
||||
log.error("更新数据集失败", e);
|
||||
if (e instanceof RenException) {
|
||||
throw (RenException) e;
|
||||
}
|
||||
throw new RenException(ErrorCode.RAG_API_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用适配器删除数据集
|
||||
*/
|
||||
private void deleteDatasetInRAG(String datasetId, Map<String, Object> ragConfig) {
|
||||
log.info("开始使用适配器删除数据集,datasetId: {}", datasetId);
|
||||
|
||||
try {
|
||||
// 从RAG配置中提取适配器类型
|
||||
String adapterType = extractAdapterType(ragConfig);
|
||||
|
||||
// 使用适配器工厂获取适配器实例
|
||||
KnowledgeBaseAdapter adapter = KnowledgeBaseAdapterFactory.getAdapter(adapterType, ragConfig);
|
||||
|
||||
// 调用适配器的删除数据集方法
|
||||
adapter.deleteDataset(datasetId);
|
||||
|
||||
log.info("数据集删除成功,datasetId: {}", datasetId);
|
||||
|
||||
} catch (Exception e) {
|
||||
// 直接传递底层适配器的详细错误信息
|
||||
log.error("删除数据集失败", e);
|
||||
if (e instanceof RenException) {
|
||||
throw (RenException) e;
|
||||
}
|
||||
throw new RenException(ErrorCode.RAG_API_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取RAG配置并验证
|
||||
*/
|
||||
private Map<String, Object> getValidatedRAGConfig(String ragModelId) {
|
||||
if (StringUtils.isBlank(ragModelId)) {
|
||||
throw new RenException(ErrorCode.RAG_MODEL_ID_NOT_NULL);
|
||||
}
|
||||
|
||||
Map<String, Object> ragConfig = getRAGConfig(ragModelId);
|
||||
|
||||
// 验证RAG配置参数
|
||||
validateRagConfig(ragConfig);
|
||||
|
||||
return ragConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否存在同名知识库
|
||||
*
|
||||
* @param knowledgeBaseDTO 知识库DTO
|
||||
* @param excludeId 排除的ID(更新时使用)
|
||||
*/
|
||||
private void checkDuplicateKnowledgeBaseName(KnowledgeBaseDTO knowledgeBaseDTO, String excludeId) {
|
||||
if (StringUtils.isNotBlank(knowledgeBaseDTO.getName())) {
|
||||
Long currentUserId = SecurityUser.getUserId();
|
||||
QueryWrapper<KnowledgeBaseEntity> queryWrapper = new QueryWrapper<KnowledgeBaseEntity>()
|
||||
.eq("name", knowledgeBaseDTO.getName())
|
||||
.eq("creator", currentUserId);
|
||||
|
||||
// 如果提供了排除ID,则排除该记录
|
||||
if (StringUtils.isNotBlank(excludeId)) {
|
||||
queryWrapper.ne("id", excludeId);
|
||||
}
|
||||
|
||||
long count = knowledgeBaseDao.selectCount(queryWrapper);
|
||||
if (count > 0) {
|
||||
throw new RenException(ErrorCode.KNOWLEDGE_BASE_NAME_EXISTS,
|
||||
MessageUtils.getMessage(ErrorCode.KNOWLEDGE_BASE_NAME_EXISTS));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从适配器获取知识库的文档数量
|
||||
*/
|
||||
private Integer getDocumentCountFromRAG(String datasetId, String ragModelId) {
|
||||
if (StringUtils.isBlank(datasetId) || StringUtils.isBlank(ragModelId)) {
|
||||
log.warn("datasetId或ragModelId为空,无法获取文档数量");
|
||||
return 0;
|
||||
}
|
||||
|
||||
log.info("开始获取知识库 {} 的文档数量", datasetId);
|
||||
|
||||
try {
|
||||
// 获取RAG配置
|
||||
Map<String, Object> ragConfig = getValidatedRAGConfig(ragModelId);
|
||||
|
||||
// 从RAG配置中提取适配器类型
|
||||
String adapterType = extractAdapterType(ragConfig);
|
||||
|
||||
// 使用适配器工厂获取适配器实例
|
||||
KnowledgeBaseAdapter adapter = KnowledgeBaseAdapterFactory.getAdapter(adapterType, ragConfig);
|
||||
|
||||
// 调用适配器的获取文档数量方法
|
||||
Integer documentCount = adapter.getDocumentCount(datasetId);
|
||||
|
||||
log.info("获取知识库 {} 的文档数量成功: {}", datasetId, documentCount);
|
||||
return documentCount;
|
||||
|
||||
} catch (Exception e) {
|
||||
// 构建详细的错误信息,包含异常类型和消息
|
||||
String baseErrorMessage = e.getClass().getSimpleName() + " - 获取知识库文档数量失败";
|
||||
String errorMessage = baseErrorMessage + (e.getMessage() != null ? ": " + e.getMessage() : "");
|
||||
log.error(errorMessage, e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+522
-1023
File diff suppressed because it is too large
Load Diff
+47
@@ -0,0 +1,47 @@
|
||||
package xiaozhi.modules.knowledge.service.impl;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import xiaozhi.modules.knowledge.service.KnowledgeBaseService;
|
||||
import xiaozhi.modules.knowledge.service.KnowledgeFilesService;
|
||||
import xiaozhi.modules.knowledge.service.KnowledgeManagerService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class KnowledgeManagerServiceImpl implements KnowledgeManagerService {
|
||||
|
||||
private final KnowledgeBaseService knowledgeBaseService;
|
||||
private final KnowledgeFilesService knowledgeFilesService;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteDatasetWithFiles(String datasetId) {
|
||||
log.info("=== 级联删除开始: datasetId={} ===", datasetId);
|
||||
|
||||
// 1. 先调用文件服务,清理该数据集下的所有文档记录 (含 RAGFlow 端)
|
||||
log.info("Step 1: 清理关联文档...");
|
||||
knowledgeFilesService.deleteDocumentsByDatasetId(datasetId);
|
||||
|
||||
// 2. 再调用知识库服务,彻底注销数据集 (含 RAGFlow 端)
|
||||
log.info("Step 2: 删除数据集主体...");
|
||||
knowledgeBaseService.deleteByDatasetId(datasetId);
|
||||
|
||||
log.info("=== 级联删除成功: datasetId={} ===", datasetId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void batchDeleteDatasetsWithFiles(List<String> datasetIds) {
|
||||
if (datasetIds == null || datasetIds.isEmpty())
|
||||
return;
|
||||
log.info("=== 批量级联删除开始: count={} ===", datasetIds.size());
|
||||
for (String id : datasetIds) {
|
||||
deleteDatasetWithFiles(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package xiaozhi.modules.knowledge.task;
|
||||
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import xiaozhi.modules.knowledge.service.KnowledgeFilesService;
|
||||
|
||||
/**
|
||||
* 知识库文档状态同步定时任务
|
||||
*
|
||||
* 作用:
|
||||
* 1. 自动扫描处于 "RUNNING" (解析中) 状态的文档
|
||||
* 2. 调用 RAGFlow 接口获取最新状态
|
||||
* 3. 状态翻转 (RUNNING -> SUCCESS/FAIL) 时,同步更新数据库
|
||||
* 4. [关键] 解析成功时,补偿更新知识库的统计信息 (TokenCount)
|
||||
*/
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
@Slf4j
|
||||
public class DocumentStatusSyncTask {
|
||||
|
||||
private final KnowledgeFilesService knowledgeFilesService;
|
||||
|
||||
/**
|
||||
* 每 30 秒执行一次同步
|
||||
* 采用 fixedDelay,确保上一次执行完 30 秒后才开始下一次,防止积压
|
||||
*/
|
||||
@Scheduled(fixedDelay = 30000)
|
||||
public void syncRunningDocuments() {
|
||||
try {
|
||||
// log.debug("开始执行文档状态同步任务...");
|
||||
knowledgeFilesService.syncRunningDocuments();
|
||||
} catch (Exception e) {
|
||||
log.error("文档状态同步任务异常", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -56,7 +56,7 @@ public class SysUserServiceImpl extends BaseServiceImpl<SysUserDao, SysUserEntit
|
||||
if (users == null || users.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
SysUserEntity entity = users.getFirst();
|
||||
SysUserEntity entity = users.get(0);
|
||||
return ConvertUtils.sourceToTarget(entity, SysUserDTO.class);
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ public class SysUserServiceImpl extends BaseServiceImpl<SysUserDao, SysUserEntit
|
||||
*/
|
||||
private String generatePassword() {
|
||||
StringBuilder password = new StringBuilder();
|
||||
|
||||
|
||||
// 确保包含至少一个数字
|
||||
password.append("0123456789".charAt(random.nextInt(10)));
|
||||
// 确保包含至少一个小写字母
|
||||
@@ -206,12 +206,12 @@ public class SysUserServiceImpl extends BaseServiceImpl<SysUserDao, SysUserEntit
|
||||
password.append("ABCDEFGHIJKLMNOPQRSTUVWXYZ".charAt(random.nextInt(26)));
|
||||
// 确保包含至少一个特殊符号
|
||||
password.append("!@#$%^&*()".charAt(random.nextInt(10)));
|
||||
|
||||
|
||||
// 生成剩余的8个字符
|
||||
for (int i = 4; i < 12; i++) {
|
||||
password.append(CHARACTERS.charAt(random.nextInt(CHARACTERS.length())));
|
||||
}
|
||||
|
||||
|
||||
// 打乱密码中字符的顺序
|
||||
char[] passwordChars = password.toString().toCharArray();
|
||||
for (int i = 0; i < passwordChars.length; i++) {
|
||||
@@ -220,7 +220,7 @@ public class SysUserServiceImpl extends BaseServiceImpl<SysUserDao, SysUserEntit
|
||||
passwordChars[i] = passwordChars[randomIndex];
|
||||
passwordChars[randomIndex] = temp;
|
||||
}
|
||||
|
||||
|
||||
return new String(passwordChars);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
-- 增加一下ragflow返回的参数(创建/查询知识库时返回)
|
||||
SET @col_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'ai_rag_dataset' AND COLUMN_NAME = 'tenant_id');
|
||||
SET @sql = IF(@col_exists = 0, 'ALTER TABLE `ai_rag_dataset` ADD COLUMN `tenant_id` varchar(32) DEFAULT NULL COMMENT ''租户ID''', 'SELECT ''Column tenant_id already exists'' AS msg');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @col_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'ai_rag_dataset' AND COLUMN_NAME = 'avatar');
|
||||
SET @sql = IF(@col_exists = 0, 'ALTER TABLE `ai_rag_dataset` ADD COLUMN `avatar` text DEFAULT NULL COMMENT ''知识库头像 (Base64)''', 'SELECT ''Column avatar already exists'' AS msg');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @col_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'ai_rag_dataset' AND COLUMN_NAME = 'embedding_model');
|
||||
SET @sql = IF(@col_exists = 0, 'ALTER TABLE `ai_rag_dataset` ADD COLUMN `embedding_model` varchar(50) DEFAULT NULL COMMENT ''嵌入模型名称''', 'SELECT ''Column embedding_model already exists'' AS msg');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @col_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'ai_rag_dataset' AND COLUMN_NAME = 'permission');
|
||||
SET @sql = IF(@col_exists = 0, 'ALTER TABLE `ai_rag_dataset` ADD COLUMN `permission` varchar(20) DEFAULT ''me'' COMMENT ''权限设置:me/team''', 'SELECT ''Column permission already exists'' AS msg');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @col_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'ai_rag_dataset' AND COLUMN_NAME = 'chunk_method');
|
||||
SET @sql = IF(@col_exists = 0, 'ALTER TABLE `ai_rag_dataset` ADD COLUMN `chunk_method` varchar(50) DEFAULT NULL COMMENT ''分块方法''', 'SELECT ''Column chunk_method already exists'' AS msg');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @col_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'ai_rag_dataset' AND COLUMN_NAME = 'parser_config');
|
||||
SET @sql = IF(@col_exists = 0, 'ALTER TABLE `ai_rag_dataset` ADD COLUMN `parser_config` text DEFAULT NULL COMMENT ''解析器配置 (JSON)''', 'SELECT ''Column parser_config already exists'' AS msg');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @col_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'ai_rag_dataset' AND COLUMN_NAME = 'chunk_count');
|
||||
SET @sql = IF(@col_exists = 0, 'ALTER TABLE `ai_rag_dataset` ADD COLUMN `chunk_count` bigint(20) DEFAULT 0 COMMENT ''分块总数''', 'SELECT ''Column chunk_count already exists'' AS msg');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @col_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'ai_rag_dataset' AND COLUMN_NAME = 'document_count');
|
||||
SET @sql = IF(@col_exists = 0, 'ALTER TABLE `ai_rag_dataset` ADD COLUMN `document_count` bigint(20) DEFAULT 0 COMMENT ''文档总数''', 'SELECT ''Column document_count already exists'' AS msg');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @col_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'ai_rag_dataset' AND COLUMN_NAME = 'token_num');
|
||||
SET @sql = IF(@col_exists = 0, 'ALTER TABLE `ai_rag_dataset` ADD COLUMN `token_num` bigint(20) DEFAULT 0 COMMENT ''总 Token 数''', 'SELECT ''Column token_num already exists'' AS msg');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- 文档表 (Shadow DB for RAGFlow)
|
||||
-- 留存一份文档id,把ragflow远端文档id和本地id关联起来(只是备份一份元信息链接,实际上文件内容的存储还是在ragflow)
|
||||
DROP TABLE IF EXISTS `ai_rag_knowledge_document`;
|
||||
CREATE TABLE `ai_rag_knowledge_document` (
|
||||
`id` varchar(36) NOT NULL COMMENT '本地唯一ID',
|
||||
`dataset_id` varchar(36) NOT NULL COMMENT '知识库ID (关联 ai_rag_dataset)',
|
||||
`document_id` varchar(64) NOT NULL COMMENT 'RAGFlow文档ID (远程ID)',
|
||||
`name` varchar(255) DEFAULT NULL COMMENT '文档名称',
|
||||
`size` bigint(20) DEFAULT NULL COMMENT '文件大小(Bytes)',
|
||||
`type` varchar(20) DEFAULT NULL COMMENT '文件类型',
|
||||
`chunk_method` varchar(50) DEFAULT NULL COMMENT '分块方法',
|
||||
`parser_config` text COMMENT '解析配置(JSON)',
|
||||
`status` varchar(10) DEFAULT '1' COMMENT '可用状态 (1:启用 0:禁用)',
|
||||
`run` varchar(32) DEFAULT 'UNSTART' COMMENT '运行状态 (UNSTART/RUNNING/CANCEL/DONE/FAIL)',
|
||||
`progress` double DEFAULT '0' COMMENT '解析进度 (0.0 ~ 1.0)',
|
||||
`thumbnail` mediumtext COMMENT '缩略图 (Base64 或 URL)',
|
||||
`process_duration` double DEFAULT '0' COMMENT '解析耗时 (单位: 秒)',
|
||||
`meta_fields` text COMMENT '自定义元数据 (JSON)',
|
||||
`source_type` varchar(32) DEFAULT 'local' COMMENT '来源类型 (local, s3, url 等)',
|
||||
`error` text COMMENT '错误信息',
|
||||
`chunk_count` int(11) DEFAULT '0' COMMENT '分块数量',
|
||||
`token_count` bigint(20) DEFAULT '0' COMMENT 'Token数量',
|
||||
`enabled` tinyint(1) DEFAULT '1' COMMENT '启用状态',
|
||||
`creator` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||
`created_at` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`updated_at` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`last_sync_at` datetime DEFAULT NULL COMMENT '最后同步时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_doc_id` (`document_id`),
|
||||
KEY `idx_dataset_id` (`dataset_id`),
|
||||
KEY `idx_status` (`status`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='知识库文档表';
|
||||
@@ -557,4 +557,11 @@ databaseChangeLog:
|
||||
- sqlFile:
|
||||
encoding: utf8
|
||||
path: classpath:db/changelog/202603091051.sql
|
||||
- changeSet:
|
||||
id: 202603111131
|
||||
author: DaGou12138
|
||||
changes:
|
||||
- sqlFile:
|
||||
encoding: utf8
|
||||
path: classpath:db/changelog/202603111131.sql
|
||||
|
||||
|
||||
@@ -204,4 +204,6 @@
|
||||
10195=OTA\u4E0A\u4F20\u6B21\u6570\u8D85\u8FC7\u9650\u5236
|
||||
10196=\u6807\u7B7E\u540D\u79F0\u5DF2\u5B58\u5728
|
||||
10197=\u6807\u7B7E\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
|
||||
10198=\u6807\u7B7E\u4E0D\u5B58\u5728
|
||||
10198=\u6807\u7B7E\u4E0D\u5B58\u5728
|
||||
10199=\u89E3\u6790\u4E2D\u6587\u4EF6\u6682\u4E0D\u652F\u6301\u6B64\u64CD\u4F5C
|
||||
|
||||
|
||||
@@ -204,4 +204,6 @@
|
||||
10195=OTA-Upload-Anzahl \u00FCberschreitet das Limit
|
||||
10196=Tag-Name existiert bereits
|
||||
10197=Tag-Name darf nicht leer sein
|
||||
10198=Tag nicht gefunden
|
||||
10198=Tag nicht gefunden
|
||||
10199=Dateianalyse l\u00E4uft, dieser Vorgang wird nicht unterst\u00FCtzt
|
||||
|
||||
|
||||
@@ -204,4 +204,6 @@
|
||||
10195=OTA upload times exceed the limit
|
||||
10196=Tag name already exists
|
||||
10197=Tag name cannot be empty
|
||||
10198=Tag not found
|
||||
10198=Tag not found
|
||||
10199=Parsing in progress, this operation is not supported
|
||||
|
||||
|
||||
@@ -202,6 +202,8 @@
|
||||
10193=ID thi\u1EBFt b\u1ECB kh\u00F4ng th\u1EC3 tr\u1ED1ng
|
||||
10194=Kh\u00F4ng t\u00ECm th\u1EA5y thi\u1EBFt b\u1ECB ho\u1EB7c thi\u1EBFt b\u1ECB kh\u00F4ng tr\u1EF1c tuy\u1EBFn
|
||||
10195=S\u1ED1 l\u1EA7n t\u1EA3i l\u00EAn OTA v\u01B0\u1EE3t qu\u00E1 gi\u1EDBi h\u1EA1n
|
||||
10196=T\u00EAn th\u1EB9� \u0111\u00E3 t\u1ED3n t\u1EA1i
|
||||
10197=T\u00EAn th\u1EB9� kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng
|
||||
10198=Kh\u00F4ng t\u00ECm th\u1EA5y th\u1EB9�
|
||||
10196=T\u00EAn th\u1EB9\uFFFD \u0111\u00E3 t\u1ED3n t\u1EA1i
|
||||
10197=T\u00EAn th\u1EB9\uFFFD kh\u00F4ng th\u1EC3 \u0111\u1EC3 tr\u1ED1ng
|
||||
10198=Kh\u00F4ng t\u00ECm th\u1EA5y th\u1EB9\uFFFD
|
||||
10199=T\u1EC7p \u0111ang \u0111\u01B0\u1EE3c ph\u00E2n t\u00EDch, thao t\u00E1c n\u00E0y kh\u00F4ng \u0111\u01B0\u1EE3c h\u1ED7 tr\u1EE3
|
||||
|
||||
|
||||
@@ -201,4 +201,5 @@
|
||||
10192=\u9002\u914D\u5668\u7C7B\u578B\u672A\u627E\u5230
|
||||
10193=\u8BBE\u5907ID\u4E0D\u80FD\u4E3A\u7A7A
|
||||
10194=\u8BBE\u5907\u4E0D\u5B58\u5728\u6216\u4E0D\u5728\u7EBF
|
||||
10195=OTA\u4E0A\u4F20\u6B21\u6570\u8D85\u8FC7\u9650\u5236
|
||||
10195=OTA\u4E0A\u4F20\u6B21\u6570\u8D85\u8FC7\u9650\u5236
|
||||
10196=\u89E3\u6790\u4E2D\u6587\u4EF6\u6682\u4E0D\u652F\u6301\u6B64\u64CD\u4F5C
|
||||
|
||||
@@ -204,4 +204,6 @@
|
||||
10195=OTA\u4E0A\u4F20\u6B21\u6578\u8D85\u904E\u9650\u5236
|
||||
10196=\u6A19\u7C64\u540D\u7A31\u5DF2\u5B58\u5728
|
||||
10197=\u6A19\u7C64\u540D\u7A31\u4E0D\u80FD\u4E3A\u7A7A
|
||||
10198=\u6A19\u7C64\u4E0D\u5B58\u5728
|
||||
10198=\u6A19\u7C64\u4E0D\u5B58\u5728
|
||||
10199=\u89E3\u6790\u4E2D\u6587\u4EF6\u66AB\u4E0D\u652F\u6301\u6B64\u64CD\u4F5C
|
||||
|
||||
|
||||
@@ -23,4 +23,14 @@
|
||||
WHERE plugin_id = #{knowledgeBaseId}
|
||||
</delete>
|
||||
|
||||
<!-- 通用维度原子更新知识库统计信息 -->
|
||||
<update id="updateStatsAfterChange">
|
||||
UPDATE ai_rag_dataset
|
||||
SET document_count = document_count + #{docDelta},
|
||||
chunk_count = chunk_count + #{chunkDelta},
|
||||
token_num = token_num + #{tokenDelta},
|
||||
updated_at = NOW()
|
||||
WHERE dataset_id = #{datasetId}
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,162 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Privacy Policy - XiaoZhi Backend Service</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
|
||||
line-height: 1.8;
|
||||
color: #333;
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
padding: 20px 30px;
|
||||
background: #f9f9fb;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
font-size: 24px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 18px;
|
||||
margin-top: 30px;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 8px 0;
|
||||
text-indent: 2em;
|
||||
}
|
||||
|
||||
.update-date {
|
||||
text-align: center;
|
||||
color: #888;
|
||||
font-size: 14px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<h1>Privacy Policy</h1>
|
||||
<div class="update-date">Last Updated: March 10, 2026</div>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
<p>Welcome to use the XiaoZhi Backend Service (hereinafter referred to as "the Service"). The operator of this Service is the actual deployer and administrator of the Service (hereinafter referred to as "Operator" or "we"). We fully understand the importance of your personal information and will do our best to protect your personal information security.
|
||||
</p>
|
||||
<p class="bold">Please carefully read and fully understand all contents of this Privacy Policy before using the Service. Once you start using the Service, it signifies that you have read and agreed to this Privacy Policy.</p>
|
||||
<p>This Privacy Policy applies to our collection, storage, use, sharing, and protection of your personal information when you use the Service through the Admin Console (management backend), API interfaces, and other means.</p>
|
||||
|
||||
<h2>I. Information We Collect</h2>
|
||||
<p>To provide services to you, we may need to collect the following information:</p>
|
||||
<p><span class="bold">1.1 Account Registration Information:</span> When you register an account, we collect your phone number or username, password, and other information to create and verify your account.</p>
|
||||
<p><span class="bold">1.2 Device Information:</span> When you bind hardware devices, we collect device identification information (such as device code, MAC address), device model, firmware version, etc., for device management and service provision.</p>
|
||||
<p><span class="bold">1.3 Agent Configuration Information:</span> When you create and configure Agents, we collect role templates, language model selections, voice parameter configurations, etc., to provide personalized AI interaction services.</p>
|
||||
<p><span class="bold">1.4 Voice Interaction Data:</span> When you use the voice interaction function, the Service uses Voice Activity Detection (VAD) to determine the start and end of your voice, processes your voice input data, and transmits it to third-party Automatic Speech Recognition (ASR) and Large Language Model (LLM) services for processing to achieve voice interaction capabilities.</p>
|
||||
<p><span class="bold">1.5 Image Data:</span> When you use the vision model function, we may process image data captured through the device camera and transmit it to third-party vision model services for analysis and understanding to achieve image recognition, scene understanding, and other functions.</p>
|
||||
<p><span class="bold">1.6 Conversation Memory Data:</span> When you enable the memory function, the Service stores summaries of your interaction history with the Agent to provide more coherent and personalized interaction experiences in subsequent conversations.</p>
|
||||
<p><span class="bold">1.7 Knowledge Base Data:</span> When you use the knowledge base function, we collect and store documents, texts, and other knowledge base content you upload for Agents to perform knowledge retrieval and Q&A during conversations.</p>
|
||||
<p><span class="bold">1.8 Voice Print Data:</span> When you use the voice print recognition function, we collect and store your voice print characteristic samples for speaker identity verification and personalized services.</p>
|
||||
<p><span class="bold">1.9 Chat History Data:</span> We store conversation history records between you and the Agents, including text conversation content, conversation time, interaction context, etc., to provide continuous conversation experience and history query functions.</p>
|
||||
<p><span class="bold">1.10 Conversation Audio Data:</span> When you use the voice interaction function, we may store audio data of your interactions with the Agents to improve voice interaction quality and enable retrieval queries.</p>
|
||||
<p><span class="bold">1.11 Agent Configuration Data:</span> When you configure Agents, we collect tags, plugin configurations, context provider settings, etc., to provide Agent customization services.</p>
|
||||
<p><span class="bold">1.12 Device Firmware Data:</span> When you use the OTA upgrade function, we record device firmware version, upgrade history, etc., for device management and firmware traceability.</p>
|
||||
<p><span class="bold">1.13 Log Information:</span> When you use the Service, we automatically collect service log information, including but not limited to access time, IP address, browser type, operation records, etc., for service operation and security assurance.</p>
|
||||
<p><span class="bold">1.14 Verification Code Information:</span> When you use phone number login, we send verification codes via SMS service for identity verification.</p>
|
||||
|
||||
<h2>II. How We Use the Collected Information</h2>
|
||||
<p>The information we collect will be used for the following purposes:</p>
|
||||
<p>(1) Providing, maintaining, and improving the Service, including core functions such as account management, device management, and Agent configuration.</p>
|
||||
<p>(2) Processing your voice interaction requests, using Voice Activity Detection (VAD) to identify voice input, calling third-party AI model services to complete speech recognition, intent recognition, semantic understanding, and speech synthesis.</p>
|
||||
<p>(3) Processing your image data, calling third-party vision model services to complete image recognition and scene understanding.</p>
|
||||
<p>(4) Storing and managing your conversation memory data to provide more coherent service experiences in subsequent interactions.</p>
|
||||
<p>(5) Storing and retrieving knowledge base content you upload so that Agents can provide more accurate knowledge Q&A during conversations.</p>
|
||||
<p>(6) Ensuring service security and stability, including identity verification, security protection, troubleshooting, etc.</p>
|
||||
<p>(7) Complying with applicable laws, regulations, and regulatory requirements.</p>
|
||||
<p class="bold">We will not use your personal information for purposes unrelated to the above. If we need to use information for other purposes not stated in this Privacy Policy, we will obtain your consent in advance.</p>
|
||||
|
||||
<h2>III. Sharing and Disclosure of Information</h2>
|
||||
<p class="bold">We will not sell your personal information to third parties. Only in the following circumstances may we share or disclose your information:</p>
|
||||
<p><span class="bold">3.1 Third-party Service Calls:</span> To achieve voice interaction, visual understanding, and other functions, your voice data, image data, and text content may be transmitted to third-party AI service providers (such as language model, speech recognition, speech synthesis, vision model service providers) for processing. We will select service providers with reasonable security capabilities, but please note that third-party service providers will process related data according to their own privacy policies.</p>
|
||||
<p><span class="bold">3.2 Legal Requirements:</span> According to applicable laws, regulations, legal procedures, or requirements from government authorities, we may need to disclose your personal information.</p>
|
||||
<p><span class="bold">3.3 Security Assurance:</span> To protect the rights, property, or safety of the Operator, other users, or the public from damage, we may use or disclose personal information within a reasonably necessary scope.</p>
|
||||
<p><span class="bold">3.4 With Consent:</span> We may share your personal information with third parties if we obtain your explicit consent.</p>
|
||||
|
||||
<h2>IV. Storage and Protection of Information</h2>
|
||||
<p><span class="bold">4.1 Storage Location:</span> Your personal information will be stored on the server where the Operator deploys the Service, including but not limited to databases (MySQL/PostgreSQL) and cache services (Redis).</p>
|
||||
<p><span class="bold">4.2 Storage Period:</span> We will retain your personal information for the period necessary to provide you with services. After you cancel your account, we will delete or anonymize your personal information within a reasonable time, unless otherwise stipulated by laws and regulations.</p>
|
||||
<p><span class="bold">4.3 Security Measures:</span> We take reasonable technical and management measures to protect the security of your personal information, including but not limited to data encryption, access control, security auditing, etc. However, please understand that the Internet is not an absolutely secure environment, and we cannot guarantee the absolute security of information transmission and storage.</p>
|
||||
<p class="bold">4.4 Security Incident Handling: If a personal information security incident occurs, we will promptly inform you of the basic situation of the security incident, possible impacts, and measures taken or to be taken, in accordance with legal requirements.</p>
|
||||
<p class="bold">4.5 Special Note for Open-source Projects: The Service is an open-source project with two operation modes:</p>
|
||||
<p>(1) <span class="bold">Self-deployment:</span> If you self-deploy the Service, the Operator is only the code provider, and actual data storage and processing are your responsibility. In this case, you are both the user of the Service and the data manager and protector.</p>
|
||||
<p>(2) <span class="bold">Test Platform:</span> If you use the test platform deployed by the Operator, your data will be managed and protected by the Operator. The test platform is only for experience and testing purposes. We may regularly clear data. Please do not upload sensitive personal information.</p>
|
||||
<p class="bold">If you use services deployed by others, please note that your data is managed and protected by that deployer.</p>
|
||||
<p class="bold">4.6 Cross-border Data Transfer: When providing intelligent interaction functions, the Service may need to call interfaces from third-party AI service providers outside mainland China. In this process, your voice data, text data, image data, etc., may be transmitted to servers outside the People's Republic of China for processing. The involved overseas service providers include but are not limited to:</p>
|
||||
<p>(1) OpenAI: Provides speech recognition (Whisper), speech synthesis (TTS), large language models (GPT), and other services.</p>
|
||||
<p>(2) Anthropic: Provides large language model (Claude) services.</p>
|
||||
<p>(3) Groq: Provides speech recognition (Whisper) services.</p>
|
||||
<p>(4) Microsoft EdgeTTS: Provides speech synthesis services.</p>
|
||||
<p>We will take necessary measures to ensure the security of your personal information during cross-border transmission in accordance with the requirements of the "Personal Information Protection Law of the People's Republic of China," "Data Cross-border Security Assessment Measures," and other laws and regulations. The Operator should clearly announce on the Admin Console whether the third-party services used involve cross-border data transfer, and inform users of the name and contact information of the data recipient, processing purposes, processing methods, and types of personal information, etc. If you do not agree to data transfer outside mainland China, you may choose to use AI services provided by domestic service providers only (such as Zhipu AI, Alibaba Cloud, Baidu Wenxin, iFlytek, etc.) or local deployment solutions (such as FunASR, FishSpeech, Ollama, etc.).</p>
|
||||
|
||||
<h2>V. Your Rights</h2>
|
||||
<p>You have the following rights regarding your personal information:</p>
|
||||
<p><span class="bold">5.1 Query and Access:</span> You can view and manage your personal information such as account information, device information, and Agent configuration through the Admin Console.</p>
|
||||
<p><span class="bold">5.2 Correction and Modification:</span> When you find that your personal information is incorrect, you can correct it through the Admin Console or contact the Operator for assistance.</p>
|
||||
<p><span class="bold">5.3 Deletion:</span> Under the following circumstances, you may request us to delete your personal information:</p>
|
||||
<p>(1) The processing purpose has been achieved, cannot be achieved, or is no longer necessary to achieve the processing purpose.</p>
|
||||
<p>(2) We collect or use personal information in violation of laws, regulations, or your agreement.</p>
|
||||
<p>(3) Account cancellation.</p>
|
||||
<p><span class="bold">5.4 Account Cancellation:</span> You can cancel your account through the account settings in the Admin Console or contact the Operator for processing. After account cancellation, we will stop providing services to you and delete your personal information within a reasonable time.</p>
|
||||
<p><span class="bold">5.5 Withdrawal of Consent:</span> You may withdraw your consent granted to us at any time. The withdrawal of consent does not affect the validity of information processing activities conducted before the withdrawal.</p>
|
||||
|
||||
<h2>VI. Protection of Minor Information</h2>
|
||||
<p>6.1 We attach great importance to the protection of minors' personal information. If you are a minor under 18 years of age, please use the Service under the guidance and consent of your guardian and do not provide any personal information to the Service.</p>
|
||||
<p>6.2 If a guardian discovers that a minor has provided personal information to us without consent, please contact the Operator. We will delete the relevant information as soon as possible.</p>
|
||||
<p>6.3 For minors who use the Service with guardian consent, we will provide stricter protection for their personal information in accordance with laws and regulations.</p>
|
||||
<p>(4) <span class="bold">Special Protection:</span> We will not proactively push commercial advertisements to children under 14 years of age, nor use their personal information for targeted advertising or user profiling.</p>
|
||||
|
||||
<h2>VII. Third-party Services Description</h2>
|
||||
<p>7.1 When providing intelligent interaction functions, the Service needs to call third-party services, including but not limited to:</p>
|
||||
<p>(1) Voice Activity Detection Service (VAD): Detects the start and end of voice input.</p>
|
||||
<p>(2) Automatic Speech Recognition Service (ASR): Converts your voice input to text.</p>
|
||||
<p>(3) Large Language Model Service (LLM): Performs semantic understanding, intent recognition, and response generation on text.</p>
|
||||
<p>(4) Text-to-Speech Service (TTS): Converts text responses to voice output.</p>
|
||||
<p>(5) Vision Model Service: Recognizes and understands images.</p>
|
||||
<p>(6) SMS Verification Code Service: Used for identity verification during user registration and login.</p>
|
||||
<p>(7) MQTT Message Broker Service: Used for message communication between devices and servers, including device control command delivery and device status reporting.</p>
|
||||
<p>(8) Database Service: Used for persistent storage of user data, device data, Agent configuration, chat history, and other information.</p>
|
||||
<p class="bold">7.2 The above third-party service providers will process data according to their respective privacy policies. We recommend that you understand the privacy policies of relevant third-party service providers before using the Service. The Operator should announce the third-party service information used on the Admin Console.</p>
|
||||
<p class="bold">7.3 We will make reasonable efforts to select third-party service providers with legitimate qualifications and security capabilities. However, we are not responsible for the data processing behavior of third-party service providers themselves.</p>
|
||||
|
||||
<h2>VIII. Use of Cookies and Similar Technologies</h2>
|
||||
<p>8.1 The Service may use Cookies and similar technologies to save your login status, record your preference settings, etc., to provide you with a better user experience.</p>
|
||||
<p>8.2 You can manage Cookies through browser settings. However, please note that disabling Cookies may affect some functions of the Service.</p>
|
||||
|
||||
<h2>IX. Changes to the Privacy Policy</h2>
|
||||
<p>9.1 We may revise this Privacy Policy based on business adjustments, changes in laws and regulations, and other reasons. The revised Privacy Policy will be published through the Service's announcement mechanisms.</p>
|
||||
<p>9.2 For significant changes, we will provide notice before the revised Privacy Policy takes effect through the Admin Console announcement or other means.</p>
|
||||
<p class="bold">9.3 If you continue to use the Service after the Privacy Policy revision, it shall be deemed that you have accepted the revised Privacy Policy. If you disagree with the revised content, please stop using the Service.</p>
|
||||
|
||||
<h2>X. Information Security Warning</h2>
|
||||
<p class="bold">10.1 Please do not disclose sensitive personal information such as your property account numbers, bank card numbers, credit card numbers, passwords, ID card numbers, etc., in voice or text interactions with AI. Any losses resulting from this shall be borne by you.</p>
|
||||
<p>10.2 Please properly keep your account and password secure, and do not share your account information with others or share accounts with others. The Operator is not responsible for personal information leakage caused by your intentional disclosure or sharing of accounts with others.</p>
|
||||
<p>10.3 If you discover that personal information may have been leaked, please contact the Operator promptly to take measures.</p>
|
||||
|
||||
<h2>XI. Applicable Law</h2>
|
||||
<p>11.1 The formulation, interpretation, execution, and dispute resolution of this Privacy Policy shall be governed by the laws of the People's Republic of China (excluding the laws of Hong Kong, Macau, and Taiwan for the purposes of this Privacy Policy).</p>
|
||||
<p>11.2 If any provision of this Privacy Policy conflicts with the current laws and regulations of the People's Republic of China, the provisions of laws and regulations shall prevail, and the remaining provisions shall remain valid.</p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,170 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>隐私政策 - 小智后端服务</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
|
||||
line-height: 1.8;
|
||||
color: #333;
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
padding: 20px 30px;
|
||||
background: #f9f9fb;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
font-size: 24px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 18px;
|
||||
margin-top: 30px;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 8px 0;
|
||||
text-indent: 2em;
|
||||
}
|
||||
|
||||
.update-date {
|
||||
text-align: center;
|
||||
color: #888;
|
||||
font-size: 14px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<h1>隐私政策</h1>
|
||||
<div class="update-date">更新日期:2026年3月10日</div>
|
||||
|
||||
<h2>引言</h2>
|
||||
<p>欢迎您使用小智后端服务(以下简称"本服务")。本服务的运营方为本服务的实际部署者和管理者(以下简称"运营者"或"我们")。我们深知个人信息对您的重要性,将尽全力保护您的个人信息安全。
|
||||
</p>
|
||||
<p class="bold">请您在使用本服务前,仔细阅读并充分理解本隐私政策的全部内容。一旦您开始使用本服务,即表示您已阅读并同意本隐私政策。</p>
|
||||
<p>本隐私政策适用于您通过智控台(管理后台)、API接口及其他方式使用本服务时,我们对您个人信息的收集、存储、使用、共享、保护等行为。</p>
|
||||
|
||||
<h2>一、我们收集的信息</h2>
|
||||
<p>为向您提供服务,我们可能需要收集以下信息:</p>
|
||||
<p><span class="bold">1.1 账号注册信息:</span>当您注册账号时,我们会收集您的手机号码或用户名、密码等信息,用于创建和验证您的账号。</p>
|
||||
<p><span class="bold">1.2 设备信息:</span>当您绑定硬件设备时,我们会收集设备的标识信息(如设备编码、MAC地址等)、设备型号、固件版本等,用于设备管理和服务提供。</p>
|
||||
<p><span class="bold">1.3 智能体配置信息:</span>当您创建和配置智能体时,我们会收集您设定的角色模板、语言模型选择、语音参数配置等信息,用于提供个性化的AI交互服务。</p>
|
||||
<p><span class="bold">1.4
|
||||
语音交互数据:</span>在您使用语音交互功能时,本服务会通过语音活动检测(VAD)判断您的语音起止状态,并处理您的语音输入数据,将其传输至第三方语音识别(ASR)和语言模型(LLM)服务进行处理,以实现语音交互功能。
|
||||
</p>
|
||||
<p><span class="bold">1.5 图像数据:</span>当您使用视觉模型功能时,我们可能会处理您通过设备摄像头采集的图像数据,并将其传输至第三方视觉模型服务进行分析和理解,用于实现图像识别、场景理解等功能。
|
||||
</p>
|
||||
<p><span class="bold">1.6 对话记忆数据:</span>当您开启记忆功能时,本服务会存储您与智能体的交互历史摘要,用于在后续对话中提供更连贯、个性化的交互体验。</p>
|
||||
<p><span class="bold">1.7 知识库数据:</span>当您使用知识库功能时,我们会收集和存储您上传的文档、文本等知识库内容,用于智能体在对话中进行知识检索和问答。</p>
|
||||
<p><span class="bold">1.8 声纹数据:</span>当您使用声纹识别功能时,我们会收集和存储您的声纹特征样本,用于说话人身份验证和个性化服务。</p>
|
||||
<p><span class="bold">1.9 聊天历史数据:</span>我们会存储您与智能体的对话历史记录,包括文本对话内容、对话时间、交互上下文等信息,用于提供连续性对话体验和历史查询功能。</p>
|
||||
<p><span class="bold">1.10 对话音频数据:</span>在您使用语音交互功能时,我们可能会存储您与智能体交互的音频数据,用于优化语音交互质量和回溯查询。</p>
|
||||
<p><span class="bold">1.11 智能体配置数据:</span>当您配置智能体时,我们会收集您设定的标签、插件配置、上下文提供者设置等信息,用于提供智能体定制化服务。</p>
|
||||
<p><span class="bold">1.12 设备固件数据:</span>当您使用OTA升级功能时,我们会记录设备固件版本、升级历史等信息,用于设备管理和固件追溯。</p>
|
||||
<p><span class="bold">1.13 日志信息:</span>当您使用本服务时,我们会自动收集服务日志信息,包括但不限于访问时间、IP地址、浏览器类型、操作记录等,用于服务运维和安全保障。</p>
|
||||
<p><span class="bold">1.14 验证码信息:</span>当您使用手机号登录时,我们会通过短信服务向您发送验证码,用于身份验证。</p>
|
||||
|
||||
<h2>二、我们如何使用收集的信息</h2>
|
||||
<p>我们收集的信息将用于以下目的:</p>
|
||||
<p>(1)提供、维护和改进本服务,包括账号管理、设备管理、智能体配置等核心功能。</p>
|
||||
<p>(2)处理您的语音交互请求,通过语音活动检测(VAD)识别语音输入,调用第三方AI模型服务完成语音识别、意图识别、语义理解和语音合成。</p>
|
||||
<p>(3)处理您的图像数据,调用第三方视觉模型服务完成图像识别和场景理解。</p>
|
||||
<p>(4)存储和管理您的对话记忆数据,以便在后续交互中提供更连贯的服务体验。</p>
|
||||
<p>(5)存储和检索您上传的知识库内容,以便智能体在对话中为您提供更准确的知识问答。</p>
|
||||
<p>(6)保障服务的安全性和稳定性,包括身份验证、安全防护、故障排查等。</p>
|
||||
<p>(7)遵守适用的法律法规和监管要求。</p>
|
||||
<p class="bold">我们不会将您的个人信息用于与上述目的无关的其他用途。如需将信息用于本隐私政策未载明的其他目的,我们会事先征得您的同意。</p>
|
||||
|
||||
<h2>三、信息的共享与披露</h2>
|
||||
<p class="bold">我们不会向第三方出售您的个人信息。仅在以下情形下,我们可能会共享或披露您的信息:</p>
|
||||
<p><span class="bold">3.1
|
||||
第三方服务调用:</span>为实现语音交互、视觉理解等功能,您的语音数据、图像数据和文本内容可能会被传输至第三方AI服务提供商(如语言模型、语音识别、语音合成、视觉模型服务商)进行处理。我们会选择具备合理安全保障能力的服务商,但请您知悉第三方服务商将按照其自身的隐私政策处理相关数据。
|
||||
</p>
|
||||
<p><span class="bold">3.2 法律要求:</span>根据适用的法律法规、法律程序或政府主管部门的要求,我们可能需要披露您的个人信息。</p>
|
||||
<p><span class="bold">3.3 安全保障:</span>为保护运营者、其他用户或公众的权益、财产或安全免遭损害,在合理必要的范围内使用或披露个人信息。</p>
|
||||
<p><span class="bold">3.4 征得同意:</span>在获得您明确同意的前提下,我们可能会与第三方共享您的个人信息。</p>
|
||||
|
||||
<h2>四、信息的存储与保护</h2>
|
||||
<p><span class="bold">4.1 存储地点:</span>您的个人信息将存储在运营者部署本服务的服务器上,包括但不限于数据库(MySQL/PostgreSQL)和缓存服务(Redis)。</p>
|
||||
<p><span class="bold">4.2 存储期限:</span>我们将在为您提供服务所必需的期限内保留您的个人信息。当您注销账号后,我们将在合理时间内删除或匿名化处理您的个人信息,法律法规另有规定的除外。</p>
|
||||
<p><span class="bold">4.3
|
||||
安全措施:</span>我们采取合理的技术和管理措施保护您的个人信息安全,包括但不限于数据加密、访问控制、安全审计等。但请您理解,互联网并非绝对安全的环境,我们无法保证信息传输和存储的绝对安全性。</p>
|
||||
<p class="bold">4.4 安全事件处理:如发生个人信息安全事件,我们将按照法律法规的要求,及时向您告知安全事件的基本情况、可能的影响、已采取或将要采取的处置措施等。</p>
|
||||
<p class="bold">4.5 开源项目特别说明:本服务为开源项目,存在两种运营模式:</p>
|
||||
<p>(1)<span class="bold">自行部署:</span>如您自行部署本服务,运营者仅为代码提供方,实际的数据存储和处理由您自行负责。在此情况下,您既是本服务的使用者,也是数据的管理者和保护者。</p>
|
||||
<p>(2)<span class="bold">测试平台:</span>如您使用运营者部署的测试平台,您的数据将由运营人员负责管理和保护。测试平台仅供体验和测试之用,我们可能会定期清理数据,建议您勿上传敏感个人信息。</p>
|
||||
<p class="bold">如您使用的是他人部署的服务,请知悉您的数据由该部署者负责管理和保护。</p>
|
||||
<p class="bold">4.6
|
||||
数据跨境传输:本服务在提供智能交互功能时,可能需要调用境外第三方AI服务提供商的接口,在此过程中,您的语音数据、文本数据、图像数据等可能会被传输至中华人民共和国境外的服务器进行处理。涉及的境外服务商包括但不限于:</p>
|
||||
<p>(1)OpenAI:提供语音识别(Whisper)、语音合成(TTS)、大语言模型(GPT)等服务。</p>
|
||||
<p>(2)Anthropic:提供大语言模型(Claude)服务。</p>
|
||||
<p>(3)Groq:提供语音识别(Whisper)服务。</p>
|
||||
<p>(4)微软EdgeTTS:提供语音合成服务。</p>
|
||||
<p>我们将依照《中华人民共和国个人信息保护法》《数据出境安全评估办法》等法律法规的要求,采取必要措施保障您的个人信息在跨境传输过程中的安全。运营者应在智控台上明确公示所使用的第三方服务是否涉及数据跨境传输,并告知数据接收方的名称、联系方式、处理目的、处理方式及个人信息的种类等信息。如您不同意将数据传输至境外,您可选择仅使用境内服务商提供的AI服务(如智谱AI、阿里云、百度文心、讯飞等)或本地部署方案(如FunASR、FishSpeech、Ollama等)。
|
||||
</p>
|
||||
|
||||
<h2>五、您的权利</h2>
|
||||
<p>您对自己的个人信息享有以下权利:</p>
|
||||
<p><span class="bold">5.1 查询与访问:</span>您可通过智控台查看和管理您的账号信息、设备信息、智能体配置等个人信息。</p>
|
||||
<p><span class="bold">5.2 更正与修改:</span>当您发现个人信息有误时,您可通过智控台自行更正,或联系运营者协助处理。</p>
|
||||
<p><span class="bold">5.3 删除:</span>在以下情形下,您可请求我们删除您的个人信息:</p>
|
||||
<p>(1)处理目的已实现、无法实现或者为实现处理目的不再必要。</p>
|
||||
<p>(2)我们违反法律法规或与您的约定收集、使用个人信息。</p>
|
||||
<p>(3)注销账号。</p>
|
||||
<p><span class="bold">5.4 账号注销:</span>您可通过智控台的账号设置功能注销账号,或联系运营者进行处理。账号注销后,我们将停止为您提供服务,并在合理时间内删除您的个人信息。</p>
|
||||
<p><span class="bold">5.5 撤回同意:</span>您可随时撤回您此前向我们作出的同意授权。撤回同意不影响撤回前已进行的信息处理活动的效力。</p>
|
||||
|
||||
<h2>六、未成年人信息保护</h2>
|
||||
<p>6.1 我们高度重视未成年人个人信息的保护。若您是未满18周岁的未成年人,请在监护人的指导和同意下使用本服务,并请勿向本服务提供任何个人信息。</p>
|
||||
<p>6.2 如果监护人发现未成年人未经其同意向我们提供了个人信息,请联系运营者,我们将尽快删除相关信息。</p>
|
||||
<p>6.3 对于经监护人同意使用本服务的未成年人,我们将按照法律法规的规定,给予其个人信息更严格的保护。</p>
|
||||
<p>(4)<span class="bold">特别保护:</span>我们不会主动向未满14周岁的儿童推送商业广告,不会将其个人信息用于定向推送或用户画像。</p>
|
||||
|
||||
<h2>七、第三方服务说明</h2>
|
||||
<p>7.1 本服务在提供智能交互功能时,需要调用第三方服务,包括但不限于:</p>
|
||||
<p>(1)语音活动检测服务(VAD):检测语音输入的起止状态。</p>
|
||||
<p>(2)语音识别服务(ASR):将您的语音输入转换为文本。</p>
|
||||
<p>(3)大语言模型服务(LLM):对文本进行语义理解、意图识别和回复生成。</p>
|
||||
<p>(4)语音合成服务(TTS):将文本回复转换为语音输出。</p>
|
||||
<p>(5)视觉模型服务:对图像进行识别和理解。</p>
|
||||
<p>(6)短信验证码服务:用于用户注册和登录时的身份验证。</p>
|
||||
<p>(7)MQTT消息代理服务(MQTT Broker):用于设备与服务器之间的消息通信,包括设备控制指令下发和设备状态上报。</p>
|
||||
<p>(8)数据库服务:用于用户数据、设备数据、智能体配置、聊天历史等信息的持久化存储。</p>
|
||||
<p class="bold">7.2 上述第三方服务提供商将按照其各自的隐私政策对数据进行处理。我们建议您在使用本服务前,了解相关第三方服务商的隐私政策。运营者应在智控台上公示所使用的第三方服务信息。</p>
|
||||
<p class="bold">7.3 我们会尽合理努力选择具备合法合规资质和安全保障能力的第三方服务商,但对于第三方服务商自身的数据处理行为,我们不承担责任。</p>
|
||||
|
||||
<h2>八、Cookie及类似技术的使用</h2>
|
||||
<p>8.1 本服务可能使用Cookie及类似技术来保存您的登录状态、记录您的偏好设置等,以便为您提供更好的使用体验。</p>
|
||||
<p>8.2 您可以通过浏览器设置管理Cookie。但请注意,如果禁用Cookie,可能会影响本服务的部分功能。</p>
|
||||
|
||||
<h2>九、隐私政策的变更</h2>
|
||||
<p>9.1 我们可能会根据业务调整、法律法规变化等原因对本隐私政策进行修订。修订后的隐私政策将通过本平台公告等方式予以发布。</p>
|
||||
<p>9.2 对于重大变更,我们将在修订生效前通过智控台公告等方式予以通知。</p>
|
||||
<p class="bold">9.3 如您在隐私政策修订后继续使用本服务,则视为您已接受修订后的隐私政策。如您不同意修订后的内容,请停止使用本服务。</p>
|
||||
|
||||
<h2>十、信息安全提示</h2>
|
||||
<p class="bold">10.1 请勿在与AI的语音或文字交互中透露您的财产账户、银行卡号、信用卡号、密码、身份证号等敏感个人信息,否则由此带来的损失由您自行承担。</p>
|
||||
<p>10.2 请妥善保管您的账号和密码,不要将账号信息告知他人或与他人共享账号。因您主动泄露或与他人共享账号导致的个人信息泄露,运营者不承担责任。</p>
|
||||
<p>10.3 如您发现个人信息可能被泄露,请及时联系运营者采取措施。</p>
|
||||
|
||||
<h2>十一、适用法律</h2>
|
||||
<p>11.1 本隐私政策的制定、解释、执行及争议解决均适用中华人民共和国法律法规(为本隐私政策之目的,不包括港澳台地区法律)。</p>
|
||||
<p>11.2 如本隐私政策的任何条款与中华人民共和国现行法律法规相抵触,以法律法规的规定为准,其余条款仍然有效。</p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,301 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>User Agreement - XiaoZhi Backend Service</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
|
||||
line-height: 1.8;
|
||||
color: #333;
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
padding: 20px 30px;
|
||||
background: #f9f9fb;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
font-size: 24px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 18px;
|
||||
margin-top: 30px;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 8px 0;
|
||||
text-indent: 2em;
|
||||
}
|
||||
|
||||
.update-date {
|
||||
text-align: center;
|
||||
color: #888;
|
||||
font-size: 14px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<h1>User Agreement</h1>
|
||||
<div class="update-date">Last Updated: March 10, 2026</div>
|
||||
|
||||
<h2>Important Notice</h2>
|
||||
<p>Welcome to use the XiaoZhi Backend Service (hereinafter referred to as "the Service"). The Service is designed to
|
||||
provide backend service support for XiaoZhi AI hardware devices, including but not limited to intelligent voice
|
||||
interaction, visual understanding, intent recognition, conversation memory, knowledge base Q&A, device
|
||||
management, and agent management. The operator of this Service is the actual deployer and administrator of the
|
||||
Service (hereinafter referred to as "Operator" or "we").
|
||||
</p>
|
||||
<p class="bold">Before registering, logging in, or using the Service, please carefully read and fully understand all
|
||||
terms of this Agreement, especially the terms that are highlighted in bold and may have significant impact on
|
||||
your interests, including but not limited to disclaimers and liability limitations.</p>
|
||||
<p class="bold">When you complete registration, login, or otherwise use the Service following the on-screen
|
||||
instructions, it signifies that you have fully read, understood, and accepted all contents of this Agreement. If
|
||||
you disagree with this Agreement or any of its terms, please stop using the Service immediately.</p>
|
||||
<p>This Agreement may be updated and revised based on actual circumstances. The revised Agreement will be published
|
||||
through the Service's announcement mechanisms. The revised Agreement shall take effect from the date of
|
||||
publication. If you continue to use the Service after the Agreement revision, it shall be deemed that you have
|
||||
accepted the revised Agreement.</p>
|
||||
|
||||
<h2>I. Definitions</h2>
|
||||
<p><span class="bold">XiaoZhi Backend Service:</span> refers to the XiaoZhi Backend Service and its backend service
|
||||
system, including but not limited to the Admin Console (management backend), API interfaces, WebSocket
|
||||
communication services, etc.
|
||||
</p>
|
||||
<p><span class="bold">Admin Console:</span> refers to the web management interface provided by the Service for
|
||||
device management, agent configuration, user management, and other functions.</p>
|
||||
<p><span class="bold">User:</span> refers to natural persons, legal persons, or other organizations who register or
|
||||
otherwise use the Service, hereinafter referred to as "you".</p>
|
||||
<p><span class="bold">Intelligent Agent (Agent):</span> refers to an AI character created and configured within the
|
||||
Service, containing a collection of capabilities such as language models, speech recognition, speech synthesis,
|
||||
visual understanding, intent recognition, conversation memory, and knowledge base.</p>
|
||||
<p><span class="bold">Device:</span> refers to ESP32 and other hardware devices connected and managed through the
|
||||
Service.</p>
|
||||
|
||||
<h2>II. Scope of Agreement</h2>
|
||||
<p>This Agreement is a legal agreement between you and the Operator regarding your use of the Service. This
|
||||
Agreement applies to all your actions when using the Service through the Admin Console or other means.</p>
|
||||
<p>The source code of the Service follows the corresponding open-source license. This Agreement governs your use of
|
||||
the Service and does not affect the rights granted to you by the open-source license itself.</p>
|
||||
|
||||
<h2>III. Account Registration and Use</h2>
|
||||
<p><span class="bold">3.1 User Eligibility:</span> You confirm that before using the Service, you should have the
|
||||
capacity for civil conduct as required by the laws of the People's Republic of China. If you are a minor, you
|
||||
should use the Service under the company and guidance of your legal guardian.</p>
|
||||
<p><span class="bold">3.2 Account Registration:</span> You may register and log in to the Service through mobile
|
||||
phone verification code, username/password, or other methods. You shall provide true, accurate, and complete
|
||||
registration information and update it promptly.</p>
|
||||
<p><span class="bold">3.3 Account Security:</span> You shall properly keep your account and password safe. All
|
||||
consequences arising from account leakage or unauthorized use by others due to your reasons shall be borne by
|
||||
you. If you discover any security risks with your account, please contact the Operator immediately.</p>
|
||||
<p><span class="bold">3.4 Account Usage Restrictions:</span> Your account is for your personal use only. Without the
|
||||
Operator's consent, you shall not transfer, rent, or lend your account to any third party in any way.</p>
|
||||
<p><span class="bold">3.5 Account Cancellation:</span> If you need to cancel your account, you may do so through the
|
||||
account settings in the Admin Console or contact the Operator for processing. After account cancellation,
|
||||
related data will be deleted and cannot be recovered. Please proceed with caution.</p>
|
||||
|
||||
<h2>IV. Service Content</h2>
|
||||
<p><span class="bold">4.1 Service Overview:</span> Relying on artificial intelligence technology, the Service
|
||||
provides intelligent interaction services for connected hardware devices through API calls to third-party
|
||||
generative AI models, including but not limited to Voice Activity Detection (VAD), Automatic Speech Recognition
|
||||
(ASR), Large Language Model (LLM), Text-to-Speech (TTS), Vision Large Language Model (VLLM), Intent Recognition,
|
||||
Conversation Memory, and Retrieval-Augmented Generation (RAG).
|
||||
</p>
|
||||
<p><span class="bold">4.2 Agent Management:</span> You can create and configure Agents through the Admin Console,
|
||||
including setting role templates, selecting language models, configuring voice parameters, setting intent
|
||||
recognition rules, managing knowledge bases, enabling conversation memory, configuring Agent plugins, etc. The
|
||||
Agent settings shall not violate national laws and regulations.</p>
|
||||
<p><span class="bold">4.3 Device Management:</span> You can bind and manage your hardware devices through the Admin
|
||||
Console, perform device configuration, firmware updates, OTA remote upgrades, etc. You shall ensure that the
|
||||
devices you manage are lawfully owned or authorized by you.</p>
|
||||
<p><span class="bold">4.4 Visual Understanding:</span> The Service supports image capture through device cameras and
|
||||
uses third-party vision models for image recognition and scene understanding. You shall ensure that image
|
||||
capture complies with relevant laws and regulations and does not infringe upon others' privacy.</p>
|
||||
<p><span class="bold">4.5 Intent Recognition:</span> The Service can understand the intent of user commands through
|
||||
intent recognition and trigger corresponding operations or services, such as controlling smart devices, querying
|
||||
information, etc.</p>
|
||||
<p><span class="bold">4.6 Conversation Memory:</span> The Service can record and store summaries of your interaction
|
||||
history with the Agent to provide more coherent and personalized interaction experiences in subsequent
|
||||
conversations. You can manage or clear memory data in the Admin Console.</p>
|
||||
<p><span class="bold">4.7 Knowledge Base:</span> The Service supports uploading documents, texts, and other content
|
||||
to build knowledge bases. Agents can retrieve knowledge base content during conversations to provide Q&A
|
||||
services. You shall ensure that uploaded knowledge base content does not infringe upon third-party intellectual
|
||||
property rights and does not contain content that violates laws and regulations.</p>
|
||||
<p><span class="bold">4.8 Voice Print Recognition:</span> The Service supports voice print recognition. You can
|
||||
register voice print samples to achieve speaker identity verification and personalized services. Voice print
|
||||
data will be used for identity verification purposes.</p>
|
||||
<p><span class="bold">4.9 Voice Cloning:</span> The Service supports voice cloning. You can clone custom voice
|
||||
timbres by providing audio samples. Cloned voices are for your personal use only and shall not be used to
|
||||
impersonate others or engage in illegal activities.</p>
|
||||
<p><span class="bold">4.10 MCP Endpoints:</span> The Service supports MCP (Model Context Protocol) and can serve as
|
||||
an MCP Server to provide tool calling capabilities to external systems, or as an MCP Client to call external MCP
|
||||
services, achieving standardized integration with external systems.</p>
|
||||
<p><span class="bold">4.11 Context Providers:</span> the Service supports Context Provider functionality, which can
|
||||
obtain real-time information from external data sources, such as weather, news, stocks, etc., providing Agents
|
||||
with richer knowledge sources.</p>
|
||||
<p><span class="bold">4.12 MQTT Protocol:</span> The Service supports MQTT (Message Queuing Telemetry Transport)
|
||||
protocol for message communication between IoT devices. You can use the MQTT protocol to send device control
|
||||
commands, monitor device status, etc.</p>
|
||||
<p><span class="bold">4.13 Service Disclaimer:</span> The conversations and responses generated by third-party AI
|
||||
models that the Service depends on are for reference only and do not constitute professional advice in any
|
||||
field. You shall not use the output content as professional advice in medical, legal, financial, or other
|
||||
professional fields. Any judgments or decisions you make based on the output content shall be entirely at your
|
||||
own responsibility.</p>
|
||||
<p class="bold">4.14 Service Fees: The Service is a free open-source project and does not charge any usage fees from
|
||||
users. It only provides platform capabilities for calling third-party services and does not involve any paid
|
||||
functions or value-added services.</p>
|
||||
<p>The Service supports multiple AI service providers with different billing models as follows:</p>
|
||||
<p>(1) <span class="bold">Free Services:</span> Some service providers offer free quotas or completely free
|
||||
services, such as Zhipu AI (free models like glm-4-flash), Microsoft EdgeTTS voice synthesis, etc.</p>
|
||||
<p>(2) <span class="bold">Pay-as-you-go:</span> Some service providers charge based on API usage, such as OpenAI,
|
||||
Alibaba Cloud Intelligent Speech, Baidu Wenxin, iFlytek, etc. You need to pay the corresponding fees to
|
||||
third-party service providers yourself. Such fees are unrelated to this Service.</p>
|
||||
<p>(3) <span class="bold">Local Deployment:</span> The Service supports fully local AI deployment solutions, such as
|
||||
FunASR speech recognition, FishSpeech voice synthesis, Ollama local large models, etc. Local deployment does not
|
||||
require network fees or API usage fees but requires sufficient local computing resources.</p>
|
||||
<p>You can choose a suitable service provider based on your actual needs and budget. For specific fee standards,
|
||||
please refer to the official documentation of each service provider.</p>
|
||||
<p><span class="bold">4.15 Service Changes:</span> The Operator reserves the right to adjust, upgrade, or terminate
|
||||
the Service content based on actual circumstances and will endeavor to provide advance notice.</p>
|
||||
|
||||
<h2>V. User Conduct Standards</h2>
|
||||
<p><span class="bold">5.1 Legal Use:</span> When using the Service, you shall comply with the laws and regulations
|
||||
of the People's Republic of China and relevant international treaties, and shall not use the Service for any
|
||||
illegal activities.</p>
|
||||
<p class="bold">5.2 Prohibited Activities: You undertake not to engage in the following activities when using the
|
||||
Service:</p>
|
||||
<p>(1) Publishing, transmitting, or storing content that endangers national security or social stability, including
|
||||
but not limited to content involving subversion of state power, damage to national honors and interests,
|
||||
incitement of ethnic hatred, etc.</p>
|
||||
<p>(2) Publishing, transmitting, or storing content that infringes upon the legitimate rights and interests of
|
||||
others, including but not limited to infringement of intellectual property rights, privacy rights, reputation
|
||||
rights, etc.</p>
|
||||
<p>(3) Publishing, transmitting, or storing obscene, pornographic, violent, terrorist, or content that incites
|
||||
crimes.</p>
|
||||
<p>(4) Publishing false information, spreading rumors, or engaging in fraudulent activities.</p>
|
||||
<p>(5) Interfering with the normal operation of the Service in any way, including but not limited to attacking
|
||||
servers, spreading malicious programs, malicious consumption of system resources, etc.</p>
|
||||
<p>(6) Reverse engineering, decompiling, or otherwise attempting to obtain the source code of the Service without
|
||||
authorization (this clause does not limit your lawful use of open-source code under the open-source license).
|
||||
</p>
|
||||
<p>(7) Using the Service for automated batch operations, malicious consumption of API call quotas or other system
|
||||
resources.</p>
|
||||
<p>(8) Inputting content that violates laws and regulations or public order and good morals in Agent settings.</p>
|
||||
<p>(9) Using the Service to harm or attempt to harm minors.</p>
|
||||
<p>(10) Other activities that violate laws and regulations, this Agreement, or may harm the legitimate rights and
|
||||
interests of the Operator and third parties.</p>
|
||||
<p><span class="bold">5.3 Handling of Violations:</span> If you violate the above conduct standards, the Operator
|
||||
has the right to take measures such as warnings, feature restrictions, service suspension, account banning,
|
||||
etc., depending on the severity, and reserves the right to pursue legal liability.</p>
|
||||
|
||||
<h2>VI. Intellectual Property</h2>
|
||||
<p><span class="bold">6.1 Open-source License:</span> The Service is an open-source project, and its source code
|
||||
follows the corresponding open-source license. You may use the relevant source code in compliance with the terms
|
||||
of that license.</p>
|
||||
<p><span class="bold">6.2 Service Content Ownership:</span> Except for open-source code, the interface design,
|
||||
icons, copy, and other independently created content by the Operator in the Service are owned by the Operator.
|
||||
</p>
|
||||
<p><span class="bold">6.3 User Content:</span> The intellectual property rights of content you input, upload, or
|
||||
generate through the Service shall be determined according to relevant laws and regulations. You grant the
|
||||
Operator the right to store and process your input content for the purpose of maintaining and improving the
|
||||
Service.</p>
|
||||
<p><span class="bold">6.4 Third-party Rights:</span> You shall respect the intellectual property rights and other
|
||||
legitimate rights of third parties when using the Service. You shall bear full responsibility for any disputes
|
||||
arising from your infringement of third-party rights.</p>
|
||||
|
||||
<h2>VII. Privacy Protection</h2>
|
||||
<p><span class="bold">7.1 Information Collection:</span> To provide the Service, the Operator may collect your
|
||||
registration information (such as phone number, username), device information, usage logs, etc. For specific
|
||||
personal information collection and usage rules, please refer to the Privacy Policy.</p>
|
||||
<p><span class="bold">7.2 Information Protection:</span> The Operator will take reasonable technical and management
|
||||
measures to protect the security of your personal information. However, due to the openness of the Internet, the
|
||||
Operator cannot absolutely guarantee information security. Please pay attention to protecting your sensitive
|
||||
personal information.</p>
|
||||
<p class="bold">7.3 Information Security Warning: Please do not disclose sensitive personal information such as your
|
||||
property accounts, bank card numbers, passwords, etc. to the AI during your use of the Service. Any losses
|
||||
resulting from this shall be borne by you.</p>
|
||||
|
||||
<h2>VIII. Disclaimer</h2>
|
||||
<p class="bold">8.1 AI-Generated Content: The Service relies on third-party AI models to provide intelligent
|
||||
interaction capabilities. The content generated by AI may be inaccurate, incomplete, or inappropriate. The
|
||||
Operator does not make any guarantees regarding the authenticity, accuracy, or completeness of AI-generated
|
||||
content.</p>
|
||||
<p class="bold">8.2 Service Interruption: The Operator shall not be responsible for service interruptions or
|
||||
abnormalities caused by the following reasons:</p>
|
||||
<p>(1) Force majeure factors such as natural disasters, epidemics, wars, etc.</p>
|
||||
<p>(2) Public service factors such as power supply failures, communication network failures, etc.</p>
|
||||
<p>(3) Service failures or policy adjustments of third-party AI model service providers.</p>
|
||||
<p>(4) Temporary service interruptions caused by system maintenance or upgrades.</p>
|
||||
<p>(5) Cybersecurity events such as hacker attacks, computer viruses, etc.</p>
|
||||
<p>(6) Service adjustments due to laws, regulations, or government control.</p>
|
||||
<p>(7) Other situations not caused by the Operator's fault.</p>
|
||||
<p><span class="bold">8.3 Third-party Services:</span> The Service may involve third-party services such as language
|
||||
models, speech recognition, speech synthesis, vision models, intent recognition, etc. You shall also comply with
|
||||
the terms of third parties when using them. For issues arising from third-party services, please contact the
|
||||
third party directly.</p>
|
||||
<p class="bold">8.4 Open-source Statement: The Service is an open-source project provided "as is". To the maximum
|
||||
extent permitted by law, the Operator does not make any express or implied warranties regarding the
|
||||
merchantability, fitness for a particular purpose, or non-infringement of the Service.</p>
|
||||
<p class="bold">8.5 Open-source Software Special Statement: This project is open-source software. This Service does
|
||||
not have any commercial cooperative relationships with any third-party API service providers (including but not
|
||||
limited to platforms for speech recognition, large models, speech synthesis, etc.) and does not provide any form
|
||||
of guarantees for their service quality and fund security. This software does not host any account keys, does
|
||||
not participate in capital flow, and does not bear the risk of recharge fund losses.</p>
|
||||
<p class="bold">8.6 Security Warning: The functions of this project are not complete and have not passed
|
||||
cybersecurity reviews. Please do not use them in production environments. If you deploy this project in a public
|
||||
network environment for learning purposes, you must take necessary protective measures, including but not
|
||||
limited to setting strong passwords, restricting access permissions, enabling HTTPS encrypted transmission, etc.
|
||||
</p>
|
||||
|
||||
<h2>IX. Protection of Minors</h2>
|
||||
<p>9.1 If you are a minor under 18 years of age, you should use the Service under the guidance and consent of your
|
||||
guardian.</p>
|
||||
<p>9.2 Guardians should strengthen supervision of minors' use of the Service and guide them to use it reasonably to
|
||||
avoid over-dependence.</p>
|
||||
<p>9.3 Minors should pay attention to personal information protection when using the Service and avoid uploading or
|
||||
disclosing sensitive personal information.</p>
|
||||
|
||||
<h2>X. Termination of Agreement</h2>
|
||||
<p><span class="bold">10.1 User Termination:</span> You have the right to stop using the Service and cancel your
|
||||
account at any time.</p>
|
||||
<p><span class="bold">10.2 Operator Termination:</span> The Operator has the right to terminate providing services
|
||||
to you under the following circumstances:</p>
|
||||
<p>(1) You violate the terms of this Agreement.</p>
|
||||
<p>(2) You use the Service for illegal activities.</p>
|
||||
<p>(3) Required by laws, regulations, or policies.</p>
|
||||
<p>(4) The Operator decides to stop operating the Service.</p>
|
||||
<p><span class="bold">10.3 Post-Termination Handling:</span> After the Agreement is terminated, the Operator has no
|
||||
obligation to retain your account information and related data. The Operator still has the right to pursue your
|
||||
liability for breaches during the validity period of the Agreement.</p>
|
||||
|
||||
<h2>XI. Governing Law and Dispute Resolution</h2>
|
||||
<p>11.1 The formation, effectiveness, interpretation, revision, termination, and dispute resolution of this
|
||||
Agreement shall be governed by the laws of the People's Republic of China.</p>
|
||||
<p>11.2 Any disputes arising from this Agreement or the Service shall be resolved through friendly negotiation
|
||||
between both parties. If negotiation fails, either party has the right to bring a lawsuit to the people's court
|
||||
with jurisdiction over the Operator's location.</p>
|
||||
<p>11.3 If any provision of this Agreement is determined to be invalid or unenforceable, it shall not affect the
|
||||
validity of the remaining provisions.</p>
|
||||
|
||||
<h2>XII. Miscellaneous</h2>
|
||||
<p>12.1 This Agreement constitutes the complete agreement between you and the Operator regarding your use of the
|
||||
Service.</p>
|
||||
<p>12.2 The Operator's failure to exercise or delay in exercising any rights under this Agreement shall not
|
||||
constitute a waiver of such rights.</p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,184 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>用户协议 - 小智后端服务</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
|
||||
line-height: 1.8;
|
||||
color: #333;
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
padding: 20px 30px;
|
||||
background: #f9f9fb;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
font-size: 24px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 18px;
|
||||
margin-top: 30px;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 8px 0;
|
||||
text-indent: 2em;
|
||||
}
|
||||
|
||||
.update-date {
|
||||
text-align: center;
|
||||
color: #888;
|
||||
font-size: 14px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<h1>用户协议</h1>
|
||||
<div class="update-date">更新日期:2026年3月10日</div>
|
||||
|
||||
<h2>提示条款</h2>
|
||||
<p>欢迎您使用小智后端服务(以下简称"本服务")。本服务旨在为小智AI硬件设备提供后端服务支持,包括但不限于智能语音交互、视觉理解、意图识别、对话记忆、知识库问答、设备管理、智能体管理等功能。本服务的运营方为本服务的实际部署者和管理者(以下简称"运营者"或"我们")。
|
||||
</p>
|
||||
<p class="bold">在您注册、登录或使用本服务之前,请您务必审慎阅读、充分理解本协议各条款内容,特别是以加粗形式提示您注意的可能与您利益有重大关系的条款,包括但不限于免责声明、责任限制等条款。</p>
|
||||
<p class="bold">当您按照页面提示完成注册、登录或以其他方式使用本服务时,即表示您已充分阅读、理解并接受本协议的全部内容。如果您不同意本协议或其中任何条款,请立即停止使用本服务。</p>
|
||||
<p>本协议可能根据实际情况进行更新和修订,修订后的协议将通过本平台公告等方式予以公示。修订后的协议自公示之日起生效,如您在协议修订后继续使用本服务,则视为您已接受修订后的协议。</p>
|
||||
|
||||
<h2>一、定义</h2>
|
||||
<p><span class="bold">小智后端服务:</span>指小智后端服务及其部署运行的后端服务系统,包括但不限于智控台(管理后台)、API接口、WebSocket通信服务等。
|
||||
</p>
|
||||
<p><span class="bold">智控台:</span>指本服务提供的Web管理界面,用于设备管理、智能体配置、用户管理等功能。</p>
|
||||
<p><span class="bold">用户:</span>指通过注册或其他方式使用本服务的自然人、法人或其他组织,以下简称"您"。</p>
|
||||
<p><span class="bold">智能体:</span>指在本服务中创建和配置的AI角色,包含语言模型、语音识别、语音合成、视觉理解、意图识别、对话记忆、知识库等能力的集合。</p>
|
||||
<p><span class="bold">设备:</span>指通过本服务进行连接和管理的ESP32等硬件设备。</p>
|
||||
|
||||
<h2>二、协议范围</h2>
|
||||
<p>本协议是您与运营者之间关于使用本服务的法律协议。本协议适用于您通过智控台或其他方式使用本服务的全部行为。</p>
|
||||
<p>本服务的源代码遵循相应的开源许可证。本协议约束您对本服务的使用行为,不影响开源许可证本身赋予您的权利。</p>
|
||||
|
||||
<h2>三、账号注册与使用</h2>
|
||||
<p><span class="bold">3.1 用户资格:</span>您确认,在使用本服务前,您应当具备中华人民共和国法律规定的与您行为相适应的民事行为能力。若您为未成年人,应在法定监护人的陪同和指导下使用本服务。</p>
|
||||
<p><span class="bold">3.2 账号注册:</span>您可通过手机号验证码或用户名密码等方式注册和登录本服务。您应当提供真实、准确、完整的注册信息,并及时更新。</p>
|
||||
<p><span class="bold">3.3 账号安全:</span>您应妥善保管您的账号和密码,因您的原因导致账号泄露或被他人冒用所产生的一切后果,由您自行承担。如发现账号存在安全隐患,请立即联系运营者。</p>
|
||||
<p><span class="bold">3.4 账号使用限制:</span>您的账号仅限您本人使用,未经运营者同意,不得以任何方式将账号转让、出租或借给第三方使用。</p>
|
||||
<p><span class="bold">3.5 账号注销:</span>如您需要注销账号,可通过智控台的账号设置功能进行操作,或联系运营者进行处理。账号注销后,相关数据将被删除且无法恢复,请谨慎操作。</p>
|
||||
|
||||
<h2>四、服务内容</h2>
|
||||
<p><span class="bold">4.1
|
||||
服务概述:</span>本服务依托人工智能技术,通过API接口调用第三方生成式人工智能模型,为连接的硬件设备提供智能交互服务,包括但不限于语音活动检测(VAD)、语音识别(ASR)、语义理解(LLM)、语音合成(TTS)、视觉理解(VLLM)、意图识别(Intent)、对话记忆(Memory)、知识库(RAG)等。
|
||||
</p>
|
||||
<p><span class="bold">4.2
|
||||
智能体管理:</span>您可通过智控台创建和配置智能体,包括设定角色模板、选择语言模型、配置语音参数、设置意图识别规则、管理知识库、开启对话记忆、配置智能体插件等。智能体的设定内容不得违反国家法律法规。</p>
|
||||
<p><span class="bold">4.3 设备管理:</span>您可通过智控台绑定和管理您的硬件设备,进行设备配置、固件更新、OTA远程升级等操作。您应确保所管理的设备为您合法拥有或已获得授权。</p>
|
||||
<p><span class="bold">4.4 视觉理解:</span>本服务支持通过设备摄像头采集图像,调用第三方视觉模型进行图像识别和场景理解。您应确保采集图像的行为符合相关法律法规,不得侵犯他人隐私。</p>
|
||||
<p><span class="bold">4.5 意图识别:</span>本服务可通过意图识别功能理解用户指令的意图,并据此触发相应的操作或服务,如控制智能设备、查询信息等。</p>
|
||||
<p><span class="bold">4.6 对话记忆:</span>本服务可记录和存储您与智能体的交互历史摘要,以便在后续对话中提供更连贯、个性化的交互体验。您可在智控台管理或清除记忆数据。</p>
|
||||
<p><span class="bold">4.7
|
||||
知识库:</span>本服务支持您上传文档、文本等内容构建知识库,智能体可在对话中检索知识库内容为您提供问答服务。您应确保上传的知识库内容不侵犯第三方知识产权,且不包含违反法律法规的内容。</p>
|
||||
<p><span class="bold">4.8 声纹识别:</span>本服务支持声纹识别功能,您可注册声纹样本以实现说话人身份验证和个性化服务。声纹数据将用于身份验证目的。</p>
|
||||
<p><span class="bold">4.9 语音克隆:</span>本服务支持语音克隆功能,您可通过提供音频样本克隆自定义音色。克隆音色仅供您本人使用,不得用于仿冒他人或从事违法违规活动。</p>
|
||||
<p><span class="bold">4.10 MCP接入点:</span>本服务支持MCP(Model Context Protocol)协议,可作为MCP Server向外部提供工具调用能力,也可作为MCP
|
||||
Client调用外部MCP服务,实现与外部系统的标准化集成。</p>
|
||||
<p><span class="bold">4.11 上下文提供者:</span>本服务支持上下文提供者(Context Provider)功能,可从外部数据源获取实时信息,如天气、新闻、股票等,为智能体提供更丰富的知识来源。
|
||||
</p>
|
||||
<p><span class="bold">4.12 MQTT协议:</span>本服务支持MQTT(Message Queuing Telemetry
|
||||
Transport)协议,用于与物联网设备之间的消息通信。您可通过MQTT协议实现设备控制指令下发、设备状态监控等功能。</p>
|
||||
<p><span class="bold">4.13
|
||||
服务说明:</span>本服务所依赖的第三方AI模型生成的对话、答复内容仅供参考,不构成任何专业建议。您不得将输出内容作为医疗、法律、金融等领域的专业建议。您根据输出内容所作的任何判断或决策,由您自行承担全部责任。
|
||||
</p>
|
||||
<p class="bold">4.14 服务费用:本服务为免费开源项目,不向用户收取任何使用费用,仅提供调用第三方服务的平台能力,不涉及任何付费功能或增值服务。</p>
|
||||
<p>本服务支持多种AI服务提供商,不同提供商的收费模式如下:</p>
|
||||
<p>(1)<span class="bold">免费服务:</span>部分服务商提供免费额度或完全免费的服务,如智谱AI(glm-4-flash等免费模型)、微软EdgeTTS语音合成等。</p>
|
||||
<p>(2)<span class="bold">按量付费服务:</span>部分服务商按API调用量计费,如OpenAI、阿里云智能语音、百度文心、讯飞等。您需要自行向第三方服务商支付相应费用,该等费用与本服务无关。</p>
|
||||
<p>(3)<span
|
||||
class="bold">本地部署方案:</span>本服务支持完全本地部署的AI方案,如FunASR语音识别、FishSpeech语音合成、Ollama本地大模型等。本地部署无需网络费用和API调用费用,但需要本地具备足够的计算资源。
|
||||
</p>
|
||||
<p>您可根据实际需求和预算选择合适的服务提供商。具体费用标准请参阅各服务商官方说明。</p>
|
||||
<p><span class="bold">4.15 服务变更:</span>运营者保留根据实际情况对服务内容进行调整、升级或终止的权利,并将尽可能提前予以通知。</p>
|
||||
|
||||
<h2>五、用户行为规范</h2>
|
||||
<p><span class="bold">5.1 合法使用:</span>您在使用本服务时,应遵守中华人民共和国的法律法规及相关国际条约,不得利用本服务从事任何违法违规活动。</p>
|
||||
<p class="bold">5.2 禁止行为:您承诺在使用本服务时不得实施以下行为:</p>
|
||||
<p>(1)发布、传输、存储危害国家安全、社会稳定的内容,包括但不限于涉及颠覆国家政权、损害国家荣誉和利益、煽动民族仇恨等内容。</p>
|
||||
<p>(2)发布、传输、存储侵犯他人合法权益的内容,包括但不限于侵犯知识产权、隐私权、名誉权等。</p>
|
||||
<p>(3)发布、传输、存储淫秽、色情、暴力、恐怖或教唆犯罪的内容。</p>
|
||||
<p>(4)发布虚假信息、散布谣言或从事欺诈行为。</p>
|
||||
<p>(5)以任何方式干扰本服务的正常运行,包括但不限于攻击服务器、传播恶意程序、恶意消耗系统资源等。</p>
|
||||
<p>(6)未经授权对本服务进行反向工程、反编译或其他试图获取系统源代码的行为(本条不限制您依据开源许可证对开源代码的合法使用)。</p>
|
||||
<p>(7)利用本服务进行自动化批量操作,恶意消耗API调用配额或其他系统资源。</p>
|
||||
<p>(8)在智能体设定中输入违反法律法规或社会公序良俗的内容。</p>
|
||||
<p>(9)利用本服务伤害或企图伤害未成年人。</p>
|
||||
<p>(10)其他违反法律法规、本协议约定或可能损害运营者及第三方合法权益的行为。</p>
|
||||
<p><span class="bold">5.3 违规处理:</span>如您违反上述行为规范,运营者有权视情节严重程度采取警告、限制功能、暂停服务、封禁账号等措施,并保留追究法律责任的权利。</p>
|
||||
|
||||
<h2>六、知识产权</h2>
|
||||
<p><span class="bold">6.1 开源许可:</span>本服务为开源项目,其源代码遵循相应的开源许可证。您可以在遵守该许可证条款的前提下使用相关源代码。</p>
|
||||
<p><span class="bold">6.2 服务内容权属:</span>除开源代码外,本服务中的界面设计、图标、文案及其他运营者独立创作的内容,其知识产权归运营者所有。</p>
|
||||
<p><span class="bold">6.3 用户内容:</span>您通过本服务输入、上传或生成的内容,其知识产权归属依照相关法律法规确定。您授予运营者为维护和改进服务之目的,对您输入内容进行存储和必要处理的权利。</p>
|
||||
<p><span class="bold">6.4 第三方权益:</span>您在使用本服务时,应尊重第三方的知识产权及其他合法权益。因您侵犯第三方权益而引发的纠纷,由您自行承担全部责任。</p>
|
||||
|
||||
<h2>七、隐私保护</h2>
|
||||
<p><span class="bold">7.1 信息收集:</span>为提供本服务,运营者可能会收集您的注册信息(如手机号、用户名)、设备信息、使用日志等。具体的个人信息收集和使用规则请参阅《隐私政策》。</p>
|
||||
<p><span class="bold">7.2 信息保护:</span>运营者将采取合理的技术和管理措施保护您的个人信息安全。但由于互联网的开放性,运营者不能绝对保证信息安全,请您注意保护个人敏感信息。</p>
|
||||
<p class="bold">7.3 信息安全提示:请勿在使用本服务过程中向AI透露您的财产账户、银行卡、密码等敏感个人信息,否则由此带来的损失由您自行承担。</p>
|
||||
|
||||
<h2>八、免责声明</h2>
|
||||
<p class="bold">8.1 AI生成内容:本服务依赖第三方AI模型提供智能交互能力,AI生成的内容可能存在不准确、不完整或不恰当之处。运营者不对AI生成内容的真实性、准确性、完整性作任何保证。</p>
|
||||
<p class="bold">8.2 服务中断:因以下原因导致服务中断或异常,运营者不承担责任:</p>
|
||||
<p>(1)不可抗力因素,如自然灾害、疫情、战争等。</p>
|
||||
<p>(2)电力供应故障、通信网络故障等公共服务因素。</p>
|
||||
<p>(3)第三方AI模型服务商的服务故障或政策调整。</p>
|
||||
<p>(4)系统维护、升级导致的临时性服务中断。</p>
|
||||
<p>(5)黑客攻击、计算机病毒等网络安全事件。</p>
|
||||
<p>(6)法律法规或政府管制导致的服务调整。</p>
|
||||
<p>(7)其他非运营者过错导致的情形。</p>
|
||||
<p><span class="bold">8.3
|
||||
第三方服务:</span>本服务可能涉及第三方提供的语言模型、语音识别、语音合成、视觉模型、意图识别等服务。您在使用时应同时遵守第三方的服务条款。因第三方服务引发的问题,请直接与第三方联系。</p>
|
||||
<p class="bold">8.4 开源声明:本服务为开源项目,按"现状"提供。在法律允许的最大范围内,运营者不就本服务的适销性、特定用途适用性或不侵权性作任何明示或暗示的保证。</p>
|
||||
<p class="bold">8.5
|
||||
开源软件特别声明:本项目为开源软件,本服务与对接的任何第三方API服务商(包括但不限于语音识别、大模型、语音合成等平台)均不存在商业合作关系,不为其服务质量及资金安全提供任何形式的担保。本软件不托管任何账户密钥、不参与资金流转、不承担充值资金损失风险。
|
||||
</p>
|
||||
<p class="bold">8.6
|
||||
安全警告:本项目功能未完善,且未通过网络安全测评,请勿在生产环境中使用。如果您在公网环境中部署学习本项目,请务必做好必要的防护措施,包括但不限于设置强密码、限制访问权限、启用HTTPS加密传输等。</p>
|
||||
|
||||
<h2>九、未成年人保护</h2>
|
||||
<p>9.1 若您是未满18周岁的未成年人,应在监护人的指导和同意下使用本服务。</p>
|
||||
<p>9.2 监护人应加强对未成年人使用本服务的监督,引导未成年人合理使用,避免过度依赖。</p>
|
||||
<p>9.3 未成年人在使用本服务时应注意个人信息保护,避免上传或透露个人敏感信息。</p>
|
||||
|
||||
<h2>十、协议终止</h2>
|
||||
<p><span class="bold">10.1 用户终止:</span>您有权随时停止使用本服务并注销账号。</p>
|
||||
<p><span class="bold">10.2 运营者终止:</span>出现以下情形时,运营者有权终止向您提供服务:</p>
|
||||
<p>(1)您违反本协议的约定。</p>
|
||||
<p>(2)您利用本服务从事违法违规活动。</p>
|
||||
<p>(3)根据法律法规或政策要求。</p>
|
||||
<p>(4)运营者决定停止运营本服务。</p>
|
||||
<p><span class="bold">10.3 终止后处理:</span>协议终止后,运营者无义务保留您的账号信息及相关数据。运营者仍有权依据本协议追究您在协议有效期内的违约责任。</p>
|
||||
|
||||
<h2>十一、法律适用与争议解决</h2>
|
||||
<p>11.1 本协议的订立、生效、解释、修订、终止及争议解决均适用中华人民共和国法律。</p>
|
||||
<p>11.2 因本协议或本服务引发的争议,双方应友好协商解决;协商不成的,任何一方有权向运营者所在地有管辖权的人民法院提起诉讼。</p>
|
||||
<p>11.3 本协议的任何条款被认定为无效或不可执行,不影响其余条款的效力。</p>
|
||||
|
||||
<h2>十二、其他</h2>
|
||||
<p>12.1 本协议构成您与运营者之间关于使用本服务的完整协议。</p>
|
||||
<p>12.2 运营者未行使或延迟行使本协议项下的任何权利,不构成对该权利的放弃。</p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -136,11 +136,11 @@
|
||||
</div>
|
||||
<div style="font-size: 14px; color: #979db1">
|
||||
{{ $t("login.agreeTo") }}
|
||||
<div style="display: inline-block; color: #5778ff; cursor: pointer">
|
||||
<div style="display: inline-block; color: #5778ff; cursor: pointer" @click="openPage('/user-agreement.html')">
|
||||
{{ $t("login.userAgreement") }}
|
||||
</div>
|
||||
{{ $t("login.and") }}
|
||||
<div style="display: inline-block; color: #5778ff; cursor: pointer">
|
||||
<div style="display: inline-block; color: #5778ff; cursor: pointer" @click="openPage('/privacy-policy.html')">
|
||||
{{ $t("login.privacyPolicy") }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -248,6 +248,13 @@ export default {
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
openPage(url) {
|
||||
const lang = this.$i18n ? this.$i18n.locale : 'zh_CN';
|
||||
if (!lang.startsWith('zh')) {
|
||||
url = url.replace('.html', '-en.html');
|
||||
}
|
||||
window.open(url, '_blank');
|
||||
},
|
||||
fetchCaptcha() {
|
||||
if (this.$store.getters.getToken) {
|
||||
if (this.$route.path !== "/home") {
|
||||
|
||||
@@ -107,9 +107,9 @@
|
||||
<!-- 保持相同的协议声明 -->
|
||||
<div style="font-size: 14px;color: #979db1;">
|
||||
{{ $t('register.agreeTo') }}
|
||||
<div style="display: inline-block;color: #5778FF;cursor: pointer;">{{ $t('register.userAgreement') }}</div>
|
||||
<div style="display: inline-block;color: #5778FF;cursor: pointer;" @click="openPage('/user-agreement.html')">{{ $t('register.userAgreement') }}</div>
|
||||
{{ $t('login.and') }}
|
||||
<div style="display: inline-block;color: #5778FF;cursor: pointer;">{{ $t('register.privacyPolicy') }}</div>
|
||||
<div style="display: inline-block;color: #5778FF;cursor: pointer;" @click="openPage('/privacy-policy.html')">{{ $t('register.privacyPolicy') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-main>
|
||||
@@ -198,6 +198,13 @@ export default {
|
||||
this.fetchCaptcha();
|
||||
},
|
||||
methods: {
|
||||
openPage(url) {
|
||||
const lang = this.$i18n ? this.$i18n.locale : 'zh_CN';
|
||||
if (!lang.startsWith('zh')) {
|
||||
url = url.replace('.html', '-en.html');
|
||||
}
|
||||
window.open(url, '_blank');
|
||||
},
|
||||
// 复用验证码获取方法
|
||||
fetchCaptcha() {
|
||||
this.form.captchaId = getUUID();
|
||||
|
||||
@@ -82,9 +82,9 @@
|
||||
<!-- 保持相同的协议声明 -->
|
||||
<div style="font-size: 14px;color: #979db1;">
|
||||
{{ $t('retrievePassword.agreeTo') }}
|
||||
<div style="display: inline-block;color: #5778FF;cursor: pointer;">{{ $t('register.userAgreement') }}</div>
|
||||
<div style="display: inline-block;color: #5778FF;cursor: pointer;" @click="openPage('/user-agreement.html')">{{ $t('register.userAgreement') }}</div>
|
||||
{{ $t('login.and') }}
|
||||
<div style="display: inline-block;color: #5778FF;cursor: pointer;">{{ $t('register.privacyPolicy') }}</div>
|
||||
<div style="display: inline-block;color: #5778FF;cursor: pointer;" @click="openPage('/privacy-policy.html')">{{ $t('register.privacyPolicy') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -167,6 +167,13 @@ export default {
|
||||
this.fetchCaptcha();
|
||||
},
|
||||
methods: {
|
||||
openPage(url) {
|
||||
const lang = this.$i18n ? this.$i18n.locale : 'zh_CN';
|
||||
if (!lang.startsWith('zh')) {
|
||||
url = url.replace('.html', '-en.html');
|
||||
}
|
||||
window.open(url, '_blank');
|
||||
},
|
||||
// 复用验证码获取方法
|
||||
fetchCaptcha() {
|
||||
this.form.captchaId = getUUID();
|
||||
|
||||
Reference in New Issue
Block a user