Skip to content

文档管理 ​

当前文档入口会按账号及知识库检查访问权限。文件检测策略与支持格式见29,分段确认必须回传解析文件 ID。下文接口分析保留作流程参考。

功能概述 ​

文档管理 功能包括以下主要操作:

  1. 获取文档列表:根据数据集 ID 获取分页文档列表。
  2. 获取单个文档详情:根据数据集 ID 和文档 ID 获取特定文档的详细信息。
  3. 获取所有文档:根据数据集 ID 获取该数据集下的所有文档。

接口实现 ​

我们提供了三个主要的 API 接口来支持文档管理功能:

  1. 获取文档列表
  2. 获取单个文档详情
  3. 获取所有文档

1. 获取文档列表 ​

请求

http
GET http://localhost:3000/api/dataset/{datasetId}/document/{pageNo}/{pageSize}
  • 路径参数:
    • datasetId:数据集的唯一标识。
    • pageNo:当前页码。
    • pageSize:每页显示的文档数量。

示例请求

http
GET http://localhost:3000/api/dataset/443309276048408576/document/1/10

响应

json
{
  "message": null,
  "data": {
    "size": 10,
    "total": 1,
    "current": 1,
    "records": [
      {
        "tenant_id": "0",
        "directly_return_similarity": 0.9,
        "creator": "",
        "is_active": true,
        "create_time": 1730853299657,
        "dataset_id": "443309276048408576",
        "title": null,
        "type": "pdf",
        "updater": "",
        "update_time": 1730853299657,
        "deleted": 0,
        "user_id": "1",
        "char_length": 22837,
        "meta": null,
        "file_id": "443431990348681216",
        "name": "ICS111_31391_Miller_Syllabus_F24.pdf",
        "paragraph_count": 6,
        "hit_handling_method": "optimization",
        "files": null,
        "id": "443662133182980096",
        "status": "2"
      }
    ]
  },
  "code": 200
}

响应字段说明

  • message:响应消息,成功时为 null。
  • data:响应数据对象。
    • size:每页文档数量。
    • total:总文档数。
    • current:当前页码。
    • records:文档列表数组,每个文档包含以下字段:
      • tenant_id:租户 ID。
      • directly_return_similarity:直接返回的相似度评分。
      • creator:文档创建者。
      • is_active:文档是否激活。
      • create_time:文档创建时间(时间戳)。
      • dataset_id:所属数据集 ID。
      • title:文档标题。
      • type:文档类型。上传文件时是文件后缀(如 pdf、docx),Web 站点抓取来的文档是 1。
      • updater:文档更新者。
      • update_time:文档更新时间(时间戳)。
      • deleted:删除标识(0 表示未删除)。
      • user_id:用户 ID。
      • char_length:文档字符长度。
      • meta:元数据。Web 站点文档里是 {"source_url":"...","selector":"..."},前端据此显示来源地址并触发同步。
      • file_id:文件 ID,Web 站点文档为 null。
      • name:文档名称。
      • paragraph_count:段落数量。
      • hit_handling_method:命中处理方法。
      • files:关联文件信息。
      • id:文档唯一标识。
      • status:文档状态,2 表示成功,3 表示失败;抓取失败的网页文档也会出现在列表里,便于重试。
  • code:响应状态码,200 表示成功。

2. 获取单个文档详情 ​

请求

http
GET http://localhost:3000/api/dataset/{datasetId}/document/{documentId}
  • 路径参数:
    • datasetId:数据集的唯一标识。
    • documentId:文档的唯一标识。

示例请求

http
GET http://localhost:3000/api/dataset/443309276048408576/document/1

响应

json
{
  "message": null,
  "data": {
    "tenant_id": "0",
    "directly_return_similarity": 0.9,
    "creator": "",
    "is_active": true,
    "create_time": 1730853299657,
    "dataset_id": "443309276048408576",
    "title": null,
    "type": "pdf",
    "url": null,
    "content": null,
    "updater": "",
    "update_time": 1730853299657,
    "deleted": 0,
    "user_id": "1",
    "char_length": 22837,
    "meta": null,
    "file_id": "443431990348681216",
    "name": "ICS111_31391_Miller_Syllabus_F24.pdf",
    "paragraph_count": 6,
    "hit_handling_method": "optimization",
    "files": null,
    "id": "443662133182980096",
    "status": "2"
  },
  "code": 200
}

