- 实时图传: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>
33 KiB
FairScan 功能细化规划(执行版)
基于
requirements/requirements.md的进一步落地拆解。 本文件用于实现阶段的任务规划、模块拆分、接口约定、风险控制与验收标准。📌 实现状态:
- P1(实时图传)✅ 已完成
- P2(PDF 上传)+ P3(统一处理任务)✅ 已完成
- 上传与处理已分离为独立接口,符合 pc-api-spec.md 规范
- 导出页提供三个按钮:仅传输 / 传输+OCR PDF / 传输+Markdown
- PC 管理面板 ✅ 已完成(/dashboard)
- MinerU 真实接入 ✅ 已完成(markdown 处理 + ZIP 打包 + 任务管理面板)
- OCRmyPDF 🔥 下一步
- P0(局域网发现)📌 待排期
重要说明:
- 本文档不是只写给当前对话中的执行者。
- 本文档应被视为一份可交给任意工程执行者或 AI 编码代理的实施说明。
- 例如 Claude Code、其他 AI 编码工具、或人工开发者,都应能依据本文件理解目标、边界、优先级与接口契约。
- 因此本文档尽量避免“只对当前上下文成立”的描述,改为更稳定的模块边界、任务拆分与接口说明。
0. 核心结论
本项目后续新增能力,分成两条彼此解耦的主链路:
-
实时图传链路
- 目标:低延迟、稳定预览
- 输入:手机相机预览帧
- 输出:PC 实时显示画面
- 特点:允许丢帧,不追求完整性
-
文档处理链路
- 目标:正式文档处理与结果回到手机
- 输入:手机端本地生成的 PDF
- 输出:Markdown 或 OCR 后的 PDF
- 特点:追求正确性与完整性,可异步处理
同时明确以下原则:
- 不在 App 内主动切换 Wi‑Fi
- 局域网相机功能的本质是实时图传,不是文档处理
- 文档处理只基于手机本地正式生成的 PDF,不基于图传流
- PC 端后处理只需预留统一任务接口,MinerU 与 OCRmyPDF 复用同一套处理协议
- 处理结果回到手机,推荐通过“手机轮询状态 + 手机主动下载产物”实现
1. 当前项目基础能力梳理
结合现有代码,当前 Android 端已经具备以下基础:
- 文档扫描采集与页面处理
- 相机实时预览、分割、文档边缘检测:
app/src/main/java/org/fairscan/app/ui/screens/camera/CameraViewModel.kt:98 - 拍照后生成处理页:
app/src/main/java/org/fairscan/app/ui/screens/camera/CameraViewModel.kt:138 - 裁切/页面编辑/顺序调整入口:
app/src/main/java/org/fairscan/app/MainActivity.kt:190
- 相机实时预览、分割、文档边缘检测:
- PDF/JPEG 导出
- 导出准备与结果管理:
app/src/main/java/org/fairscan/app/ui/screens/export/ExportViewModel.kt:66 - PDF 生成入口:
app/src/main/java/org/fairscan/app/ui/screens/export/ExportViewModel.kt:76 - PDF 写入封装:
app/src/main/java/org/fairscan/app/data/FileManager.kt:46
- 导出准备与结果管理:
- 设置页基础结构
- 设置存储:
app/src/main/java/org/fairscan/app/ui/screens/settings/SettingsRepository.kt:31 - 设置界面:
app/src/main/java/org/fairscan/app/ui/screens/settings/SettingsScreen.kt:57
- 设置存储:
- 应用容器可扩展网络模块注入
- 容器入口:
app/src/main/java/org/fairscan/app/FairScanApp.kt:46
- 容器入口:
这意味着后续新增能力不需要重做扫描器,而是围绕以下两条主链路扩展:
- 实时图传链路:手机相机预览 -> PC 实时显示
- 文档处理链路:手机扫描成 PDF -> PC 处理 -> 结果回到手机
阅读的文档顺序
- IMPLEMENTATION_COMPLETE.md - 了解已完成的工作
- FIXES_SUMMARY.md - 理解技术决策和修复方案 3. NEXT_STEPS.md - 明确下一步的实现方向 你每次完成一个任务就需要更新这些文档
2. 需求重述与产品化定义
2.1 原有离线扫描功能
这部分以现有实现为基础,后续原则是:
- 保持当前扫描主流程稳定
- 不让实时图传影响正式扫描质量
- 后续所有文档处理都复用现有扫描结果
建议统一定义“文档结果对象”:
- 页面集合(已裁切、已旋转、已滤镜处理)
- 本地导出的 PDF 文件
- 可选 JPEG 文件集合
- 文档元信息(文件名、页数、时间)
2.2 局域网相机功能
这里明确产品定位:
- 该功能本质上是局域网实时图传
- 主要目标是:低延迟、稳定、可预览
- PC 端主要用途是:
- 实时观察手机画面
- 辅助取景
- 远端监看
- 不把图传流直接作为 MinerU/OCRmyPDF 的输入
- 不从图传流直接生成正式 PDF
也就是说:
- 图传负责“看”
- 扫描链路负责“生成正式文档”
2.3 离线扫描 PDF 发送到 PC 主机
主链路定义如下:
- 手机端完成扫描与页面处理
- 手机端本地生成 PDF
- 手机端把 PDF 发送到 PC 主机
- PC 主机接收 PDF 后再执行后处理任务
这条链路的好处是:
- 延续现有扫描架构
- 手机端产物清晰、统一
- PC 端只负责重型处理任务
- 图传模块与文档处理模块不会互相拖累
2.4 统一 PC 后处理能力
这里明确一个关键约束:
- PC 端后处理只需要预留统一接口,不需要为 MinerU 与 OCRmyPDF 设计两套完全不同的协议。
建议抽象为一套统一任务模型:
- 输入:手机上传的 PDF
- 处理类型:
markdown或ocrpdf - 输出:
markdown-> 返回.md及相关资源ocrpdf-> 返回处理后的.pdf
也就是说:
- 接口统一
- 任务状态统一
- 产物查询统一
- 差异只体现在处理类型和产物 MIME 类型
2.5 结果回到手机
从产品描述上可以说:
- PC 处理完毕后,把结果回传到手机
但从工程实现角度,推荐这样定义:
- 手机端上传后拿到
taskId - 手机端轮询任务状态
- 任务完成后,手机端拉取产物列表
- 手机端主动下载产物到本地
这样做比“PC 主动推送到手机”更适合 Android:
- 不需要手机长期监听端口
- 更适合前台/后台切换
- 更容易失败重试
- 也更适合未来交由不同执行者实现
3. 建议的总体架构
建议按“手机端 + PC 端服务”的双端架构设计。
3.1 两条主链路
A. 实时图传链路
手机相机预览帧
-> 抽帧/压缩
-> WebSocket 发送
-> PC 实时预览
特点:
- 目标是低延迟
- 允许丢帧
- 不追求逐帧可靠到达
- 不参与正式 PDF 生成
B. 文档处理链路
手机扫描采集
-> 手机本地页面处理
-> 手机本地生成 PDF
-> HTTP 上传到 PC
-> 创建统一处理任务
-> PC 执行对应处理器
-> 手机查询任务状态
-> 手机下载处理结果
特点:
- 目标是正确性与完整性
- 使用正式文档产物作为输入
- 允许异步处理
- 与图传链路解耦
3.2 手机端职责(当前仓库)
- 继续负责扫描采集、裁切、页面编辑、导出 PDF
- 提供局域网发现与主机配置能力
- 提供实时图传能力
- 上传本地 PDF 到 PC
- 发起统一处理任务
- 轮询任务状态并下载结果
- 在 UI 中展示连接状态、任务状态、结果入口
3.3 PC 端职责(建议新建单独项目)
- 广播局域网服务信息
- 接收图传帧并实时显示
- 接收手机上传的 PDF 文件
- 暴露统一处理任务接口
- 根据处理类型调用 MinerU 或 OCRmyPDF
- 提供任务查询与产物下载接口
3.4 推荐协议选型
为了降低复杂度,建议如下:
- 局域网发现:mDNS / NSD
- 实时图传:WebSocket 二进制帧
- 文件上传:HTTP multipart/form-data
- 任务创建:HTTP POST
- 任务状态查询:HTTP 轮询
- 结果下载:HTTP GET
第一版不建议直接做:
- App 内切换 Wi‑Fi
- 自定义复杂 UDP 视频协议
- PC 主动推送文件到手机
- 多主机自动同步
3.5 关于实时性的技术取舍
由于实时性优先,建议这样分层:
V1 方案
- 低频抽帧
- JPEG 压缩
- WebSocket 发送
- 明确丢帧策略
优点:
- 实现快
- 调试简单
- 适合先验证局域网低延迟图传是否满足需求
V2 升级预案(仅在 V1 不满足时再评估)
- 使用 MediaCodec 编码 H.264
- 再评估 WebRTC / RTP / 更底层的视频链路
不建议首版直接上 V2,因为会显著提高开发复杂度。
4. 模块拆分规划
4.1 模块 A:局域网连接与主机发现
目标
让手机端可以:
- 自动发现同一局域网中的 FairScan PC 服务
- 手动填写主机地址作为兜底
- 保存当前选中的 PC 主机配置
手机端新增能力
- 新增网络设置项
- 主机 IP / 域名
- 端口
- 协议(第一期建议仅 http)
- 显示当前手机 IP
- 显示当前发现到的主机列表
- 支持一键选择已发现主机
- 测试连接按钮
- 可选:打开系统 Wi‑Fi 设置入口
局域网发现机制
推荐采用:
- mDNS/NSD 自动发现 + 手动输入兜底
推荐服务标识
- mDNS service type:
_fairscan._tcp - service instance name:
FairScan-PC-{deviceName}
推荐 TXT Record 字段
name:设备显示名features:upload,stream,process,downloadversion:PC 服务版本apiVersion:接口版本
说明:
- 这里建议把后处理能力统一成
process,而不是在发现层暴露过多具体工具细节。 - 是否支持
markdown/ocrpdf,可以通过健康检查响应或任务能力字段进一步细分。
Android 端发现状态模型
DiscoveryState
- Idle
- Discovering
- Success(list)
- Empty
- Error(message)
发现结果建议结构
DiscoveredHost
- serviceName
- displayName
- host
- port
- features[]
- version
- lastSeenAt
- isReachable
建议新增数据项
在 SettingsRepository 中新增:
serverHostserverPortserverDisplayNamelastSelectedServiceIdstreamQualitypostProcessModeautoDownloadProcessedResult
建议涉及文件
app/src/main/java/org/fairscan/app/ui/screens/settings/SettingsRepository.ktapp/src/main/java/org/fairscan/app/ui/screens/settings/SettingsScreen.ktapp/src/main/java/org/fairscan/app/ui/screens/settings/SettingsViewModel.kt- 建议新增:
app/src/main/java/org/fairscan/app/network/NetworkInfoProvider.ktapp/src/main/java/org/fairscan/app/network/ServerEndpoint.ktapp/src/main/java/org/fairscan/app/network/discovery/LanServiceDiscovery.ktapp/src/main/java/org/fairscan/app/network/discovery/NsdLanServiceDiscovery.ktapp/src/main/java/org/fairscan/app/network/discovery/DiscoveryState.ktapp/src/main/java/org/fairscan/app/network/discovery/DiscoveredHost.kt
验收标准
- 用户可以扫描到局域网中的 FairScan PC 服务
- 用户可以从发现列表中选择目标主机
- 自动发现失败时仍可手动输入地址
- 选择主机后可通过
GET /health校验连通性
4.2 模块 B:实时网络图传
目标
把手机作为一个低延迟局域网实时图传设备,让 PC 端可以实时看到画面。
功能定位
这一模块的核心不是文档处理,而是:
- 实时预览
- 低延迟
- 稳定连接
- 图传状态清晰
推荐实现路线
第一版建议:
- 从 CameraX 预览/分析流中取图
- 按固定频率抽帧
- 压缩为 JPEG
- 通过 WebSocket 发送二进制帧到 PC
- PC 端显示实时画面
当前可接入入口:
app/src/main/java/org/fairscan/app/ui/screens/camera/CameraViewModel.kt:98
关键原则
- 必须允许丢帧,不能把帧积压在队列里
- 必须以实时性优先,而不是完整性优先
- 图传失败不能影响正式扫描
- 图传流不参与正式 PDF 生成
压缩档位建议
| 档位 | 最长边 | JPEG质量 | 目标FPS | 用途 |
|---|---|---|---|---|
| Low | 640 | 45 | 8~12 | 低延迟预览 |
| Balanced | 960 | 60 | 6~10 | 默认 |
| High | 1280 | 75 | 5~8 | 高清预览 |
手机端子任务
- 设计图传状态模型
- 新增帧压缩器
- 新增图传客户端
- 增加丢帧策略
- 在相机界面增加图传开关和状态提示
- 增加断线重连策略
- 增加简单性能指标
建议涉及文件
已有接入点:
app/src/main/java/org/fairscan/app/ui/screens/camera/CameraViewModel.kt:98app/src/main/java/org/fairscan/app/ui/screens/camera/CameraScreen.ktapp/src/main/java/org/fairscan/app/ui/screens/camera/CameraPreview.kt
建议新增:
app/src/main/java/org/fairscan/app/network/stream/StreamClient.ktapp/src/main/java/org/fairscan/app/network/stream/FrameCompressor.ktapp/src/main/java/org/fairscan/app/network/stream/StreamState.ktapp/src/main/java/org/fairscan/app/network/stream/StreamQualityPreset.ktapp/src/main/java/org/fairscan/app/network/stream/FrameDropController.kt
验收标准
- 手机连接 PC 后可持续发送实时预览帧
- 在局域网环境下主观延迟明显低于文件传输式刷新
- 不同压缩档位的延迟和清晰度有可见差异
- 图传开启时,正式扫描/导出功能仍可正常使用
4.3 模块 C:手机本地生成 PDF 并上传到 PC
目标
保持现有手机扫描方案不变,在手机端完成正式文档生成后,再把 PDF 上传给 PC。
推荐实现路线
- 手机端按现有流程完成扫描
- 使用现有导出逻辑生成 PDF
- 调用上传接口把 PDF 发给 PC
当前稳定入口:
app/src/main/java/org/fairscan/app/ui/screens/export/ExportViewModel.kt:76app/src/main/java/org/fairscan/app/ui/screens/export/ExportViewModel.kt:84app/src/main/java/org/fairscan/app/data/FileManager.kt:46
设计原则
- 正式文档输入只认手机本地生成的 PDF
- 不使用实时图传流直接做正式文档处理
- 上传是文档处理链路的前半段,不与实时图传混合
手机端子任务
- 定义上传请求/响应模型
- 导出页增加“发送到 PC”按钮
- 支持发送后立即创建后处理任务,或只上传不处理
- 展示上传进度与结果
- 记录返回的文件标识或任务标识
建议涉及文件
app/src/main/java/org/fairscan/app/ui/screens/export/ExportViewModel.kt:66app/src/main/java/org/fairscan/app/MainActivity.kt:203- 建议新增:
app/src/main/java/org/fairscan/app/network/upload/PdfUploadClient.ktapp/src/main/java/org/fairscan/app/network/upload/UploadModels.ktapp/src/main/java/org/fairscan/app/ui/screens/export/NetworkExportState.kt
验收标准
- 用户可以把当前扫描结果导出成 PDF 并发送给 PC
- 上传进度可见
- 成功后能拿到后续处理所需的文件标识或任务标识
4.4 模块 D:统一 PC 后处理接口
目标
为 PC 端预留一套统一的后处理任务接口,由处理类型决定具体使用 MinerU 还是 OCRmyPDF。
设计原则
- 统一任务创建接口
- 统一任务状态接口
- 统一产物列表接口
- 统一产物下载接口
- 差异只体现在:
processType- 输出文件类型
推荐任务类型
processType
- markdown
- ocrpdf
输入输出约定
输入
- 一个已上传或本次提交的 PDF
- 一个
processType
输出
- 当
processType=markdown- 主要产物:
.md - 可选附加产物:图片资源目录、JSON、日志
- 主要产物:
- 当
processType=ocrpdf- 主要产物:处理后的
.pdf - 可选附加产物:日志、识别报告
- 主要产物:处理后的
推荐接口契约
1. 创建任务
POST /tasks/process
请求体建议:
{
"fileId": "uploaded-file-id",
"processType": "markdown",
"options": {}
}
2. 查询任务状态
GET /tasks/{taskId}
返回体建议:
{
"taskId": "task-123",
"status": "running",
"processType": "markdown",
"progress": 50,
"message": "processing",
"artifacts": []
}
3. 查询产物列表
GET /tasks/{taskId}/artifacts
返回体建议:
[
{
"artifactId": "artifact-1",
"fileName": "result.md",
"mimeType": "text/markdown",
"role": "primary"
}
]
4. 下载产物
GET /artifacts/{artifactId}/download
手机端实现含义
手机端不需要关心 PC 内部到底调用了 MinerU 还是 OCRmyPDF,只需要关心:
- 要处理哪个文件
- 处理类型是什么
- 当前任务状态是什么
- 可以下载哪些产物
这样设计的好处
- PC 端工具实现可替换
- 后续新增其他处理器时接口不必大改
- 文档可交给不同 AI 或开发者实现而不易跑偏
- Android 端状态管理更统一
建议新增文件
app/src/main/java/org/fairscan/app/network/tasks/TaskClient.ktapp/src/main/java/org/fairscan/app/network/tasks/TaskModels.ktapp/src/main/java/org/fairscan/app/network/tasks/ArtifactDownloadClient.ktapp/src/main/java/org/fairscan/app/ui/screens/export/ProcessingTaskState.kt
验收标准
- 手机端可通过统一接口发起
markdown任务 - 手机端可通过统一接口发起
ocrpdf任务 - 任务状态查询逻辑对两类任务保持一致
- 产物下载逻辑对两类任务保持一致
4.5 模块 E:处理结果回到手机端
目标
让 PC 端的处理结果真正回到手机端,而不是停留在 PC 上。
推荐实现方式
产品上:
- 结果回传手机
技术上:
- 手机端主动下载
为什么不建议 PC 主动推送到手机
- Android 端长期开放监听端口不稳定
- 前后台切换复杂
- 手机网络权限与系统限制更多
- 局域网内由手机主动拉取更简单可靠
手机端下载结果后的处理建议
- 下载到应用缓存目录
- 再提供:
- 打开
- 分享
- 保存到用户指定目录
- 作为新文档导入应用
验收标准
- 任务完成后手机端可获取产物列表
- 手机端可把产物下载回本地
- 下载失败时可重试
- 用户可明确区分“任务失败”和“下载失败”
5. 推荐开发阶段划分
第一阶段:局域网发现与连接校验
目标:先把“发现谁、连接谁”做稳定。
范围
- 设置页新增 PC 主机配置
- mDNS/NSD 发现机制
- 手动输入兜底
GET /health健康检查
阶段验收
- 手机端可自动发现同局域网中的 FairScan PC 服务
- 发现失败时可手动输入地址
- 健康检查可明确提示成功/失败
第二阶段:实时图传闭环
目标:优先完成低延迟实时图传。
范围
- 图传客户端
- 相机页图传开关
- 图传压缩档位
- PC 端实时预览
- 复用第一阶段的主机发现结果
阶段验收
- 手机端可以把实时预览帧发送到 PC
- PC 端能低延迟显示画面
- 图传质量档位切换有效
- 图传失败不影响正常扫描
第三阶段:手机本地 PDF 上传到 PC
目标:打通文档处理链路的前半段。
范围
- 手机本地导出 PDF
- 上传到 PC
- 上传状态展示
阶段验收
- 当前扫描文档可生成 PDF 并上传至 PC
- 上传结果可见
- 可关联后续处理任务
第四阶段:统一处理任务与结果下载
目标:打通文档处理链路的后半段。
范围
- 统一处理任务接口
markdown处理类型ocrpdf处理类型- 手机查询任务状态
- 手机下载结果文件
阶段验收
- 手机可用统一接口发起两种处理类型
- PC 可根据类型调用不同处理器
- 结果文件可从 PC 下载回手机
第五阶段:体验优化
范围
- 最近连接记录
- 自动下载开关
- 失败重试
- 后台通知
- 发现结果去重与缓存
- 可选:UDP/网段探测作为发现兜底
5.1 局域网发现专项方案
目标
在不切换 Wi‑Fi 的前提下,让手机端自动发现同一局域网中运行中的 FairScan PC 服务。
主方案
- PC 端广播
_fairscan._tcp - Android 端 NSD 搜索
_fairscan._tcp - 用户确认选择目标主机
- 手机端调用
GET /health校验
发现流程
- PC 启动 HTTP 服务
- PC 注册 mDNS 服务
- 手机点击“扫描局域网主机”
- Android NSD 开始发现
- 解析 host、port、features
- 展示设备列表
- 用户选择设备
- 手机执行
GET /health - 校验成功后保存为当前目标主机
备用方案触发条件
只有在以下情况长期存在时,才考虑第二通道:
- 大量设备无法发现 mDNS
- 企业网络场景较多
- Windows 防火墙导致广播不稳定
此时再评估:
- 自定义 UDP 广播
- 指定网段 HTTP 探测
默认不建议首版同时做两套发现机制。
6. Android 端建议修改点清单
6.1 权限与清单
当前 Manifest 尚未为新网络能力补齐联网权限:
app/src/main/AndroidManifest.xml:1
后续大概率需要新增:
android.permission.INTERNETandroid.permission.ACCESS_WIFI_STATE- 第一版不建议使用
android.permission.CHANGE_WIFI_STATE
如果使用明文 HTTP 局域网服务,还要评估:
- network security config
- 或仅在开发阶段允许局域网明文流量
6.2 设置页
当前设置页很适合作为局域网协作入口:
app/src/main/java/org/fairscan/app/ui/screens/settings/SettingsScreen.kt:57app/src/main/java/org/fairscan/app/ui/screens/settings/SettingsRepository.kt:31
建议新增“局域网协作”分组:
- PC 主机地址
- 端口
- 当前手机 IP
- 扫描局域网主机按钮
- 已发现主机列表
- 图传质量预设
- 默认处理类型
- 自动下载结果开关
- 测试连接按钮
- 打开系统 Wi‑Fi 设置快捷入口(可选)
6.3 相机页
当前相机实时分析入口适合接入图传:
app/src/main/java/org/fairscan/app/ui/screens/camera/CameraViewModel.kt:98
建议新增:
- 图传开关
- 图传状态文本
- 当前目标主机提示
- 压缩档位快速切换
- 近似发送帧率或发送状态提示
6.4 导出页
当前导出能力已较完整:
app/src/main/java/org/fairscan/app/ui/screens/export/ExportViewModel.kt:66
建议新增按钮:
- 发送到 PC
- 发送并处理(Markdown)
- 发送并处理(OCR PDF)
- 下载处理结果(当任务完成后显示)
6.5 任务与结果页面
建议后续增加一个轻量任务状态区域,至少包含:
- 上传中
- 等待处理
- 处理中
- 处理成功
- 处理失败
- 下载中
- 下载成功
- 下载失败
6.6 AppContainer 注入
当前容器适合新增网络模块注入:
app/src/main/java/org/fairscan/app/FairScanApp.kt:46
建议后续加入:
lanServiceDiscoverystreamClientuploadClienttaskClientartifactDownloadClientnetworkInfoProvider
7. PC 端服务建议最小方案
7.1 目标边界
PC 端在本阶段只需要提供:
- 图传接收能力
- 文件接收能力
- 统一处理任务接口骨架
- 任务状态返回能力
- 产物下载能力
这里特别强调:
- 对当前阶段来说,PC 端只需预留好统一接口
- MinerU 与 OCRmyPDF 的内部执行器可以后续再逐步接入
- 但接口契约应先稳定下来,避免 Android 端后面反复改协议
7.2 推荐技术路线
如果 MinerU 与 OCRmyPDF 最终都运行在 Python 环境,最自然的是:
- PC 端统一使用 Python FastAPI
7.3 PC 端最小能力
- HTTP 服务
- WebSocket 图传接收
- mDNS 服务广播
- 上传文件保存
- 统一任务接口
- 任务状态查询
- 结果文件下载
7.4 最小接口建议
GET /health- 健康检查
WS /stream- 实时图传接收
POST /upload/pdf- 上传 PDF
POST /tasks/process- 发起统一处理任务
GET /tasks/{id}- 查询任务状态
GET /tasks/{id}/artifacts- 查询产物列表
GET /artifacts/{artifactId}/download- 下载产物
7.5 统一处理任务接口示例
创建任务请求示例
{
"fileId": "uploaded-file-id",
"processType": "ocrpdf",
"options": {}
}
状态返回示例
{
"taskId": "task-123",
"status": "completed",
"processType": "ocrpdf",
"progress": 100,
"message": "done"
}
产物列表示例
[
{
"artifactId": "artifact-1",
"fileName": "result.pdf",
"mimeType": "application/pdf",
"role": "primary"
}
]
7.6 目录规划建议
incoming/原始上传文件tasks/任务工作目录outputs/pdf/OCR 输出outputs/markdown/Markdown 输出logs/服务日志与任务日志
7.7 广播能力建议
mDNS TXT Record 中建议广播:
stream=1upload=1process=1download=1apiVersion=1
如需更细粒度,也可通过 GET /health 返回:
{
"name": "FairScan-PC-Office",
"status": "ok",
"features": ["stream", "upload", "process", "download"],
"processTypes": ["markdown", "ocrpdf"]
}
8. 风险与难点
8.1 实时图传的延迟与稳定性
风险:
- CameraX 分析 + 压缩 + 网络发送会叠加延迟
- 发送队列积压会使画面越来越慢
应对:
- 固定抽帧
- 只保留最新帧
- 上一帧未发完则直接丢弃当前帧
- 后台线程压缩与发送
- 优先保证低延迟而不是高保真
8.2 Android 网络与 Wi‑Fi 限制
风险:
- 获取 Wi‑Fi 名称和网络信息在新系统上限制较多
- App 内切换 Wi‑Fi 成本高且兼容性差
应对:
- 不在 App 内切换 Wi‑Fi
- 只显示网络信息
- 必要时提供“打开系统 Wi‑Fi 设置”入口
8.3 局域网发现兼容性
风险:
- 某些路由器可能屏蔽 mDNS 多播
- Windows 防火墙可能阻止服务广播
- 无线与有线终端可能被隔离
应对:
- 使用
NSD + 手动输入 + /health 校验三段式兜底 - 设置页提供简单排障提示
- 后续再评估 UDP/网段探测
8.4 PC 后处理环境依赖
风险:
- MinerU 与 OCRmyPDF 依赖较重
- Python 环境与外部工具安装复杂
- 内部执行器后续可能替换实现
应对:
- Android 端只依赖统一处理接口,不依赖具体工具细节
- PC 端先稳定接口契约,再逐步补充内部执行器
- 通过
processTypes或等价字段声明当前支持的处理类型
8.5 结果回到手机的可靠性
风险:
- 任务成功但下载失败
- 用户切到后台后任务状态丢失
- 下载到本地后存储路径不清晰
应对:
- 区分“任务失败”和“下载失败”
- 记录最近任务与产物信息
- 下载后提供打开、分享、另存为入口
9. 建议的任务清单(可直接进入开发)
P0:局域网发现与基础连接
Task P0-1:扩展设置仓库与设置页
- 增加 PC 主机地址和端口配置
- 增加发现结果展示区域
- 增加“扫描局域网主机”按钮
- 增加图传质量配置
- 增加默认处理类型配置
- 增加自动下载结果开关
- 显示手机当前 IP
Task P0-2:实现局域网发现基础能力
- 接入 Android NSD
- 定义
DiscoveredHost与DiscoveryState - 扫描
_fairscan._tcp - 发现后支持一键填充 host/port
- 失败时保留手动输入兜底
Task P0-3:补充网络基础设施
- 增加网络权限
- 增加基础 HTTP 客户端
- 增加统一错误模型
- 增加
GET /health校验
Task P0-4:实现 PC 最小服务骨架
GET /health- mDNS 注册
_fairscan._tcp - 广播服务能力信息
P1:实时图传
Task P1-1:实现图传状态模型
- 未连接
- 连接中
- 已连接
- 发送中
- 出错
Task P1-2:实现帧压缩与抽帧策略
- 低/中/高三档
- 限帧率
- 丢帧策略
- 只保留最新帧
Task P1-3:相机页接入图传控制
- 开关
- 状态提示
- 主机信息展示
- 复用已发现或已保存的目标主机
Task P1-4:实现 PC 端实时预览
WS /stream- 页面或桌面窗口显示
Task P1-5:图传与发现联动
- 直接选择发现到的主机作为图传目标
- 根据
features判断主机是否支持stream
P2:手机本地 PDF 上传
Task P2-1:实现 PDF 上传客户端
- 导出页新增“发送到 PC”按钮
- 生成 PDF 后发给 PC 服务
- 展示上传进度和结果
Task P2-2:联调上传闭环
- 手机扫描文档
- 手机本地生成 PDF
- 上传到 PC 成功
- 手动输入和自动发现两条路径都可工作
P3:统一处理任务与结果下载
Task P3-1:实现统一任务接口客户端
- 支持
processType=markdown - 支持
processType=ocrpdf - 统一查询任务状态
- 统一查询产物列表
Task P3-2:实现统一结果下载流程
- 下载
.md结果 - 下载
.pdf结果 - 基于
mimeType决定本地处理方式
Task P3-3:统一任务状态 UI
- 等待中
- 处理中
- 成功
- 失败
- 下载中
- 下载成功
- 下载失败
Task P3-4:PC 端统一接口占位实现
POST /tasks/processGET /tasks/{id}GET /tasks/{id}/artifactsGET /artifacts/{artifactId}/download- 先允许返回 mock 或占位结果,再逐步接入真实处理器
P4:体验优化
Task P4-1:发现结果去重与缓存
- 按 service name 或 host:port 去重
- 记住最近选择设备
- 显示最近发现时间
Task P4-2:后台任务与通知
- 上传后台继续
- 处理结果通知
- 下载结果通知
Task P4-3:高级兜底方案评估
- UDP 广播发现
- 网段 HTTP 探测
- 仅在主方案不稳定时启用
10. 建议的验收用例
用例 1:局域网发现
- PC 服务启动并广播
_fairscan._tcp - 手机点击“扫描局域网主机”
- 手机看到可用设备列表
- 用户选择设备后自动填充 host/port
GET /health验证通过
用例 2:实时图传
- 手机开启图传
- PC 端能实时看到画面
- 切换压缩档位后画面质量与延迟明显变化
- 图传关闭后不影响正常扫描
用例 3:手机本地 PDF 上传
- 手机按原方案扫描 3 页文档
- 手机本地生成 PDF
- 上传到 PC 成功
- PC 成功保存原始 PDF
用例 4:统一处理接口返回 Markdown 结果
- 手机使用
processType=markdown发起任务 - PC 返回任务状态
- PC 提供
.md结果下载 - 手机成功下载 Markdown 结果
用例 5:统一处理接口返回 OCR PDF 结果
- 手机使用
processType=ocrpdf发起任务 - PC 返回任务状态
- PC 提供
.pdf结果下载 - 手机成功下载 OCR 后 PDF
用例 6:异常处理
- 主机地址错误
- PC 服务未启动
- mDNS 发现失败
- 上传中断网
- 当前
processType不受支持 - 下载结果失败
- UI 都能给出明确失败信息
11. 建议的实现优先级
推荐开发顺序:
- 主机发现 + 健康检查
- 实时图传
- 手机本地 PDF 上传到 PC
- 统一处理任务接口与结果下载
- 发现机制与任务体验优化
理由:
- 你当前最关心的是实时图传,所以图传优先
- 图传与文档处理解耦,优先完成图传不会阻碍后续 PDF 链路
- PC 端后处理细节未来可替换,因此应先稳定统一接口契约
- 文档处理链路应尽量让 Android 端只依赖抽象接口,不依赖具体工具内部实现
一句话概括:
- 先把“实时看画面”做好,再把“正式处理文档并回到手机”做好;PC 内部处理器可以后补,但统一接口要先定下来。
12. 对执行者的说明
本节是写给任何执行这份文档的人或 AI 的。
12.1 不要误解的点
- “局域网相机”不是文档处理功能,而是实时图传功能。
- 文档处理输入来自手机本地正式生成的 PDF,而不是图传流。
- PC 端现阶段最重要的是统一接口契约,不是先把 MinerU/OCRmyPDF 完整接好。
- Android 端应依赖统一处理接口,不要直接写死两套后处理协议。
12.2 可以接受的实现策略
- PC 端统一处理接口可以先返回 mock 结果
- 只要契约稳定,内部执行器可以后续逐步替换成真实 MinerU / OCRmyPDF
- Android 端先把:
- 上传
- 创建任务
- 查询状态
- 下载产物 的全链路走通即可
12.3 不建议的实现策略
- 不要把图传流直接接到 MinerU / OCRmyPDF
- 不要在 App 内做 Wi‑Fi 切换
- 不要同时为
markdown与ocrpdf设计两套完全独立的客户端协议 - 不要让 Android 端过早耦合 PC 内部处理器实现细节
12.4 如果由 AI 编码代理执行
执行顺序建议严格按以下优先级推进:
- 发现与连接
- 实时图传
- PDF 上传
- 统一处理接口
- 结果下载
- 再考虑真实接入 MinerU/OCRmyPDF
如果 AI 只能做一部分任务,优先确保:
- 接口稳定
- 状态模型稳定
- UI 路径清晰
- 占位实现可联调
13. 与原始需求的映射关系
- “文件原有的离线扫描功能”
- 对应当前现有扫描/导出链路
- “手机网络图传功能”
- 对应模块 B,且定位为低延迟实时图传
- “局域网内压缩广播的实时网络摄像头”
- 对应模块 B,第一版建议做点对点实时图传
- “压缩力度可选”
- 对应图传质量预设
- “离线扫描 PDF 通过 Wi‑Fi 协议发送给 PC”
- 对应模块 C
- “显示自己的 IP 和端口”
- 对应模块 A
- “MinerU 转成 Markdown”
- 对应统一处理接口中的
processType=markdown
- 对应统一处理接口中的
- “OCRmyPDF 转成双层 PDF”
- 对应统一处理接口中的
processType=ocrpdf
- 对应统一处理接口中的
- “PC 处理完毕后再传回手机”
- 对应模块 E,推荐技术实现为手机主动下载结果