收口 MinerU OCR 任务链与上下文
This commit is contained in:
@@ -36,7 +36,7 @@ node scripts/task490-runtime-surfaces-smoke.js
|
||||
- Rust SSR 文档页 / Page Aggregate:local-first 默认优先 `task167-local-markdown-title-body-options-no-convex-smoke.js`;Page Aggregate browser conversion / compat fallback 改动补跑 `task522-page-aggregate-compat-fallback-contract.js`;cloud/control-plane 文档可补跑 `task110-page-title-single-truth-smoke.js`、`task-page-aggregate-body-sync-smoke.js`、`task-page-aggregate-options-sync-smoke.js`、`task-page-aggregate-refresh-persistence-smoke.js`
|
||||
- leptos-tiptap runtime surface:`task490-runtime-surfaces-smoke.js`;需要验证保存回读可补跑 `task121-rust-web-editor-island-hydration-smoke.js`,但它仍使用 `/api/tree/commands create` 准备文档,不作为无 Convex 默认基线;需要验证浮层互斥和更多菜单状态时再跑 `task158-e30-menu-state-smoke.js`
|
||||
- local-first 本地工作区:`task164-desktop-hot-local-folder-main-entry-smoke.js`、`task166-local-first-managed-workspace-no-convex-smoke.js`、`task167-local-markdown-title-body-options-no-convex-smoke.js`、`task436-local-markdown-open-document-external-change-smoke.js`、`task443-local-markdown-asset-upload-smoke.js`、`task451-local-markdown-conflict-resolution-ui-smoke.js`、`task452-local-search-index-browser-smoke.js`、`task453-local-folder-page-ai-changed-files-smoke.js`;WorkspacePath / ObjectIdentity runtime 消费统一改动补跑 `task524-workspace-object-identity-matrix-smoke.js`
|
||||
- local-folder OCR:`task526-local-folder-ocr-api-smoke.js` 覆盖图片 resource tab 手动 OCR、工具条状态、mock OCR API、sidecar 落盘、jobs/status/read、`includeOcr=true` 搜索 owner page、显式插入 OCR 链接和 OCR sidecar Markdown resource tab 打开;它不代表全局 OCR 任务栏 / 任务抽屉、active job store 或 `local_ocr.job.updated` 已完成。
|
||||
- local-folder OCR:`task526-local-folder-ocr-api-smoke.js` 覆盖图片 resource tab 手动 OCR、工具条状态、mock OCR API、sidecar 落盘、jobs/status/read、全局 OCR 任务栏 / 任务抽屉、`includeOcr=true` 搜索 owner page、显式插入 OCR 链接和 OCR sidecar Markdown resource tab 打开;`TASK520_OCR_CONTEXT=1 node scripts/task520-page-ai-raw-resource-target-smoke.js` 覆盖 Page AI active image/PDF resource target 读取 OCR sidecar context。
|
||||
- local Markdown conflict regression:`task510-local-markdown-conflict-regression-group.js` 串联真实冲突、连续上传、新建页面、外部恢复、多 tab CAS 与上传 409 孤儿策略;可用 `MNOTE_CONFLICT_REGRESSION_TASKS=a.js,b.js` 做定点子集。
|
||||
- tree realtime / live cache:`task446-tree-rename-dual-browser-live-smoke.js`、`task447-tree-move-order-dual-browser-live-smoke.js`、`task448-tree-resync-recovery-dual-browser-smoke.js`、`task449-tree-sse-reconnect-snapshot-recovery-smoke.js`
|
||||
- 资源对象与 mindmap:`task455-local-folder-mindmap-clean-smoke.js`、`task456-resource-object-shell-sync-smoke.js`、`task166-mindmap-phase6-block-smoke.js`、`task167-mindmap-kmind-parity-smoke.js`、`task168-mindmap-put-validator-smoke.js`;Page AI mindmap skill / 资源生成改动补跑 `task503-mindmap-skill-capability-smoke.js`,真实 mindmap resource tab / Page AI target 改动补跑 `task525-page-ai-mindmap-resource-target-smoke.js`
|
||||
|
||||
@@ -102,6 +102,17 @@ async function saveScreenshot(page, name) {
|
||||
return target;
|
||||
}
|
||||
|
||||
function cleanupRoot(root) {
|
||||
for (let attempt = 0; attempt < 5; attempt += 1) {
|
||||
try {
|
||||
fs.rmSync(root, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
||||
return;
|
||||
} catch (error) {
|
||||
if (attempt === 4) throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
fs.mkdirSync(OUT_DIR, { recursive: true });
|
||||
const actorId = "mnote-e2e";
|
||||
@@ -109,7 +120,9 @@ async function main() {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), "mnote-task520-raw-target-"));
|
||||
const rootUri = fileUrl(root);
|
||||
const pagePath = "Page.md";
|
||||
const rawPath = "Page/notes.txt";
|
||||
const expectOcrContext = process.env.TASK520_OCR_CONTEXT === "1";
|
||||
const rawPath = expectOcrContext ? "Page/photo.png" : "Page/notes.txt";
|
||||
const ocrPath = "Page.ocr/photo.png.ocr.md";
|
||||
const documentId = localMdDocumentId(pagePath);
|
||||
const captured = [];
|
||||
let caughtError = null;
|
||||
@@ -117,7 +130,41 @@ async function main() {
|
||||
fs.mkdirSync(path.join(root, "Page"), { recursive: true });
|
||||
writeWorkspaceManifest(root, actorId, workspaceId);
|
||||
fs.writeFileSync(path.join(root, pagePath), "# Page\n\nTask520 page\n", "utf8");
|
||||
fs.writeFileSync(path.join(root, rawPath), "Task520 raw resource target\n", "utf8");
|
||||
if (expectOcrContext) {
|
||||
fs.writeFileSync(path.join(root, rawPath), Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a]));
|
||||
fs.mkdirSync(path.join(root, "Page.ocr"), { recursive: true });
|
||||
fs.writeFileSync(
|
||||
path.join(root, ocrPath),
|
||||
"---\nmnote_ocr_version: 1\nprovider: mock\nmodel_version: vlm\nowner_document: ../Page.md\nsource_path: ./Page/photo.png\nsource_root_relative_path: Page/photo.png\nsource_size: 6\nsource_mtime_ms: 1\nstatus: done\ncreated_at: 1\nupdated_at: 1\n---\n\nTask520 OCR sidecar context text\n",
|
||||
"utf8",
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(root, ".mnote", "ocr-index.json"),
|
||||
`${JSON.stringify({
|
||||
version: 1,
|
||||
entries: {
|
||||
[rawPath]: {
|
||||
jobId: "ocr_task520",
|
||||
ownerDocumentId: documentId,
|
||||
ownerDocumentPath: pagePath,
|
||||
sourceRootRelativePath: rawPath,
|
||||
ocrRootRelativePath: ocrPath,
|
||||
provider: "mock",
|
||||
modelVersion: "vlm",
|
||||
status: "done",
|
||||
sourceSize: 6,
|
||||
sourceMtimeMs: 1,
|
||||
createdAtMs: 1,
|
||||
updatedAtMs: 1,
|
||||
plainTextPreview: "Task520 OCR sidecar context text",
|
||||
},
|
||||
},
|
||||
}, null, 2)}\n`,
|
||||
"utf8",
|
||||
);
|
||||
} else {
|
||||
fs.writeFileSync(path.join(root, rawPath), "Task520 raw resource target\n", "utf8");
|
||||
}
|
||||
|
||||
const browser = await chromium.launch({
|
||||
headless: process.env.HEADFUL !== "1",
|
||||
@@ -243,7 +290,8 @@ async function main() {
|
||||
const targetChip = page.locator("[data-page-ai-target-chip]");
|
||||
await targetChip.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
const chipText = (await targetChip.innerText({ timeout: UI_TIMEOUT_MS })).trim();
|
||||
assert(chipText.includes("notes.txt"), `raw resource 打开后 target chip 应指向 notes.txt: ${chipText}`);
|
||||
const expectedName = expectOcrContext ? "photo.png" : "notes.txt";
|
||||
assert(chipText.includes(expectedName), `raw resource 打开后 target chip 应指向 ${expectedName}: ${chipText}`);
|
||||
|
||||
await page.locator("[data-page-ai-input]").fill("Task520 raw target", { timeout: UI_TIMEOUT_MS });
|
||||
await page.locator('[data-page-ai-action="send"]').click({ timeout: UI_TIMEOUT_MS });
|
||||
@@ -268,19 +316,26 @@ async function main() {
|
||||
assert.strictEqual(runBody.targetPackage?.currentFile?.relativePath, rawPath, `targetPackage currentFile 应指向 raw resource: ${JSON.stringify(runBody.targetPackage)}`);
|
||||
assert.strictEqual(runBody.targetPackage?.currentFile?.objectIdentity, "resource:file:" + rootUri + ":" + rawPath, `currentFile objectIdentity 不应退化为 [object Object]: ${JSON.stringify(runBody.targetPackage?.currentFile)}`);
|
||||
assert(runBody.targetPackage?.allowedFiles?.includes(rawPath), `allowedFiles 应只包含 raw resource: ${JSON.stringify(runBody.targetPackage?.allowedFiles)}`);
|
||||
if (expectOcrContext) {
|
||||
assert.strictEqual(activeEditorRef.ocrContext?.source, "local_ocr_sidecar", `active_editor 应携带 OCR sidecar context: ${JSON.stringify(activeEditorRef)}`);
|
||||
assert.strictEqual(activeEditorRef.ocrContext?.ocrRootRelativePath, ocrPath, `active_editor OCR path 不正确: ${JSON.stringify(activeEditorRef.ocrContext)}`);
|
||||
assert(activeEditorRef.ocrContext?.plainTextPreview?.includes("Task520 OCR sidecar context text"), `active_editor OCR preview 缺失: ${JSON.stringify(activeEditorRef.ocrContext)}`);
|
||||
assert.strictEqual(runBody.targetPackage?.ocrContext?.ocrRootRelativePath, ocrPath, `targetPackage 应携带 OCR sidecar context: ${JSON.stringify(runBody.targetPackage)}`);
|
||||
assert.strictEqual(runBody.targetPackage?.currentFile?.ocrRootRelativePath, ocrPath, `currentFile 应携带 OCR sidecar path: ${JSON.stringify(runBody.targetPackage?.currentFile)}`);
|
||||
}
|
||||
|
||||
const screenshot = await saveScreenshot(page, "01-raw-resource-target");
|
||||
const result = { ok: true, task: TASK, baseUrl: BASE_URL, root, rootUri, documentId, rawPath, screenshot, captured };
|
||||
const result = { ok: true, task: TASK, baseUrl: BASE_URL, root, rootUri, documentId, rawPath, ocrPath: expectOcrContext ? ocrPath : "", screenshot, captured };
|
||||
fs.writeFileSync(RESULT_PATH, `${JSON.stringify(result, null, 2)}\n`, "utf8");
|
||||
console.log(JSON.stringify(result, null, 2));
|
||||
} catch (error) {
|
||||
caughtError = error;
|
||||
await saveScreenshot(page, "failure").catch(() => undefined);
|
||||
} finally {
|
||||
fs.rmSync(root, { recursive: true, force: true });
|
||||
await page.close().catch(() => undefined);
|
||||
await context.close().catch(() => undefined);
|
||||
await browser.close().catch(() => undefined);
|
||||
cleanupRoot(root);
|
||||
}
|
||||
|
||||
if (caughtError) {
|
||||
|
||||
@@ -134,6 +134,17 @@ async function main() {
|
||||
await page.waitForFunction(() => document.querySelector('[data-mnote-local-ocr-status="done"]'), null, {
|
||||
timeout: UI_TIMEOUT_MS,
|
||||
});
|
||||
await page.getByTestId("mnote-local-ocr-task-toggle").waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
await page.getByTestId("mnote-local-ocr-task-toggle").click({ timeout: UI_TIMEOUT_MS });
|
||||
await page.getByTestId("mnote-local-ocr-task-drawer").waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
await page.waitForFunction(
|
||||
(sourcePath) => {
|
||||
const row = document.querySelector(`[data-mnote-local-ocr-task-row="${CSS.escape(sourcePath)}"]`);
|
||||
return row && row.getAttribute("data-mnote-local-ocr-task-status") === "done";
|
||||
},
|
||||
sourceRootRelativePath,
|
||||
{ timeout: UI_TIMEOUT_MS },
|
||||
);
|
||||
const uiOcrPath = await page.locator('[data-mnote-local-ocr-path]').first().getAttribute("data-mnote-local-ocr-path");
|
||||
assert(uiOcrPath && uiOcrPath.endsWith(".ocr.md"), `UI OCR path invalid: ${uiOcrPath}`);
|
||||
screenshots.ocrToolbar = path.join(OUTPUT_DIR, "02-ocr-toolbar.png");
|
||||
|
||||
Reference in New Issue
Block a user