响应字段说明

  • message:响应消息,成功时为 null。
  • data:文档详细信息对象,包含以下字段:
    • tenant_id:租户 ID。
    • directly_return_similarity:命中处理方式为直接返回时使用的相似度阈值。
    • creator:文档创建者。
    • is_active:文档是否参与检索。
    • create_time:文档创建时间(时间戳)。
    • dataset_id:所属知识库 ID。
    • title:文档标题。
    • type:文档类型,上传文件时是文件后缀,Web 站点抓取来的文档是 1。
    • updater:文档更新者。
    • update_time:文档更新时间(时间戳)。
    • deleted:删除标识(0 表示未删除)。
    • user_id:用户 ID。
    • char_length:文档字符长度。
    • meta:元数据。Web 站点文档里是 {"source_url":"...","selector":"..."},抓取来源见 爬取网页数据。
    • file_id:文件 ID,Web 站点文档为 null。
    • name:文档名称。
    • paragraph_count:段落数量。
    • hit_handling_method:命中处理方法。
    • files:关联文件信息。
    • id:文档唯一标识。
    • status:文档状态,2 表示成功,3 表示失败。
  • code:响应状态码,200 表示成功。

文档不存在或不属于当前账号时返回 {"code":400,"message":"文档不存在或无权访问"}。

3. 获取所有文档 ​

请求

http
GET http://localhost:3000/api/dataset/{datasetId}/document
  • 路径参数:
    • datasetId:数据集的唯一标识。

示例请求

http
GET http://localhost:3000/api/dataset/443309276048408576/document

响应

json
{
  "message": null,
  "data": [
    {
      "tenant_id": "0",
      "directly_return_similarity": 0.9,
      "creator": "",
      "is_active": true,
      "create_time": 1730853299657,
      "dataset_id": "443309276048408576",
      "title": null,
      "type": "pdf",
      "updater": "",
      "update_time": 1730853299657,
      "deleted": 0,
      "user_id": "1",
      "char_length": 22837,
      "meta": null,
      "file_id": "443431990348681216",
      "name": "ICS111_31391_Miller_Syllabus_F24.pdf",
      "paragraph_count": 6,
      "hit_handling_method": "optimization",
      "files": null,
      "id": "443662133182980096",
      "status": "1"
    }
  ],
  "code": 200
}

响应字段说明

  • message:响应消息,成功时为 null。
  • data:文档列表数组,每个文档包含以下字段:
    • tenant_id:租户 ID。
    • directly_return_similarity:直接返回的相似度评分。
    • creator:文档创建者。
    • is_active:文档是否激活。
    • create_time:文档创建时间(时间戳)。
    • dataset_id:所属数据集 ID。
    • title:文档标题。
    • type:文档类型(如 PDF)。
    • updater:文档更新者。
    • update_time:文档更新时间(时间戳)。
    • deleted:删除标识(0 表示未删除)。
    • user_id:用户 ID。
    • char_length:文档字符长度。
    • meta:元数据。
    • file_id:文件 ID。
    • name:文档名称。
    • paragraph_count:段落数量。
    • hit_handling_method:命中处理方法。
    • files:关联文件信息。
    • id:文档唯一标识。
    • status:文档状态。
  • code:响应状态码,200 表示成功。

代码实现 ​

以下是文档管理功能的核心代码实现,包括 API 控制器和服务层。

1. API 控制器 ​

文件:ApiDatasetController.java

java
import java.util.List;

import nexus.io.annotation.Get;
import nexus.io.annotation.RequestPath;
import nexus.io.jfinal.aop.Aop;
import nexus.io.mosskb.service.MossKbDocumentService;
import nexus.io.model.result.ResultVo;
import nexus.io.tio.boot.http.TioRequestContext;

@RequestPath("/api/dataset")
public class ApiDatasetController {

  /**
   * 获取指定数据集下的文档列表(分页)
   *
   * @param datasetId 数据集 ID
   * @param pageNo    当前页码
   * @param pageSize  每页文档数量
   * @return ResultVo 包含分页文档列表
   */
  @Get("/{datasetId}/document/{pageNo}/{pageSize}")
  public ResultVo pageDocument(Long datasetId, Integer pageNo, Integer pageSize) {
    // 获取当前用户 ID
    Long userId = TioRequestContext.getUserIdLong();
    // 调用文档服务获取分页文档列表
    return Aop.get(MossKbDocumentService.class).page(userId, datasetId, pageNo, pageSize);
  }

  /**
   * 获取指定数据集下的单个文档详情
   *
   * @param datasetId  数据集 ID
   * @param documentId 文档 ID
   * @return ResultVo 包含文档详细信息
   */
  @Get("/{datasetId}/document/{documentId}")
  public ResultVo getDocument(Long datasetId, Long documentId) {
    // 获取当前用户 ID
    Long userId = TioRequestContext.getUserIdLong();
    // 调用文档服务获取文档详情
    return Aop.get(MossKbDocumentService.class).get(userId, datasetId, documentId);
  }

