Metadata-Version: 2.5
Name: monocr-onnx
Version: 0.5.0
Summary: On-device Mon (mnw) OCR, powered by ONNX Runtime
Project-URL: Homepage, https://github.com/MonDevHub/monocr-onnx
Project-URL: Repository, https://github.com/MonDevHub/monocr-onnx
Project-URL: Issues, https://github.com/MonDevHub/monocr-onnx/issues
Project-URL: Documentation, https://github.com/MonDevHub/monocr-onnx/tree/main/python
Author-email: Janakh <janakh@example.com>
License: MIT
License-File: LICENSE
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Scientific/Engineering :: Image Recognition
Requires-Python: >=3.11
Requires-Dist: click>=8.0.0
Requires-Dist: numpy>=1.21.0
Requires-Dist: onnxruntime>=1.15.0
Requires-Dist: opencv-python-headless>=4.5.0
Requires-Dist: pdf2image>=1.16.0
Requires-Dist: pillow>=9.0.0
Requires-Dist: requests>=2.25.0
Requires-Dist: tqdm>=4.60.0
Description-Content-Type: text/markdown

# MonOCR (Python)

[![PyPI](https://img.shields.io/pypi/v/monocr-onnx.svg)](https://pypi.org/project/monocr-onnx/)

On-device OCR for the Mon language (mnw), running on ONNX Runtime. Part of
[monocr-onnx](https://github.com/MonDevHub/monocr-onnx), which also has
JavaScript, Go and Rust bindings.

## Install

```bash
pip install "monocr-onnx>=0.4.1"
```

Requires Python 3.11+. Keep the floor: 0.1.0 is the only release that accepts
Python 3.9 or 3.10, so an unpinned install there resolves to it, and 0.1.x pairs
a 225-character charset with a 277-class graph and returns wrong characters.

The wheel is pure Python and every native dependency publishes wheels for glibc
Linux (x86_64 and aarch64), macOS and x64 Windows, so no compiler is needed
there. On an Intel Mac that means onnxruntime 1.23.2, its last Intel-macOS wheel,
and Python 3.11 to 3.13. Two platforms are not covered: `opencv-python-headless`
has never published a Windows-on-ARM wheel, so pip builds it from source there,
and neither it nor `onnxruntime` publishes a musllinux wheel, so Alpine and other
musl distributions cannot install `onnxruntime`, which has no sdist. It runs on
the CPU only.

## Quick start

```python
from monocr_onnx import MonOCR, read_pdf

# Downloads the pinned model on first run and caches it by revision.
engine = MonOCR()

# A page: segmented into lines, joined with newlines.
print(engine.predict("page.png"))

# A line you have already cropped: read whole, never split.
print(engine.predict_line("line.png"))

# A PDF: one string per page. Needs poppler (below).
pages = read_pdf("book.pdf")
```

`predict` is an alias for `predict_page`. It does not accept a PDF: it opens the
path as an image and raises `PIL.UnidentifiedImageError`. Use `read_pdf`.

## API

| Call | Returns |
| :--- | :--- |
| `MonOCR(model_path=None, charset_path=None)` | The engine. Omit both paths to use the pinned model and its charset. |
| `.predict(image)` / `.predict_page(image)` | `str`, one line of text per detected line, for a path or PIL image. A detected line too wide for the model is cut into tiles. |
| `.predict_line(image)` | `str`, for a path or PIL image of one line. A crop too wide for the model is squeezed to fit, not tiled. |
| `read_image(path)` / `read_images(paths, workers=4)` | `str` / `list[str]` |
| `read_pdf(path)` / `read_pdfs(paths, workers=4)` | `list[str]`, one per page / `list[list[str]]` |
| `read_image_with_accuracy(path, ground_truth)` | `(str, float)`: the text, and `100 × (1 − edit distance ÷ length of the longer string)` |

The module-level functions also take `model_path` and `charset_path` as
keyword arguments.

Loading raises `ModelContractError` when the model's output class count is not
the charset's length plus one (277 for the 276-character charset; CTC reserves
index 0 for the blank) or its input height is not 160. A mismatched pair would still run and
still return text; it would just be the wrong text. Decoding raises
`ModelOutputError` when the model returns NaN or infinite scores, and
`ModelContractError` when the logits are not `[1, sequence, 277]`, rather than
turning a broken output into a blank or wrong line.

## CLI

```bash
monocr-onnx image input.jpg
monocr-onnx pdf document.pdf
monocr-onnx batch ./input
monocr-onnx download        # pre-fetch the model and charset
```

The command is `monocr-onnx`, not `monocr`. It was `monocr` up to 0.3.2, which
collided with the command installed by the separate
[`monocr`](https://pypi.org/project/monocr/) package.

## PDFs need poppler

`read_pdf` goes through `pdf2image`, which shells out to poppler's `pdftoppm`.
Without it the call raises a `RuntimeError` naming poppler.

```bash
brew install poppler                 # macOS
sudo apt-get install poppler-utils   # Debian, Ubuntu
```

On Windows: `scoop install poppler`, `choco install poppler`,
`conda install -c conda-forge poppler`, or the prebuilt binaries from
[oschwartz10612/poppler-windows](https://github.com/oschwartz10612/poppler-windows/releases)
with `Library\bin` added to `PATH`. `read_pdf` does not forward pdf2image's
`poppler_path`, so `PATH` is the route. Check with `pdfinfo -v` in a new shell.

## What to expect

- **First run downloads the model**, 46.2 MB, from revision `d3d9d5e` of
  [janakhpon/monocr](https://huggingface.co/janakhpon/monocr), never from `main`.
  Both files are checked by sha256 and cached under
  `~/.monocr/models/<revision>/`, so a new pin is a cache miss rather than a
  silent reuse of old weights. Nothing works offline until that has happened
  once.
- **Speed.** On an Apple M5 with the model cached, a typeset page takes about
  2 s.
- **No accuracy figure is claimed by this package.** The model card reports a
  held-out CER of 0.0100 on 150 unseen rendered lines in a typeface the model
  never trained on, with a 95% interval of [0.0056, 0.0147]. Those lines come
  from the same synthetic generator as the training data, so nothing on the card
  is measured on photographed pages. Read its caveats before quoting the number.
- **Bindings disagree.** The four bindings do not yet return identical text for
  the same page; see the
  [root README](https://github.com/MonDevHub/monocr-onnx#limitations).
- **Upgrading from 0.1.0:** a stale `~/.monocr/models/monocr.onnx` may still be
  on disk. Nothing reads it; `monocr-onnx download` points it out and it is safe
  to delete.

## License

MIT
