Files
Fairscan_cyy/requirements/pc-api-spec.md
MobKBK 1848a88fcf
Some checks failed
Android CI / build (push) Has been cancelled
初步完成框架
- 实时图传:WebSocket JPEG 帧发送 + 帧率控制 + PC 浏览器预览
- PDF 上传与处理:上传/处理分离,支持 ocrpdf 和 markdown 两种类型
- MinerU 真实接入:markdown 处理 + images ZIP 打包
- OCRmyPDF 接入:ocrpdf 生成可搜索双层 PDF
- 手机端任务管理面板:轮询状态 + SAF 目录选择下载
- PC 管理面板:/dashboard 文件与任务管理
- 网络层:OkHttp 客户端、WebSocket 图传、局域网发现占位

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-04 17:03:18 +08:00

790 lines
16 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.
# FairScan PC 端统一接口规范(草案 v0.1
> 本文档定义 FairScan 手机端与 PC 端之间的最小稳定接口契约。
>
> 适用对象:
>
> - 人工开发者
> - Claude Code
> - 其他 AI 编码代理
>
> 设计目标:
>
> - 让不同执行者都能按同一接口实现,不因上下文差异而跑偏
> - 优先稳定协议与字段,而不是优先绑定具体内部实现
> - 允许 PC 端先做“接口占位实现”,后续再逐步接入真实 MinerU / OCRmyPDF
---
## 1. 设计范围
本文档覆盖以下能力:
1. 局域网服务发现配套信息
2. 健康检查接口
3. 实时图传接口
4. PDF 上传接口
5. 统一处理任务接口
6. 任务状态查询接口
7. 处理产物查询接口
8. 处理产物下载接口
本文档**不**约束以下内容:
- PC 端内部具体使用什么库执行 MinerU
- PC 端内部具体使用什么方式调用 OCRmyPDF
- PC 端图传画面最终是显示在网页、桌面窗口还是其他 UI 中
- Android 端 UI 的具体布局样式
也就是说:
- **本文档约束的是“外部协议”**
- **不强制约束“内部实现”**
---
## 2. 核心原则
### 2.1 图传与文档处理解耦
- 实时图传只负责低延迟画面预览
- 正式文档处理只基于手机本地生成的 PDF
- 图传流不得直接作为 MinerU / OCRmyPDF 的正式输入
### 2.2 统一处理接口
PC 端后处理统一使用一套任务接口。
支持的处理类型:
- `markdown`
- `ocrpdf`
差异只体现在:
- `processType`
- 返回产物的 MIME 类型
### 2.3 手机主动下载结果
“PC 处理后结果回到手机”在工程上定义为:
- 手机查询任务状态
- 手机获取产物列表
- 手机主动下载产物
不要求 PC 主动回连手机进行推送。
### 2.4 允许占位实现
第一阶段允许 PC 端:
- 返回 mock 任务
- 返回 mock 产物
- 先不真正接入 MinerU / OCRmyPDF
只要对外接口契约稳定即可。
---
## 3. 术语定义
### 3.1 File
指手机上传到 PC 的原始 PDF 文件。
### 3.2 Task
指 PC 端异步处理任务。
### 3.3 Artifact
指任务完成后可下载的结果文件。
### 3.4 Primary Artifact
指该处理类型最核心的主产物:
- `markdown` -> `.md`
- `ocrpdf` -> `.pdf`
### 3.5 Auxiliary Artifact
指附加产物,例如:
- 资源图片
- 日志文件
- JSON 中间结果
- 识别报告
---
## 4. 协议总览
| 能力 | 方法 | 路径 | 说明 |
|---|---|---|---|
| 健康检查 | GET | `/health` | 检查服务可用性与能力 |
| 实时图传 | WS | `/stream` | 接收手机实时图像帧 |
| 上传 PDF | POST | `/upload/pdf` | 上传正式文档 PDF |
| 创建处理任务 | POST | `/tasks/process` | 发起统一处理任务 |
| 查询任务状态 | GET | `/tasks/{taskId}` | 查询任务执行状态 |
| 查询任务产物 | GET | `/tasks/{taskId}/artifacts` | 获取结果文件列表 |
| 下载产物 | GET | `/artifacts/{artifactId}/download` | 下载结果文件 |
| 下载原始文件 | GET | `/files/{fileId}/download` | 下载已上传的原始 PDF |
默认基础地址示例:
```text
http://{host}:{port}
```
例如:
```text
http://192.168.1.10:8080
```
---
## 5. 通用约定
### 5.1 编码与格式
- JSON 请求与响应统一使用 UTF-8
- 除下载接口外,默认返回 `application/json`
- 图传 WebSocket 使用二进制消息承载 JPEG 帧
### 5.2 ID 规则
以下字段都视为**不透明字符串**
- `fileId`
- `taskId`
- `artifactId`
客户端不得依赖这些 ID 的内部结构。
### 5.3 时间字段
如果服务返回时间字段,建议使用 RFC 3339 / ISO 8601例如
```text
2026-06-04T12:34:56Z
```
时间字段不是第一阶段强制要求,但如果提供,应统一格式。
### 5.4 状态枚举
任务状态建议使用以下枚举:
```text
queued
running
completed
failed
```
如后续需要,可扩展:
```text
canceled
```
### 5.5 错误返回格式
推荐所有错误统一返回:
```json
{
"error": {
"code": "INVALID_REQUEST",
"message": "processType is required"
}
}
```
推荐错误码:
- `INVALID_REQUEST`
- `UNSUPPORTED_PROCESS_TYPE`
- `FILE_NOT_FOUND`
- `TASK_NOT_FOUND`
- `ARTIFACT_NOT_FOUND`
- `PROCESSING_FAILED`
- `SERVICE_UNAVAILABLE`
### 5.6 版本兼容原则
- 第一阶段不强制引入 `/api/v1` 路径前缀
- 通过 `apiVersion` 字段表达协议版本
- 后续如需重大变更,再评估路径版本化
---
## 6. 局域网发现配套约定
### 6.1 mDNS 服务标识
- service type`_fairscan._tcp`
- service instance name`FairScan-PC-{deviceName}`
### 6.2 推荐 TXT Record 字段
- `name`:设备显示名
- `features``stream,upload,process,download`
- `apiVersion`:如 `1`
- `version`PC 服务版本
### 6.3 关于 `process` 能力
这里建议广播能力使用:
- `process`
而不是直接广播多个内部工具名。
原因:
- 发现层只需表达“能不能处理”
- 具体支持哪些 `processType`,可通过 `/health` 返回
- 这样后续新增其他处理器时不需要修改发现层语义
---
## 7. 健康检查接口
## 7.1 GET `/health`
### 作用
- 判断服务是否在线
- 返回最小能力信息
- 返回支持的处理类型
### 请求
无请求体。
### 成功响应示例
```json
{
"name": "FairScan-PC-Office",
"status": "ok",
"version": "0.1.0",
"apiVersion": "1",
"features": ["stream", "upload", "process", "download"],
"processTypes": ["markdown", "ocrpdf"]
}
```
### 字段说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `name` | string | 是 | 设备显示名 |
| `status` | string | 是 | 固定为 `ok` |
| `version` | string | 否 | PC 服务版本 |
| `apiVersion` | string | 是 | 接口版本 |
| `features` | string[] | 是 | 服务能力 |
| `processTypes` | string[] | 否 | 当前支持的处理类型 |
### 状态码
- `200 OK`
---
## 8. 实时图传接口
## 8.1 WS `/stream`
### 作用
接收手机端发送的实时画面帧。
### 连接方式
- 客户端发起 WebSocket 连接
- 连接成功后开始发送二进制帧
- 每条二进制消息代表**一张完整 JPEG 图像**
### 帧格式
- 二进制消息
- 内容JPEG 文件完整字节流
- 一条消息 = 一帧
### 服务端要求
- 服务端可只保留最新帧
- 服务端不要求逐帧确认
- 服务端允许丢弃旧帧以保证实时性
### 客户端要求
- 不得无限积压待发送帧
- 若上一帧尚未发完,允许直接丢弃当前帧
- 连接断开后由客户端自行决定是否重连
### 第一阶段最小可接受行为
- 服务端只需能接收 JPEG 帧并显示或缓存最新一帧
- 不要求复杂多端会话管理
- 不要求录像、回放、时间轴等高级功能
### 状态码
- WebSocket Upgrade 成功即视为可用
---
## 9. PDF 上传接口
## 9.1 POST `/upload/pdf`
### 作用
上传手机端正式生成的 PDF 文件。
### 请求类型
```text
multipart/form-data
```
### 表单字段
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `file` | file | 是 | PDF 文件 |
### 约束
- `file` 的 MIME 类型应为 `application/pdf`
- 服务端可根据需要限制上传大小
- 若文件过大,建议返回 `413 Payload Too Large`
### 成功响应示例
```json
{
"fileId": "file-123",
"fileName": "Scan 2026-06-04 12.34.56.pdf",
"mimeType": "application/pdf",
"sizeBytes": 1048576
}
```
### 字段说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `fileId` | string | 是 | 服务端文件标识 |
| `fileName` | string | 是 | 保存后的文件名 |
| `mimeType` | string | 是 | 固定为 `application/pdf` |
| `sizeBytes` | number | 是 | 文件字节大小 |
### 状态码
- `201 Created`
- `400 Bad Request`
- `413 Payload Too Large`
- `500 Internal Server Error`
---
## 10. 统一处理任务接口
## 10.1 POST `/tasks/process`
### 作用
使用统一接口发起后处理任务。
### 请求示例
```json
{
"fileId": "file-123",
"processType": "markdown",
"options": {}
}
```
### 请求字段说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `fileId` | string | 是 | 由上传接口返回的文件标识 |
| `processType` | string | 是 | `markdown``ocrpdf` |
| `options` | object | 否 | 预留扩展字段,首版可为空对象 |
### 处理类型定义
| `processType` | 含义 | 预期主产物 |
|---|---|---|
| `markdown` | 执行 Markdown 转换 | `text/markdown` |
| `ocrpdf` | 执行 OCR PDF 处理 | `application/pdf` |
### 成功响应示例
```json
{
"taskId": "task-123",
"status": "queued",
"processType": "markdown",
"fileId": "file-123"
}
```
### 状态码
- `202 Accepted`
- `400 Bad Request`
- `404 Not Found``fileId` 不存在)
- `422 Unprocessable Entity``processType` 不支持时可选)
- `500 Internal Server Error`
### 第一阶段占位实现要求
如果真实 MinerU / OCRmyPDF 尚未接入,允许这样实现:
- 接口正常收请求
- 正常返回 `taskId`
- 任务状态可直接从 `queued` -> `completed`
- 产物可先返回 mock 文件或占位文件
这样做的目标是:
- 先稳定客户端协议
- 先打通 Android 联调链路
- 后续再逐步替换成真实处理器
---
## 11. 查询任务状态接口
## 11.1 GET `/tasks/{taskId}`
### 作用
返回单个任务的当前状态。
### 成功响应示例
```json
{
"taskId": "task-123",
"status": "running",
"processType": "markdown",
"fileId": "file-123",
"progress": 50,
"message": "processing",
"artifactsAvailable": false
}
```
### 字段说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `taskId` | string | 是 | 任务标识 |
| `status` | string | 是 | `queued` / `running` / `completed` / `failed` |
| `processType` | string | 是 | 任务处理类型 |
| `fileId` | string | 是 | 输入文件标识 |
| `progress` | number | 否 | 建议 0~100 |
| `message` | string | 否 | 当前状态说明 |
| `artifactsAvailable` | boolean | 否 | 是否已有可下载产物 |
### 失败响应示例
```json
{
"error": {
"code": "TASK_NOT_FOUND",
"message": "task not found"
}
}
```
### 状态码
- `200 OK`
- `404 Not Found`
---
## 12. 查询任务产物接口
## 12.1 GET `/tasks/{taskId}/artifacts`
### 作用
列出某个任务已经生成的所有产物。
### 成功响应示例
#### Markdown 任务示例
```json
[
{
"artifactId": "artifact-1",
"fileName": "result.md",
"mimeType": "text/markdown",
"role": "primary",
"sizeBytes": 2048
}
]
```
#### OCR PDF 任务示例
```json
[
{
"artifactId": "artifact-2",
"fileName": "result.pdf",
"mimeType": "application/pdf",
"role": "primary",
"sizeBytes": 3145728
}
]
```
### 字段说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `artifactId` | string | 是 | 产物标识 |
| `fileName` | string | 是 | 文件名 |
| `mimeType` | string | 是 | MIME 类型 |
| `role` | string | 是 | `primary` / `auxiliary` / `log` |
| `sizeBytes` | number | 否 | 文件大小 |
### 约束
-`markdown`,应至少存在一个 `role=primary``mimeType=text/markdown` 的产物
-`ocrpdf`,应至少存在一个 `role=primary``mimeType=application/pdf` 的产物
### 状态码
- `200 OK`
- `404 Not Found`
---
## 13. 产物下载接口
## 13.1 GET `/artifacts/{artifactId}/download`
### 作用
下载指定产物文件。
### 响应
- 响应体为二进制文件流
- `Content-Type` 应与产物 `mimeType` 一致
- `Content-Disposition` 建议包含文件名
### 成功行为示例
- 下载 Markdown`Content-Type: text/markdown`
- 下载 OCR PDF`Content-Type: application/pdf`
### 状态码
- `200 OK`
- `404 Not Found`
---
## 14. 原始文件下载接口
## 14.1 GET `/files/{fileId}/download`
### 作用
下载已上传但尚未处理的原始 PDF 文件。
### 响应
- 响应体为二进制文件流
- `Content-Type: application/pdf`
- `Content-Disposition` 包含原始文件名
### 典型用途
- PC 管理面板中直接下载查看手机上传的原始 PDF
- 手机端重新获取已上传的文件
### 状态码
- `200 OK`
- `404 Not Found`(文件 ID 不存在或文件已从磁盘删除)
---
## 15. 两类处理任务的差异说明
## 15.1 `processType=markdown`
### 目标
把 PDF 处理为 Markdown 文档。
### 最低要求
- 至少返回一个 `.md` 主产物
### 可选附加产物
- 图片资源
- 日志
- JSON 中间结果
## 15.2 `processType=ocrpdf`
### 目标
把 PDF 处理为 OCR 后的可搜索 PDF。
### 最低要求
- 至少返回一个 `.pdf` 主产物
### 可选附加产物
- 日志
- 识别报告
---
## 16. 典型调用流程
## 16.1 实时图传流程
1. 手机发现并选择 PC 主机
2. 手机调用 `/health` 确认支持 `stream`
3. 手机建立 `WS /stream`
4. 手机按抽帧策略发送 JPEG 帧
5. PC 实时显示最新帧
## 16.2 文档处理流程
1. 手机本地生成 PDF
2. 手机 `POST /upload/pdf`
3. 手机获得 `fileId`
4. 手机 `POST /tasks/process`
5. 手机获得 `taskId`
6. 手机轮询 `GET /tasks/{taskId}`
7. 任务完成后,手机调用 `GET /tasks/{taskId}/artifacts`
8. 手机调用 `GET /artifacts/{artifactId}/download`
9. 手机保存、打开或分享结果
---
## 17. 第一阶段可接受的占位实现
如果当前目标只是让 Android 端和 PC 端先联调通,这一阶段允许:
### 17.1 `markdown` 占位实现
- 收到 `processType=markdown`
- 直接生成一个示例 `.md` 文件
- 任务短时间内进入 `completed`
### 17.2 `ocrpdf` 占位实现
- 收到 `processType=ocrpdf`
- 直接复制输入 PDF 为新文件,或生成一个占位 PDF
- 任务短时间内进入 `completed`
### 17.3 为什么允许这样做
这样可以先验证:
- 接口字段是否稳定
- Android 端状态流是否完整
- 下载逻辑是否可用
- 不同 `mimeType` 的本地处理是否正确
等这些都稳定后,再接入真实处理器更安全。
---
## 18. 对执行者的约束说明
本节适用于任何执行这份接口文档的人或 AI。
### 18.1 必须遵守的约束
- 不要为 `markdown``ocrpdf` 设计两套独立任务协议
- 不要让 Android 端依赖 PC 内部执行器实现细节
- 不要把图传流直接作为正式文档处理输入
- 不要把“结果回到手机”实现成 PC 主动推送手机的唯一方式
### 18.2 优先级建议
如果执行资源有限,优先实现:
1. `/health`
2. `/upload/pdf`
3. `/tasks/process`
4. `/tasks/{id}`
5. `/tasks/{id}/artifacts`
6. `/artifacts/{artifactId}/download`
7. `WS /stream`
说明:
- 如果当前主要目标是联调文档处理链路,可先暂缓图传 UI
- 如果当前主要目标是实时性验证,可先实现 `WS /stream`
- 但无论如何,统一处理接口契约应保持不变
---
## 19. 与 Android 端实现的对应关系
PC 接口与 Android 模块建议对应如下:
| PC 接口 | Android 模块 |
|---|---|
| `/health` | discovery / server endpoint |
| `WS /stream` | stream client |
| `/upload/pdf` | upload client |
| `/tasks/process` | task client |
| `/tasks/{id}` | task polling logic |
| `/tasks/{id}/artifacts` | artifact query logic |
| `/artifacts/{artifactId}/download` | artifact download client |
| `/files/{fileId}/download` | raw file download client |
---
## 20. 后续扩展预留
后续如果需要扩展,可在不破坏主契约的情况下增加:
- 更多 `processType`
- 更多 `options` 字段
- 任务取消接口
- 批量任务接口
- 任务日志查询接口
- 结果 ZIP 打包下载接口
但第一阶段不建议过早加入这些扩展。
---
## 21. 一句话总结
这份接口规范的核心思想是:
- **实时图传走一条轻量、低延迟链路**
- **文档处理走一条统一任务接口链路**
- **MinerU 与 OCRmyPDF 共用同一处理协议,只通过 `processType` 区分**
- **允许先用占位实现把联调跑通,再逐步接入真实处理器**