Files
Fairscan_cyy/requirements/implementation-plan.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

33 KiB
Raw Permalink Blame History

FairScan 功能细化规划(执行版)

基于 requirements/requirements.md 的进一步落地拆解。 本文件用于实现阶段的任务规划、模块拆分、接口约定、风险控制与验收标准。

📌 实现状态

  • P1实时图传 已完成
  • P2PDF 上传)+ P3统一处理任务 已完成
    • 上传与处理已分离为独立接口,符合 pc-api-spec.md 规范
    • 导出页提供三个按钮:仅传输 / 传输+OCR PDF / 传输+Markdown
  • PC 管理面板 已完成(/dashboard
  • MinerU 真实接入 已完成markdown 处理 + ZIP 打包 + 任务管理面板)
  • OCRmyPDF 🔥 下一步
  • P0局域网发现📌 待排期

重要说明:

  • 本文档不是只写给当前对话中的执行者
  • 本文档应被视为一份可交给任意工程执行者或 AI 编码代理的实施说明。
  • 例如 Claude Code、其他 AI 编码工具、或人工开发者,都应能依据本文件理解目标、边界、优先级与接口契约。
  • 因此本文档尽量避免“只对当前上下文成立”的描述,改为更稳定的模块边界、任务拆分与接口说明。

0. 核心结论

本项目后续新增能力,分成两条彼此解耦的主链路:

  1. 实时图传链路

    • 目标:低延迟、稳定预览
    • 输入:手机相机预览帧
    • 输出PC 实时显示画面
    • 特点:允许丢帧,不追求完整性
  2. 文档处理链路

    • 目标:正式文档处理与结果回到手机
    • 输入:手机端本地生成的 PDF
    • 输出Markdown 或 OCR 后的 PDF
    • 特点:追求正确性与完整性,可异步处理

同时明确以下原则:

  • 不在 App 内主动切换 WiFi
  • 局域网相机功能的本质是实时图传,不是文档处理
  • 文档处理只基于手机本地正式生成的 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

这意味着后续新增能力不需要重做扫描器,而是围绕以下两条主链路扩展:

  1. 实时图传链路:手机相机预览 -> PC 实时显示
  2. 文档处理链路:手机扫描成 PDF -> PC 处理 -> 结果回到手机

阅读的文档顺序

  1. IMPLEMENTATION_COMPLETE.md - 了解已完成的工作
  2. 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
  • 处理类型:markdownocrpdf
  • 输出:
    • 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 内切换 WiFi
  • 自定义复杂 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
  • 显示当前发现到的主机列表
  • 支持一键选择已发现主机
  • 测试连接按钮
  • 可选:打开系统 WiFi 设置入口

局域网发现机制

推荐采用:

  • mDNS/NSD 自动发现 + 手动输入兜底

推荐服务标识

  • mDNS service type_fairscan._tcp
  • service instance nameFairScan-PC-{deviceName}

推荐 TXT Record 字段

  • name:设备显示名
  • featuresupload,stream,process,download
  • versionPC 服务版本
  • apiVersion:接口版本

说明:

  • 这里建议把后处理能力统一成 process,而不是在发现层暴露过多具体工具细节。
  • 是否支持 markdown / ocrpdf,可以通过健康检查响应或任务能力字段进一步细分。

Android 端发现状态模型

DiscoveryState
- Idle
- Discovering
- Success(list)
- Empty
- Error(message)

发现结果建议结构

DiscoveredHost
- serviceName
- displayName
- host
- port
- features[]
- version
- lastSeenAt
- isReachable

建议新增数据项

SettingsRepository 中新增:

  • serverHost
  • serverPort
  • serverDisplayName
  • lastSelectedServiceId
  • streamQuality
  • postProcessMode
  • autoDownloadProcessedResult

