Skip to main content

LLM OCR

Turn PDFs and images into clean Markdown with vision LLMs:
Gemini, OpenAI, Claude, or a local model through Ollama.

PyPI CI Python Downloads License

A scanned order summary on the left and the Markdown produced by ocr-llm on the right

pip install ocr-llm
export GEMINI_API_KEY="..."   # or OPENAI_API_KEY / ANTHROPIC_API_KEY
ocr-llm document.pdf -o document.md

Or from Python:

from llm_ocr import LLMOCR, Gemini

markdown = LLMOCR(Gemini()).convert_sync("document.pdf")

It handles multi-page PDFs concurrently, keeps pages in order, retries failed requests, and works with any OpenAI-compatible server.

Installation

pip install ocr-llm

Gemini and OpenAI work out of the box. Claude needs an extra:

pip install "ocr-llm[anthropic]"

PDF input needs poppler: brew install poppler on macOS, sudo apt-get install poppler-utils on Debian/Ubuntu. Images work without it.

Providers

Provider Class API key Default model
Gemini Gemini GEMINI_API_KEY gemini-2.5-flash
OpenAI OpenAI OPENAI_API_KEY gpt-4o-mini
Claude Anthropic ANTHROPIC_API_KEY claude-sonnet-5-5

Keys are read from the environment, or passed as api_key=. Choose a model with model=: either a constant such as Gemini.PRO_2_5 or any model name as a string, so new models work without a library update.

from llm_ocr import Anthropic, Gemini, OpenAI

Gemini(model=Gemini.PRO_2_5)
Anthropic(model="claude-haiku-5-5")

# Ollama, vLLM, LM Studio, OpenRouter: anything that speaks the OpenAI API
OpenAI(base_url="http://localhost:11434/v1", model="llava")

Local models with Ollama

Two Ollama server settings matter:

  • Context length. At the default 200 DPI a page takes about 4,300 tokens with qwen2.5vl, more than the 4,096-token context Ollama picks on machines with little memory, so every page fails. Start the server with OLLAMA_CONTEXT_LENGTH=8192, or lower dpi.
  • Parallel requests. Ollama works on OLLAMA_NUM_PARALLEL requests at a time (often 1) and queues the rest, so a max_concurrency above that does not make it faster. Set them to the same value. Servers built for batching, such as vLLM, do benefit from higher concurrency.
OLLAMA_CONTEXT_LENGTH=8192 ollama serve
ollama pull qwen2.5vl:3b
ocr-llm document.pdf --base-url http://localhost:11434/v1 --model qwen2.5vl:3b --concurrency 1

For a server on this machine (localhost), requests time out after 30 minutes instead of the OpenAI SDK's 10, so pages waiting in the queue are not cancelled and sent again. Pass timeout= (in seconds) to OpenAI(...) to change it.

Usage

convert_sync is the simplest entry point and also works in notebooks:

from llm_ocr import LLMOCR, OpenAI

ocr = LLMOCR(OpenAI())
markdown = ocr.convert_sync("document.pdf", output_path="document.md")

In async code, use convert and its siblings:

import asyncio

from llm_ocr import LLMOCR, Gemini


async def main():
    async with LLMOCR(Gemini()) as ocr:
        report = await ocr.convert("report.pdf")
        receipt = await ocr.convert("receipt.png")  # images work too

        # bytes from an upload or object store; PDF or image is detected
        with open("report.pdf", "rb") as f:
            from_bytes = await ocr.convert_bytes(f.read())


asyncio.run(main())

convert_image also accepts raw bytes or a PIL.Image.Image.

Command line

# Uses whichever of GEMINI_API_KEY / OPENAI_API_KEY / ANTHROPIC_API_KEY is set
ocr-llm document.pdf -o document.md

ocr-llm scan.png --provider anthropic --instructions "Tables only"

ocr-llm document.pdf --base-url http://localhost:11434/v1 --model llava

Without -o, the Markdown goes to stdout. ocr-llm --help lists every option.

Configuration

from llm_ocr import LLMOCR, OCRConfig, OpenAI

config = OCRConfig(
    dpi=300,
    max_concurrency=8,
    additional_instructions="Write formulas in LaTeX.",
)
ocr = LLMOCR(OpenAI(), config=config)
Option Default Description
dpi 200 Resolution for rendering PDF pages (72 to 600)
max_pages None Stop after this many pages
llm_batch_size 1 Pages sent to the model per request
max_concurrency 4 Concurrent requests; use 1 on low rate limits
max_retries 3 Attempts per request (not for permanent 4xx errors)
retry_delay 1.0 Seconds between attempts, multiplied by the attempt
include_page_markers False Insert <!-- Page N --> between pages
custom_prompt None Replace the built-in prompt
additional_instructions None Text appended to the prompt
convert_to_grayscale False Send grayscale images
optimize_png True Smaller PNGs at the cost of slower encoding
use_cropbox True Render the PDF crop box instead of the media box
batch_size 5 Pages rendered per poppler call
thread_count 4 Poppler rendering threads

Logging

Progress is reported through the standard logging module (it was print() before 1.1.0). To see it:

import logging

logging.basicConfig(level=logging.INFO)

Warnings, such as a page the model returned no text for, appear on stderr even without this. Such pages are left out of the output, so check for them.

Project

Changelog · Contributing · Roadmap · MIT License

Metadata

Release files for ocr-llm 1.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ocr-llm 1.2.1
File Size Uploaded Provenance Actions
ocr_llm-1.2.1.tar.gz 21.9 kB With provenance Details for ocr_llm-1.2.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for ocr-llm 1.2.1
File Interpreter ABI Platform Actions
ocr_llm-1.2.1-py3-none-any.whl Python 3 none any Details for ocr_llm-1.2.1-py3-none-any.whl

Total release size: 43.4 kB

Release files / ocr_llm-1.2.1.tar.gz

Download URL ocr_llm-1.2.1.tar.gz
Size 21.9 kB
Tags Source
SHA-256 checksum
How to use checksums
f30809d21e793e5c10157fb3077bafdfd50d0792c27f765154981e06378fb76e
BLAKE2b-256 checksum
How to use checksums
2eea85bc0d471d239ddf38475eb697d33155dc5227b21ce3d6b18aa41fa12c6a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

Release files / ocr_llm-1.2.1-py3-none-any.whl

Download URL ocr_llm-1.2.1-py3-none-any.whl
Size 21.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7564c3daa590ad703627b0a747ed5a6c13715da2c6579029ce22388a6b4da034
BLAKE2b-256 checksum
How to use checksums
c6f3c13eca0e33525d5d5964b2be68c2f9b93fb604c33d43cb50ef35c065a3b0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

Security for ocr-llm 1.2.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for ocr_llm-1.2.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page