Page IR Extraction
Page IR extraction is the first stage of the pipeline. It converts each selected PDF
page into a structured, layout-faithful PageIR that records what is visibly present
on that page without assigning document-wide curriculum semantics.
For the broader workflow, see the pipeline overview and architecture.
Purpose
The goal of this stage is to create a reliable page-level representation that later stages can verify, stitch, and interpret.
A PageIR preserves page-local information such as:
- headings, paragraphs, lists, captions, figures, and artifacts;
- tables, rows, cells, and visible spanning structure;
- text and language information;
- bounding boxes in rendered-page pixel coordinates;
- visible local codes when present; and
- item-level boundary hints indicating whether content appears complete, truncated, resumed, or both.
This stage does not decide the document-wide curriculum hierarchy or create Academic Standards or Learning Components.
Entry point and configuration
The extraction command is implemented in:
From the backend/ directory, run:
The command reads the page_ir_extraction section of the shared RunConfig.
Important settings include:
| Setting | Purpose |
|---|---|
pdf_fp |
Source curriculum PDF |
output_dir |
Root directory for pipeline results |
dpi |
Resolution used to render PDF pages to PNG |
start_page / end_page |
Optional 0-based page range |
languages |
Expected source-language context |
use_extracted_hints |
Whether to provide usable PyMuPDF text/table hints to the extraction agent |
extraction_instructions |
Optional document-specific instructions for the extraction agent |
validation_instructions |
Optional document-specific instructions for the validation agent |
overwrite |
Whether to regenerate existing PageIR JSON files |
Document-specific instructions
extraction_instructions and validation_instructions let a curriculum profile give
this stage's two agents rules that apply to one document, such as how to tell a new
table from a table that continues from the previous page. Each field reaches only its
own agent: extraction_instructions goes to the extraction agent, and
validation_instructions goes to the validation agent.
The text is added at the end of the agent's system prompt, under a heading that tells
the agent to follow it wherever it conflicts with the generic extraction rules. It does
not override the output contract: the PageIR schema and the deterministic quality
checks still apply.
Both fields are optional. When a field is unset or blank, the agent's prompt is exactly the same as it would be without the field.
When the rules affect page structure, give them to both agents. If the validation agent
rejects an extraction, its corrected PageIR replaces the extraction, so a validation
agent that does not know the rules can undo them.
For a worked example, see examples/funda_wande/config_english_curriculum.json, which
uses both fields to describe how that PDF's tables continue across pages.
Changing either field does not update PageIRs that already exist. Set overwrite to
true or use a new output_dir so the affected pages are extracted again.
How extraction works
For each selected page, the pipeline performs the following steps:
-
Render the page to PNG. The PDF page is rendered at the configured DPI. The rendered image provides the visual evidence used by the extraction and validation agents.
-
Optionally collect PDF-layer hints. When
use_extracted_hintsis enabled, PyMuPDF can provide text-layer and table-layer hints. Unusable text layers are rejected by quality gates before they reach the model.
The hints are supplementary rather than a replacement for the image. The rendered page is authoritative for content presence, layout, reading order, block type, bounding boxes, and structure. For text that is visibly present, a usable PDF text layer can be used to preserve character-level spelling, including diacritics and non-Latin characters.
-
Extract a structured
PageIR. A page-level extraction agent receives the image, expected languages, and any usable hints and returns structured output conforming to thePageIRschema. -
Run deterministic quality checks. Python validates the extracted structure. If a quality check fails, the agent is given the error and can retry with a corrected output.
-
Audit the accepted extraction against the page image. A separate validation agent compares the structured
PageIRwith the original rendered page. If it finds material errors, it returns a complete correctedPageIR. Any correction must itself pass the deterministic quality checks.
When use_extracted_hints is enabled, the
correction guard then checks the correction against the page's
PDF text layer before it is accepted.
- Finalize Python-owned metadata and persist the page.
The pipeline fills fields such as the document key, PDF name, DPI, page index,
coordinate space, and image dimensions. The page-level
boundary_stateis derived deterministically from item-level boundary hints and is not authored directly by the LLM.
The accepted result is then written as the canonical PageIR for that page.
Validation
The extraction stage combines schema validation, deterministic quality checks, and an independent image-based audit.
Representative Python checks include:
- image dimensions and bounding-box bounds;
- duplicate, placeholder, or implausible full-page bounding boxes;
- required block content and extraction-time text constraints;
- figure, footnote, and artifact plausibility;
- table integrity and likely collapsed table grids;
- item-level continuation-state consistency; and
- gross visual reading order.
A model response is therefore not accepted simply because it matches the JSON schema. It must also satisfy extraction-specific quality rules, and the resulting page is independently checked against the source image.
Correction guard
When use_extracted_hints is true, the pipeline checks each correction from the
validation agent before accepting it. The check stops corrections that add text the page
does not contain.
The guard counts how often each word appears in three places: the correction, the page's
PDF text layer, and the extraction agent's PageIR. A word counts as added when it
appears more times in the correction than in the text layer, and also more times than in
the extraction. This catches both words that are not on the page at all and on-page text
that the correction repeats more often than the page has it.
If the correction adds any word, the pipeline rejects it, keeps the extraction agent's
PageIR, and logs a warning that names the page and the added words. Otherwise the
correction is accepted as usual.
Some details:
- Only text read from the page is compared: block text, list items, figure captions, and table cells. Artifact blocks (running headers, footers, and page numbers), figure alt text, and text embedded in figures are skipped.
- Letter case and curly versus straight quotes make no difference. Single characters and words made only of digits are not counted.
- The guard does not check a correction when the page has no usable text layer. That covers a missing layer, a layer that fails the hint quality checks, and a layer that contains fewer than half of the distinct words in the extraction, which usually means it is garbled. The last check applies only when the extraction has at least 10 distinct words.
- The guard never changes an agent's prompt, and it does not run when
use_extracted_hintsis false.
The warning goes to the terminal output and is not written to any output file. The validation agent's verdicts are not saved either, so a rejected correction leaves no trace in the run's artifacts. If you need a record of rejections, keep the terminal output.
Output artifacts
Results are stored under the stable document key:
<output_dir>/<doc_key>/extraction/
├── extraction_run.json
├── page_images/
│ ├── 0000.png
│ ├── 0001.png
│ └── ...
├── page_irs/
│ ├── 0000.json
│ ├── 0001.json
│ └── ...
└── page_irs_raw/
└── ... extraction attempt and retry artifacts ...
The main artifacts are:
page_images/— rendered page images used as visual evidence;page_irs/— acceptedPageIRJSON files used by the next pipeline stage;page_irs_raw/— extraction-attempt metadata, parsed outputs, and quality-error artifacts useful for debugging retries; andextraction_run.json— run metadata, status, model information, timestamps, and aggregate extraction/validation token usage.
If a PageIR already exists and overwrite is false, the page extraction is skipped.
This allows an interrupted or partial run to resume without regenerating completed
pages.
Stage boundary
Page IR extraction is intentionally page-local. Item-level continuation labels are initial observations only; this stage does not establish a trusted relationship between content on adjacent pages.
The next stage, Page IR continuity verification, evaluates those page breaks using bounded evidence from both pages before continuity metadata is allowed to influence document stitching.