Multimodal & Document AI · 2 to 3 hours
Validate page-region citations
Implement a validator for page-region citations and predict its result on fixed cases. Then design extraction for a mixed PDF with a rotated scan and a table split across two pages.
Implementation and pipeline design
3 h
Used in interview rounds:
Live Coding (Medium)Overview
Build a document-processing contract that keeps evidence intact through extraction, transformation, retrieval, and answering. You will implement a validator for page-region citations, predict its results on fixed cases, map a box from a rotated scan, and design extraction for a mixed PDF, including what a structural check leaves unproven.
Study time: 2 to 3 hours
Interview format: Implementation exercise with deterministic fixtures, followed by a pipeline design discussion
By the end you can
- Define page and block records that keep revision, route, status, and evidence regions
- Map an OCR box from a rotated scan back to upright page coordinates
- Implement a page-region validator with a fixed rule order and exact error messages
- Explain what a structurally valid citation proves and what other checks must cover
- Choose a measure for each stage: OCR, layout, tables, retrieval, and answering
- Write review rules that keep an unresolved page visible in the document status
Prerequisites
Helpful background: Python or JavaScript. The reference validator is in TypeScript and Python, and the linked practice problem runs in JavaScript or Python.
This topic covers routing uncertain inputs, page-region and time-range evidence, and document and media pipelines. RAG & Data Pipelines covers generic ingestion, chunking, and the document lifecycle.
Define the pipeline contract
Separate ingestion, extraction, normalization, validation, indexing, and answering. Each stage should produce a versioned result with explicit success, partial-success, and failure states. Avoid turning a missing page into an empty successful result.
For each document, retain an immutable revision identifier, original content hash, media type, tenant or access scope, page count, and processing configuration. Hashes help identify content; they do not grant authorization or establish who created it.
For every page, store processing status, dimensions, coordinate convention, rotation, and the extraction method used. A mixed PDF may have native text on one page and OCR output on another.
Route pages based on evidence
Attempt native extraction when appropriate, then assess its usefulness. Empty text, invalid character patterns, or a major mismatch with visible content can trigger OCR or review. A nonempty text layer is not enough to trust it.
Use layout analysis for multi-column pages and tables. Use visual models for diagrams or regions whose meaning is not represented by extracted text. Preserve competing outputs when they disagree instead of silently treating the latest response as correct.
Define a processing budget: maximum pages, image dimensions, audio duration, retries, and escalation cost. If limits are reached, report which parts were processed and which remain unavailable.
A canonical intermediate representation
Represent a document as pages containing typed blocks: paragraphs, headings, tables, figures, code regions, and selection marks. Give each block a stable identifier within a specific extraction revision.
Store raw text separately from normalized text. Record the mapping between derived content and source regions. When OCR is rerun, block boundaries and IDs may change; do not attach old citations to the new extraction without a verified mapping.
Tables need cells with row and column positions, spans, text, and evidence. Captions and footnotes should remain linked to the objects they qualify. Provider layout services can expose these elements, but a canonical application representation avoids binding downstream code to one response schema.
Coordinates and transforms
Coordinates may be pixels, physical page units, or normalized fractions. Origins and rotation conventions vary. Declare these explicitly and convert at the boundary.
This guide uses zero-based physical page indexes and normalized rectangles [x0, y0, x1, y1] with an upper-left origin on the canonical upright page. A rectangle encloses a region but may include unrelated content; polygons can preserve finer geometry.
If OCR runs on a cropped, rotated, or deskewed image, retain the transform needed to map its output back to the original page. Normalization alone does not undo cropping, rotation, or perspective changes.
Map a box from a rotated scan
Worked example
Suppose page 1 of a fictional handout was scanned sideways and stored turned 90 degrees clockwise, and OCR ran on the stored image as it is. Coordinates are normalized, with the origin at the upper left of each image.
A point at (u, v) on the upright page appears in the clockwise-turned image at (x', y') = (1 - v, u): the page's top edge becomes the image's right edge. Inverting gives u = y' and v = 1 - x', so a box maps as:
Clockwise turn, image box to upright page box
[x0', y0', x1', y1'] -> [y0', 1 - x1', y1', 1 - x0']
| Step | Value |
|---|---|
| OCR box in the stored image | [0.75, 0.125, 0.875, 0.625], a tall strip near the right edge |
| Horizontal range on the page, from y' | 0.125 to 0.625 |
| Vertical range on the page, from 1 - x' | 1 - 0.875 = 0.125 to 1 - 0.75 = 0.25 |
| Box on the upright page | [0.125, 0.125, 0.625, 0.25], a wide strip near the top: one line of text |
Store the rotation with the page record and apply the inverse before saving evidence. Dividing pixel coordinates by the image size normalizes a box but leaves it in the turned frame. A counterclockwise turn needs a different mapping, derived the same way. Cropping adds an offset and scale, and deskewing a small rotation; undo them in reverse order.
The page-region validator
The validator checks one citation region against authoritative document metadata. The caller passes the expected revision and page count from the document record, never from the region itself.
type EvidenceRegion = {
documentRevision: string;
pageIndex: number; // zero-based physical page
box: [number, number, number, number]; // [x0, y0, x1, y1], normalized, upper-left origin
};
// Returns a new { documentRevision, pageIndex, box } with no other fields,
// or throws an Error with the message of the first rule that fails.
declare function validateRegion(
region: unknown,
expectedRevision: unknown,
pageCount: unknown
): EvidenceRegion;Python names the function validate_region, reads the keys document_revision and page_index, raises ValueError, and returns the four coordinates as floats.
| Order | Rule | Message when it fails |
|---|---|---|
| 1 | The expected revision is a non-empty string | Invalid expected revision |
| 2 | The page count is an integer of at least 1, not a boolean | Invalid page count |
| 3 | The region is an object (a dict in Python), not an array or null | Region must be an object |
| 4 | The region's revision equals the expected revision | Wrong document revision |
| 5 | The page index is an integer, not a boolean, with 0 <= index < page count | Invalid page index |
| 6 | The box is an array (a list or tuple in Python) of exactly four values | Expected four coordinates |
| 7 | Every coordinate is a finite number, not a boolean, string, NaN, or infinity. In Python it is an int or float that converts to a finite float | Coordinates must be finite numbers |
| 8 | 0 <= x0 < x1 <= 1 and 0 <= y0 < y1 <= 1 | Invalid normalized rectangle |
Booleans need an explicit check in both languages: Python's bool is a subclass of int, and JavaScript's Number(true) is 1. The result is built from the checked values, so fields the caller did not ask for never reach downstream code.
Code exercise
Page-region validator
Implement validateRegion (JavaScript) or validate_region (Python) to the contract above. Apply the rules in the stated order, throw (raise ValueError in Python) with the exact message of the first rule that fails, and return a new record with only the three contract fields.
Expected
The practice problem's fixtures use expected revision handout-v2 and page count 3. Its tests compare each returned record exactly (no extra fields; Python coordinates as floats) and each error by its exact message, so rule order matters whenever an input breaks more than one rule. Check your code against the prediction table below before you run them.
Limitations
The validator checks structure and identity only: one rectangle on one page, with no polygons or media time ranges. It trusts the caller's expected revision and page count, and production code should also cap payload size before validating. JavaScript cannot tell 1.0 from 1, so a page index of 1.0 passes in JavaScript but fails in Python, where it is a float.
Predict the validator's results
Apply the rules by hand first; the rows then serve as your test set.
Predict the outcome
Predict the validator's results
Use expected revision handout-v2 and page count 3 for every row. Inputs use JavaScript notation; in Python the keys are document_revision and page_index, NaN is float("nan"), and true is True. Write the returned record or the exact error message for each row before you reveal the answers.
| Row | Region revision | Page index | Box | Other input fields | Result |
|---|---|---|---|---|---|
| R1 | `handout-v2` | 2 | [0.1, 0.2, 0.6, 0.25] | none | ? |
| R2 | `handout-v1` | 2 | [0.1, 0.2, 0.6, 0.25] | none | ? |
| R3 | `handout-v2` | 3 | [0.1, 0.2, 0.6, 0.25] | none | ? |
| R4 | `handout-v2` | 0 | [0, 0, 1, 1] | none | ? |
| R5 | `handout-v2` | 2 | [0.6, 0.2, 0.1, 0.25] | none | ? |
| R6 | `handout-v2` | -1 | [0.1, 0.2, 0.6, 0.25] | none | ? |
| R7 | `handout-v2` | 2 | [0.1, 0.2, 0.1, 0.25] | none | ? |
| R8 | `handout-v2` | 2 | [0.1, NaN, 0.6, 0.25] | none | ? |
| R9 | `handout-v2` | 2 | [0, 0, 1.2, 0.5] | none | ? |
| R10 | `handout-v2` | `true` | [0.1, 0.2, 0.6, 0.25] | none | ? |
| R11 | `handout-v2` | 2 | [true, 0.2, 0.6, 0.25] | none | ? |
| R12 | `handout-v1` | 5 | [0.1, 0.2, 0.6, 0.25] | none | ? |
| R13 | `handout-v2` | 2 | [0.1, 0.2, 0.6] | none | ? |
| R14 | `handout-v2` | 1 | [0.25, 0.5, 0.75, 0.625] | `label: "answer key"`, `verified: true` | ? |
Extraction schemas and normalization
For each extracted field, keep the raw value, normalized value, status, and evidence list. Normalize only with an explicit rule. For example, 03/04/2026 is ambiguous without a known date convention; silently choosing a month changes meaning.
Distinguish absent, unreadable, conflicting, and not-applicable values. Validation should check both syntax and relationships: a JSON number can still have the wrong unit, and a plausible total can belong to the wrong row. Use deterministic arithmetic for totals and unit conversions, and route a mismatch to review instead of overwriting source values to make them reconcile.
Chunking and retrieval
Chunk by meaningful structure while preserving evidence links. A table row may need its column headers and units repeated in the retrieval representation. A code block may need the preceding exercise instruction. Do not split these relationships merely to achieve equal character counts.
Text embeddings cannot retrieve what transcription omitted; visual retrieval can help locate a diagram but does not provide exact field values by itself.
Store access metadata with every derivative and filter retrieval by authorized scope. A shared embedding index must not become a way to search another tenant's source content.
Audio and video alignment
Media evidence is a time range instead of a box. Store transcript segments with start and end times in a declared unit, the media revision, and any offset introduced by trimming. Align speech and screen frames on that one timeline: a spoken "this line" needs the frame visible at that moment. Reconcile overlapping windows by time range rather than appending every result, and keep uncertain speaker labels apart from verified identities.
Evaluate each stage and the final task
| Stage | Useful measure | Important limit |
|---|---|---|
| OCR | Character or word error rate | Small symbol errors can matter disproportionately |
| Layout | Region matching and reading-order accuracy | High overlap does not prove correct semantics |
| Fields | Precision and recall with normalization rules | Aggregates can hide critical-field failures |
| Tables | Cell values and structure correctness | Text-only scoring misses wrong cell placement |
| Retrieval | Relevant evidence recall at a budget | Retrieved evidence may still be misinterpreted |
| Answering | Correctness and citation support | Fluent prose is not a quality metric |
| Audio and video | Transcript and temporal alignment quality | Good transcription can still miss visual evidence |
Character error rate is the edit distance divided by the reference character count under a stated normalization (empty references, punctuation, casing, whitespace). For code, score operators and indentation separately where they change meaning.
Review interface and feedback
Show the source region beside the extracted field. Let reviewers correct the value, evidence, and uncertainty independently. Preserve the original model output and the reviewer action for audit and evaluation.
Use review outcomes to locate systematic errors by document family, language, quality, and layout. Do not automatically turn every correction into training data without checking authorization, provenance, and split contamination.
Design extraction for a mixed handout
This exercise applies the earlier sections to one upload. It is the scenario for the canonical question.
Design exercise
Design extraction for a mixed handout
Suppose a coding-practice platform lets instructors upload exercise handouts as PDFs. Its study assistant answers learner questions and cites a highlighted region of a page. The current upload is revision handout-v2, with three pages.
| Page | What the file contains | What processing observed |
|---|---|---|
| 0 | Problem statement and a starter code block, with a text layer | Native extraction returns readable text that matches the rendered page |
| 1 | A scanned worksheet with no text layer, stored turned 90 degrees counterclockwise. The top half of the upright page holds the start of a test-case table: a header row (input, expected output, time limit) and rows 1 to 4. The bottom half is a hand-drawn diagram | OCR on the stored image places the header row at image box [0.125, 0.25, 0.25, 0.875]. Row 3's expected output reads as 1O or 10, with low confidence |
| 2 | Rows 5 to 8 of the same table with no header row, then a footnote: "All time limits are in milliseconds." Has a text layer | Native extraction returns the rows as tab-separated lines and the footnote as a paragraph |
A learner asks: "What is the time limit for test case 6?"
Requirements
- Records per page (route, rotation, status) and for the document as a whole
- Records for the table and the footnote, each with evidence in upright page coordinates
- The transform for page 1 and the upright-page box for the header row
- A plan to answer the learner's question, with every region it cites
- Review rules for low-confidence or conflicting values
Constraints
- Evidence regions follow the validator's shape: revision, zero-based page index, and a normalized box with an upper-left origin on the upright page
- Use only the observations in the table; no better scan is available
Deliverables
- A page table and a document status
- Example records for the logical table and its two segments (JSON or a table)
- The transform, the mapped header box, and the arithmetic
- The answer plan for test case 6 with its citations, and the review rules
Completion checklist
- I can implement the validator so every prediction row returns its expected record or message, in JavaScript or Python.
- I can map a box from a rotated scan to upright page coordinates and say where the transform is stored.
- I can keep a table split across pages as one table, with its header, units, and per-cell evidence.
- I can describe three wrong citations that pass the validator and the check that catches each one.
Sources
- Microsoft Document Intelligence layout model Describes layout output: pages with a rotation angle, width, height, and unit; paragraphs with roles and bounding polygons; table cells with row and column indexes; and post-processing tables that span pages into one table.
- Google Document AI Document reference Documents text anchors into the full document text, bounding polygons with normalized vertices from 0 to 1, per-page transforms applied to the original image, and table header rows, body rows, and cell spans.
- pypdf: Extract text from a PDF Explains why PDF text extraction is heuristic: no text from images (scans need OCR), text layers that can differ from what is displayed, and tables stored as positioned text.
The handout, coordinates, fixtures, schema, validator, and rubric are original synthetic teaching material about a fictional application. No OCR engine, media model, or end-to-end extraction service is run by this guide. Study times and readiness thresholds are editorial estimates. Product and library details are as of November 2026.
Related on CodeSnatch
Lessons, problems, and articles that build the skills this question uses.
Practice problem
Practice the index mapping behind a 90 degree turn, the same algebra used to map a box from a rotated scan.
AI Engineering
A smaller validator task that checks runtime JSON types, booleans included, in both JavaScript and Python.
Question bank
Traces typeof, NaN, and Number() quirks that a coordinate check has to handle before it trusts a value.
AI Engineering
Separates validation layers and names what a passing validator still cannot prove about the output.
Community article
Practitioner notes on keeping a table whole with its header row and citing chunks by stable ID.
Practice the interview question
Answer it in your own words before you look at the reference answer.
