pdfmux

io.github.NameetP由 GitHub 帳號 NameetP 發布v1.8.7更新於 Oct 25, 2026

PDF-to-Markdown extraction that audits its own output and flags any extractor's silent drops.

概覽

AI 產生的概覽

本機 MCP 伺服器,將 PDF 轉為 Markdown、JSON 或 RAG 分塊,並稽核自身輸出、查核其他擷取器是否無聲漏頁。

可以做什麼
將 PDF 轉為 Markdown、JSON、CSV 或適合 RAG 的分塊,逐頁在多個本機後端間路由並可選用 LLM 備援,支援整個目錄批次處理與長文件串流輸出。分析與稽核擷取品質,回傳每頁信心分數、覆蓋率與被標記的頁面,而不是無聲捨棄。使用發票、收據、合約、履歷、論文等內建範本擷取結構化資料。讀取 PDF 中繼資料,並可將其他引擎的輸出與來源 PDF 比對,回報被無聲漏掉的頁面。
適用情境
適合助理需要讀取或索引 PDF 以供 RAG 流程使用時,尤其是含掃描頁、表格或複雜版面的混合批次;也適合需要信心分數並明確標出失敗頁面、而非留下無聲缺口的場景。亦可用於檢查現有擷取引擎是否漏頁。
執行需求
以本機程序執行,透過 pip install pdfmux 安裝(需 Python 3.11+);掃描頁建議加裝 OCR 擴充。選用的 GEMINI_API_KEY 可啟用付費 Gemini Flash 備援,未設定則完全在本機執行。僅在設定後才會將頁面傳送給第三方 LLM 供應商。
安裝前請注意
選用的 GEMINI_API_KEY 會啟用逐頁計費的 LLM 呼叫;提供成本模式與預算上限,premium 模式會對每頁呼叫 LLM。設定雲端 LLM 供應商後,PDF 頁面內容會傳送給該供應商。本機遙測會記錄各類文件中哪個擷取器表現較好。付費的雲端清單簽章服務為獨立服務,並非必要。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 pdfmux,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

pdfmux

[CI] [PyPI] [Python 3.11+] [License: MIT] [Downloads]

Self-healing PDF extraction that flags the pages it can't read instead of dropping them — and now certifies any extractor's output for silent drops. Open-source LlamaParse alternative for RAG pipelines, MCP server for Claude Desktop, LangChain + LlamaIndex loaders.

pdfmux extracts PDFs and checks its own work — and now certifies any extractor's, telling you which pages it silently dropped. Free, MIT. Patent-pending method. pip install pdfmux.

Two jobs, one tool:

  • Self-healing extraction. The only PDF extractor that audits its own output. Catches blank pages, scrambled columns, broken tables — re-extracts them with a stronger backend, and flags what it still can't read instead of silently dropping it. So your LLM gets clean data, not silent garbage. Routes each page to the best of 7 built-in extraction backends + BYOK LLM fallback (Gemini / Claude / GPT-4o / Ollama). One CLI. One API. Zero config.
  • Certify Anything — new in v1.8.1. pdfmux verify audits any extraction engine's output against the source PDF — Reducto, Mistral OCR, LlamaParse, Docling, your in-house parser — and tells you which pages it silently dropped. Free, MIT, patent-clean.

[pdfmux terminal demo]

PDF ──> pdfmux router ──> best extractor per page ──> audit ──> re-extract failures ──> Markdown / JSON / chunks            |            ├─ PyMuPDF         (digital text, 0.01s/page)            ├─ OpenDataLoader  (complex layouts, 0.05s/page)            ├─ RapidOCR        (scanned pages, CPU-only)            ├─ Docling         (tables, 97.9% TEDS)            ├─ Surya           (heavy OCR fallback)            ├─ Marker          (academic papers, neural)            ├─ Mistral OCR     ($0.002/page, 96.6% tables)            └─ YOUR LLM        (Gemini / Gemma 3 / Claude / GPT-4o / Ollama / Mistral — BYOK via YAML)

