Skip to content

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

500 Commits

Folders and files

Repository files navigation

Scriptorium

Scriptorium

把文档源转换成可编辑、可标注、可评测的 HTML,并保留足够的结构证据用于翻译和回渲染。

简体中文 English

Python Status Output Benchmark

快速开始 · 核心流程 · Benchmark · Gallery Demo · 文档

Scriptorium 是一个 source-neutral 的文档到 HTML 转换与评测引擎。当前主路径覆盖 PNG/JPEG/TIFF/WebP 图片、网页截图、PDF、网页打印 PDF 和 image-only PDF;图片源会作为一等 source 进入 IR,而不是先伪装成 PDF。

它会把源文档的文本、图像、矢量形状、OCR 结果和外部结构 JSON 合并到一个 DocumentIR,再导出带坐标和结构标记的 HTML。每个可编辑节点都保留来源、bbox、样式、role、reading stream 和编辑/翻译字段,后续可以写回 edited_text 或 translated_text,再打印或转换回 PDF。

适合什么场景

场景 Scriptorium 提供什么
文档编辑实验 把局部文本节点变成可定位、可替换、可回写的 HTML 元素。
文档翻译回渲染 保留源视觉层,翻译写入 translated_text,用浏览器实测 fitting,并检测 replacement mask、overflow 和邻近冲突。
论文/年报/门户页结构分析 识别多栏正文、表格岛、卡片网格、脚注、边栏、页眉页脚和局部 reading streams。
OCR/版面模型验证 接入 PaddleOCR-VL、PP-Structure、Docling、OpenDataLoader 和 ROOR 风格结构 JSON,让 OCR/结构 JSON 主导 image source 的语义层,并做 native-only 与 native-plus-structure A/B benchmark。
转换质量回归 HTML 打印回 PDF 后,输出视觉相似度、页面尺寸/页数匹配、语义顺序和风险指标。

为什么不是只用截图

很多 PDF-to-HTML / OCR-to-HTML 工具会把整页渲染成背景图,再覆盖一层透明文本。这样视觉上容易接近,但局部编辑、翻译、阅读顺序和结构标注都很弱。

Scriptorium 支持两条路径:

  • structured:尽量用 HTML/SVG 重建文本、图像和形状,便于检查结构和可编辑性。
  • fidelity:保留 SVG/raster 源视觉层,同时把识别出的文本和结构节点作为透明坐标锚点;编辑或翻译后,只对变更节点生成经浏览器 fitting 的局部 replacement overlay。

输出 HTML 中的节点会带上 data-scriptorium-* 元数据,例如 role、source、bbox、style id、reading order、reading stream、translation target 和 replacement risk。完整字段说明见 实现说明。

检测到的表格岛和卡片网格岛会把严格的原生局部 successor 证据与全页 candidate consensus 分开报告。诊断专用的 protected path-cover 候选会把有效 island 严格边作为约束,并单独报告拒绝或未解决的边。这样能稳定翻译流,同时不会假装正文或跨区域 handoff 已经解决。

独立 HTML 内置 window.ScriptoriumEdits:浏览器内的局部修改会生成可校验的 scriptorium-html-edits/v1 补丁,可通过 scriptorium apply-html-edits 写回同一份 DocumentIR 后再导出或打印。

Web page PDF conversion preview
网页 / 门户页 source
用 Playwright 打印 PDF 或截图,再转换成带 OCR/native 坐标锚点的 HTML。
Benchmark score preview
论文 / 年报 / 手册
用相同 benchmark 追踪不同 source 的视觉、语义顺序、候选分歧和翻译回渲染风险。

打开独立 Gallery Demo · GitHub 内查看

快速开始

python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
pip install -e .

图片、截图或扫描页可以直接作为 source 输入。已有 OCR/结构 JSON 时,它会先生成文本锚点,再用结构证据补 role、reading order 和 reading streams:

scriptorium convert \
  path/to/page.png \
  --input-kind image \
  --ocr-json path/to/page.ocr.json \
  --structure-json path/to/page.structure.json \
  --out-dir outputs/image-source

