Files
mnote/bugs/03-rust-web/process/3-27-mineru-ocr-design-without-runtime-implementation-v1.md
T
lix-2026 1882db7681 收口 MNote P0 P1 P2 审查尾项
- 归档 OnlyOffice live bridge、Page AI、mindmap、design governance 与相关 bug 条目
- 补齐 MinerU OCR 后端 runtime 合同与 smoke/test 基线
- 收口 ChatOnly/Doubao、ObjectIdentity、Page Aggregate compat 与 runtime owner 文档口径

验证:
- cargo test --manifest-path rust/Cargo.toml -p mnote-web local_ocr -- --test-threads=1
- cargo test --manifest-path rust/Cargo.toml -p mnote-web onlyoffice_bridge -- --test-threads=1
- git diff --check
- git diff --cached --check
- codegraph index . --force && codegraph status .
- codegraph sync . && codegraph status .
2026-06-01 09:29:12 +08:00

104 lines
7.3 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.
# 3-27 MinerU OCR 后端 runtime 已落地但缺前端任务链
## 状态
- 状态:process
- Owner03-rust-web / local-folder OCR / MinerU sidecar
- 发现时间:2026-05-31
## 现象
P2 目标中包含 MinerU OCR 能力收口。当前已补后端 mock route、真实 MinerU HTTP client、sidecar 写入、`.mnote/ocr-index.json``includeOcr=true` 搜索命中和浏览器 API smoke。但 active job store、realtime job event、前端入口/任务栏仍未落地。
## 证据
- `rust/crates/mnote-web/src/routes/local_ocr.rs` 已注册 `jobs/status/read/insert``provider=mock` 能写入 `{pageStem}.ocr/*.ocr.md``.mnote/ocr-index.json`
- `provider=mineru` 在有 token 时会走真实 HTTP client:申请上传 URL、PUT 上传、轮询结果、下载 zip、提取 Markdown,并写入 `{pageStem}.ocr/*.ocr.md` / `.mnote/ocr-index.json`。该路径已有本地 HTTP mock 单测覆盖,不访问外网。
- `local_search_index` 已支持 `includeOcr=true` 命中 OCR owner page`task526-local-folder-ocr-api-smoke.js` 已覆盖浏览器上下文调用 mock OCR API、搜索命中和显式 insert 链接。
- 设计中的活动任务生命周期、`local_ocr.job.updated` 和浏览器可见入口仍未完成。
## 影响
- 用户无法从本地图片或图片型 PDF 通过 UI 手动触发 MinerU OCR。
- 搜索的 `includeOcr=true` 已能命中 OCR sidecar,但真实 MinerU 结果仍缺 UI 触发链和任务状态可见性。
- AI 资源上下文无法优先读取已有 OCR Markdown。
## 下一步
1. 已完成后端 mock 最小闭环:路径规划、sidecar frontmatter、`.mnote/ocr-index.json`、mock OCR job route、status/read、Page Tree 过滤和 `includeOcr=true` 搜索 owner page。
2. 已补浏览器 API smokemock OCR、status/read/jobs、`includeOcr=true` 搜索 owner page 和显式 insert link。
3. 下一步接长任务状态、`local_ocr.job.updated` realtime 事件、前端 OCR 入口/任务栏和 AI 资源上下文读取 OCR sidecar。
## 验收
- [x] Rust route/helper 测试覆盖 sidecar 路径/frontmatter、index stale/error redaction、mock OCR job 写入、status/read、无 token、越界拒绝、非图片/PDF 拒绝、mock 失败 response 脱敏和显式 insert link。
- [x] local search 测试覆盖 OCR 命中返回 owner pageOCR sidecar 不作为普通页面。
- [x] Page Tree 测试覆盖 OCR sidecar 可在 File Tree 作为资源文件可见,但不作为普通页面进入 Page Tree。
- [x] Rust route 测试覆盖无 token response 形态。
- [x] Rust route 测试覆盖 `provider=mineru` 后端成功路径:申请上传 URL、PUT 上传、轮询结果、下载 zip、提取 Markdown、写 sidecar/index。
- [~] 浏览器 smoke 覆盖图片/PDF 手动 OCR、任务栏状态、打开 OCR、搜索 OCR 命中和插入 OCR 链接。(当前 `task526` 覆盖 mock OCR API、搜索命中、显式 insert link 和 OCR sidecar resource tab 打开;真实 UI 入口/任务栏待做)
## 2026-06-01 后端 mock 闭环记录
新增 `rust/crates/mnote-web/src/routes/local_ocr.rs`,注册:
- `POST /api/local-folder/ocr/jobs`
- `GET /api/local-folder/ocr/jobs`
- `GET /api/local-folder/ocr/status`
- `GET /api/local-folder/ocr/read`
- `POST /api/local-folder/ocr/insert`
当前真实 MinerU HTTP client 仍未接入;`provider=mock` 用于本地后端闭环和测试,`provider=mineru` 在缺少 token 时返回 `mineru_token_missing`,有 token 时返回 `mineru_runtime_not_enabled`,避免伪装真实能力已完成。
已通过验证:
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_ocr -- --test-threads=1`
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_search_ocr -- --test-threads=1`
2026-06-01 续补 route 边界测试:
- 越界来源路径拒绝:`local_ocr_path_escape`
- 非图片/PDF 来源拒绝:`local_ocr_source_type_unsupported`
- provider `mineru` 且缺 token 时拒绝:`mineru_token_missing`
- mock 失败响应与 `.mnote/ocr-index.json` 失败条目统一脱敏为 `provider_error_redacted`
- 显式 `ocr/insert` link 模式把 `[OCRphoto.png](./Page.ocr/photo.png.ocr.md)` 追加进 owner Markdown;未调用 insert 时不改正文
本文继续保持 `process`:前端 OCR 入口、任务栏和 active job / realtime event 尚未完成。
2026-06-01 只读复核更新:
- Subagent 复核确认:route/mock/search 测试已落地,早期“没有实际 OCR route”的描述已经过时。
- 本 bug 不归档的阻塞点更新为:真实 MinerU HTTP client、active job store / `local_ocr.job.updated`、前端入口/任务栏、AI 资源上下文读取 OCR sidecar 和完整 UI browser smoke。
2026-06-01 浏览器 API smoke 续补:
- 新增 `scripts/task526-local-folder-ocr-api-smoke.js`,在真实浏览器登录态页面内通过 `fetch` 串起 `POST /api/local-folder/ocr/jobs``status``read``jobs``/api/search/documents includeOcr=true``POST /api/local-folder/ocr/insert`
- 已验证 `provider=mock` 会生成 `docs/Page.ocr/photo.png.ocr.md``includeOcr=false` 不命中 OCR 文本,`includeOcr=true` 返回 owner page 且带 `hasOcr/ocrEvidence`,显式 insert 才向 owner Markdown 追加 `[OCRphoto.png](...)`
- 续补后已验证 OCR sidecar 可作为 Markdown resource tab 打开,截图写入 `tmp/task526-local-folder-ocr-api-smoke/02-ocr-resource-tab.png`
- 已通过:
- `node --check scripts/task526-local-folder-ocr-api-smoke.js`
- `MNOTE_UI_BASE_URL=http://127.0.0.1:3301 MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3301 node scripts/task526-local-folder-ocr-api-smoke.js`
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_ocr -- --test-threads=1`
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_search_ocr -- --test-threads=1`
2026-06-01 MinerU API 口径复核:
- 官方文档当前仍以 `https://mineru.net/api/v4/extract/task``https://mineru.net/api/v4/file-urls/batch` 作为精准解析入口;`model_version` 支持 `pipeline` / `vlm` / `MinerU-HTML`Markdown/JSON 为默认结果格式,图片/PDF/Office 等文档受文件大小与页数限制。
- 当前设计稿中的“申请上传地址 -> PUT 上传 -> 轮询批量结果 -> 下载 zip -> 提取 Markdown”方向仍成立。
- 旧回归测试曾要求 `MNOTE_MINERU_API_TOKEN` 存在且 provider 为 `mineru` 时返回 `mineru_runtime_not_enabled`;该口径已被真实后端 runtime 合同测试替代。
## 2026-06-01 后端 MinerU runtime 补齐记录
- `rust/crates/mnote-web/src/routes/local_ocr.rs` 已补 `mineru_api_base_url``mineru_poll_interval``mineru_max_polls` 配置函数。
- `provider=mineru` 后端路径已接入 `run_mineru_ocr`,执行申请上传 URL、PUT 上传、轮询 batch 结果、下载 zip、提取 Markdown。
- 新增本地 HTTP mock 测试 `local_ocr_jobs_route_runs_mineru_runtime_against_http_mock`,不访问外网,验证真实 client 合同和 sidecar/index 写入。
- 已通过:
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_ocr -- --test-threads=1`
本文继续保持 `process` 的剩余原因:
- 前端本地文件 / 图片 / PDF 资源没有 OCR 操作入口。
- OCR jobs 仍是同步请求 + `.mnote/ocr-index.json` 历史状态,没有 active job store。
- 缺少 `local_ocr.job.updated` realtime event 与全局任务栏 UI。
- AI 资源上下文还没有优先读取 OCR sidecar。