建议涉及文件

  • app/src/main/java/org/fairscan/app/ui/screens/settings/SettingsRepository.kt
  • app/src/main/java/org/fairscan/app/ui/screens/settings/SettingsScreen.kt
  • app/src/main/java/org/fairscan/app/ui/screens/settings/SettingsViewModel.kt
  • 建议新增:
    • app/src/main/java/org/fairscan/app/network/NetworkInfoProvider.kt
    • app/src/main/java/org/fairscan/app/network/ServerEndpoint.kt
    • app/src/main/java/org/fairscan/app/network/discovery/LanServiceDiscovery.kt
    • app/src/main/java/org/fairscan/app/network/discovery/NsdLanServiceDiscovery.kt
    • app/src/main/java/org/fairscan/app/network/discovery/DiscoveryState.kt
    • app/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 高清预览

手机端子任务

  1. 设计图传状态模型
  2. 新增帧压缩器
  3. 新增图传客户端
  4. 增加丢帧策略
  5. 在相机界面增加图传开关和状态提示
  6. 增加断线重连策略
  7. 增加简单性能指标

建议涉及文件

已有接入点:

  • app/src/main/java/org/fairscan/app/ui/screens/camera/CameraViewModel.kt:98
  • app/src/main/java/org/fairscan/app/ui/screens/camera/CameraScreen.kt
  • app/src/main/java/org/fairscan/app/ui/screens/camera/CameraPreview.kt

建议新增:

  • app/src/main/java/org/fairscan/app/network/stream/StreamClient.kt
  • app/src/main/java/org/fairscan/app/network/stream/FrameCompressor.kt
  • app/src/main/java/org/fairscan/app/network/stream/StreamState.kt
  • app/src/main/java/org/fairscan/app/network/stream/StreamQualityPreset.kt
  • app/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:76
  • app/src/main/java/org/fairscan/app/ui/screens/export/ExportViewModel.kt:84
  • app/src/main/java/org/fairscan/app/data/FileManager.kt:46

设计原则

  • 正式文档输入只认手机本地生成的 PDF
  • 不使用实时图传流直接做正式文档处理
  • 上传是文档处理链路的前半段,不与实时图传混合

手机端子任务

  1. 定义上传请求/响应模型
  2. 导出页增加“发送到 PC”按钮
  3. 支持发送后立即创建后处理任务,或只上传不处理
  4. 展示上传进度与结果
  5. 记录返回的文件标识或任务标识

建议涉及文件

  • app/src/main/java/org/fairscan/app/ui/screens/export/ExportViewModel.kt:66
  • app/src/main/java/org/fairscan/app/MainActivity.kt:203
  • 建议新增:
    • app/src/main/java/org/fairscan/app/network/upload/PdfUploadClient.kt
    • app/src/main/java/org/fairscan/app/network/upload/UploadModels.kt
    • app/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.kt
  • app/src/main/java/org/fairscan/app/network/tasks/TaskModels.kt
  • app/src/main/java/org/fairscan/app/network/tasks/ArtifactDownloadClient.kt
  • app/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 局域网发现专项方案

目标

在不切换 WiFi 的前提下,让手机端自动发现同一局域网中运行中的 FairScan PC 服务。

主方案

  • PC 端广播 _fairscan._tcp
  • Android 端 NSD 搜索 _fairscan._tcp
  • 用户确认选择目标主机
  • 手机端调用 GET /health 校验

发现流程

  1. PC 启动 HTTP 服务
  2. PC 注册 mDNS 服务
  3. 手机点击“扫描局域网主机”
  4. Android NSD 开始发现
  5. 解析 host、port、features
  6. 展示设备列表
  7. 用户选择设备
  8. 手机执行 GET /health
  9. 校验成功后保存为当前目标主机

备用方案触发条件

只有在以下情况长期存在时,才考虑第二通道:

  • 大量设备无法发现 mDNS
  • 企业网络场景较多
  • Windows 防火墙导致广播不稳定

此时再评估:

  • 自定义 UDP 广播
  • 指定网段 HTTP 探测

默认不建议首版同时做两套发现机制。


6. Android 端建议修改点清单

6.1 权限与清单

