Files
leaudit-platform-frontend/docs/合同文档上传与接口说明.md
T

358 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 合同文档上传与接口说明(v2
本文档详细说明 DocAuditAI 中与“合同文档上传”相关的 API 接口、参数、请求示例、响应示例以及后端处理流程。路径均以后端实际路由挂载为准:所有业务接口统一前缀为 `/admin`,本文档涉及的文档管理接口统一前缀为 `/admin/documents`
---
### 鉴权与基础信息
- **基础前缀**: `/admin/documents`
- **认证方式**:
- 推荐:`Authorization: Bearer <JWT>`(后端中间件会将用户信息注入 `req.state.current_user`
- 参考文档:`docs/接口认证方式统一说明.md`
- **存储后端**: MinIO(参考 `core/storage/minio_client.py``core/config.py` 中的 `MINIO_CONFIG`
- **异步任务**: Celery,队列名称默认为 `f"{REDIS_KEY_PREFIX}_tasks"`
---
### 文档类型枚举(后端基准)
来自 `core/utils/enums.py`
- `1` 合同文档(代码: HT,完整中文: 合同文档)
- `2` 行政许可决定书(代码: XZXK,完整中文: 行政许可决定书)
- `3` 行政处罚决定书(代码: XZCF,完整中文: 行政处罚决定书)
- `4` 合同对比模板(代码: HTMB,完整中文: 合同对比模板)
- `99` 其他文档(代码: QT,完整中文: 其他文档)
> 说明:客户端在 `upload_info` 中通常只需要传 `type_id`,后端会基于枚举推导短代码与中文全称。
---
## 接口清单
#### 1) 上传通用文档(支持合同/许可/处罚/其他)
- 方法与路径: `POST /admin/documents/upload`
- 表单参数:
- `file`: 文件(支持 PDF、Word.doc/.docx 会自动转换为 PDF
- `upload_info`: JSON 字符串,示例:
```json
{
"type_id": 1,
"document_number": "HT_20250111_120000_001",
"is_test_document": true,
"remark": "示例备注",
"evaluation_level": "普通"
}
```
- cURL 示例:
```bash
curl -X POST "http://127.0.0.1:8008/admin/documents/upload" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-F "file=@./samples/contract.pdf" \
-F 'upload_info={"type_id":1,"remark":"示例备注","evaluation_level":"普通"}'
```
- JavaScript fetch 示例:
```javascript
const form = new FormData();
form.append('file', fileInput.files[0]);
form.append('upload_info', JSON.stringify({ type_id: 1, remark: '示例备注' }));
const res = await fetch('/admin/documents/upload', {
method: 'POST',
headers: { Authorization: 'Bearer ' + token },
body: form
});
const data = await res.json();
```
- 响应示例:
```json
{
"success": true,
"result": {
"id": 123,
"file_name": "contract.pdf",
"file_size": 1024000,
"file_url": "https://minio.example.com/bucket/documents/...",
"type_id": 1,
"type_description": "HT",
"type_full_description": "合同文档",
"document_number": "HT_20250111_120000_001",
"storage_type": "minio",
"background_processing": true,
"api_version": "v2",
"is_test_document": true,
"remark": "示例备注",
"evaluation_level": "普通"
}
}
```
> 说明:合同(type_id=1)、许可(2)、处罚(3)会自动投递 Celery 任务进行 OCR/抽取/评查。
---
#### 2) 上传合同模板(用于与合同文档结构对比)
- 方法与路径: `POST /admin/documents/upload_contract_template`
- 表单参数:
- `file`: 模板 PDF/WordWord将自动转PDF
- `upload_info`: JSON 字符串,字段:
- `document_id`(必填):源合同文档ID
- `comparison_id`(可选):已有对比记录ID,未提供将自动创建
- cURL 示例:
```bash
curl -X POST "http://127.0.0.1:8008/admin/documents/upload_contract_template" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-F "file=@./samples/contract_template.pdf" \
-F 'upload_info={"document_id":123}'
```
- 响应示例:
```json
{
"success": true,
"result": {
"id": 456, // comparison_id(新建或传入)
"document_id": 789, // 模板对应的新建文档ID
"file_name": "contract_template.pdf",
"file_size": 204800,
"file_url": "https://minio.example.com/...",
"template_path": "documents/.../contract_template.pdf",
"template_contract_name": "contract_template.pdf",
"status": "Waiting",
"api_version": "v2"
}
}
```
---
#### 3) 合同文档追加附件并合并
- 方法与路径: `POST /admin/documents/contracts/{document_id}/append_attachments`
- 路径参数:
- `document_id`: 合同文档IDtype_id 必须为 1
- 表单参数:
- `files`: 多个附件(支持 PDF、Word(doc/docx)、ZIP、RARZIP/RAR 内仅合并其中的 PDF
- `merge_mode`: `overwrite`(默认,覆盖原文档路径)或 `new`(新建一条文档记录)
- `is_reprocess`: 是否触发 OCR/抽取/评查(默认 true)
- `remark`: 备注
- cURL 示例(支持压缩包作为附件来源):
```bash
curl -X POST "http://127.0.0.1:8008/admin/documents/contracts/123/append_attachments" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-F "files=@./samples/appendix1.pdf" \
-F "files=@./samples/attachments.zip" \
-F "merge_mode=overwrite" -F "is_reprocess=true" -F "remark=附加材料"
```
- 响应示例(new 模式):
```json
{
"success": true,
"result": {
"id": 901, // 新文档ID
"file_name": "contract_merged_20250111123000.pdf",
"file_size": 512000,
"file_url": "https://minio.example.com/...",
"type_id": 1,
"document_number": "HT_20250111_...",
"storage_type": "minio",
"is_merged": true,
"attachments_count": 2,
"merge_mode": "new",
"background_processing": true,
"api_version": "v2"
}
}
```
---
#### 4) 合同模板记录追加附件并合并
- 方法与路径: `POST /admin/documents/contract_templates/{comparison_id}/append_attachments`
- 路径参数:
- `comparison_id`: 合同结构对比记录ID
- 表单参数:
- `files`: 多个 PDF 附件
- `is_reprocess`: 是否触发模板 OCR 与对比(默认 true)
- `remark`: 备注
- cURL 示例:
```bash
curl -X POST "http://127.0.0.1:8008/admin/documents/contract_templates/456/append_attachments" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-F "files=@./samples/template_appendix.pdf" \
-F "is_reprocess=true" -F "remark=补充分条款"
```
- 响应示例:
```json
{
"success": true,
"result": {
"id": 456,
"document_id": 790, // 新模板文档ID
"file_name": "template_merged_20250111123500.pdf",
"file_size": 256000,
"file_url": "https://minio.example.com/...",
"template_path": "documents/.../template_merged_20250111123500.pdf",
"status": "Waiting",
"api_version": "v2",
"is_merged": true,
"attachments_count": 1
}
}
```
---
#### 5) 一体化:上传并分配交叉评查任务(支持单 PDF 或压缩包)
- 方法与路径: `POST /admin/documents/cross_review/documents/upload_and_assign`
- 表单参数:
- `file`: 单个 PDF、Word 或压缩包(zip/rar/7z/tar
- `upload_info`: JSON 字符串(至少包含 `type_id`
- `assign_user_ids`: JSON 数组字符串(如 `[1,2,3]`
- cURL 示例(批量:zip 内多个 PDF 将逐个入库并触发处理):
```bash
curl -X POST "/admin/documents/cross_review/documents/upload_and_assign" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
-F "file=@./samples/contracts.zip" \
-F 'upload_info={"type_id":1,"task_name":"自动分配任务","doc_type":"合同文档"}' \
-F 'assign_user_ids=[1,2,3]'
```
- 响应示例(压缩包):
```json
{
"success": true,
"message": "已处理3个PDF。",
"pdf_files": ["a.pdf","b.pdf","c.pdf"],
"results": [ {"success": true, "document_id": 101, ... }, ... ],
"assigned_users": { "result": { /* 任务分配详情 */ } }
}
```
---
#### 6) 获取文档列表(按用户权限过滤)
- 方法与路径: `GET /admin/documents/list`
- 查询参数:
- `page`(默认 1)、`page_size`(默认 20,最大 100
- `search`(可选,模糊匹配 name 或 document_number
- `type_id`(可选)、`status`(可选)
- 认证后端会基于 `req.state.current_user.user_id` 过滤用户可见文档
- cURL 示例:
```bash
curl -G "/admin/documents/list" \
-H "Authorization: Bearer <YOUR_TOKEN>" \
--data-urlencode "page=1" \
--data-urlencode "page_size=20" \
--data-urlencode "search=合同"
```
- 响应示例:
```json
{
"total": 42,
"items": [
{
"id": 123,
"name": "contract.pdf",
"document_number": "HT_20250111_120000_001",
"type_id": 1,
"status": "Processed",
"upload_time": "2025-01-11T12:01:02",
"created_at": "2025-01-11T12:00:00",
"updated_at": "2025-01-11T12:10:00"
}
],
"page": 1,
"page_size": 20
}
```
---
## 处理流程说明(后端链路)
> 关键实现文件:`app/routes/v2/documents/documents.py`
1. 校验与预处理
- 校验文件大小(`MAX_FILE_SIZE`)与类型
- Word 自动转换为 PDF`core/utils/office_convert.ensure_pdf_from_upload`
- 生成安全文件名
2. 生成存储路径并上传 MinIO
- 路径规则:`documents/{INSTANCE_NAME}/{中文类型}/{YYYY}/{MM月DD日}/{文件名_时分秒}/{文件名}`
- 上传后得到 `storage_path` 与 `file_url`
3. 写入数据库(PostgREST
- 组装文档数据(含 `user_id`、`file_size`、`remark` 等)
- `document_service.async_insert_document` 入库,返回文档ID
4. 追加合并详细逻辑(仅合同附件追加支持压缩包)
- 入口:`POST /admin/documents/contracts/{document_id}/append_attachments`
- 校验:`document_id` 必须为合同文档(type_id=1),否则返回错误
- 下载原 PDF:从 MinIO 将原文档 `path` 下载到本地临时文件
- 处理附件输入:
- 支持的外层类型:`.pdf`、`.doc`、`.docx`、`.zip`、`.rar`
- 当为 PDF:直接保存到临时目录,加入合并列表
- 当为 Word.doc/.docx):先转换为 PDF(同单文件上传逻辑),再加入合并列表
- 当为 ZIP/RAR:先落地为临时压缩包,再调用 `document_upload_service.extract_archive` 解压,仅收集其中的 PDF 路径加入合并列表
- 对于其他类型:返回错误(仅支持 PDF/ZIP/RAR/Word
- 若最终未收集到任何 PDF:返回错误
- 合并顺序:始终使用【原PDF】+【附件PDF列表】顺序,调用 `merge_pdfs` 生成合并结果临时文件
- 目标路径:沿用原 `path` 的父目录,文件名追加 `_merged_{时间戳}.pdf`
- 入库与更新:
- `merge_mode=overwrite`(默认):更新原文档 `path/name/file_size/status=Waiting/remark`
- `merge_mode=new`:调用文档写入流程新建记录,并带上 `remark`
- 触发处理:当 `is_reprocess=true` 时,读入合并后的字节内容,调用 `_submit_ocr_task_v2` 投递后续 OCR/抽取/评查
- 返回:新/原文档标识、URL、大小、是否合并、附件数量、`merge_mode` 等
5. 投递异步任务(Celery
- 合同(1):`process_contract_ocr`
- 行政许可(2)、行政处罚(3):`process_document_ocr_v2`
- 合同模板(4):`process_contract_template_ocr`
- 队列:`{REDIS_KEY_PREFIX}_tasks`,默认过期 24htime_limit 600s
6. 后处理与状态更新
- OCR完成后按需进入抽取与评查
- 文档状态:`Cutting`/`Extractioning`/`Evaluationing`/`Processed`/`Failed`
---
## 错误处理与返回
- 统一响应模型:
- 成功:`{"success": true, "result": { ... }}`
- 失败:`{"success": false, "error": "错误消息"}`
- 常见错误:
- `400``upload_info` 非法、文件为空或类型不支持
- `413`:文件过大(超过 `MAX_FILE_SIZE`
- `500`:存储/数据库/任务投递异常
---
## 使用建议与注意事项
- 合同类建议始终以 PDF 上传,可减少转换耗时与兼容性问题
- 压缩包仅支持解出 PDF 后逐一入库与处理(zip/rar/7z/tar
- 建议合理设置 `remark` 与 `evaluation_level` 便于后续筛选
- 若需追踪异步任务状态,请结合 Flower 与后端日志(`logs/`
---
## 变更记录
- 2025-09-11:首版编制,依据 `app/routes/v2/documents/documents.py` 与相关服务模块撰写