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

1386 lines
33 KiB
Markdown
Raw Permalink 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 功能细化规划(执行版)
> 基于 `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
- 处理类型:`markdown``ocrpdf`
- 输出:
- `markdown` -> 返回 `.md` 及相关资源
- `ocrpdf` -> 返回处理后的 `.pdf`
也就是说:
- **接口统一**
- **任务状态统一**
- **产物查询统一**
- **差异只体现在处理类型和产物 MIME 类型**
### 2.5 结果回到手机
从产品描述上可以说:
- PC 处理完毕后,把结果回传到手机
但从工程实现角度,推荐这样定义:
- 手机端上传后拿到 `taskId`
- 手机端轮询任务状态
- 任务完成后,手机端拉取产物列表
- 手机端主动下载产物到本地
这样做比“PC 主动推送到手机”更适合 Android
- 不需要手机长期监听端口
- 更适合前台/后台切换
- 更容易失败重试
- 也更适合未来交由不同执行者实现
---
## 3. 建议的总体架构
建议按“手机端 + PC 端服务”的双端架构设计。
### 3.1 两条主链路
#### A. 实时图传链路
```text
手机相机预览帧
-> 抽帧/压缩
-> WebSocket 发送
-> PC 实时预览
```
特点:
- 目标是低延迟
- 允许丢帧
- 不追求逐帧可靠到达
- 不参与正式 PDF 生成
#### B. 文档处理链路
```text
手机扫描采集
-> 手机本地页面处理
-> 手机本地生成 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 name`FairScan-PC-{deviceName}`
#### 推荐 TXT Record 字段
- `name`:设备显示名
- `features``upload,stream,process,download`
- `version`PC 服务版本
- `apiVersion`:接口版本
说明:
- 这里建议把后处理能力统一成 `process`,而不是在发现层暴露过多具体工具细节。
- 是否支持 `markdown` / `ocrpdf`,可以通过健康检查响应或任务能力字段进一步细分。
#### Android 端发现状态模型
```text
DiscoveryState
- Idle
- Discovering
- Success(list)
- Empty
- Error(message)
```
#### 发现结果建议结构
```text
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`
- 输出文件类型
### 推荐任务类型
```text
processType
- markdown
- ocrpdf
```
### 输入输出约定
#### 输入
- 一个已上传或本次提交的 PDF
- 一个 `processType`
#### 输出
-`processType=markdown`
- 主要产物:`.md`
- 可选附加产物图片资源目录、JSON、日志
-`processType=ocrpdf`
- 主要产物:处理后的 `.pdf`
- 可选附加产物:日志、识别报告
### 推荐接口契约
#### 1. 创建任务
- `POST /tasks/process`
请求体建议:
```json
{
"fileId": "uploaded-file-id",
"processType": "markdown",
"options": {}
}
```
#### 2. 查询任务状态
- `GET /tasks/{taskId}`
返回体建议:
```json
{
"taskId": "task-123",
"status": "running",
"processType": "markdown",
"progress": 50,
"message": "processing",
"artifacts": []
}
```
#### 3. 查询产物列表
- `GET /tasks/{taskId}/artifacts`
返回体建议:
```json
[
{
"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 统一处理任务接口示例
#### 创建任务请求示例
```json
{
"fileId": "uploaded-file-id",
"processType": "ocrpdf",
"options": {}
}
```
#### 状态返回示例
```json
{
"taskId": "task-123",
"status": "completed",
"processType": "ocrpdf",
"progress": 100,
"message": "done"
}
```
#### 产物列表示例
```json
[
{
"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` 返回:
```json
{
"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
- 定义 `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-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 切换
- 不要同时为 `markdown``ocrpdf` 设计两套完全独立的客户端协议
- 不要让 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推荐技术实现为手机主动下载结果