  /**
   * 获取指定数据集下的所有文档
   *
   * @param datasetId 数据集 ID
   * @return ResultVo 包含文档列表
   */
  @Get("/{datasetId}/document")
  public ResultVo documentList(Long datasetId) {
    Long userId = TioRequestContext.getUserIdLong();
    return Aop.get(MossKbDocumentService.class).list(userId, datasetId);
  }
}

代码说明

  • 注解 @RequestPath("/api/dataset"):定义控制器的基础路径为 /api/dataset。
  • 方法 pageDocument:
    • 注解 @Get("/{datasetId}/document/{pageNo}/{pageSize}"):定义 GET 请求路径。
    • 参数:
      • datasetId:数据集 ID。
      • pageNo:当前页码。
      • pageSize:每页文档数量。
    • 功能:获取指定数据集下的分页文档列表。
  • 方法 getDocument:
    • 注解 @Get("/{datasetId}/document/{documentId}"):定义 GET 请求路径。
    • 参数:
      • datasetId:数据集 ID。
      • documentId:文档 ID。
    • 功能:获取指定数据集下的单个文档详情。
  • 方法 documentList:
    • 注解 @Get("/{datasetId}/document"):定义 GET 请求路径。
    • 参数:
      • datasetId:数据集 ID。
    • 功能:获取指定数据集下的所有文档列表。
  • 依赖注入:通过 Aop.get(MossKbDocumentService.class) 获取 MossKbDocumentService 服务实例。

2. 服务层 ​

文件:MossKbDocumentService.java

java
package nexus.io.mosskb.service;

import java.util.List;

import com.jfinal.kit.Kv;
import nexus.io.db.TableInput;
import nexus.io.db.TableResult;
import nexus.io.db.activerecord.Row;
import nexus.io.kit.RecordUtils;
import nexus.io.mosskb.constant.TableNames;
import nexus.io.mosskb.model.ResultPage;
import nexus.io.model.page.Page;
import nexus.io.model.result.ResultVo;
import nexus.io.table.services.ApiTable;

public class MossKbDocumentService {

  /**
   * 分页获取文档列表
   *
   * @param userId    当前用户 ID
   * @param datasetId 数据集 ID
   * @param pageNo    当前页码
   * @param pageSize  每页文档数量
   * @return ResultVo 包含分页文档列表
   */
  public ResultVo page(Long userId, Long datasetId, Integer pageNo, Integer pageSize) {
    TableInput tableInput = new TableInput();
    if (userId != 1) { // 假设 userId 为 1 的用户为管理员
      tableInput.set("user_id", userId);
    }
    tableInput.set("dataset_id", datasetId)
              .setPageNo(pageNo)
              .setPageSize(pageSize);

    TableResult<Page<Row>> tableResult = ApiTable.page(TableNames.moss_kb_document, tableInput);
    Page<Row> page = tableResult.getData();
    int totalRow = page.getTotalRow();
    List<Row> list = page.getList();

    List<Kv> kvs = RecordUtils.recordsToKv(list, false);
    ResultPage<Kv> resultPage = new ResultPage<>(pageNo, pageSize, totalRow, kvs);

    return ResultVo.ok(resultPage);
  }

  /**
   * 获取所有文档列表
   *
   * @param userId    当前用户 ID
   * @param datasetId 数据集 ID
   * @return ResultVo 包含文档列表
   */
  public ResultVo list(Long userId, Long datasetId) {
    TableInput tableInput = new TableInput();
    if (userId != 1) { // 假设 userId 为 1 的用户为管理员
      tableInput.set("user_id", userId);
    }
    tableInput.set("dataset_id", datasetId);

    TableResult<List<Row>> tableResult = ApiTable.list(TableNames.moss_kb_document, tableInput);
    List<Row> records = tableResult.getData();

    List<Kv> kvs = RecordUtils.recordsToKv(records, false);
    return ResultVo.ok(kvs);
  }

  /**
   * 获取单个文档详情
   *
   * @param userId     当前用户 ID
   * @param datasetId  数据集 ID
   * @param documentId 文档 ID
   * @return ResultVo 包含文档详细信息
   */
  public ResultVo get(Long userId, Long datasetId, Long documentId) {
    TableInput tableInput = TableInput.by("id", documentId);
    if (userId != 1) { // 非管理员用户需额外过滤
      tableInput.set("user_id", userId);
    }
    tableInput.set("dataset_id", datasetId);

    Row data = ApiTable.get(TableNames.moss_kb_document, tableInput).getData();
    if (data == null) {
      return ResultVo.error("文档未找到");
    }
    return ResultVo.ok(data.toKv());
  }
}