scriptorium export-html \
  outputs/image-source/document.ir.json \
  --out-dir outputs/image-source/html \
  --display-mode fidelity

保存的 PaddleOCR-VL JSON 会保留模型输入画布尺寸。Scriptorium 会通过其中的 width/height 映射像素 bbox,因此同一次模型运行可以安全地在不同转换或 benchmark DPI 下重放。

只需要布局和模型阅读顺序时,可跳过 OCR/VLM 识别,直接运行 PP-DocLayoutV3:

pip install -r requirements-ocr.txt
scriptorium run-paddle-layout path/to/paper.pdf \
  --page-ranges 1-3 --device cpu \
  --output outputs/paper.pp-doclayoutv3.json

扩大到 32 页 train-only 语料后,PP-DocLayoutV3 的序列化 relation F1 为 0.88870500,但其中同一 block 内的 line precision 为 0.99456226,真正跨 block 的 raw direct transition precision 只有 0.70343137;按 partial-label endpoint 评分为 287/362 = 0.79281768,另有 46 条 unscored。因此总 F1 不再作为模型顺序能力的代表, Provider 仍保持 review-only。完整方法和独立 test 结果见 外部基准。

若需要可重放的 PP-StructureV3 版面证据,可先安装可选 OCR 运行时、保存模型 JSON,再走普通的结构 A/B 路径:

pip install -r requirements-ocr.txt

scriptorium run-pp-structure path/to/paper.pdf \
  --max-pages 1 --dpi 144 --device cpu \
  --output outputs/paper.pp-structure.json

scriptorium benchmark-structure-ab path/to/paper.pdf \
  --max-pages 1 --dpi 144 \
  --structure-json outputs/paper.pp-structure.json \
  --out-dir outputs/paper-structure-ab

默认运行只聚焦布局;需要表格单元格或公式时可加 --table-recognition 或 --formula-recognition。保存的 JSON 是可审查证据,不会自动替换 native PDF 文本,也不等于整页阅读顺序已经无歧义。

对于数字 PDF,还可以使用 Apache-2.0 的 OpenDataLoader XY-Cut++ CPU provider。 它需要 Java 11+,输出始终为 review-only,不改变 runtime order:

pip install -r requirements-opendataloader.txt

scriptorium run-opendataloader path/to/paper.pdf \
  --page-ranges 1-3 \
  --output outputs/paper.opendataloader.json

Docling Heron 也可用于 PDF 或图片的布局候选。其标准化 JSON 默认是 review-only,并与 runtime order 和 successor consensus 隔离:

pip install -r requirements-docling.txt

scriptorium run-docling path/to/page.png \
  --output outputs/page.docling.json

请将标准化的 --output 用于结构 A/B;--raw-output 仅用于审查原始 Docling 结果。当前 held-out 结果不支持把 Docling reading order 提升为默认排序器。

需要研究真正的 successor relation 时,可以从 ROOR 官方 train split 本地训练轻量、 支持校准分叉的语义 ranker。输入可以是不含答案 relation 的 structure JSON 或多页 DocumentIR,输出默认 review-only:

pip install -r requirements-semantic-order.txt
scriptorium train-relation-ranker path/to/ROOR-Datasets/data \
  --semantic-scorer bert-tiny-uncased-nsp \
  --semantic-objective pointwise-plus-pairwise-borda \
  --granularity-augmentation successor-chain-blocks-v1 \
  -o outputs/models/relation-ranker.joblib
scriptorium run-relation-ranker page.structure.json \
  --model outputs/models/relation-ranker.joblib \
  -o outputs/page.relations.json

