- 实时图传: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>
16 KiB
FairScan PC 端统一接口规范(草案 v0.1)
本文档定义 FairScan 手机端与 PC 端之间的最小稳定接口契约。
适用对象:
- 人工开发者
- Claude Code
- 其他 AI 编码代理
设计目标:
- 让不同执行者都能按同一接口实现,不因上下文差异而跑偏
- 优先稳定协议与字段,而不是优先绑定具体内部实现
- 允许 PC 端先做“接口占位实现”,后续再逐步接入真实 MinerU / OCRmyPDF
1. 设计范围
本文档覆盖以下能力:
- 局域网服务发现配套信息
- 健康检查接口
- 实时图传接口
- PDF 上传接口
- 统一处理任务接口
- 任务状态查询接口
- 处理产物查询接口
- 处理产物下载接口
本文档不约束以下内容:
- PC 端内部具体使用什么库执行 MinerU
- PC 端内部具体使用什么方式调用 OCRmyPDF
- PC 端图传画面最终是显示在网页、桌面窗口还是其他 UI 中
- Android 端 UI 的具体布局样式
也就是说:
- 本文档约束的是“外部协议”
- 不强制约束“内部实现”
2. 核心原则
2.1 图传与文档处理解耦
- 实时图传只负责低延迟画面预览
- 正式文档处理只基于手机本地生成的 PDF
- 图传流不得直接作为 MinerU / OCRmyPDF 的正式输入
2.2 统一处理接口
PC 端后处理统一使用一套任务接口。
支持的处理类型:
markdownocrpdf
差异只体现在:
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->.mdocrpdf->.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 |
默认基础地址示例:
http://{host}:{port}
例如:
http://192.168.1.10:8080
5. 通用约定
5.1 编码与格式
- JSON 请求与响应统一使用 UTF-8
- 除下载接口外,默认返回
application/json - 图传 WebSocket 使用二进制消息承载 JPEG 帧
5.2 ID 规则
以下字段都视为不透明字符串:
fileIdtaskIdartifactId
客户端不得依赖这些 ID 的内部结构。
5.3 时间字段
如果服务返回时间字段,建议使用 RFC 3339 / ISO 8601,例如:
2026-06-04T12:34:56Z
时间字段不是第一阶段强制要求,但如果提供,应统一格式。
5.4 状态枚举
任务状态建议使用以下枚举:
queued
running
completed
failed
如后续需要,可扩展:
canceled
5.5 错误返回格式
推荐所有错误统一返回:
{
"error": {
"code": "INVALID_REQUEST",
"message": "processType is required"
}
}
推荐错误码:
INVALID_REQUESTUNSUPPORTED_PROCESS_TYPEFILE_NOT_FOUNDTASK_NOT_FOUNDARTIFACT_NOT_FOUNDPROCESSING_FAILEDSERVICE_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,downloadapiVersion:如1version:PC 服务版本
6.3 关于 process 能力
这里建议广播能力使用:
process
而不是直接广播多个内部工具名。
原因:
- 发现层只需表达“能不能处理”
- 具体支持哪些
processType,可通过/health返回 - 这样后续新增其他处理器时不需要修改发现层语义
7. 健康检查接口
7.1 GET /health
作用
- 判断服务是否在线
- 返回最小能力信息
- 返回支持的处理类型
请求
无请求体。
成功响应示例
{
"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 文件。
请求类型
multipart/form-data
表单字段
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
file |
file | 是 | PDF 文件 |
约束
file的 MIME 类型应为application/pdf- 服务端可根据需要限制上传大小
- 若文件过大,建议返回
413 Payload Too Large
成功响应示例
{
"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 Created400 Bad Request413 Payload Too Large500 Internal Server Error
10. 统一处理任务接口
10.1 POST /tasks/process
作用
使用统一接口发起后处理任务。
请求示例
{
"fileId": "file-123",
"processType": "markdown",
"options": {}
}
请求字段说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
fileId |
string | 是 | 由上传接口返回的文件标识 |
processType |
string | 是 | markdown 或 ocrpdf |
options |
object | 否 | 预留扩展字段,首版可为空对象 |
处理类型定义
processType |
含义 | 预期主产物 |
|---|---|---|
markdown |
执行 Markdown 转换 | text/markdown |
ocrpdf |
执行 OCR PDF 处理 | application/pdf |
成功响应示例
{
"taskId": "task-123",
"status": "queued",
"processType": "markdown",
"fileId": "file-123"
}
状态码
202 Accepted400 Bad Request404 Not Found(fileId不存在)422 Unprocessable Entity(processType不支持时可选)500 Internal Server Error
第一阶段占位实现要求
如果真实 MinerU / OCRmyPDF 尚未接入,允许这样实现:
- 接口正常收请求
- 正常返回
taskId - 任务状态可直接从
queued->completed - 产物可先返回 mock 文件或占位文件
这样做的目标是:
- 先稳定客户端协议
- 先打通 Android 联调链路
- 后续再逐步替换成真实处理器
11. 查询任务状态接口
11.1 GET /tasks/{taskId}
作用
返回单个任务的当前状态。
成功响应示例
{
"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 | 否 | 是否已有可下载产物 |
失败响应示例
{
"error": {
"code": "TASK_NOT_FOUND",
"message": "task not found"
}
}
状态码
200 OK404 Not Found
12. 查询任务产物接口
12.1 GET /tasks/{taskId}/artifacts
作用
列出某个任务已经生成的所有产物。
成功响应示例
Markdown 任务示例
[
{
"artifactId": "artifact-1",
"fileName": "result.md",
"mimeType": "text/markdown",
"role": "primary",
"sizeBytes": 2048
}
]
OCR PDF 任务示例
[
{
"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 OK404 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 OK404 Not Found
14. 原始文件下载接口
14.1 GET /files/{fileId}/download
作用
下载已上传但尚未处理的原始 PDF 文件。
响应
- 响应体为二进制文件流
Content-Type: application/pdfContent-Disposition包含原始文件名
典型用途
- PC 管理面板中直接下载查看手机上传的原始 PDF
- 手机端重新获取已上传的文件
状态码
200 OK404 Not Found(文件 ID 不存在或文件已从磁盘删除)
15. 两类处理任务的差异说明
15.1 processType=markdown
目标
把 PDF 处理为 Markdown 文档。
最低要求
- 至少返回一个
.md主产物
可选附加产物
- 图片资源
- 日志
- JSON 中间结果
15.2 processType=ocrpdf
目标
把 PDF 处理为 OCR 后的可搜索 PDF。
最低要求
- 至少返回一个
.pdf主产物
可选附加产物
- 日志
- 识别报告
16. 典型调用流程
16.1 实时图传流程
- 手机发现并选择 PC 主机
- 手机调用
/health确认支持stream - 手机建立
WS /stream - 手机按抽帧策略发送 JPEG 帧
- PC 实时显示最新帧
16.2 文档处理流程
- 手机本地生成 PDF
- 手机
POST /upload/pdf - 手机获得
fileId - 手机
POST /tasks/process - 手机获得
taskId - 手机轮询
GET /tasks/{taskId} - 任务完成后,手机调用
GET /tasks/{taskId}/artifacts - 手机调用
GET /artifacts/{artifactId}/download - 手机保存、打开或分享结果
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 优先级建议
如果执行资源有限,优先实现:
/health/upload/pdf/tasks/process/tasks/{id}/tasks/{id}/artifacts/artifacts/{artifactId}/downloadWS /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区分 - 允许先用占位实现把联调跑通,再逐步接入真实处理器