文档管理
当前文档入口会按账号及知识库检查访问权限。文件检测策略与支持格式见29,分段确认必须回传解析文件 ID。下文接口分析保留作流程参考。
功能概述
文档管理 功能包括以下主要操作:
- 获取文档列表:根据数据集 ID 获取分页文档列表。
- 获取单个文档详情:根据数据集 ID 和文档 ID 获取特定文档的详细信息。
- 获取所有文档:根据数据集 ID 获取该数据集下的所有文档。
接口实现
我们提供了三个主要的 API 接口来支持文档管理功能:
- 获取文档列表
- 获取单个文档详情
- 获取所有文档
1. 获取文档列表
请求
GET http://localhost:3000/api/dataset/{datasetId}/document/{pageNo}/{pageSize}
- 路径参数:
datasetId:数据集的唯一标识。pageNo:当前页码。pageSize:每页显示的文档数量。
示例请求
GET http://localhost:3000/api/dataset/443309276048408576/document/1/10
响应
{
"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. 获取单个文档详情
请求
GET http://localhost:3000/api/dataset/{datasetId}/document/{documentId}
- 路径参数:
datasetId:数据集的唯一标识。documentId:文档的唯一标识。
示例请求
GET http://localhost:3000/api/dataset/443309276048408576/document/1
响应
{
"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. 获取所有文档
请求
GET http://localhost:3000/api/dataset/{datasetId}/document
- 路径参数:
datasetId:数据集的唯一标识。
示例请求
GET http://localhost:3000/api/dataset/443309276048408576/document
响应
{
"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
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
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:每页文档数量。
- 功能:
- 创建
TableInput对象,用于构建查询参数。 - 根据用户 ID 进行权限控制,如果用户不是管理员(假设
userId != 1),则仅查询该用户创建的文档。 - 设置数据集 ID、页码和页大小。
- 调用
ApiTable.page方法执行分页查询,获取TableResult。 - 从
TableResult中提取Page<Row>对象,获取总行数和记录列表。 - 将记录列表转换为键值对列表 (
List<Kv>)。 - 构建
ResultPage<Kv>对象,包含分页信息和文档列表。 - 返回成功的
ResultVo对象,包含ResultPage数据。
- 创建
- 参数:
- 方法
list:- 参数:
userId:当前用户的 ID,用于权限控制。datasetId:数据集 ID,用于过滤文档。
- 功能:
- 创建
TableInput对象,用于构建查询参数。 - 根据用户 ID 进行权限控制,如果用户不是管理员,则仅查询该用户创建的文档。
- 设置数据集 ID。
- 调用
ApiTable.list方法获取文档列表。 - 将记录列表转换为键值对列表 (
List<Kv>)。 - 返回成功的
ResultVo对象,包含文档列表数据。
- 创建
- 参数:
- 方法
get:- 参数:
userId:当前用户的 ID,用于权限控制。datasetId:数据集 ID,用于过滤文档。documentId:文档 ID,用于查询特定文档。
- 功能:
- 创建
TableInput对象,并设置文档 ID 作为查询条件。 - 根据用户 ID 进行权限控制:
- 如果用户是管理员 (
userId == 1),则仅根据数据集 ID 过滤。 - 否则,增加用户 ID 过滤,确保用户只能访问自己的文档。
- 如果用户是管理员 (
- 调用
ApiTable.get方法获取单条记录 (Row)。 - 检查记录是否存在,若不存在则返回错误信息。
- 将
Row转换为键值对 (Kv)。 - 返回成功的
ResultVo对象,包含文档详细信息。
- 创建
- 参数:
- 依赖组件:
ApiTable:用于执行数据库表的分页查询和单条记录查询。RecordUtils:用于将数据库记录转换为键值对格式。ResultVo和ResultPage:用于标准化 API 响应结构。
权限控制
在上述实现中,我们假设 userId 为 1 的用户为管理员,具有查看所有数据集和文档的权限。非管理员用户只能查看自己创建的数据集和文档。这种权限控制确保了数据的安全性和隐私性。
异常处理
当前实现未详细展示异常处理逻辑。建议在实际开发中加入以下内容:
- 参数校验:确保请求参数的有效性,如
datasetId和documentId的存在性、pageNo和pageSize的合理性。 - 权限验证:在服务层进一步验证用户是否有权访问指定的数据集和文档。
- 错误响应:在发生异常时,返回适当的错误消息和状态码,如
400 Bad Request、401 Unauthorized、404 Not Found等。
测试
为了确保文档管理功能的正确性和稳定性,建议编写以下测试用例:
- 获取文档列表:
- 查询存在的数据集,验证返回的文档列表是否正确。
- 查询不存在的数据集,验证返回的错误信息。
- 测试不同的
pageNo和pageSize参数,确保分页逻辑正确。
- 获取单个文档详情:
- 查询存在的文档,验证返回的文档详细信息是否正确。
- 查询不存在的文档,验证返回的错误信息。
- 验证权限控制,确保用户无法访问未授权的文档。
- 获取所有文档:
- 查询存在的数据集,验证返回的所有文档列表是否正确。
- 查询不存在的数据集,验证返回的错误信息。
- 验证权限控制,确保用户只能获取自己有权限查看的文档。
总结
通过上述接口和代码实现,我们成功地为系统添加了文档管理功能。该功能允许用户根据数据集管理和检索文档,支持分页查询、详细信息查看以及获取所有文档。未来,可以进一步扩展此功能,如添加文档上传、编辑、删除等操作,以满足更全面的文档管理需求。