默认 v6 会分别学习绝对 successor confidence 和候选组内 pairwise-Borda 顺序;固定外部评测中, ROOR validation top/branch/path-cover F1 为 0.7293/0.7447/0.7209,Comp-HRDoc native/ path-cover F1 为 0.8999/0.9193。使用 --semantic-objective pointwise 可复现 v4。只加载本机 生成的 joblib 模型;manifest 会校验 SHA-256 并记录训练拆分、OOF 与校准指标。 实验性 v7 使用按文档 cross-fit 的 logistic head 估计 Borda winner 是否正确,不改变候选顺序; 通过 --semantic-objective pointwise-plus-pairwise-borda-calibrated 启用。它在全新且零重叠的 Comp-HRDoc 250 页窗口上将 native/plus-role F1 提高 +0.0050/+0.0052,但 ROOR path-cover F1 回退 -0.0088;因此 v6 仍是默认,两者都只输出 review-only evidence。 实验性 v8 将发出 confidence 与 incoming path priority 分开,只在共享 target 的 rank-1 edge 之间局部重排 priority。它在 fit OOF/固定 calibration 上提高 +0.0022/+0.0048,但冻结后在 新的零重叠 Comp-HRDoc 250 页窗口回退 -0.0005/-0.0006,因此未晋升也未事后调参; runtime_reorder 继续关闭。 实验性 v9 改为学习 baseline trajectory 上的 forced-completion regret,并在每个 decoder state 重新比较 feasible action。它保持 top/branch edge 不变,5-fold fit OOF 与固定 calibration 的 path-cover F1 分别提高 +0.0095/+0.0066;可通过显式 objective pointwise-plus-pairwise-borda-calibrated-path-opportunity-cost 训练。由于尚无独立同粒度外部 relation corpus,v6 仍是默认,v9 只输出 review metadata,runtime_reorder 保持关闭。 V10 保留 v6 objective 与 decoder,只在 ROOR fit 上加入 2-4 节点 coarse-block 训练增强。 它在冻结的 97 页 OmniDocBench gate 上把 path-cover F1 从 0.40270270 提高到 0.47789825,paired-page bootstrap 95% 下界为 0.10878042,通过全部预注册 gate。 推荐语义 relation 训练显式加入 --granularity-augmentation successor-chain-blocks-v1;推理输出仍为 review-only, runtime_reorder 不变。 显式 figure/table role 也会保留:局部 caption 几何关系会产生 review-only figure -> caption 或 caption -> table 证据,但不会改变 runtime 顺序; 多行 caption 使用不含答案的 layout block membership,这类证据与 learned text edge 分开标记。多个 figure/table 与 caption 同时出现时,使用全局一对一匹配, 先最大化有效配对数,再最大化总几何得分,不再让输入列表中靠前的图形抢占 caption。 Caption locality 不强制 bbox 水平相交,而使用 train-only 校准的 0.35 页宽中心距离 和 0.12 页高纵向间隔,因此可覆盖合法的左对齐/偏移 caption,同时拒绝远栏候选。

独立跨域关系基准可从 Comp-HRDoc 固定 test 文档生成;命令会把官方 order label 与 answer-free layout anchors 分开保存:

scriptorium fetch-comphrdoc --max-pages 5 \
  --out-dir data/external/comphrdoc-test

大规模 relation-only 实验可生成固定跨文档 floating prefix,无需下载或重新分发 页面图像,然后运行可复现的 A/B:

scriptorium fetch-comphrdoc-relations --sample-count 250 \
  --out-dir data/external/comphrdoc-relations
scriptorium train-floating-ranker /path/to/CompHRDoc.zip \
  --output outputs/models/floating-ranker.joblib
scriptorium benchmark-comphrdoc-relations data/external/comphrdoc-relations \
  --model outputs/models/relation-ranker.joblib \
  --floating-model outputs/models/floating-ranker.joblib

训练 provider 会在每个候选阈值上执行全局一对一 assignment,并用 source/target 两侧 竞争候选的最小 score gap 校准 margin。它还会从官方 train 文档的四折 cross-fit clean/mild/stress 视图训练 12 维线性 correctness forecaster;noise-aware gate 必须与原 confidence/margin gate 同时通过。固定 250 页 test 的 strict precision 为 clean 0.98461538、mild 0.97604790、stress 0.93965517。Stress 仍低于 0.97,因此输出继续 只是 review 证据,不是自动 runtime constraint。Corpus report 同时评分 noise-aware graphical subset、body/floating 联合 path cover、degree/cycle conflict 和 label-audit conflict。 可使用 --noise-profile mild 或 stress 运行确定性合成鲁棒性检查;这些 profile 不能取代真实 OCR provider benchmark。

