把文档源转换成可编辑、可标注、可评测的 HTML,并保留足够的结构证据用于翻译和回渲染。
快速开始 · 核心流程 · 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 后再导出或打印。
![]() 网页 / 门户页 source 用 Playwright 打印 PDF 或截图,再转换成带 OCR/native 坐标锚点的 HTML。 |
![]() 论文 / 年报 / 手册 用相同 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.jsonDocling 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.joblibSuite 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]
主要模块:
| 模块 | 作用 |
|---|---|
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:
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,适合做转换、评测和架构实验,不是面向终端用户的桌面文档编辑器。
- English README
- 中文镜像 README
- 实现说明
- 优化路线
- 外部基准
- Implementation notes
- Optimization roadmap
- External benchmarks
pytest