当前 Manifest 尚未为新网络能力补齐联网权限:

  • app/src/main/AndroidManifest.xml:1

后续大概率需要新增:

  • android.permission.INTERNET
  • android.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:57
  • app/src/main/java/org/fairscan/app/ui/screens/settings/SettingsRepository.kt:31

建议新增“局域网协作”分组:

  • PC 主机地址
  • 端口
  • 当前手机 IP
  • 扫描局域网主机按钮
  • 已发现主机列表
  • 图传质量预设
  • 默认处理类型
  • 自动下载结果开关
  • 测试连接按钮
  • 打开系统 WiFi 设置快捷入口(可选)

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

建议后续加入:

  • lanServiceDiscovery
  • streamClient
  • uploadClient
  • taskClient
  • artifactDownloadClient
  • networkInfoProvider

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=1
  • upload=1
  • process=1
  • download=1
  • apiVersion=1

如需更细粒度,也可通过 GET /health 返回:

{
  "name": "FairScan-PC-Office",
  "status": "ok",
  "features": ["stream", "upload", "process", "download"],
  "processTypes": ["markdown", "ocrpdf"]
}

8. 风险与难点

8.1 实时图传的延迟与稳定性

风险:

  • CameraX 分析 + 压缩 + 网络发送会叠加延迟
  • 发送队列积压会使画面越来越慢

应对:

  • 固定抽帧
  • 只保留最新帧
  • 上一帧未发完则直接丢弃当前帧
  • 后台线程压缩与发送
  • 优先保证低延迟而不是高保真

8.2 Android 网络与 WiFi 限制

风险:

  • 获取 WiFi 名称和网络信息在新系统上限制较多
  • App 内切换 WiFi 成本高且兼容性差

应对:

  • 不在 App 内切换 WiFi
  • 只显示网络信息
  • 必要时提供“打开系统 WiFi 设置”入口

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
  • 定义 DiscoveredHostDiscoveryState
  • 扫描 _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-4PC 端统一接口占位实现

  • POST /tasks/process
  • GET /tasks/{id}
  • GET /tasks/{id}/artifacts
  • GET /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. 建议的实现优先级

推荐开发顺序:

  1. 主机发现 + 健康检查
  2. 实时图传
  3. 手机本地 PDF 上传到 PC
  4. 统一处理任务接口与结果下载
  5. 发现机制与任务体验优化

理由:

  • 你当前最关心的是实时图传,所以图传优先
  • 图传与文档处理解耦,优先完成图传不会阻碍后续 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 内做 WiFi 切换
  • 不要同时为 markdownocrpdf 设计两套完全独立的客户端协议
  • 不要让 Android 端过早耦合 PC 内部处理器实现细节

12.4 如果由 AI 编码代理执行

执行顺序建议严格按以下优先级推进:

  1. 发现与连接
  2. 实时图传
  3. PDF 上传
  4. 统一处理接口
  5. 结果下载
  6. 再考虑真实接入 MinerU/OCRmyPDF

如果 AI 只能做一部分任务,优先确保:

  • 接口稳定
  • 状态模型稳定
  • UI 路径清晰
  • 占位实现可联调

13. 与原始需求的映射关系

  • “文件原有的离线扫描功能”
    • 对应当前现有扫描/导出链路
  • “手机网络图传功能”
    • 对应模块 B且定位为低延迟实时图传
  • “局域网内压缩广播的实时网络摄像头”
    • 对应模块 B第一版建议做点对点实时图传
  • “压缩力度可选”
    • 对应图传质量预设
  • “离线扫描 PDF 通过 WiFi 协议发送给 PC”
    • 对应模块 C
  • “显示自己的 IP 和端口”
    • 对应模块 A
  • “MinerU 转成 Markdown”
    • 对应统一处理接口中的 processType=markdown
  • “OCRmyPDF 转成双层 PDF”
    • 对应统一处理接口中的 processType=ocrpdf
  • “PC 处理完毕后再传回手机”
    • 对应模块 E推荐技术实现为手机主动下载结果