pro-ledin-ocr 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pro_ledin_ocr-0.1.0/.gitignore +14 -0
- pro_ledin_ocr-0.1.0/LICENSE +21 -0
- pro_ledin_ocr-0.1.0/PKG-INFO +127 -0
- pro_ledin_ocr-0.1.0/README.md +78 -0
- pro_ledin_ocr-0.1.0/SKILL.md +211 -0
- pro_ledin_ocr-0.1.0/pyproject.toml +65 -0
- pro_ledin_ocr-0.1.0/references/engines.md +331 -0
- pro_ledin_ocr-0.1.0/references/troubleshooting.md +296 -0
- pro_ledin_ocr-0.1.0/src/pro/ledin/ocr/__init__.py +52 -0
- pro_ledin_ocr-0.1.0/src/pro/ledin/ocr/__main__.py +5 -0
- pro_ledin_ocr-0.1.0/src/pro/ledin/ocr/cli.py +276 -0
- pro_ledin_ocr-0.1.0/src/pro/ledin/ocr/core.py +1364 -0
- pro_ledin_ocr-0.1.0/src/pro/ledin/ocr/probe.sh +186 -0
- pro_ledin_ocr-0.1.0/tests/test_ocr.py +275 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 mxl
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pro-ledin-ocr
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Layered OCR workhorse: extract text from scanned PDFs and images (tesseract, PyMuPDF, easyocr, paddleocr, vision-api).
|
|
5
|
+
Project-URL: Homepage, https://github.com/ledin-pro/ocr
|
|
6
|
+
Project-URL: Repository, https://github.com/ledin-pro/ocr
|
|
7
|
+
Author: mxl
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: cyrillic,ocr,pdf,tesseract,text-extraction,vision
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Image Recognition
|
|
20
|
+
Classifier: Topic :: Text Processing
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Provides-Extra: all
|
|
23
|
+
Requires-Dist: easyocr; extra == 'all'
|
|
24
|
+
Requires-Dist: numpy; extra == 'all'
|
|
25
|
+
Requires-Dist: openai>=1.0; extra == 'all'
|
|
26
|
+
Requires-Dist: opencv-python; extra == 'all'
|
|
27
|
+
Requires-Dist: paddleocr; extra == 'all'
|
|
28
|
+
Requires-Dist: paddlepaddle; extra == 'all'
|
|
29
|
+
Requires-Dist: pymupdf; extra == 'all'
|
|
30
|
+
Requires-Dist: pytesseract; extra == 'all'
|
|
31
|
+
Provides-Extra: cv
|
|
32
|
+
Requires-Dist: numpy; extra == 'cv'
|
|
33
|
+
Requires-Dist: opencv-python; extra == 'cv'
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: pillow; extra == 'dev'
|
|
36
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
37
|
+
Provides-Extra: easyocr
|
|
38
|
+
Requires-Dist: easyocr; extra == 'easyocr'
|
|
39
|
+
Provides-Extra: paddle
|
|
40
|
+
Requires-Dist: paddleocr; extra == 'paddle'
|
|
41
|
+
Requires-Dist: paddlepaddle; extra == 'paddle'
|
|
42
|
+
Provides-Extra: pdf
|
|
43
|
+
Requires-Dist: pymupdf; extra == 'pdf'
|
|
44
|
+
Provides-Extra: pytesseract
|
|
45
|
+
Requires-Dist: pytesseract; extra == 'pytesseract'
|
|
46
|
+
Provides-Extra: vision
|
|
47
|
+
Requires-Dist: openai>=1.0; extra == 'vision'
|
|
48
|
+
Description-Content-Type: text/markdown
|
|
49
|
+
|
|
50
|
+
# pro-ledin-ocr
|
|
51
|
+
|
|
52
|
+
Layered OCR workhorse: extract text from scanned PDFs and images (PNG/JPG/TIFF/
|
|
53
|
+
HEIC/WEBP) using a tiered engine stack. The baseline path (poppler + tesseract)
|
|
54
|
+
needs zero extra Python installs; heavier engines are opt-in extras.
|
|
55
|
+
|
|
56
|
+
- Import name: `pro.ledin.ocr`
|
|
57
|
+
- Console scripts: `ocr`, `ocr-probe`
|
|
58
|
+
- PyPI: `pro-ledin-ocr`
|
|
59
|
+
|
|
60
|
+
## Install
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install pro-ledin-ocr # baseline
|
|
64
|
+
pip install "pro-ledin-ocr[vision]" # + OpenAI-compatible vision-api engine
|
|
65
|
+
pip install "pro-ledin-ocr[all]" # + pymupdf, opencv, easyocr, paddleocr
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
System binaries required for the local path: `poppler` (pdftoppm, pdftotext,
|
|
69
|
+
pdfinfo) and `tesseract` (with language packs).
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
brew install poppler tesseract tesseract-lang # macOS
|
|
73
|
+
sudo apt install poppler-utils tesseract-ocr-all # Debian/Ubuntu
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## CLI
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
ocr-probe myfile.pdf # triage: does it need OCR?
|
|
80
|
+
ocr myfile.pdf --format all # md + txt + json
|
|
81
|
+
ocr scan.png --format md
|
|
82
|
+
ocr russian_doc.pdf --lang rus+eng --format md
|
|
83
|
+
ocr scan.pdf --preprocess full # deskew + denoise
|
|
84
|
+
ocr slides.pdf --engine vision --pages 9,12 # hand pages to a multimodal agent
|
|
85
|
+
ocr slides.pdf --engine vision-api \
|
|
86
|
+
--vision-api-url https://api.example.com/v1 \
|
|
87
|
+
--vision-api-key "$KEY" --vision-model my-vision-model
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
See `ocr --help` for the full flag reference.
|
|
91
|
+
|
|
92
|
+
## Library
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from pro.ledin import ocr
|
|
96
|
+
|
|
97
|
+
pages = ocr.recognize("scan.pdf", ocr.RecognizeOptions(engine="tesseract", lang="rus+eng"))
|
|
98
|
+
markdown = ocr.to_markdown(pages, "scan.pdf")
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`recognize()` never calls `sys.exit()`; catch `ocr.OcrError` for recoverable
|
|
102
|
+
failures (unsupported input, missing binaries/packages, vision-api config).
|
|
103
|
+
|
|
104
|
+
## Engine tiers
|
|
105
|
+
|
|
106
|
+
| Tier | Engine | Best for | Cost |
|
|
107
|
+
|------|--------|----------|------|
|
|
108
|
+
| 0 | pdftotext / PyMuPDF | Real text layers | Free, instant |
|
|
109
|
+
| 1 | tesseract (default) | Clean scans, typed text, 160+ languages | Free |
|
|
110
|
+
| 2 | easyocr | Handwriting, degraded scans | Free, heavy |
|
|
111
|
+
| 2.5 | paddleocr | CJK, multilingual, angled text | Free |
|
|
112
|
+
| 3 | vision (agent reads PNGs) | Tables, charts, complex layouts | Agent tokens |
|
|
113
|
+
| 3.5 | vision-api (OpenAI-compatible) | Headless batch, complex layouts | API cost |
|
|
114
|
+
|
|
115
|
+
Full docs: `SKILL.md`, `references/engines.md`, `references/troubleshooting.md`.
|
|
116
|
+
|
|
117
|
+
## Development
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
uv sync --extra dev
|
|
121
|
+
uv run --extra dev pytest
|
|
122
|
+
uv build
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## License
|
|
126
|
+
|
|
127
|
+
MIT
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# pro-ledin-ocr
|
|
2
|
+
|
|
3
|
+
Layered OCR workhorse: extract text from scanned PDFs and images (PNG/JPG/TIFF/
|
|
4
|
+
HEIC/WEBP) using a tiered engine stack. The baseline path (poppler + tesseract)
|
|
5
|
+
needs zero extra Python installs; heavier engines are opt-in extras.
|
|
6
|
+
|
|
7
|
+
- Import name: `pro.ledin.ocr`
|
|
8
|
+
- Console scripts: `ocr`, `ocr-probe`
|
|
9
|
+
- PyPI: `pro-ledin-ocr`
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install pro-ledin-ocr # baseline
|
|
15
|
+
pip install "pro-ledin-ocr[vision]" # + OpenAI-compatible vision-api engine
|
|
16
|
+
pip install "pro-ledin-ocr[all]" # + pymupdf, opencv, easyocr, paddleocr
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
System binaries required for the local path: `poppler` (pdftoppm, pdftotext,
|
|
20
|
+
pdfinfo) and `tesseract` (with language packs).
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
brew install poppler tesseract tesseract-lang # macOS
|
|
24
|
+
sudo apt install poppler-utils tesseract-ocr-all # Debian/Ubuntu
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## CLI
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
ocr-probe myfile.pdf # triage: does it need OCR?
|
|
31
|
+
ocr myfile.pdf --format all # md + txt + json
|
|
32
|
+
ocr scan.png --format md
|
|
33
|
+
ocr russian_doc.pdf --lang rus+eng --format md
|
|
34
|
+
ocr scan.pdf --preprocess full # deskew + denoise
|
|
35
|
+
ocr slides.pdf --engine vision --pages 9,12 # hand pages to a multimodal agent
|
|
36
|
+
ocr slides.pdf --engine vision-api \
|
|
37
|
+
--vision-api-url https://api.example.com/v1 \
|
|
38
|
+
--vision-api-key "$KEY" --vision-model my-vision-model
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
See `ocr --help` for the full flag reference.
|
|
42
|
+
|
|
43
|
+
## Library
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from pro.ledin import ocr
|
|
47
|
+
|
|
48
|
+
pages = ocr.recognize("scan.pdf", ocr.RecognizeOptions(engine="tesseract", lang="rus+eng"))
|
|
49
|
+
markdown = ocr.to_markdown(pages, "scan.pdf")
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`recognize()` never calls `sys.exit()`; catch `ocr.OcrError` for recoverable
|
|
53
|
+
failures (unsupported input, missing binaries/packages, vision-api config).
|
|
54
|
+
|
|
55
|
+
## Engine tiers
|
|
56
|
+
|
|
57
|
+
| Tier | Engine | Best for | Cost |
|
|
58
|
+
|------|--------|----------|------|
|
|
59
|
+
| 0 | pdftotext / PyMuPDF | Real text layers | Free, instant |
|
|
60
|
+
| 1 | tesseract (default) | Clean scans, typed text, 160+ languages | Free |
|
|
61
|
+
| 2 | easyocr | Handwriting, degraded scans | Free, heavy |
|
|
62
|
+
| 2.5 | paddleocr | CJK, multilingual, angled text | Free |
|
|
63
|
+
| 3 | vision (agent reads PNGs) | Tables, charts, complex layouts | Agent tokens |
|
|
64
|
+
| 3.5 | vision-api (OpenAI-compatible) | Headless batch, complex layouts | API cost |
|
|
65
|
+
|
|
66
|
+
Full docs: `SKILL.md`, `references/engines.md`, `references/troubleshooting.md`.
|
|
67
|
+
|
|
68
|
+
## Development
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
uv sync --extra dev
|
|
72
|
+
uv run --extra dev pytest
|
|
73
|
+
uv build
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## License
|
|
77
|
+
|
|
78
|
+
MIT
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ocr
|
|
3
|
+
description: >
|
|
4
|
+
Extract text from scanned PDFs and images (PNG/JPG/TIFF/HEIC) using OCR. Use
|
|
5
|
+
this skill whenever a PDF's text cannot be selected or copied, the document is a
|
|
6
|
+
scan or photo, text is rendered as images rather than a selectable layer, or the
|
|
7
|
+
file is a receipt, screenshot, fax, ID card, form, or presentation slide image.
|
|
8
|
+
Also use for non-English and Cyrillic-language scans, when pdftotext or pypdf
|
|
9
|
+
return empty or garbled output, or when a user says "this PDF has no text" or
|
|
10
|
+
"I can't copy from this file". Handles language auto-detection, deskew and
|
|
11
|
+
denoise for messy scans, tables and charts via vision escalation, and produces
|
|
12
|
+
Markdown plus plain-text output. Always reach for this skill before giving up on
|
|
13
|
+
a document that appears to have no readable text.
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# OCR Skill
|
|
17
|
+
|
|
18
|
+
Extracts text from scanned PDFs and images using a layered engine stack.
|
|
19
|
+
The baseline path runs with zero additional installs (poppler + tesseract are
|
|
20
|
+
assumed present). Heavier tools are added only when a page needs them.
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install pro-ledin-ocr # baseline (tesseract + poppler on PATH)
|
|
26
|
+
pip install "pro-ledin-ocr[vision]" # + OpenAI-compatible vision-api engine
|
|
27
|
+
pip install "pro-ledin-ocr[all]" # + pymupdf, opencv, easyocr, paddleocr
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
System binaries still required for the local path: `poppler` (pdftoppm,
|
|
31
|
+
pdftotext, pdfinfo) and `tesseract`. Installs the `ocr` and `ocr-probe`
|
|
32
|
+
console scripts.
|
|
33
|
+
|
|
34
|
+
## When to use this skill
|
|
35
|
+
|
|
36
|
+
- PDF where text cannot be selected/copied in a viewer
|
|
37
|
+
- PDF produced by scanning a paper document or photographing a page
|
|
38
|
+
- Office-generated PDF where text is rasterized into image masks (common with
|
|
39
|
+
some Word/PowerPoint exports — `pdftotext` returns near-empty output)
|
|
40
|
+
- Any standalone image file containing text (PNG, JPG, TIFF, HEIC, WEBP)
|
|
41
|
+
- Non-English documents, especially Cyrillic/Russian
|
|
42
|
+
- Receipts, invoices, forms, ID cards, screenshots of documents
|
|
43
|
+
- When a previous attempt with `pdftotext`, `pypdf`, or `pdfplumber` failed
|
|
44
|
+
|
|
45
|
+
## Decision tree
|
|
46
|
+
|
|
47
|
+
Work through this in order. Stop at the first successful step.
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
1. Is input an image (png/jpg/tiff/heic/webp)?
|
|
51
|
+
└─ Yes → OCR directly (skip probe). Go to step 3.
|
|
52
|
+
|
|
53
|
+
2. PDF input: run ocr-probe FILE
|
|
54
|
+
├─ needs_ocr = false → real text layer exists.
|
|
55
|
+
│ Run: pdftotext -layout FILE - (or PyMuPDF get_text())
|
|
56
|
+
│ Done — fast, free, no OCR needed.
|
|
57
|
+
└─ needs_ocr = true → continue to step 3.
|
|
58
|
+
|
|
59
|
+
3. Baseline OCR:
|
|
60
|
+
ocr FILE --format all
|
|
61
|
+
(auto-detects language via OSD, DPI from page size, preprocessing level)
|
|
62
|
+
Emits: FILE.md FILE.txt FILE_ocr.json
|
|
63
|
+
quality report on stderr: per-page confidence, flagged pages.
|
|
64
|
+
|
|
65
|
+
4. Review quality report. Escalate flagged pages only:
|
|
66
|
+
├─ low confidence OR tables/charts/forms
|
|
67
|
+
│ → ocr FILE --engine vision --pages <flagged>
|
|
68
|
+
│ Renders persistent PNGs and hands them to the current multimodal agent
|
|
69
|
+
│ to read (Claude, GPT, or another model with image/file reading).
|
|
70
|
+
│ Agent produces Markdown (use Markdown table syntax for tables).
|
|
71
|
+
├─ CJK / multilingual / angled dense text
|
|
72
|
+
│ → ocr FILE --engine paddleocr
|
|
73
|
+
│ (opt-in; installs paddleocr+paddlepaddle, downloads models on first run)
|
|
74
|
+
├─ handwriting detected (very low conf, cursive)
|
|
75
|
+
│ → ocr FILE --engine easyocr
|
|
76
|
+
└─ skewed/noisy scan (scanned paper, phone photo)
|
|
77
|
+
→ ocr FILE --preprocess full
|
|
78
|
+
|
|
79
|
+
5. Need a selectable/searchable PDF?
|
|
80
|
+
→ ocr FILE --searchable-pdf OUT.pdf
|
|
81
|
+
(requires: brew install ocrmypdf)
|
|
82
|
+
|
|
83
|
+
6. Processing a folder or re-running repeatedly?
|
|
84
|
+
→ ocr FILE1 FILE2 … --cache ocr_cache.json
|
|
85
|
+
Add --skip-ocr to triage-only mode (skip OCR, text-layer files only).
|
|
86
|
+
Add --force to ignore cache and re-process.
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Quick start (90% of cases)
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
# Probe first to confirm OCR is needed
|
|
93
|
+
ocr-probe myfile.pdf
|
|
94
|
+
|
|
95
|
+
# Extract everything (md + txt + json quality report)
|
|
96
|
+
ocr myfile.pdf --format all
|
|
97
|
+
|
|
98
|
+
# Image input
|
|
99
|
+
ocr scan.png --format all
|
|
100
|
+
|
|
101
|
+
# Russian/Cyrillic doc — language auto-detected, but can be forced
|
|
102
|
+
ocr russian_doc.pdf --lang rus+eng --format md
|
|
103
|
+
|
|
104
|
+
# Messy scan (skewed, noisy)
|
|
105
|
+
ocr scan.pdf --preprocess full --format all
|
|
106
|
+
|
|
107
|
+
# Table-heavy slide / complex layout → vision tier
|
|
108
|
+
ocr slides.pdf --engine vision
|
|
109
|
+
|
|
110
|
+
# CJK / multilingual doc → PaddleOCR (opt-in)
|
|
111
|
+
ocr doc.png --engine paddleocr
|
|
112
|
+
|
|
113
|
+
# Headless vision via an OpenAI-compatible endpoint (all config via flags)
|
|
114
|
+
ocr slides.pdf --engine vision-api \
|
|
115
|
+
--vision-api-url https://api.example.com/v1 \
|
|
116
|
+
--vision-api-key "$MY_KEY" --vision-model my-vision-model
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
For `vision-api`, page images over ~7.5 MB are auto-re-encoded to JPEG (full
|
|
120
|
+
resolution first, dimensions reduced only if still too large) to stay under
|
|
121
|
+
the API's 10 MB per-image cap; this re-encode path requires Pillow. Images
|
|
122
|
+
already under the limit are sent untouched with their detected media type.
|
|
123
|
+
|
|
124
|
+
## Engine tiers (summary)
|
|
125
|
+
|
|
126
|
+
| Tier | Engine | Best for | Cost |
|
|
127
|
+
|------|--------|----------|------|
|
|
128
|
+
| 0 | pdftotext / PyMuPDF | Real text layers | Free, instant |
|
|
129
|
+
| 1 | tesseract (default) | Clean scans, typed text, 160+ languages | Free, ~3–4s/page |
|
|
130
|
+
| 2 | easyocr | Handwriting, degraded scans | Free, heavy (~2 GB) |
|
|
131
|
+
| 2.5 | paddleocr (opt-in) | CJK, multilingual (100+), angled text | Free, models on first run |
|
|
132
|
+
| 3 | vision (agent reads PNGs) | Tables, charts, complex layouts | Agent/model tokens |
|
|
133
|
+
| 4 | cloud APIs | High-volume, max accuracy | Paid + key |
|
|
134
|
+
|
|
135
|
+
See `references/engines.md` for full details, escalation thresholds, language
|
|
136
|
+
maps, DPI guidance, preprocessing levels, and install commands.
|
|
137
|
+
|
|
138
|
+
## Output formats
|
|
139
|
+
|
|
140
|
+
| Flag | Output |
|
|
141
|
+
|------|--------|
|
|
142
|
+
| `--format md` | `# filename` + `## Page N` headers, prose text |
|
|
143
|
+
| `--format txt` | pages separated by `----- Page N -----` |
|
|
144
|
+
| `--format json` | per-page text + word confidence + bboxes + quality report |
|
|
145
|
+
| `--format all` | all three formats written to disk |
|
|
146
|
+
| `--searchable-pdf OUT` | invisible text layer overlaid on original PDF |
|
|
147
|
+
|
|
148
|
+
## All CLI flags
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
ocr INPUT [INPUT ...]
|
|
152
|
+
--engine auto|tesseract|easyocr|paddleocr|vision|vision-api default: auto
|
|
153
|
+
--lang auto|<tesseract codes> default: auto (OSD detection)
|
|
154
|
+
--format md|txt|json|all default: md
|
|
155
|
+
--out PATH default: stdout (md/txt) or ./
|
|
156
|
+
--dpi N|auto default: auto (300 A4, 150 wide)
|
|
157
|
+
--preprocess none|basic|enhanced|full|auto default: auto
|
|
158
|
+
--pages RANGE (e.g. 1-3,5)
|
|
159
|
+
--max-pages N
|
|
160
|
+
--psm N (default 3; use 6 for dense single-block pages)
|
|
161
|
+
--min-conf F (default 60.0 — flag pages below this for review)
|
|
162
|
+
--cache PATH --force --skip-ocr
|
|
163
|
+
--no-cleanup (skip whitespace / ligature cleanup)
|
|
164
|
+
--vision-api-url URL (OpenAI-compatible base URL for vision-api)
|
|
165
|
+
--vision-api-key KEY (required for vision-api; env vars are NOT read)
|
|
166
|
+
--vision-model NAME (required for vision-api; no default)
|
|
167
|
+
--searchable-pdf OUT.pdf
|
|
168
|
+
--json-report PATH
|
|
169
|
+
--verbose
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Library usage
|
|
173
|
+
|
|
174
|
+
The package also works as an importable library for other skills/scripts that
|
|
175
|
+
want structured OCR results in-process instead of shelling out to the CLI:
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
from pro.ledin import ocr
|
|
179
|
+
|
|
180
|
+
pages = ocr.recognize("scan.pdf", ocr.RecognizeOptions(engine="tesseract", lang="rus+eng"))
|
|
181
|
+
markdown = ocr.to_markdown(pages, "scan.pdf")
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
- `recognize(path, options=None, *, caps=None, cache=None)` is the entry
|
|
185
|
+
point: it manages a throwaway render directory and returns the same
|
|
186
|
+
per-page dicts the CLI builds internally. Format the result with
|
|
187
|
+
`to_markdown()`, `to_text()`, or `to_json()`.
|
|
188
|
+
- `RecognizeOptions` mirrors the CLI's recognition flags (`engine`, `lang`,
|
|
189
|
+
`dpi`, `preprocess`, `pages`, `max_pages`, `psm`, `min_conf`, `no_cleanup`,
|
|
190
|
+
`force`, `vision_api_url`, `vision_api_key`, `vision_model`, `timeout`,
|
|
191
|
+
`verbose`). Output-only flags (`--out`, `--format`, `--json-report`,
|
|
192
|
+
`--searchable-pdf`) are CLI-only and have no library equivalent.
|
|
193
|
+
- `--engine vision` is an interactive agent handoff (renders pages and prints
|
|
194
|
+
a manifest for a multimodal agent to read) and is not usable via
|
|
195
|
+
`recognize()`; it raises `OcrError` if requested. Use another engine or the
|
|
196
|
+
CLI directly.
|
|
197
|
+
- Catch `OcrError` for recoverable failures (unsupported input, missing
|
|
198
|
+
binaries/packages, vision-api config/request errors) — the library never
|
|
199
|
+
calls `sys.exit()`, unlike the CLI.
|
|
200
|
+
- For `engine="vision-api"`, `RecognizeOptions.timeout` (seconds) bounds the
|
|
201
|
+
HTTP request via the openai SDK's own client timeout. Local engines
|
|
202
|
+
(tesseract/easyocr/paddleocr) run in-process with no external kill switch,
|
|
203
|
+
since there is no longer a subprocess to terminate on timeout.
|
|
204
|
+
- The `healthos` skill uses this API (via `import`) to recognize family medical
|
|
205
|
+
documents without spawning a subprocess per file.
|
|
206
|
+
|
|
207
|
+
## Troubleshooting
|
|
208
|
+
|
|
209
|
+
See `references/troubleshooting.md` for: rasterized-text PDFs, garbled Cyrillic,
|
|
210
|
+
rotated pages, table/chart handling, handwriting, multi-column layouts, and
|
|
211
|
+
large-folder batch jobs.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pro-ledin-ocr"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Layered OCR workhorse: extract text from scanned PDFs and images (tesseract, PyMuPDF, easyocr, paddleocr, vision-api)."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [{ name = "mxl" }]
|
|
14
|
+
keywords = ["ocr", "pdf", "tesseract", "vision", "text-extraction", "cyrillic"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Environment :: Console",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3.10",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Topic :: Scientific/Engineering :: Image Recognition",
|
|
25
|
+
"Topic :: Text Processing",
|
|
26
|
+
]
|
|
27
|
+
dependencies = []
|
|
28
|
+
|
|
29
|
+
[project.optional-dependencies]
|
|
30
|
+
vision = ["openai>=1.0"]
|
|
31
|
+
pdf = ["pymupdf"]
|
|
32
|
+
cv = ["opencv-python", "numpy"]
|
|
33
|
+
pytesseract = ["pytesseract"]
|
|
34
|
+
easyocr = ["easyocr"]
|
|
35
|
+
paddle = ["paddleocr", "paddlepaddle"]
|
|
36
|
+
all = ["openai>=1.0", "pymupdf", "opencv-python", "numpy", "pytesseract", "easyocr", "paddleocr", "paddlepaddle"]
|
|
37
|
+
dev = ["pytest>=8.0", "pillow"]
|
|
38
|
+
|
|
39
|
+
[project.scripts]
|
|
40
|
+
ocr = "pro.ledin.ocr.cli:main"
|
|
41
|
+
ocr-probe = "pro.ledin.ocr.cli:probe_main"
|
|
42
|
+
|
|
43
|
+
[project.urls]
|
|
44
|
+
Homepage = "https://github.com/ledin-pro/ocr"
|
|
45
|
+
Repository = "https://github.com/ledin-pro/ocr"
|
|
46
|
+
|
|
47
|
+
[tool.hatch.build.targets.wheel]
|
|
48
|
+
packages = ["src/pro"]
|
|
49
|
+
|
|
50
|
+
[tool.hatch.build.targets.wheel.force-include]
|
|
51
|
+
"src/pro/ledin/ocr/probe.sh" = "pro/ledin/ocr/probe.sh"
|
|
52
|
+
|
|
53
|
+
[tool.hatch.build.targets.sdist]
|
|
54
|
+
include = [
|
|
55
|
+
"src/pro",
|
|
56
|
+
"tests",
|
|
57
|
+
"references",
|
|
58
|
+
"SKILL.md",
|
|
59
|
+
"README.md",
|
|
60
|
+
"LICENSE",
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
[tool.pytest.ini_options]
|
|
64
|
+
testpaths = ["tests"]
|
|
65
|
+
pythonpath = ["src"]
|