Open Source
Explore the latest AI open-source projects from GitHub and HuggingFace.
Explore the latest AI open-source projects from GitHub and HuggingFace.
**pdf-inspector** is a Rust library that answers one question fast: does this PDF actually need OCR? Built by Firecrawl for its own document pipeline, it classifies a PDF as text-based, scanned, image-based or mixed in roughly 10–50 ms, then extracts position-aware text and converts it to clean Markdown — all locally, with no ML models and no external services. The repository was created on **6 February 2026** and sits at roughly **11,550 stars and 780 forks**, with commits through 5 August and 10 contributors. It is MIT-licensed and ships on crates.io, npm, and PyPI, plus a browser WebAssembly build. ## The Routing Problem Document pipelines that feed LLMs tend to have one expensive default: send every PDF to an OCR service. That costs 2–10 seconds and real money per document. Firecrawl's observation is that roughly **54% of PDFs don't need it** — reports, papers, invoices and legal filings usually carry a perfectly good text layer already. The classifier is deliberately cheap. It parses the xref table and page tree without a full object load, then looks for `Tj`/`TJ` text operators and `Do` image operators in content streams across sampled pages. That detects 300+ page PDFs in milliseconds. The result is not a single verdict but a `pages_needing_ocr` list, which enables per-page routing instead of an all-or-nothing decision on the whole document. Four scan strategies trade accuracy against speed: | Strategy | Behavior | Best for | |---|---|---| | `EarlyExit` (default) | Stops on first non-text page | Pipelines routing text PDFs to fast extraction | | `Full` | Scans every page, no early exit | Accurate Mixed vs Scanned classification | | `Sample(n)` | Samples n evenly distributed pages | Very large PDFs where speed dominates | | `Pages(vec)` | Scans specific page numbers | When the caller already knows where to look | The resulting flow is: classify in ~20 ms, and if it is text-based with high confidence, extract locally in ~150 ms. Otherwise pay for OCR. The document is loaded once and shared between detection and extraction, so choosing to extract costs no redundant parse. ## What Extraction Produces This is not a text dump. The extractor walks PDF operators into positioned `TextItem`s with font metadata, then runs column detection, line grouping and reading-order resolution before Markdown conversion. Headings come from font-size tiers relative to body text with 0.5pt clustering; code blocks from monospace font detection (Courier, Consolas, Menlo, JetBrains Mono); bold and italic from font-name patterns. Table detection runs dual-mode — rectangle-based detection from the PDF's own drawing operations, plus heuristic detection from text alignment — which is what lets it handle financial tables, footnotes and tables that continue across pages. Multi-column newspaper layouts, RTL text, CID fonts via ToUnicode CMap decoding, hyphenation rejoining, drop caps, dot-leader collapsing and page-number filtering are all handled explicitly. It also flags broken font encodings, so a caller can fall back to OCR when the text layer exists but is garbage — the failure mode that silently corrupts naive extraction pipelines. ## The Benchmark On the opendataloader-bench corpus of 200 PDFs with OCR disabled, refreshed 31 July 2026 on an M4 Pro: | Engine | Overall | Reading Order | Tables | Headings | Speed | |---|---|---|---|---|---| | pdf-inspector | 0.875 | 0.915 | 0.814 | 0.788 | 0.470s | | liteparse | 0.873 | 0.913 | 0.693 | 0.811 | 0.750s | | opendataloader | 0.831 | 0.902 | 0.489 | 0.739 | 2.569s | | pymupdf4llm | 0.735 | 0.886 | 0.401 | 0.424 | 17.117s | | markitdown | 0.589 | 0.844 | 0.273 | 0.000 | 16.165s | The table margin is the real gap — 0.814 against 0.693 for the nearest competitor — and the 36× speed difference against pymupdf4llm is the kind of number that changes pipeline architecture rather than just a config value. Per-document predictions and evaluator output are published in a reproducible results branch, and a paired benchmark harness ships for comparing two local builds against the same corpus revision. ## Caveats **The benchmark is the vendor's own.** Firecrawl ran the comparison, chose the corpus, and picked which engines appear. The methodology is unusually well documented — versions pinned, median of five runs, warm-up excluded, raw output published — but it is still a self-published result and the near-tie with liteparse on overall score (0.875 vs 0.873) is closer than the framing suggests. **It deliberately does not do OCR.** This is a router and a fast path, not a complete document solution. Anyone with a corpus of scans still needs the expensive service; pdf-inspector only tells you which documents to send there. **Heading detection is its weakest column.** At 0.788 it trails liteparse's 0.811, and font-size-tier heuristics will misread documents that signal structure by weight or spacing rather than size. **Structure detection is heuristic throughout.** Code blocks inferred from font names, lists from bullet-character prefixes, tables partly from text alignment — these work well on conventional documents and will degrade on unusual typography. There is no model to fall back on when the heuristics miss. **78 open issues.** The surface is broad — four language bindings, WebAssembly, two CLI tools — and the parsing edge cases in real-world PDFs are effectively unbounded. ## Verdict The insight is an economic one rather than a research one: OCR is the expensive step in most document pipelines, and a large fraction of the documents entering those pipelines never needed it. Making the classification cheap enough to run unconditionally — 20 ms against 2–10 seconds — turns an unconditional cost into a conditional one. Teams running document ingestion at scale for RAG or extraction should benchmark it against their own corpus, particularly if tables matter; the table score is where the daylight is. Teams whose documents are mostly scans will find it useful as a pre-filter and nothing more.