A multi-stage pipeline that extracts structured text, tables, figures, and charts from academic PDFs (born-digital, scanned, and hybrid) into a clean canonical JSON export suitable for downstream LLM consumption.
Auto-discovered from pipeline/stages/ (run python run_pipeline.py --list-stages):
| Stage | Purpose |
|---|---|
00_forensics | Per-page classification + quality signals |
01_grobid | GROBID structural parsing |
01a_render_pages | Render PDF pages to PNG |
02_layout_anchor | PP-DocLayoutV3 layout blocks |
02a_mineru_layout | MinerU 2.5 CUDA layout (GPU) |
02b_olmocr_reading_order | olmOCR reading order (GPU) |
03_pdffigures2 | Figure/table crop + caption link (pure-Python) |
04_text_candidates | Text candidates from embedded/OCR (with 04a/04b/04c router) |
05_semantic_view_docling | Docling VLM semantic view (GPU) |
05a_table_structure | Table structure recognition |
06_charts_deplot | Chart → table via DePlot + VLM (GPU) |
06a_complex_charts | Iterative VLM chart reasoning (GPU) |
07_resolver_canonical | Merge candidates, VLM escalation (GPU) |
08_canonical_builder | Build canonical document model |
08a_visual_verify | VLM visual verification (GPU) |
09_clean_export | Emit canonical JSON + CSV/Markdown |
http://localhost:8070 by default).pipeline/pipeline_config.json.Install Python deps:
pip install -r requirements.txt
The authoritative config is pipeline/pipeline_config.json. An annotated example
with inline comments is at pipeline/pipeline_config.example.jsonc. For every
config key, see docs/PIPELINE_CONFIG.md.
Key runtime config:
grobid.url — GROBID service URL (default http://localhost:8070).vlm_manager.server_host — Qwen3.5-4B VLM server URL (default
http://localhost:8000, served by llama-cpp-python). The model downloads
automatically via HuggingFace Hub on first use (cache_dir: null => ~/.cache).resolver.vlm_model, verifier_vlm.* — VLM models for escalation/verification.No secrets are required. The default server_api_key is the literal
"not-needed" placeholder.
# Run the full pipeline on a directory of PDFs
python run_pipeline.py --input_dir corpus
# Run a subset of stages
python run_pipeline.py --input_dir corpus --only-stages 00,01,01a
python run_pipeline.py --input_dir corpus --from-stage 02
# Resume after a crash / re-run failures
python run_pipeline.py --input_dir corpus --resume --max-workers 4
python run_pipeline.py --input_dir corpus --failed-only
# Force a stage to re-run
python run_pipeline.py --input_dir corpus --only-stages 02_layout_anchor --force
# List discovered stages or dump resolved config
python run_pipeline.py --list-stages
python run_pipeline.py --print-config
A demo PDF is included in corpus/ so you can do a quick smoke test:
python run_pipeline.py --input_dir corpus --to-stage 01a --continue-on-error
Outputs are written to runs/<run_id>/ (one subdirectory per paper, with
per-stage out/, err/, and a DONE marker; a manifest.json tracks status).
generate_assets.py re-implements stages 01a/02/03 inline (no pipeline import)
and is useful to regenerate just the rendered pages + layout + figures/tables:
python generate_assets.py --input_dir corpus --run_id myrun --force
run_pipeline.py # pipeline entrypoint (auto-discovers stages)
generate_assets.py # standalone assets regenerator (01a/02/03)
requirements.txt
pipeline/
core/ # config loader, manifest, paths, stage loader/runner, util
stages/ # one file per stage (auto-discovered by STAGE dict + run_stage())
tools/ # OCR/chart/VLM helper modules, model loader, model cache
pipeline_config.json # authoritative runtime config
pipeline_config.example.jsonc
docs/
PIPELINE_CONFIG.md
architecture_overview.txt
architecture_details.txt
corpus/ # demo input PDFs (one sample included)
--max-workers). CPU-only stages parallelize safely.2 commits
Python
100.0%
A multi-stage pipeline that extracts structured text, tables, figures, and charts from academic PDFs (born-digital, scanned, and hybrid) into a clean canonical JSON export suitable for downstream LLM consumption.
Auto-discovered from pipeline/stages/ (run python run_pipeline.py --list-stages):
| Stage | Purpose |
|---|---|
00_forensics | Per-page classification + quality signals |
01_grobid | GROBID structural parsing |
01a_render_pages | Render PDF pages to PNG |
02_layout_anchor | PP-DocLayoutV3 layout blocks |
02a_mineru_layout | MinerU 2.5 CUDA layout (GPU) |
02b_olmocr_reading_order | olmOCR reading order (GPU) |
03_pdffigures2 | Figure/table crop + caption link (pure-Python) |
04_text_candidates | Text candidates from embedded/OCR (with 04a/04b/04c router) |
05_semantic_view_docling | Docling VLM semantic view (GPU) |
05a_table_structure | Table structure recognition |
06_charts_deplot | Chart → table via DePlot + VLM (GPU) |
06a_complex_charts | Iterative VLM chart reasoning (GPU) |
07_resolver_canonical | Merge candidates, VLM escalation (GPU) |
08_canonical_builder | Build canonical document model |
08a_visual_verify | VLM visual verification (GPU) |
09_clean_export | Emit canonical JSON + CSV/Markdown |
http://localhost:8070 by default).pipeline/pipeline_config.json.Install Python deps:
pip install -r requirements.txt
The authoritative config is pipeline/pipeline_config.json. An annotated example
with inline comments is at pipeline/pipeline_config.example.jsonc. For every
config key, see docs/PIPELINE_CONFIG.md.
Key runtime config:
grobid.url — GROBID service URL (default http://localhost:8070).vlm_manager.server_host — Qwen3.5-4B VLM server URL (default
http://localhost:8000, served by llama-cpp-python). The model downloads
automatically via HuggingFace Hub on first use (cache_dir: null => ~/.cache).resolver.vlm_model, verifier_vlm.* — VLM models for escalation/verification.No secrets are required. The default server_api_key is the literal
"not-needed" placeholder.
# Run the full pipeline on a directory of PDFs
python run_pipeline.py --input_dir corpus
# Run a subset of stages
python run_pipeline.py --input_dir corpus --only-stages 00,01,01a
python run_pipeline.py --input_dir corpus --from-stage 02
# Resume after a crash / re-run failures
python run_pipeline.py --input_dir corpus --resume --max-workers 4
python run_pipeline.py --input_dir corpus --failed-only
# Force a stage to re-run
python run_pipeline.py --input_dir corpus --only-stages 02_layout_anchor --force
# List discovered stages or dump resolved config
python run_pipeline.py --list-stages
python run_pipeline.py --print-config
A demo PDF is included in corpus/ so you can do a quick smoke test:
python run_pipeline.py --input_dir corpus --to-stage 01a --continue-on-error
Outputs are written to runs/<run_id>/ (one subdirectory per paper, with
per-stage out/, err/, and a DONE marker; a manifest.json tracks status).
generate_assets.py re-implements stages 01a/02/03 inline (no pipeline import)
and is useful to regenerate just the rendered pages + layout + figures/tables:
python generate_assets.py --input_dir corpus --run_id myrun --force
run_pipeline.py # pipeline entrypoint (auto-discovers stages)
generate_assets.py # standalone assets regenerator (01a/02/03)
requirements.txt
pipeline/
core/ # config loader, manifest, paths, stage loader/runner, util
stages/ # one file per stage (auto-discovered by STAGE dict + run_stage())
tools/ # OCR/chart/VLM helper modules, model loader, model cache
pipeline_config.json # authoritative runtime config
pipeline_config.example.jsonc
docs/
PIPELINE_CONFIG.md
architecture_overview.txt
architecture_details.txt
corpus/ # demo input PDFs (one sample included)
--max-workers). CPU-only stages parallelize safely.2 commits
Python
100.0%