0. Directory Convention
All intermediate files and final artifacts must strictly follow the directory structure below,Placing any generated files in the project root directory is prohibited:
项目根目录/
├── resources/
│ ├── pages/ # 切分出的单页 PNG 图片
│ ├── figures/ # 从页面中裁剪出的独立科研配图(全局编号)
│ ├── md/ # 每页的 Markdown 提取结果 (page_1.md, page_2.md, ...)
│ ├── scripts/ # 所有 Python 辅助脚本(可跨任务复用,清理时不删除)
│ ├── compiled_paper.md # 最终汇总的完整 Markdown
│ ├── config.json # 任务配置(源 PDF、格式规范),整个任务期间不变
│ └── checkpoint.json # 运行时进度(当前页、计数器、失败页),随处理更新
├── outputs/
│ ├── <name>_checkpoint_p<N>.docx # 核查点中间版本
│ └── <name>_final_<date>.docx # 最终交付版本
├── ocr_kb/
│ └── SKILL.md # 本文件
└── <source>.pdf # 用户提供的原始 PDF
0.5 resources/config.json Specification (Task Configuration)
Created at the start of each new task,not modified throughout the entire task. When continuing work, read it directly. All pipelines share the same schema.
{
"source_file": "2103.10360v2.pdf",
"source_type": "pdf",
"pipeline": "A",
"format_style": "IEEE",
"template_file": null,
"total_units": 16,
"unit_type": "page",
"created_at": "2026-04-02T13:00:00+08:00"
}
| Field | Description |
|---|---|
source_file |
Source file name specified by the user (PDF / DOC / DOCX / MD) |
source_type |
File type:"pdf" / "doc" / "docx" / "md" |
pipeline |
Pipeline type:"A"(OCR)/ "B"(re-typesetting) / "C"(direct MD conversion) |
format_style |
Typesetting format (IEEE / APA / user-defined / ...) |
template_file |
User-provided .docx template path, or if none, null |
total_units |
Total number of processing units (Pipeline A = number of pages, Pipeline B/C = number of sections) |
unit_type |
Progress unit:"page"(Pipeline A)/ "section"(Pipeline B/C) |
created_at |
Task creation time |
[!NOTE] Pipeline A always uses
source_type: "pdf",pipeline: "A",unit_type: "page"。
0.6 resources/checkpoint.json Specification (Runtime Checkpoint)
Updated after each completed unit (page or section) of extraction + DOCX append. **This is the sole basis for checkpoint recovery.** All pipelines share the same schema.
{
"current_unit": 7,
"unit_type": "page",
"last_verified_unit": 6,
"total_units": 16,
"docx_path": "outputs/GLM_checkpoint_p6.docx",
"global_figure_count": 4,
"global_table_count": 2,
"global_equation_count": 15,
"needs_review": [3],
"completed_units": [1, 2, 3, 4, 5, 6],
"status": "suspended"
}
| Field | Description |
|---|---|
current_unit |
Number of the next unit to process |
unit_type |
Unit type:"page"(Pipeline A)/ "section"(Pipeline B/C) |
last_verified_unit |
Number of the last unit that passed quality check |
total_units |
Total number of units (synchronized from config.json) |
docx_path |
Path to the current latest intermediate DOCX version |
global_figure_count |
Global figure counter (only increases, never decreases) |
global_table_count |
Global table counter (only increases, never decreases) |
global_equation_count |
Global formula counter (only increases, never decreases) |
needs_review |
List of unit numbers marked as "needs review" |
completed_units |
List of unit numbers whose extraction has been completed |
status |
"running" / "suspended" / "completed" |
Update timing(taking Pipeline A as an example; B/C replace "page" with "section"):
- Each time a unit is completed: update
current_unit、completed_units, counters - After every 2 units are checked: update
last_verified_unit - If a problem is found during quality check: add the unit number to
needs_reviewadd the unit number - Before suspending every 4 units: set
status = "suspended", save the intermediate DOCX version - After all are completed: set
status = "completed"
Pipeline A intermediate version naming: use _checkpoint_p<N> to indicate the page number. Pipeline B/C use _checkpoint_s<N> to indicate the section.
0.7 Script Contracts
[!IMPORTANT] If the following scripts already exist in
resources/scripts/,reuse them directly; do not regenerate them. Create them only when they do not exist, and they must strictly follow the interfaces below.
split_pdf.py
用法: python resources/scripts/split_pdf.py <pdf_path> <output_dir> [--dpi 300]
输入: PDF 文件路径,输出目录路径
输出: output_dir/page_1.png, page_2.png, ..., page_N.png
退出码: 0 成功,非 0 失败
stdout: 最后一行输出 "TOTAL_PAGES=N"
extract_figures.py
用法: python resources/scripts/extract_figures.py <page_image> <page_num> <coords_json> <output_dir> <start_index>
输入:
- page_image: 单页 PNG 路径
- page_num: 页码(用于日志)
- coords_json: JSON 字符串,格式 [{"x0%": 10, "y0%": 30, "x1%": 90, "y1%": 70, "caption": "Figure N: ..."}]
- output_dir: 输出目录
- start_index: 全局起始编号(从 checkpoint.global_figure_count + 1 开始)
输出: output_dir/figure_<start_index>.png, figure_<start_index+1>.png, ...
退出码: 0 成功,非 0 失败
stdout: 最后一行输出 "FIGURES_EXTRACTED=K"
generate_docx.py
用法: python resources/scripts/generate_docx.py <compiled_md> <config_json> <output_path>
输入:
- compiled_md: 汇总后的 Markdown 文件路径
- config_json: 任务配置文件路径(读取 format_style 等信息)
- output_path: 输出 DOCX 文件路径
输出: 指定路径的 .docx 文件
退出码: 0 成功,非 0 失败
latex_to_omml.py
用法: python ocr_kb/scripts/latex_to_omml.py <latex_string> [--inline]
输入:
- latex_string: LaTeX 公式字符串(不含 $ 定界符)
- --inline: 可选标志,输出行内 <m:oMath> 而非块级 <m:oMathPara>
输出: 标准输出打印完整的 OMML XML 片段
- 无 --inline时: <m:oMathPara>...</m:oMathPara>
- 有 --inline时: <m:oMath>...</m:oMath>
退出码: 0 成功,非 0 失败
stderr: 转换失败时输出错误信息(不支持的 LaTeX 命令等)
支持范围: 基础运算、分式(\frac)、上下标、根号(\sqrt)、
希腊字母、求和/积分(\sum/\int)、矩阵(\matrix/\pmatrix)、
常用数学符号(\leq/\geq/\neq/\approx/\infty 等)
[!NOTE] This script is located in
ocr_kb/scripts/(not inresources/scripts/), because it is a tool built into the Skill rather than a temporary script generated by the task. All pipelines share this script.
1. Page-by-Page Close Reading and Append Writing (Page-by-Page Extraction)
For each single-page image that has been split (resources/pages/page_N.png), perform the following operations:
1.1 Plain Text Reading
Read the image closely page by page using visual capabilities, and extract the text exactly as it is.
[!CAUTION] Heading Format Specification: Never retain redundant or incorrect Markdown heading symbols in the text (such as
#### 3.2.3). When the DOCX is finally generated, the formatting script will automatically map to the target template (such as IEEE's Roman numerals I, II, A, B, etc.). The extracted Markdown must use extremely clean#levels (such as##for level-one headings,###for level-two headings),absolutely forbiddenfor the original document's old numbering or redundant#symbols to remain in the final body text.
1.2 Formula Transcription
Standalone formulas or inline formulas on the page (including individual mathematical symbols in tables and figure captions such as $d_{model}$),mustall be read into standard LaTeX syntax (use $ $for inline, use $$ $$for standalone blocks). Each standalone formula increments checkpoint.json of global_equation_count。
[!IMPORTANT] This is to ensure that when the DOCX is finally generated, the Python script can precisely capture these two types of boundaries through regular expressions and call
latex_to_omml.pyto mount them all as native Word OMML formulas (<m:oMath>or<m:oMathPara>). Never omit the wrapping of variables, otherwise they can only be rendered as plain text.
1.3 Illustration Recognition and Intelligent Cropping
[!IMPORTANT] Forbiddento directly insert a full-page screenshot as an image into Markdown. It is necessary toprecisely identify and crop out independent scientific figures。
Specific process:
- Identify: When visually reading the current page, determine whether there is an independent scientific figure (Figure) or an independent table image (Table presented in image form) on the page.
- Locate: Determine the approximate percentage coordinates of the figure's position on the page
(x0%, y0%, x1%, y1%)。 - Global numbering: From
checkpoint.jsonreadglobal_figure_count, new figures on this page start numbering fromglobal_figure_count + 1. After cropping is complete, updateglobal_figure_count. Tables likewise useglobal_table_count。 - Crop: Use
resources/scripts/extract_figures.pyorPyMuPDF'spage.get_pixmap(clip=Rect(...))method to crop from the high-resolution page rendering according to the coordinatesseparatefigures, and save them toresources/figures/figure_N.png(N is the global number). - Reference: In Markdown, use the path of the cropped independent image:

1.4 Write
Write the extraction result of the current page to resources/md/page_N.md。
1.5 Update Checkpoint
After each page_N.md is written and appended to the DOCX, immediately update checkpoint.json:
current_unit += 1completed_unitsadd the current page number- Update
global_figure_count/global_table_count/global_equation_count
2. Page-by-Page DOCX Generation and Two-Page Verification (Incremental DOCX Generation)
[!IMPORTANT] No longer wait until all pages have been extracted to generate the DOCX all at once.As soon as the extraction of one page of MD is completed, immediately append that page's content to the DOCX file being built。
2.1 Single-Page Process
读一页图片 → 写 page_N.md → 将 page_N.md 内容追加到 DOCX → 更新 checkpoint.json
2.2 Two-page verification (every 2 pages)
After completing the DOCX append of every 2 pages, aself-check verification:
- Review the typesetting effect of the 2 pages just appended in the DOCX (fonts, formulas, figure placement, heading levels).
- Compare against the original page images to confirm there is no information loss or formatting corruption.
- Verification passed: update
checkpoint.jsoninlast_verified_unit。 - Verification failed:
- in
checkpoint.json'sneeds_reviewarray, record the problematic page numbers. - Try to fix immediately. If the fix succeeds, remove the page number from
needs_review. - If it cannot be fixed,do not block subsequent page processing, but before the final summary
needs_reviewmust be cleared to zero.
- in
2.3 Context limit protection
- After continuously processing 4 pages, you must actively suspend:
- Set
checkpoint.json'sstatusto"suspended"。 - Save the current intermediate DOCX version to
outputs/(naming rules see §2.4). - Use
notify_userto notify the user to send "continue" to refresh the context window.
- Set
- After resuming, read
checkpoint.json, and continue fromcurrent_unit.
2.4 Intermediate version naming rules
| Type | Naming format | Example |
|---|---|---|
| Checkpoint intermediate version | outputs/<原文件名>_checkpoint_p<最后完成页码>.docx |
outputs/GLM_checkpoint_p6.docx |
| Final delivery version | outputs/<原文件名>_final_<YYYYMMDD>.docx |
outputs/GLM_final_20260402.docx |
[!NOTE] Each time a new checkpoint version is saved,keep the previous versiondo not delete it, so that you can roll back if problems occur.
3. Final Typesetting
3.1 needs_review zero-clearing check
Before entering finalization, check checkpoint.json 's needs_review:
- is not empty: list all page numbers pending review, re-verify and fix them page by page. Only continue after all are fixed.
- is empty: proceed directly to the summary.
3.2 Summary
Merge resources/md/page_1.md ~ page_N.md in order into resources/compiled_paper.md。
3.3 Generate the final DOCX
Use resources/scripts/generate_docx.py, according to config.json generate the final typesetting file with the format specification specified in it, and save it to outputs/。
3.4 Applying typesetting formats
Typesetting parameters are read from config.json 's format_params (parsed and written at startup by the main SKILL.md §2.2).
The complete parameter tables for specific format presets (IEEE / APA / Chinese dissertations, etc.) are defined inmain SKILL.md §6 Typesetting Format Specification Libraryand are not repeated in this file.
DOCX generation method for Pipeline A: Use docx/SKILL.md use docx-js to create a new document, or use the unpack-edit-pack method to edit based on a template.
For detailed typesetting rules on images, tables, headers and footers, columns, and formulas, seemain SKILL.md §5 General Typesetting Rules。
3.5 Update Checkpoint
Set checkpoint.json 's status = "completed", and record the final file path.
4. Execution Triggers
4.1 New Task
When the user sends "format this PDF according to a certain format" (the main SKILL.md routes to Pipeline A):
- Cleanup confirmation: Perform environment cleanup confirmation per main SKILL.md §1.1.
- Select source file: Per main SKILL.md §1.2, confirm the source PDF and select Pipeline A.
- Create configuration: Write
resources/config.json(pipeline: "A",unit_type: "page")。 - Split images: Run
resources/scripts/split_pdf.py。 - Establish progress: Create
resources/checkpoint.json(current_unit = 1,unit_type: "page", all counters reset to zero). - Page-by-page loop: Execute per §1 and §2.
- Aggregate and finalize: Execute per §3.
- Output report: Output the completion report per main SKILL.md §5.
4.2 Resume from Breakpoint
When the user sends "continue":
- Read
resources/checkpoint.json。 - From
current_unitspecified page number, continue the page-by-page loop. - All global counters are restored from the checkpoint and are not reset.
4.3 Partial Rerun
When the user sends "rerun page N" or "rerun page N":
- Read
resources/checkpoint.json, confirm that page N is incompleted_units. - Re-read
resources/pages/page_N.png, re-execute the extraction process of §1. - Overwrite
resources/md/page_N.md。 - Note: If the page has figures, the corresponding
figure_*.pngmust be updated, butdo not change the global numbering—reuse the original numbering. - From
needs_reviewremove N (if it exists). - Regenerate the final DOCX (re-execute §3.2 ~ §3.3).
4.4 Batch Rerun
When the user sends "rerun pages X-Y":
Per §4.3, execute a rerun for each page in the range one by one.
5. Completion Report
[!IMPORTANT] After all pages have been processed and the final DOCX has been generated,mustoutput the following summary; it cannot be omitted.
【完成报告】
源文件:<config.source_file>
输入类型:<config.source_type>
处理管道:Pipeline <config.pipeline>
格式规范:<config.format_style>
总单元数:<checkpoint.total_units>(<config.unit_type>)
提取公式数:<checkpoint.global_equation_count>
裁剪配图数:<checkpoint.global_figure_count>
提取表格数:<checkpoint.global_table_count>
核查点版本数:<outputs/ 中 checkpoint 文件的数量>
最终文件:outputs/<最终文件名>.docx
遗留问题:<needs_review 中的单元编号 / 无>