NEW TextLens 2.0 — model-agnostic OCR infrastructure →

OCR without the
OCR complexity.

Read text, tables and layout from images and PDFs with one line of Python. TextLens picks the right engine for your hardware — a laptop CPU, a Raspberry Pi or a GPU server — and only runs OCR on the pages that need it.

$ pip install textlens-ocr
No PyTorch or CUDA needed Runs locally MIT licensed
from textlens import OCR

result = OCR()("report.pdf")

print(result.text)          # plain text
result.to_markdown()        # headings, lists, tables
result.save("output/")      # .json .md .txt + tables as .csv
# only page 3 went through the OCR model
for page in result.pages:
    print(page.number, page.provenance.source)
1 native
2 native
3 ocr
4 native
One-line APIOCR()("file").text
~31 MB default modelPP-OCRv6 on ONNX Runtime
Selective PDF OCRnative text first, OCR only when needed
Laptop → Pi → GPUsame code, routed per device

What's in 2.0

Everything between a file and structured text

TextLens is the layer around OCR models: it reads documents, decides what needs OCR, picks a model for your hardware, and hands back one consistent result.

Selective PDF OCR

Each page is inspected first. Digital pages are read directly with exact text; only scanned, garbled or image-only pages are OCR'd — each with a reason code.

ocr="auto" | "force" | "off"

One unified result

Pages, blocks, lines, words, tables and formulas with bounding boxes, confidence and provenance — the same shape whichever model produced it.

text · markdown · html · json · csv

Hardware-aware routing

Profiles like edge, fast and accurate choose a model that fits your RAM, VRAM and runtimes — with fallbacks when confidence is low.

router.explain() shows why

Light by default

The core install is Pillow, numpy, pypdfium2 and ONNX Runtime. No PyTorch, no OpenCV, no CUDA — it runs on a Raspberry Pi 4/5 and any laptop CPU.

pip install textlens-ocr

Bring bigger models

Swap in document VLMs — GLM-OCR, LightOnOCR, HunyuanOCR — on a GPU, or any model served by vLLM through an OpenAI-compatible endpoint.

OCR(model="glm-ocr")

Fields to JSON

Give a schema, get typed values back with the page and box each came from. Works locally with heuristics, or with a VLM when one is installed.

ocr.extract(file, schema=…)

RAG-ready chunks

Section-aware chunks with page numbers and bounding boxes for citations, ready to drop into any vector store.

result.to_chunks()

Server, CLI & MCP

A FastAPI server with async jobs, API keys, rate limits and Prometheus metrics; a full CLI; and an MCP server so AI agents can read your documents.

textlens serve · textlens mcp

Number-plate recognition

An optional ANPR pipeline: plate detection, recognition, plate formats for India, the UK, the EU, the US, Brazil and more, and tracking with voting for video.

textlens anpr car.jpg --region in

How it works

Inspect first. OCR only what needs it.

Most PDFs already contain their text. TextLens reads it directly — fast and exact — and sends only the pages that really are images to an OCR model.

01

Open

Images, PDFs, DOCX, PPTX, bytes or URLs.

02

Inspect

Classify each page: native, scanned, garbled, invisible OCR layer.

03

Route

Pick a model that fits the page, the profile and your hardware.

04

Read

Native extraction or OCR, with layout, tables and reading order.

05

Result

One schema with boxes, confidence and where each page came from.

Know what's in a PDF before you process it

  • No rendering, no OCR. textlens inspect classifies every page in milliseconds.
  • Reason codes such as scanned, suspected_garbled_text and invisible_text_layer explain each decision.
  • Stream large files page by page with ocr.stream() at constant memory.
  • Lazy documents with textlens.load() — only touched pages are processed.
selective_ocr.py
from textlens import OCR

ocr = OCR(profile="fast")

report = ocr.inspect("report.pdf")
print(report.summary())
# mixed PDF (4 pages); 2 page(s) need OCR

for page in ocr.stream("report.pdf"):
    print(page.number, page.classification, page.provenance.source)

Quickstart

From install to text in a minute

Python 3.10 or newer. The first run downloads the default model (about 31 MB, SHA-256 verified) into ~/.cache/textlens.

# the core: CPU OCR + PDFs, no PyTorch
pip install textlens-ocr

# optional extras
pip install "textlens-ocr[gpu]"        # document VLMs on NVIDIA GPUs
pip install "textlens-ocr[server]"     # REST API
pip install "textlens-ocr[documents]"  # Word and PowerPoint files
pip install "textlens-ocr[all]"        # everything except vLLM

# check your setup
textlens doctor

Models & profiles

Pick speed or accuracy — TextLens picks the model

Choose a profile and the router finds the best installed model that fits your hardware. Or name a model directly.

ProfileUse it for
autoDefault — decides from your hardware
edgeRaspberry Pi, Jetson, low-memory devices
fastLow latency on any CPU
balancedGood accuracy without a big model
accurateThe strongest model you have installed
documentLayout, tables and formulas first
serverThroughput on a shared GPU server
profiles.py
from textlens import OCR

OCR(profile="edge")          # small devices
OCR(profile="accurate")      # best installed model
OCR(model="glm-ocr")         # a specific model

# a model served by vLLM or any OpenAI-compatible API
OCR(model="paddleocr-vl", endpoint="http://gpu-box:8000/v1")
ModelRuns onGood atLicenseHow
ppocrv6-small defaultAny CPU, Pi, JetsonPrinted text, lines, boxesApache-2.0built in
glm-ocrGPU ≥ 4 GBText, tables, formulas, MarkdownMITlocal
lighton-ocrGPU ≥ 6 GBText, tables, formulas, MarkdownApache-2.0local
hunyuan-ocrGPU ≥ 6 GBLayouts, charts, extractionTencent communitylocal
smolvlmCPU or small GPURough textApache-2.0local
paddleocr-vlGPU server100+ languages, tables, chartsApache-2.0served
deepseek-ocr-2GPU server ≥ 10 GBDense, long documentsApache-2.0served

local — textlens models install <name> downloads the weights. served — run the model in vLLM or SGLang and point TextLens at it. Always check a model's license before commercial use: textlens models info <name>.

Results

Structured output you can build on

  • Pages → blocks → lines → words, each with a bounding box and confidence.
  • Tables as rows, CSV or HTML; formulas as LaTeX when the model supports it.
  • Provenance on every page: native or OCR, which model, and why.
  • Exports to text, Markdown, HTML, JSON and CSV, or a full artifact folder.
  • Chunks for RAG with page numbers and boxes for citations.
result = OCR()("invoice.png")

for page in result.pages:
    for block in page.ordered_blocks():
        print(block.type, block.bbox, block.confidence)
        for line in block.lines:
            print("  ", line.text)

result.to_json()          # the full schema
result.save("output/")

Deploy anywhere

The same code from a Raspberry Pi to a GPU cluster

Start on your laptop. Move to an edge device, a container or a GPU server without changing how you call it.

Laptop / any CPU

The default install. PP-OCRv6 on ONNX Runtime; PDFs with a text layer never touch a model.

pip install textlens-ocr
textlens ocr scan.png

Raspberry Pi & edge

64-bit Pi OS, Jetson or industrial PCs. Works fully offline once the model is cached.

textlens setup --profile edge --yes
TEXTLENS_OFFLINE=1 textlens ocr cam.jpg

NVIDIA GPU

Install a CUDA build of PyTorch, then the gpu extra. textlens doctor prints the exact command.

pip install "textlens-ocr[gpu]"
textlens models install glm-ocr

REST server

API keys, rate limits, upload limits, async jobs, NDJSON streaming, /metrics for Prometheus.

pip install "textlens-ocr[server]"
textlens serve --host 0.0.0.0 --workers 2

Docker & Kubernetes

CPU image with the model baked in, plus GPU and Jetson references and a Kubernetes manifest.

docker build -f deploy/docker/Dockerfile \
  -t textlens .

AI agents (MCP)

Let Claude and other MCP clients OCR, inspect and extract from files in a workspace you choose.

pip install "textlens-ocr[mcp]"
textlens mcp --workspace .

Batch processing

Process whole folders, watch it live

textlens batch ./documents -o results/ shares one model across files, resumes where it stopped, and opens a live dashboard with CPU, RAM and GPU telemetry and a printable PDF report.

TextLens batch dashboard showing jobs, live logs and hardware telemetry

Walkthrough

See TextLens in action

A walkthrough of installing TextLens and running local OCR from Python and the command line.

Upgrading from 0.x

Your 0.x code keeps working

The 0.x API — OCR(model=…).read(), the read command and the /api/v1 endpoints — still works. New code should use OCR()(source), which returns the richer result.

upgrade
pip install -U textlens-ocr

# 0.x — still supported
text = OCR(model="glm-ocr").read("scan.png")

# 2.0 — recommended
result = OCR()("scan.png")
text = result.text

Open source, and built in the open

TextLens is MIT licensed. Star the repo, open an issue, or send a pull request — new backends plug in through a small, documented interface.