可将已保存的 PaddleOCR-VL 或 Docling 输出与渲染 oracle anchor 匹配:

scriptorium run-paddle-layout-corpus data/external/comphrdoc-rendered \
  --out-dir outputs/provider-structure --partition all --device cpu

scriptorium benchmark-provider-anchor-suite data/external/comphrdoc-rendered \
  outputs/provider-structure --floating-model outputs/models/floating-ranker.joblib

Suite report 会分开 serialized_within_anchor、serialized_direct_between_anchors,并输出 native candidate support / provider confidence 曲线。冻结 gate 必须只读取 fit partition; 独立 test 只加载 gate 文件评分。Comp-HRDoc relation 是 partial label:当前报告将候选分为 eligible、scorable 与 unscored,precision 只对 label endpoint universe 内的边计分。 旧 209/219 是 partial-label-unaware 历史值;同一已打开 test window 的当前结果为 256/268 = 0.95522388,另有 16 条未评分边。页首与页末 Wilson 下界仍未过线。

64 页 train-only suite 的 gate v4 把可观测候选与允许计入支持票的通道分开。默认三通道的 aggregate OOF 为 192/195 = 0.98461538,calibration 为 21/21;加入 recursive XY-cut 后 calibration 变为 23/24,说明它还不能作为独立支持票。Fold、bucket、Wilson 和数量门槛 仍未全部通过,因此继续 reject-runtime-promotion,没有打开新的 test window。

Provider paragraph 仍允许多条 oracle line 映射到同一 block;figure/table 则使用 全局一对一 assignment。报告保留官方 relation 的原始分数,并额外输出 graphical_relation_audit,比较官方 graphical label 与 answer-free 局部几何建议。 该审计只用于发现 label/association 冲突,不是替代 ground truth,也不会改变 runtime。 同一报告中的 provider_degradation 会分开 missing、hallucination、size、split、merge、 overlap、duplicate 和 type confusion,并报告 bbox 误差、OCR/标题文本保真度与 clean/mild/stress 描述性距离。图表内部的小型 OCR 块单独记为 nested content,不误报为幻检。

可选的 Surya FastLayout provider 用独立环境安装。运行前必须明确接受模型权重 许可;输出的 learned order、label 和 successor relation 全部是 review-only, 不会改变 runtime role、reading stream 或顺序:

python3 -m venv .venv-surya
. .venv-surya/bin/activate
pip install -r requirements-surya.txt
pip install -e .

scriptorium run-surya-layout path/to/paper.pdf \
  --page-ranges 1-3 --device cpu \
  --accept-model-license \
  --output outputs/paper.surya-layout.json

若 learned-order head、detector feature map 或有效 permutation 缺失,或页面超过模型 支持的 box 容量,命令会直接失败,不会把 raster fallback 误记为 learned evidence。

当模型给出显式 block_order 的正文/段落 block,且匹配到的 native 行全部位于同一 已选 flow segment 和列中时,Scriptorium 会把它们提升为 external-block-body-* 本地翻译流。这个边界不会重排页面,也不会跨越 table、grid、caption、页眉页脚、 脚注或边栏;它用于让翻译和编辑按真实段落分批处理,而不是把 model block 当成全页 阅读顺序。

也可以用内置 PDF fixture 快速跑通完整链路:

scriptorium make-fixture --out-dir data/fixture

scriptorium convert \
  data/fixture/sample.pdf \
  --ocr-json data/fixture/sample.ocr.json \
  --out-dir outputs/sample

scriptorium export-html \
  outputs/sample/document.ir.json \
  --out-dir outputs/sample/html \
  --display-mode structured

打印回 PDF 并评分:

scriptorium print-pdf \
  outputs/sample/html/index.html \
  --pdf outputs/sample/export.pdf

scriptorium compare-pdf \
  data/fixture/sample.pdf \
  outputs/sample/export.pdf \
  --out-dir outputs/sample/pdf-quality

外部 OCR/结构模型不是核心依赖。没有 OCR/结构 JSON 时,image source 仍会得到整页图片 visual layer;有 OCR 或 Paddle/PP-Structure/Docling/ROOR 风格结构 JSON 时,会生成透明文本锚点和 reading-stream 证据。OpenDataLoader 本身只处理 PDF,不改变 image source 的一等输入地位。