代码说明

  • 方法 page:
    • 参数:
      • userId:当前用户的 ID,用于权限控制。
      • datasetId:数据集 ID,用于过滤文档。
      • pageNo:当前页码。
      • pageSize:每页文档数量。
    • 功能:
      1. 创建 TableInput 对象,用于构建查询参数。
      2. 根据用户 ID 进行权限控制,如果用户不是管理员(假设 userId != 1),则仅查询该用户创建的文档。
      3. 设置数据集 ID、页码和页大小。
      4. 调用 ApiTable.page 方法执行分页查询,获取 TableResult。
      5. 从 TableResult 中提取 Page<Row> 对象,获取总行数和记录列表。
      6. 将记录列表转换为键值对列表 (List<Kv>)。
      7. 构建 ResultPage<Kv> 对象,包含分页信息和文档列表。
      8. 返回成功的 ResultVo 对象,包含 ResultPage 数据。
  • 方法 list:
    • 参数:
      • userId:当前用户的 ID,用于权限控制。
      • datasetId:数据集 ID,用于过滤文档。
    • 功能:
      1. 创建 TableInput 对象,用于构建查询参数。
      2. 根据用户 ID 进行权限控制,如果用户不是管理员,则仅查询该用户创建的文档。
      3. 设置数据集 ID。
      4. 调用 ApiTable.list 方法获取文档列表。
      5. 将记录列表转换为键值对列表 (List<Kv>)。
      6. 返回成功的 ResultVo 对象,包含文档列表数据。
  • 方法 get:
    • 参数:
      • userId:当前用户的 ID,用于权限控制。
      • datasetId:数据集 ID,用于过滤文档。
      • documentId:文档 ID,用于查询特定文档。
    • 功能:
      1. 创建 TableInput 对象,并设置文档 ID 作为查询条件。
      2. 根据用户 ID 进行权限控制:
        • 如果用户是管理员 (userId == 1),则仅根据数据集 ID 过滤。
        • 否则,增加用户 ID 过滤,确保用户只能访问自己的文档。
      3. 调用 ApiTable.get 方法获取单条记录 (Row)。
      4. 检查记录是否存在,若不存在则返回错误信息。
      5. 将 Row 转换为键值对 (Kv)。
      6. 返回成功的 ResultVo 对象,包含文档详细信息。
  • 依赖组件:
    • ApiTable:用于执行数据库表的分页查询和单条记录查询。
    • RecordUtils:用于将数据库记录转换为键值对格式。
    • ResultVo 和 ResultPage:用于标准化 API 响应结构。

权限控制 ​

在上述实现中,我们假设 userId 为 1 的用户为管理员,具有查看所有数据集和文档的权限。非管理员用户只能查看自己创建的数据集和文档。这种权限控制确保了数据的安全性和隐私性。

异常处理 ​

当前实现未详细展示异常处理逻辑。建议在实际开发中加入以下内容:

  1. 参数校验:确保请求参数的有效性,如 datasetId 和 documentId 的存在性、pageNo 和 pageSize 的合理性。
  2. 权限验证:在服务层进一步验证用户是否有权访问指定的数据集和文档。
  3. 错误响应:在发生异常时,返回适当的错误消息和状态码,如 400 Bad Request、401 Unauthorized、404 Not Found 等。

测试 ​

为了确保文档管理功能的正确性和稳定性,建议编写以下测试用例:

  1. 获取文档列表:
    • 查询存在的数据集,验证返回的文档列表是否正确。
    • 查询不存在的数据集,验证返回的错误信息。
    • 测试不同的 pageNo 和 pageSize 参数,确保分页逻辑正确。
  2. 获取单个文档详情:
    • 查询存在的文档,验证返回的文档详细信息是否正确。
    • 查询不存在的文档,验证返回的错误信息。
    • 验证权限控制,确保用户无法访问未授权的文档。
  3. 获取所有文档:
    • 查询存在的数据集,验证返回的所有文档列表是否正确。
    • 查询不存在的数据集,验证返回的错误信息。
    • 验证权限控制,确保用户只能获取自己有权限查看的文档。

总结 ​

通过上述接口和代码实现,我们成功地为系统添加了文档管理功能。该功能允许用户根据数据集管理和检索文档,支持分页查询、详细信息查看以及获取所有文档。未来,可以进一步扩展此功能,如添加文档上传、编辑、删除等操作,以满足更全面的文档管理需求。

MIT Licensed