Install

bash
pip install pdfmux

That handles digital PDFs. For any real-world batch, install pdfmux[ocr] too — almost every directory of PDFs has at least one scan, and without OCR those pages return empty text:

bash
pip install "pdfmux[ocr]"             # ⭐ recommended — RapidOCR for scanned pages (~200MB, CPU)

Other backends, by document type:

bash
pip install "pdfmux[tables]"          # Docling — table-heavy docs (~500MB)pip install "pdfmux[opendataloader]"  # OpenDataLoader — complex layouts (Java 11+)pip install "pdfmux[marker]"          # Marker — neural extraction for academic paperspip install "pdfmux[llm]"             # Gemini fallback (default LLM)pip install "pdfmux[llm-claude]"      # Claude (Sonnet / Opus)pip install "pdfmux[llm-openai]"      # GPT-4o familypip install "pdfmux[llm-ollama]"      # Ollama (any local model)pip install "pdfmux[llm-mistral]"     # Mistral OCR API ($0.002/page)pip install "pdfmux[llm-all]"         # all LLM providers (incl. Gemma via Gemini key)pip install "pdfmux[watch]"           # `pdfmux watch <dir>` auto-convert on changepip install "pdfmux[all]"             # everything

Requires Python 3.11+.

Quick Start

CLI

bash
# zero config — just workspdfmux convert invoice.pdf# invoice.pdf -> invoice.md (2 pages, 95% confidence, via pymupdf4llm)
# RAG-ready chunks with token limitspdfmux convert report.pdf --chunk --max-tokens 500
# cost-aware extraction with budget cappdfmux convert report.pdf --mode economy --budget 0.50
# schema-guided structured extraction (5 built-in presets)pdfmux convert invoice.pdf --schema invoice
# BYOK any LLM for hardest pagespdfmux convert scan.pdf --llm-provider claude
# use a built-in or saved profile (invoices, receipts, papers, contracts, bulk-rag)pdfmux convert invoice.pdf --profile invoices
# predict cost before running anythingpdfmux estimate big-report.pdf --llm-provider gemini
# stream pages as NDJSON as they finish (great for long documents)pdfmux stream report.pdf --quality high
# auto-convert any new PDFs that land in a folderpdfmux watch ./inbox/ -o ./output/
# diff two extractions side-by-sidepdfmux diff old.pdf new.pdf
# batch a directory — writes manifest.json with per-doc confidencepdfmux convert ./docs/ -o ./output/
# CI mode: fail the run if any document is below 0.20 confidencepdfmux convert ./docs/ -o ./output/ --strict --min-confidence 0.20
# pre-flight a directory: which extras do you actually need for THIS batch?pdfmux doctor --check ./docs/
# results are cached by file hash — re-runs are instant; bypass with --no-cachepdfmux convert report.pdf --no-cachepdfmux convert report.pdf --clear-cache

Python

For batch processing, use batch_extract() — not a subprocess.run(['pdfmux', ...]) loop. Same pipeline, no per-file process spawn, handles non-ASCII filenames:

python
import pdfmuxfrom pathlib import Path
# Batch extract — yields (path, result) tuples as each PDF completes.pdfs = list(Path("./inbox").glob("*.pdf"))for path, result in pdfmux.batch_extract(pdfs, quality="standard"):    if isinstance(result, Exception):        print(f"FAILED {path.name}: {result}")        continue    if result.confidence < 0.50:        print(f"REVIEW {path.name} ({result.confidence:.2f})")    else:        print(f"OK     {path.name} ({result.confidence:.2f})")
# Single-file helpers.text   = pdfmux.extract_text("report.pdf")             # markdown stringdata   = pdfmux.extract_json("report.pdf")             # locked schema dictchunks = pdfmux.chunk("report.pdf", max_tokens=500)    # RAG-ready chunks

Don't wrap pdfmux with your own pypdf/pdfplumber fallback. pdfmux already routes per page through PyMuPDF → RapidOCR → vision LLM. PyMuPDF tolerates malformed PDFs that pypdf rejects ("Stream has ended unexpectedly"), so a downstream pypdf fallback turns recoverable PDFs into failures. Trust the router; check the confidence score on the result.

Certify Anything

pdfmux verify audits any extraction engine's output against the source PDF and tells you which pages it silently dropped — not just pdfmux's own extraction. Point it at the output of Reducto, Mistral OCR, LlamaParse, Docling, or your in-house parser and it re-derives the source text with pdfmux's own audit pass, aligns the extraction to it, and scores every page.

The failure it catches: a page where the source has real text but the engine returned nothing — while reporting success. That "silent drop" is the exact failure that poisons a RAG index without a single error in the logs.

bash
# Certify pdfmux's own extraction of a documentpdfmux verify --source report.pdf --engine pdfmux
# Certify ANOTHER engine's output (JSON / Markdown / text)pdfmux verify --source report.pdf --extracted reducto.json --engine-name reducto
# Batch a whole directory — the "M pages silently dropped across N docs" reportpdfmux verify --source ./pdfs/ --extracted ./engine-outputs/ -o certification.json
# CI gate: exit non-zero unless the overall verdict is PASSpdfmux verify --source report.pdf --extracted out.json --strict

Every run prints a PASS / REVIEW / FAIL verdict, overall confidence and coverage, and — when it finds them — the silently dropped pages by number:

pdfmux verify — report.pdf · engine: reducto  FAIL   confidence 71% · coverage 68%  reducto: FAIL; 3 page(s) SILENTLY DROPPED (pages 7, 12, 31); overall  confidence 71%, coverage 68% across 40 page(s).
❌ 3 page(s) SILENTLY DROPPED: 7, 12, 31

Per page you get a verdict (pass / review / fail), confidence, coverage, alignment, hallucination-risk, and table/heading integrity. Batch mode rolls that up into a single "N pages silently dropped across M documents" line — the report you run on 100 of your own PDFs to find the silent failures already in your pipeline.

It works on any engine's output

--extracted accepts JSON, Markdown, or plain text (--extracted-format auto | json | markdown | text). When the extraction exposes real per-page structure, pdfmux compares page-by-page; when it's a single blob, it falls back to content-presence checks so it never fabricates a "silent drop" from a pagination mismatch.

Python API

python
from pdfmux import verify_extraction, verify_batch
# Single document → a CertificationManifestmanifest = verify_extraction("report.pdf", "reducto.json", engine="reducto")print(manifest.verdict)        # "PASS" | "REVIEW" | "FAIL"print(manifest.silent_drops)   # e.g. (7, 12, 31)  — 1-indexed page numbersprint(manifest.coverage)       # 0.0–1.0
# Many documents → a BatchCertification ("M pages dropped across N docs")batch = verify_batch([("a.pdf", "a.json"), ("b.pdf", "b.json")], engine="llamaparse")print(batch.total_silent_drops, "pages dropped across", batch.doc_count, "docs")

Each manifest carries a tamper-evident SHA-256 content signature over its canonical body and an embedded, honest limitations list: the certifier is lexical, not linguistic — it detects missing and garbled content, not faithful paraphrase or translation.

MCP

verify_extraction is exposed as an MCP tool (the 7th — see MCP Server), so an agent can certify an engine's output in the same session it extracts.

Free, MIT, patent-clean

Certify Anything reuses only pdfmux's shipped MIT audit layer. It does not include, and does not require, the patent-pending decision-trace method — that stays in pdfmux Cloud/Pro. pip install pdfmux gives you the full verify command at no cost.

Full reference: docs/CERTIFY-ANYTHING.md.

When you need to prove it to someone else

A local install can audit an extraction, but it cannot attest to one — anything it signs, anyone could forge. pdfmux Cloud returns an Ed25519-signed manifest over the extraction: your auditor verifies it offline, against a published public key, without an account and without trusting pdfmux.

bash
pdfmux verify-manifest manifest.json      # free, MIT, offline — no account

Verification is free and open forever; only generation is paid ($49/mo). That asymmetry is deliberate — you should never need our permission to check our work.

Free tool, no signup: app.pdfmux.com/audit — upload a PDF and see which pages your current extractor silently dropped. Measured accuracy (and its blind spots) published in pdfmux-bench.

Architecture

                           ┌─────────────────────────────┐                           │     Segment Detector         │                           │  text / tables / images /    │                           │  formulas / headers per page │                           └─────────────┬───────────────┘                                         │                    ┌────────────────────────────────────────┐                    │            Router Engine                │                    │                                        │                    │   economy ── balanced ── premium        │                    │   (minimize $)  (default)  (max quality)│                    │   budget caps: --budget 0.50            │                    └────────────────────┬───────────────────┘                                         │          ┌──────────┬──────────┬────────┴────────┬──────────┐          │          │          │                  │          │     PyMuPDF   OpenData    RapidOCR           Docling     LLM     digital   Loader      scanned            tables    (BYOK)     0.01s/pg  complex     CPU-only           97.9%    any provider               layouts                        TEDS          │          │          │                  │          │          └──────────┴──────────┴────────┬────────┴──────────┘                                         │                    ┌────────────────────────────────────────┐                    │           Quality Auditor               │                    │                                        │                    │   4-signal dynamic confidence scoring   │                    │   per-page: good / bad / empty          │                    │   if bad -> re-extract with next backend│                    └────────────────────┬───────────────────┘                                         │                    ┌────────────────────────────────────────┐                    │           Output Pipeline               │                    │                                        │                    │   heading injection (font-size analysis)│                    │   table extraction + normalization      │                    │   text cleanup + merge                  │                    │   confidence score (honest, not inflated)│                    └────────────────────────────────────────┘

Key design decisions

  • Router, not extractor. pdfmux does not compete with PyMuPDF or Docling. It picks the best one per page.
  • Agentic multi-pass. Extract, audit confidence, re-extract failures with a stronger backend. Bad pages get retried automatically.
  • Segment-level detection. Each page is classified by content type (text, tables, images, formulas, headers) before routing.
  • 4-signal confidence. Dynamic quality scoring from character density, OCR noise ratio, table integrity, and heading structure. Not hardcoded thresholds.
  • Document cache. Each PDF is opened once, not once per extractor. Shared across the full pipeline.
  • Data flywheel. Local telemetry tracks which extractors win per document type. Routing improves with usage.

Features

FeatureWhat it doesCommand
Zero-config extractionRoutes to best backend automaticallypdfmux convert file.pdf
RAG chunkingSection-aware chunks with token estimatespdfmux convert file.pdf --chunk --max-tokens 500
Cost modeseconomy / balanced / premium with budget capspdfmux convert file.pdf --mode economy --budget 0.50
Schema extraction5 built-in presets (invoice, receipt, contract, resume, paper)pdfmux convert file.pdf --schema invoice
ProfilesSave and re-use config; built-ins for invoices/receipts/papers/contracts/bulk-ragpdfmux convert file.pdf --profile invoices
BYOK LLMGemini, Gemma 3, Claude, GPT-4o, Ollama, Mistral, any OpenAI-compatible APIpdfmux convert file.pdf --llm-provider claude
Cost estimatePredict spend before runningpdfmux estimate file.pdf --llm-provider gemini
Streaming outputNDJSON events page-by-page for long docspdfmux stream file.pdf
Smart cacheHash-keyed result cache, 30-day TTL, 1 GB LRUpdfmux convert file.pdf (auto), --no-cache to bypass
Watch modeAuto-convert any PDF added to a folderpdfmux watch ./inbox/
DiffCompare two extractionspdfmux diff a.pdf b.pdf
BenchmarkEval all installed extractors against ground truthpdfmux benchmark
DoctorShow installed backends, coverage gaps, recommendationspdfmux doctor
MCP serverAI agents read PDFs via stdio or HTTPpdfmux serve
Batch processingConvert entire directoriespdfmux convert ./docs/
Page-level streaming APIBounded-memory page iteration for large filesfor page in ext.extract("500pg.pdf")
Retry with backoffEvery LLM provider auto-retries with exponential backoff + Retry-After(built-in)

CLI Reference

pdfmux convert

bash
pdfmux convert <file-or-dir> [options]
Options:  -o, --output PATH          Output file or directory  -f, --format FORMAT        markdown | json | csv | llm (default: markdown)  -q, --quality QUALITY      fast | standard | high (default: standard)  -s, --schema SCHEMA        JSON schema file or preset (invoice, receipt, contract, resume, paper)  --chunk                    Output RAG-ready chunks  --max-tokens N             Max tokens per chunk (default: 500)  --mode MODE                economy | balanced | premium (default: balanced)  --budget AMOUNT            Max spend per document in USD  --llm-provider PROVIDER    LLM backend: gemini | claude | openai | ollama  --confidence               Include confidence score in output  --stdout                   Print to stdout instead of file

pdfmux serve

Start the MCP server for AI agent integration.

bash
pdfmux serve              # stdio mode (Claude Desktop, Cursor)pdfmux serve --http 8080  # HTTP mode

pdfmux doctor

bash
pdfmux doctor# ┌──────────────────┬─────────────┬─────────┬──────────────────────────────────┐# │ Extractor        │ Status      │ Version │ Install                          │# ├──────────────────┼─────────────┼─────────┼──────────────────────────────────┤# │ PyMuPDF          │ installed   │ 1.25.3  │                                  │# │ OpenDataLoader   │ installed   │ 0.3.1   │                                  │# │ RapidOCR         │ installed   │ 3.0.6   │                                  │# │ Docling          │ missing     │ --      │ pip install pdfmux[tables]       │# │ Surya            │ missing     │ --      │ pip install pdfmux[ocr-heavy]    │# │ LLM (Gemini)     │ configured  │ --      │ GEMINI_API_KEY set               │# └──────────────────┴─────────────┴─────────┴──────────────────────────────────┘

pdfmux benchmark

bash
pdfmux benchmark report.pdf# ┌──────────────────┬────────┬────────────┬─────────────┬──────────────────────┐# │ Extractor        │   Time │ Confidence │      Output │ Status               │# ├──────────────────┼────────┼────────────┼─────────────┼──────────────────────┤# │ PyMuPDF          │  0.02s │        95% │ 3,241 chars │ all pages good       │# │ Multi-pass       │  0.03s │        95% │ 3,241 chars │ all pages good       │# │ RapidOCR         │  4.20s │        88% │ 2,891 chars │ ok                   │# │ OpenDataLoader   │  0.12s │        97% │ 3,310 chars │ best                 │# └──────────────────┴────────┴────────────┴─────────────┴──────────────────────┘

pdfmux estimate

Predict spend (and which backends will run) before processing.

bash
pdfmux estimate report.pdf --quality high --llm-provider gemini# Pages       : 47# Extractors  : pymupdf4llm + gemini-2.5-flash on 9 pages# Estimated   : $0.0234# Cache hit?  : no  (first run for this file)

pdfmux stream

Emit NDJSON events as pages complete — useful for very long PDFs and live UIs.

bash
pdfmux stream long.pdf --quality high# {"event":"classified","page_count":312,"plan":"pymupdf+gemini-fallback"}# {"event":"page","page_num":0,"confidence":0.97,"chars":1842}# {"event":"page","page_num":1,"confidence":0.92,"chars":1611,"ocr":true}# ...# {"event":"complete","confidence":0.94,"cost_usd":0.0712}

pdfmux watch

Auto-convert any PDFs that land in a directory. Survives until Ctrl+C.

bash
pdfmux watch ./inbox/ -o ./output/ --profile bulk-rag

pdfmux diff

Side-by-side extraction comparison (quality, content, cost).

bash
pdfmux diff a.pdf b.pdf --quality standard

pdfmux profiles

Saved configs at ~/.config/pdfmux/profiles.yaml. Built-ins ship for the common shapes; save your own for project defaults.

bash
pdfmux profiles list# invoices    quality=standard, schema=invoice, format=json# receipts    quality=fast,     schema=receipt, format=json# papers      quality=high,     chunk=true, max_tokens=500# contracts   quality=high,     schema=contract# bulk-rag    quality=standard, format=llm, chunk=true
pdfmux profiles show invoicespdfmux profiles save my-default --quality high --format llm --chunkpdfmux profiles delete my-default
# use a profile when convertingpdfmux convert file.pdf --profile invoices

Python API

Text extraction

python
import pdfmux
text = pdfmux.extract_text("report.pdf")                    # -> str (markdown)text = pdfmux.extract_text("report.pdf", quality="fast")    # PyMuPDF only, instanttext = pdfmux.extract_text("report.pdf", quality="high")    # LLM-assisted

Structured extraction

python
data = pdfmux.extract_json("report.pdf")# data["page_count"]   -> 12# data["confidence"]   -> 0.91# data["ocr_pages"]    -> [2, 5, 8]# data["pages"][0]["key_values"]  -> [{"key": "Date", "value": "2026-02-28"}]# data["pages"][0]["tables"]      -> [{"headers": [...], "rows": [...]}]

RAG chunking

python
chunks = pdfmux.chunk("report.pdf", max_tokens=500)for c in chunks:    print(f"{c['title']}: {c['tokens']} tokens (pages {c['page_start']}-{c['page_end']})")

Schema-guided extraction

python
data = pdfmux.extract_json("invoice.pdf", schema="invoice")# Uses built-in invoice preset: extracts date, vendor, line items, totals# Also accepts a path to a custom JSON Schema file

Streaming (bounded memory)

python
from pdfmux.extractors import get_extractor
ext = get_extractor("fast")for page in ext.extract("large-500-pages.pdf"):  # Iterator[PageResult]    process(page.text)  # constant memory, even on 500-page PDFs

Types and errors

python
from pdfmux import (    # Enums    Quality,              # FAST, STANDARD, HIGH    OutputFormat,         # MARKDOWN, JSON, CSV, LLM    PageQuality,          # GOOD, BAD, EMPTY
    # Data objects (frozen dataclasses)    PageResult,           # page: text, page_num, confidence, quality, extractor    DocumentResult,       # document: pages, source, confidence, extractor_used    Chunk,                # chunk: title, text, page_start, page_end, tokens
    # Errors    PdfmuxError,          # base -- catch this for all pdfmux errors    FileError,            # file not found, unreadable, not a PDF    ExtractionError,      # extraction failed    ExtractorNotAvailable,# requested backend not installed    FormatError,          # invalid output format    AuditError,           # audit could not complete)

Framework Integrations

LangChain

bash
pip install langchain-pdfmux
python
from langchain_pdfmux import PDFMuxLoader
loader = PDFMuxLoader("report.pdf", quality="standard")docs = loader.load()  # -> list[Document] with confidence metadata

LlamaIndex

bash
pip install llama-index-readers-pdfmux
python
from llama_index.readers.pdfmux import PDFMuxReader
reader = PDFMuxReader(quality="standard")docs = reader.load_data("report.pdf")  # -> list[Document]

MCP Server (AI Agents)

Listed on mcpservers.org. One-line setup:

json
{  "mcpServers": {    "pdfmux": {      "command": "npx",      "args": ["-y", "pdfmux-mcp"]    }  }}

Or via Claude Code:

bash
claude mcp add pdfmux -- npx -y pdfmux-mcp

Tools exposed: convert_pdf, analyze_pdf, extract_structured, extract_streaming, get_pdf_metadata, batch_convert.

BYOK LLM Configuration

pdfmux supports any LLM via 5 lines of YAML. Bring your own keys -- nothing leaves your machine unless you configure it to.

yaml
# ~/.pdfmux/llm.yamlprovider: claude          # gemini | claude | openai | ollama | any OpenAI-compatiblemodel: claude-sonnet-4-20250514api_key: ${ANTHROPIC_API_KEY}base_url: https://api.anthropic.com  # optional, for custom endpointsmax_cost_per_page: 0.02   # budget cap

Supported providers:

ProviderModelsLocal?Cost
Gemini2.5 Flash, 2.5 ProNo~$0.01/page
Gemma 327B IT, 12B IT (great for Arabic)No (via Gemini key)~$0.0002/page
ClaudeSonnet, OpusNo~$0.015/page
GPT-4oGPT-4o, GPT-4o-miniNo~$0.01/page
Mistralmistral-ocr-latestNo$0.002/page
OllamaAny local modelYesFree
CustomAny OpenAI-compatible APIConfigurableVaries

Every provider's extract_page() is wrapped in @with_retry(max_attempts=3, backoff_base=2.0), which honors Retry-After headers on 429s and skips retries on auth failures so a bad key fails fast.

Arabic & RTL Support

pdfmux ships first-class support for Arabic, Persian, Urdu, and Hebrew. Out of the box, RTL detection runs on every PDF and PyMuPDF-extracted pages are passed through the Unicode Bidirectional Algorithm so glyphs that were stored in left-to-right order render in correct reading order.

bash
# Default install — already includes python-bidi for RTL reorderingpip install pdfmux
# Recommended for Arabic-heavy docs — adds Gemma vision OCR# (Gemma speaks the OpenAI protocol, so it needs the openai SDK)pip install "pdfmux[llm-openai]"
# One credential covers Gemma + Gemini (same Google endpoint)export GEMINI_API_KEY=...

What happens automatically:

  • pdfmux convert detects Arabic content and routes pages with >5% Arabic characters through the Arabic-aware extractor chain.
  • PyMuPDF, RapidOCR, and Docling outputs are post-processed with the Bidi algorithm — markdown headings (#) and pipe-table rows preserve structure, only inner text is reordered.
  • DocumentResult.has_arabic is set to True whenever any page contains Arabic script.

What requires opt-in:

  • Vision LLM extraction. Set --llm-provider gemma (or any vision provider) to route Arabic pages through Gemma instead of PyMuPDF.
  • Aggressive normalization (Tatweel removal, Alef/Yeh unification, Tashkeel stripping) — call pdfmux.arabic.normalize_arabic(text) on extracted strings if you need canonicalized output for search or embedding.
python
from pdfmux.arabic import (    is_arabic_text,    is_rtl_dominant,    fix_bidi_order,    normalize_arabic,)
text = "مرحبا بالعالم"assert is_arabic_text(text)assert is_rtl_dominant(text)
# Fix glyph order from PyMuPDF / OCR enginesvisual = fix_bidi_order(text)
# Canonicalize for indexing — strip Tatweel, unify Alef variants, drop diacriticsindexable = normalize_arabic("أَحْمَدْ")  # → "احمد"

Proof: a real customer batch

We measured pdfmux on 433 real customer documents — technical and safety data sheets, mixed digital and scanned, some encoding-corrupted. Run the naive way first (an early pdfmux CLI in a subprocess, pypdf fallback, no OCR), the pipeline silently dropped 16 documents — 11 of them with no log line at all. That was our own tool failing at the exact thing it promises.

Rebuilt with the per-page audit + budgeted OCR cascade: 433 of 433 processed, zero silent failures. Every unrecoverable page is flagged, not dropped.

(A small internal confidence-calibration set also ships under eval/ — it's a regression guard on the confidence gate, not a competitive benchmark; see eval/README.md.)

Benchmark

On opendataloader-bench — 200 real-world PDFs (financial filings, academic papers, legal contracts, government reports) — pdfmux scores 0.903 overall — #2 of the 8 engines measured, behind opendataloader-hybrid (0.909). Re-run 2026-07-16 (reproduction below).

RankEngineOverallReading orderTables (TEDS)LicenseGPU
1opendataloader-hybrid0.9090.9350.928Apache-2.0No
2pdfmux0.9030.9200.911MITNo
3Docling0.8770.9000.887MITOptional
4marker0.8610.8900.808freeGPU
5mineru0.8310.8570.873freeGPU

Full per-document scores: the 200-PDF head-to-head · methodology: best PDF extraction library, benchmarked.

Smart Result Cache

Re-running the same extraction is instant. pdfmux hashes every input PDF (SHA-256) and keys results on (file_hash, quality, format, schema). Cache files live under ~/.cache/pdfmux/results/, expire after 30 days, and are LRU-evicted at 1 GB.

bash
pdfmux convert big-report.pdf            # first run: 14.2spdfmux convert big-report.pdf            # cache hit: 0.05spdfmux convert big-report.pdf --no-cache # bypass cache (still writes back)pdfmux convert big-report.pdf --clear-cache  # purge and re-run

The cache also speeds up --profile, --schema, and --format switches — each combination is keyed independently, so you can flip between Markdown and JSON for the same document for free after the first extraction.

Confidence Scoring

Every result includes a 4-signal confidence score:

  • 95-100% -- clean digital text, fully extractable
  • 80-95% -- good extraction, minor OCR noise on some pages
  • 50-80% -- partial extraction, some pages unrecoverable
  • <50% -- significant content missing, warnings included

When confidence drops below 80%, pdfmux tells you exactly what went wrong and how to fix it:

Page 4: 32% confidence. 0 chars extracted from image-heavy page.  -> Install pdfmux[ocr] for RapidOCR support on 6 image-heavy pages.

Cost Modes

ModeBehaviorTypical cost
economyRule-based backends only. No LLM calls.$0/page
balancedLLM only for pages that fail rule-based extraction.~$0.002/page avg
premiumLLM on every page for maximum quality.~$0.01/page

Set a hard budget cap: --budget 0.50 stops LLM calls when spend reaches $0.50 per document.

Why pdfmux?

pdfmux is not another PDF extractor. It is the orchestration layer that picks the right extractor per page, verifies the result, and retries failures.

ToolGood atLimitation
PyMuPDFFast digital textCannot handle scans or image layouts
DoclingTables (97.9% accuracy)Slow on non-table documents
MarkerNeural extraction for academic papersNeeds GPU for speed; overkill for digital PDFs
Mistral OCRTables (96.6% TEDS), $0.002/pageCloud-only API
UnstructuredEnterprise platformComplex setup, paid tiers
LlamaParseCloud-nativeRequires API keys, not local
ReductoHigh accuracy$0.015/page, closed source
pdfmuxOrchestrates all of the aboveRoutes per page, audits, re-extracts

Open source Reducto alternative: what costs $0.015/page elsewhere is free with pdfmux's rule-based backends, or ~$0.002/page average with BYOK LLM fallback.

Development

bash
git clone https://github.com/NameetP/pdfmux.gitcd pdfmuxpython3.12 -m venv .venv && source .venv/bin/activatepip install -e ".[dev]"
pytest              # 659 testsruff check src/ tests/ruff format src/ tests/

Contributing

  1. Fork the repo
  2. Create a branch (git checkout -b feature/your-feature)
  3. Write tests for new functionality
  4. Ensure pytest and ruff check pass
  5. Open a PR

License

The pdfmux library and MCP server in this repository are MIT licensed — free for any use, and every released version stays MIT.

The confidence-budgeted decision-trace method (the persisted per-page decision trace with retained rejected candidates, and the monotonic repair guard) is patent-pending (US Provisional App No. 64/106,302) and is reserved for pdfmux Cloud/Pro under a separate commercial license — it is not part of the MIT grant. See LICENSING.md and NOTICE.

來源:README.md,提交 3e6e88d

工具

0
SourceWeft 尚未在沙箱中啟動過該軟體包,因此其工具未知。

版本歷史

1
  1. v1.8.7最新Sep 16, 2026

評分

已滿足適用檢查項的 50%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分

    請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。

  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具15 分

    請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。

  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分