可选 OCR 依赖放在 requirements-ocr.txt。Image-only OCR fallback 依赖系统 tesseract 和对应语言数据;本地运行 PP-StructureV3 时,还需要按 实现说明 设置对应 Paddle CPU 兼容环境变量。

核心流程

flowchart LR
  S[Document / image source] --> A{Source kind}
  A -->|Digital PDF| B[Native PDF Extractor]
  A -->|Image / screenshot| C[Image Renderer]
  A --> C2[Render Pages]
  C --> E[OCR / Structure JSON Adapter]
  C2 --> E
  B --> D[Image-only OCR Fallback]
  B --> E[Structure JSON Adapter]
  E --> F[Structure Evidence Fusion]
  B --> G[DocumentIR]
  C --> G
  C2 --> G
  D --> G
  F --> G
  G --> H[Annotation + Reading Streams]
  H --> I[Structured / Fidelity HTML]
  I --> J[Edit or Translate]
  J --> I
  I --> K[Print PDF]
  K --> L[Visual + Semantic Benchmark]
Loading

主要模块:

模块 作用
native_pdf.py 提取 native 文本、图像、drawing 和页面几何。
structure_evidence.py 归一化 PaddleOCR-VL / PP-Structure / Docling / ROOR 风格的结构证据。
paddle_layout_provider.py 运行 PP-DocLayoutV3,保存 review-only layout/order JSON 与可复核 provenance。
opendataloader_provider.py 运行 OpenDataLoader XY-Cut++ 并生成 review-only block/relation JSON。
ocr.py 把 OCR/结构 JSON 归一为 image/source text anchors,并记录语义层来源;对 image source,结构 JSON 可以是 semantic driver。
reading_order.py 处理多栏、表格岛、卡片网格、脚注、边栏、caption 和 reading streams。
provider_degradation.py 分解真实 OCR/layout provider 的几何、粒度、类型与文本退化。
html_export.py 导出 structured/fidelity HTML,保留编辑和翻译锚点。
benchmark.py 运行视觉、语义顺序、结构 A/B 和翻译回渲染 benchmark。

Benchmark

运行内置 benchmark:

scriptorium benchmark --out-dir outputs/benchmark-baseline --dpi 192

对外部文档运行高保真路径选择:

scriptorium benchmark path/to/file.pdf \
  --out-dir outputs/my-benchmark \
  --dpi 144 \
  --html-mode auto \
  --fidelity-background auto

对比 native-only 与外部结构证据:

scriptorium benchmark-structure-ab \
  path/to/source.pdf \
  --structure-json path/to/source.structure.json \
  --out-dir outputs/structure-ab \
  --dpi 144

压测翻译回渲染:

scriptorium benchmark path/to/file.pdf \
  --html-mode fidelity \
  --fidelity-background auto \
  --translation-stress pseudo-expand \
  --out-dir outputs/translation-stress \
  --dpi 144

图片源也可以直接 benchmark。视觉评分会比较源图片 visual layer 与 HTML 打印 PDF 的渲染结果;结构 JSON 会先生成 OCR/text anchors,再参与 reading-stream 和结构证据融合,并在报告中写入 semantic_layer_driver:

scriptorium benchmark path/to/page.png \
  --input-kind image \
  --image-dpi 96 \
  --structure-json path/to/page.structure.json \
  --html-mode structured \
  --out-dir outputs/image-benchmark

