Metadata-Version: 2.4
Name: pro-ledin-ocr
Version: 0.3.0
Summary: Layered OCR workhorse: extract text from scanned PDFs and images (tesseract, PyMuPDF, easyocr, paddleocr, vision-api).
Project-URL: Homepage, https://github.com/ledin-pro/ocr
Project-URL: Repository, https://github.com/ledin-pro/ocr
Author: mxl
License-Expression: MIT
License-File: LICENSE
Keywords: cyrillic,ocr,pdf,tesseract,text-extraction,vision
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Image Recognition
Classifier: Topic :: Text Processing
Requires-Python: >=3.10
Provides-Extra: all
Requires-Dist: easyocr; extra == 'all'
Requires-Dist: numpy; extra == 'all'
Requires-Dist: openai>=1.0; extra == 'all'
Requires-Dist: opencv-python; extra == 'all'
Requires-Dist: paddleocr; extra == 'all'
Requires-Dist: paddlepaddle; extra == 'all'
Requires-Dist: pymupdf; extra == 'all'
Requires-Dist: pytesseract; extra == 'all'
Provides-Extra: cv
Requires-Dist: numpy; extra == 'cv'
Requires-Dist: opencv-python; extra == 'cv'
Provides-Extra: dev
Requires-Dist: pillow; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Provides-Extra: easyocr
Requires-Dist: easyocr; extra == 'easyocr'
Provides-Extra: paddle
Requires-Dist: paddleocr; extra == 'paddle'
Requires-Dist: paddlepaddle; extra == 'paddle'
Provides-Extra: pdf
Requires-Dist: pymupdf; extra == 'pdf'
Provides-Extra: pytesseract
Requires-Dist: pytesseract; extra == 'pytesseract'
Provides-Extra: vision
Requires-Dist: openai>=1.0; extra == 'vision'
Description-Content-Type: text/markdown

# pro-ledin-ocr

[![skills.sh](https://skills.sh/b/ledin-pro/ocr)](https://skills.sh/ledin-pro/ocr)

Layered OCR workhorse: extract text from scanned PDFs and images (PNG/JPG/TIFF/
HEIC/WEBP) using a tiered engine stack. The baseline path (poppler + tesseract)
needs zero extra Python installs; heavier engines are opt-in extras.

- Import name: `pro.ledin.ocr`
- Console scripts: `ocr`, `ocr-probe`, `peepshow-sink-ocr`
- PyPI: `pro-ledin-ocr`

## Install

```bash
pip install pro-ledin-ocr            # baseline
pip install "pro-ledin-ocr[vision]"  # + OpenAI-compatible vision-api engine
pip install "pro-ledin-ocr[all]"     # + pymupdf, opencv, easyocr, paddleocr
```

System binaries required for the local path: `poppler` (pdftoppm, pdftotext,
pdfinfo) and `tesseract` (with language packs).

```bash
brew install poppler tesseract tesseract-lang      # macOS
sudo apt install poppler-utils tesseract-ocr-all   # Debian/Ubuntu
```

## CLI

```bash
ocr-probe myfile.pdf                          # triage: does it need OCR?
ocr myfile.pdf --format all                   # md + txt + json
ocr scan.png --format md
ocr russian_doc.pdf --lang rus+eng --format md
ocr scan.pdf --preprocess full                # deskew + denoise
ocr slides.pdf --engine vision --pages 9,12   # hand pages to a multimodal agent
ocr table.png --engine vision \
  --vision-prompt "Extract only table rows and preserve empty cells"
ocr slides.pdf --engine vision-api \
  --vision-api-url https://api.example.com/v1 \
  --vision-api-key "$KEY" --vision-model my-vision-model \
  --vision-prompt-file prompts/faithful-ocr.txt
```

See `ocr --help` for the full flag reference.

## Peepshow sink

`peepshow-sink-ocr` reads peepshow's JSON payload from stdin, recognizes each
primary frame, and atomically writes `<outputDir>/ocr.json`:

```bash
peepshow video.mp4 --sink ocr
peepshow video.mp4 \
  --sink-cmd 'peepshow-sink-ocr --engine tesseract --lang rus+eng'
```

No extra Python dependency is required for the sink interface. Peepshow only
needs the installed `peepshow-sink-ocr` executable on `PATH`. The default local
engine still requires Tesseract; `vision-api` requires
`pip install "pro-ledin-ocr[vision]"`.

Configure named sink runs through `PEEPSHOW_SINK_OCR_*` variables:

```bash
export PEEPSHOW_SINK_OCR_ENGINE=vision-api
export PEEPSHOW_SINK_OCR_VISION_API_URL=https://api.example.com/v1
export PEEPSHOW_SINK_OCR_VISION_API_KEY="$KEY"
export PEEPSHOW_SINK_OCR_VISION_MODEL=my-vision-model
export PEEPSHOW_SINK_OCR_TIMEOUT=120
peepshow video.mp4 --sink ocr
```

The sink never changes peepshow's manifest or frames and prints no OCR content
to stdout. `vision-api` sends frame images to the configured external endpoint.
Protect both API credentials and output directories containing recognized text.

## Library

```python
from pro.ledin import ocr

pages = ocr.recognize(
    "scan.pdf",
    ocr.RecognizeOptions(
        engine="vision-api",
        vision_api_key="key",
        vision_model="model",
        vision_prompt="Preserve checkbox states and labels.",
    ),
)
markdown = ocr.to_markdown(pages, "scan.pdf")
```

`recognize()` never calls `sys.exit()`; catch `ocr.OcrError` for recoverable
failures (unsupported input, missing binaries/packages, vision-api config).

## Engine tiers

| Tier | Engine | Best for | Cost |
|------|--------|----------|------|
| 0 | pdftotext / PyMuPDF | Real text layers | Free, instant |
| 1 | tesseract (default) | Clean scans, typed text, 160+ languages | Free |
| 2 | easyocr | Handwriting, degraded scans | Free, heavy |
| 2.5 | paddleocr | CJK, multilingual, angled text | Free |
| 3 | vision (agent reads PNGs) | Tables, charts, complex layouts | Agent tokens |
| 3.5 | vision-api (OpenAI-compatible) | Headless batch, complex layouts | API cost |

Full docs: `skills/ocr/SKILL.md`, `skills/ocr/references/engines.md`,
`skills/ocr/references/peepshow-sinks.md`, and
`skills/ocr/references/troubleshooting.md`.

## Development

```bash
uv sync --extra dev
uv run --extra dev pytest
uv build
```

## License

MIT
