Files
mnote/bugs/03-rust-web/done/3-27-mineru-ocr-design-without-runtime-implementation-v1.md
T

9.4 KiB
Raw Blame History

3-27 MinerU OCR 后端 runtime 已落地但缺前端任务链

状态

  • 状态:done
  • Owner03-rust-web / local-folder OCR / MinerU sidecar
  • 发现时间:2026-05-31

现象

P2 目标中包含 MinerU OCR 能力收口。当前已补后端 mock route、真实 MinerU HTTP client、sidecar 写入、.mnote/ocr-index.jsonincludeOcr=true 搜索命中、resource tab 图片/PDF OCR 工具条、附件/File Tree 资源菜单入口、active job store、local_ocr.job.updated realtime event、全局任务栏/任务抽屉、AI OCR sidecar context 和浏览器 UI smoke。

证据

  • rust/crates/mnote-web/src/routes/local_ocr.rs 已注册 jobs/status/read/insertprovider=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;增量刷新也已排除 hash 后缀 OCR sidecar,不再把 *.ocr.md 当普通页面命中。
  • task526-local-folder-ocr-api-smoke.js 已覆盖浏览器上下文调用 mock OCR API、图片 resource tab 手动 OCR、工具条状态、打开 OCR、搜索命中和显式 insert 链接。
  • 活动任务生命周期、local_ocr.job.updated、全局任务抽屉和 AI OCR context 已完成并有测试/smoke 覆盖。

影响

  • 用户已能从本地图片/PDF resource tab、附件菜单和 File Tree 资源菜单触发 OCR;离开当前资源后可通过全局 OCR 任务抽屉查看状态、打开 OCR、对失败/stale 任务重试。
  • 搜索的 includeOcr=true 已能命中 OCR sidecarincludeOcr=false 不应命中普通 OCR sidecar;本轮补了增量索引过滤测试。
  • AI image/PDF resource context 会优先读取已有 OCR Markdown,并把 OCR context 附到 active_editor contextRef 与 targetPackage。

下一步

  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。

验收

  • Rust route/helper 测试覆盖 sidecar 路径/frontmatter、index stale/error redaction、mock OCR job 写入、status/read、无 token、越界拒绝、非图片/PDF 拒绝、mock 失败 response 脱敏和显式 insert link。
  • local search 测试覆盖 OCR 命中返回 owner page,普通与 hash 后缀 OCR sidecar 不作为普通页面。
  • Page Tree 测试覆盖 OCR sidecar 可在 File Tree 作为资源文件可见,但不作为普通页面进入 Page Tree。
  • Rust route 测试覆盖无 token response 形态。
  • Rust route 测试覆盖 provider=mineru 后端成功路径:申请上传 URL、PUT 上传、轮询结果、下载 zip、提取 Markdown、写 sidecar/index。
  • 浏览器 smoke 覆盖图片/PDF 手动 OCR、任务栏状态、打开 OCR、搜索 OCR 命中和插入 OCR 链接。

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:全局任务栏、active job store / realtime event 和 AI 资源上下文尚未完成。

2026-06-01 只读复核更新:

  • Subagent 复核确认:route/mock/search 测试已落地,早期“没有实际 OCR route”的描述已经过时。
  • 本 bug 不归档的阻塞点更新为: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,在真实浏览器登录态页面内通过 UI 和 fetch 串起图片 resource tab OCR 工具条、POST /api/local-folder/ocr/jobsstatusreadjobs/api/search/documents includeOcr=truePOST /api/local-folder/ocr/insert
  • 已验证 provider=mock 会生成 docs/Page.ocr/photo.png.ocr.mdresource tab 工具条显示 OCR 完成并可打开/插入;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/03-ocr-resource-tab.pngOCR 工具条截图写入 tmp/task526-local-folder-ocr-api-smoke/02-ocr-toolbar.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/taskhttps://mineru.net/api/v4/file-urls/batch 作为精准解析入口;model_version 支持 pipeline / vlm / MinerU-HTMLMarkdown/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_urlmineru_poll_intervalmineru_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

2026-06-01 OCR P2 收口记录

  • AppState 新增 OCR active job store 与 local_ocr_job_txPOST /api/local-folder/ocr/jobs 在 queued / uploading / mineru_processing / downloading / writing_sidecar / done / failed 阶段更新 index 并广播 local_ocr.job.updated
  • /api/local-folder/events 会把同 root 的 OCR job update 作为 SSE 事件透出。
  • document-resource-tab-runtime.js 新增全局 OCR 任务 dock / drawer,从 jobs API 恢复状态,并通过 local_ocr.job.updated 更新;支持打开 OCR sidecar 与失败/stale 重试。
  • sidebar-page-ai-target-runtime.js / sidebar-page-ai-runtime.js 在 Page AI run 前读取 active image/PDF 资源已有 OCR sidecar,把 mnote.local_ocr_context.v1 放入 active_editor contextRef、targetPackage、currentFile 和 primary target。
  • task526-local-folder-ocr-api-smoke.js 覆盖全局 OCR 任务抽屉状态。
  • TASK520_OCR_CONTEXT=1 node scripts/task520-page-ai-raw-resource-target-smoke.js 覆盖 Page AI OCR sidecar context。
  • 已通过:
    • node --check rust/crates/mnote-web/browser/document-resource-tab-runtime.js
    • node --check rust/crates/mnote-web/browser/sidebar-page-ai-runtime.js
    • node --check rust/crates/mnote-web/browser/sidebar-page-ai-target-runtime.js
    • node --check scripts/task526-local-folder-ocr-api-smoke.js
    • node --check scripts/task520-page-ai-raw-resource-target-smoke.js
    • cargo fmt --check --all
    • 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
    • MNOTE_UI_BASE_URL=http://127.0.0.1:3000 MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3000 node scripts/task526-local-folder-ocr-api-smoke.js
    • TASK520_OCR_CONTEXT=1 MNOTE_UI_BASE_URL=http://127.0.0.1:3000 MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3000 node scripts/task520-page-ai-raw-resource-target-smoke.js