需要验证关系式阅读顺序时,可以下载官方 ROOR 验证集的固定前缀。生成的 structure/*.structure.json 只保留图片、文本和 bbox anchor;官方 ro_linkings 只写入相邻的评测 sidecar,绝不会作为 --structure-json 输入融合:

scriptorium fetch-roor \
  --split val \
  --sample-count 49 \
  --out-dir data/external/roor-validation-full-v1

两个以上独立 provider 使用同一组稳定 element ID 时,可以求交得到更低噪声的 review proposal。结果仍保持 sidecar_status: proposal,不能触发 runtime reorder:

scriptorium consensus-reading-sidecars \
  outputs/native/reading-order.sidecar.proposal.json \
  outputs/pp/reading-order.sidecar.proposal.json \
  outputs/surya/reading-order.sidecar.proposal.json \
  --output outputs/reading-order.consensus.proposal.json

一组冻结 semantic-order gate 使用固定 OmniDocBench v1.0 English 多栏页。V9 已被否决; 随后预注册的 V10 只用 ROOR fit 多粒度增强,在相同 97 页 gate 上将 aggregate/page-macro path-cover F1 提高 +0.07519555/+0.14886192,bootstrap 95% 区间为 [0.10878042, 0.19327117],双栏和三栏均提升。完整协议与分层结果见 外部基准。

最新的答案隔离 dependency 实验使用 64 张 SciPostLayoutTree poster。带全局 opportunity-cost 与 learned abstention 的 V18 在盲测推理前未通过 fit gate;预注册 V19 保留每条 V17 edge,并把新集 learned-control F1 从 0.41379310 提高到 0.41785375,但 geometry 明显更强,达到 0.64522822,且 bootstrap 区间跨 0。Runtime reorder 继续关闭;已经打开的 SciPost label 永久禁止用于后续调优。详见 V19 结果。

完整运行命令、关系指标和边界见 外部基准。

代表性样本的当前结果如下。详细命令、样本来源、checksum 和完整指标见 外部基准。

样本 页数 主要压力 Visual similarity 备注
Hacker News 打印 PDF 2 真实门户/列表页 0.9800288 有 semantic sidecar。
Attention Is All You Need 15 论文多栏和公式/图表 0.96840246 用于论文阅读顺序回归。
Transformer-XL 11 双栏论文和复杂页面尺寸 0.95679576 用于多栏 successor edge 验证。
BYD 2024 年报 40 中文年报、表格、密集线框 0.89780001 当前中文复杂 PDF 压力样本。
JD 首页截图 PDF 1 Image-only 电商首页 0.99576887 通过 OCR 生成透明编辑锚点。
JD 首页截图 PNG 1 一等 image source 路径 0.99236799 与 image-only PDF 兼容路径产生同规模 OCR/结构锚点。

visual_similarity = 1 - max_diff_ratio。报告同时记录页数/尺寸匹配、diff 分布、reading-order risk、candidate disagreement、grid/table/stream 统计和 replacement 风险。

编辑和翻译

source_text 永远保留原始识别结果。局部编辑写入 edited_text,翻译写入 translated_text。fidelity 模式会在打印时隐藏未修改节点,只为编辑或翻译后的节点生成局部、与源背景相容的 replacement layer。

翻译回渲染目前重点解决三类问题:

  • 长译文如何在原 bbox 内 fit。Chromium 会在字体加载后实测字形排版,搜索受限缩放,并在确有收益时压缩行高;静态 estimate 与实际 clipping 会分开记录,前者只用于 fallback 和 triage。
  • replacement mask 如何覆盖源文本但不破坏邻近元素。每个方向的 mask 都会在相邻可见元素处停止;亮色源文本落在深色 raster 边缘时会采样深色 mask,而不是固定白底。打印时还会把 source render pixel 映射到 96-DPI CSS 坐标,保证 replacement box、padding 和字号在导出 PDF 中不偏移。
  • 多栏、表格岛、卡片网格和边栏如何作为独立 reading stream 分批翻译。

这部分还不是完整的交互式文档编辑器。当前更像一个可测量的转换内核:它把风险显式标出来,让后续 UI、人工复核或模型结构证据有稳定的数据入口。

当前边界

  • 复杂页面的视觉还原可以靠 fidelity 背景层做得很接近;真正困难的是语义顺序、局部流结构和翻译后 replacement 冲突。
  • 没有结构先验时,门户页、商品网格、公告表格和扫描 OCR 页面的阅读顺序可能存在合理歧义。
  • PaddleOCR-VL / PP-Structure / Docling 结构 JSON 已可作为 evidence 融合,但模型运行时保持可选。
  • 项目仍是 research prototype,适合做转换、评测和架构实验,不是面向终端用户的桌面文档编辑器。

文档

开发

pytest

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages