rusto 0.3.2__tar.gz → 0.4.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.
rusto-0.4.0/PKG-INFO ADDED
@@ -0,0 +1,189 @@
1
+ Metadata-Version: 2.4
2
+ Name: rusto
3
+ Version: 0.4.0
4
+ Summary: Pure Rust OCR library for Python based on RapidOCR, Indra OCR, and pure-Rust MNN (rusto-nn)
5
+ Author-email: RustO Contributors <contact@rusto.dev>
6
+ License-Expression: MIT
7
+ Requires-Python: >=3.8
8
+ Description-Content-Type: text/markdown
9
+ Provides-Extra: test
10
+ Requires-Dist: pytest>=7.0; extra == "test"
11
+
12
+ # rusto (Python SDK)
13
+
14
+ Official Python bindings for **RustO!** — a high-performance, pure-Rust OCR engine powered by Indra OCR, PaddleOCR, and the pure-Rust MNN (`rusto-nn`) inference runtime via UniFFI.
15
+
16
+ ## Features
17
+
18
+ - **Zero-Config Indra OCR**: `RustO.initialize()` automatically downloads and caches the default `indraocr` models on first run from Hugging Face Hub.
19
+ - **Context Manager Support**: Deterministic native resource cleanup with `with RustO.initialize() as engine:` or `engine.close()`.
20
+ - **Full Document Pipeline**: Neural document unwarping (`with_auto_unwarp()`), page orientation detection (`with_orientation_detection()`), semantic layout analysis, and reading-order recovery (`with_layout_reading()`).
21
+ - **Fluent Builder API**: Chain `.as_lines()`, `.as_words()`, `.as_spatial()`, `.as_tsv()`, or `.with_output(...)` into a single `.run()` terminal method.
22
+ - **Zero-Copy Raw RGB Support**: Feed NumPy / OpenCV / Pillow RGB8 buffers directly via `.rgb(pixels, width, height, stride)`.
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ pip install rusto
28
+ ```
29
+
30
+ ## Quick Start
31
+
32
+ ```python
33
+ from rusto import RustO
34
+
35
+ # Zero-config initialization (auto-downloads Indra OCR models from Hugging Face Hub if not cached)
36
+ with RustO.initialize() as engine:
37
+ result = (
38
+ engine.detect_text("invoice.png")
39
+ .with_auto_unwarp()
40
+ .with_layout_reading()
41
+ .as_lines()
42
+ .run()
43
+ )
44
+
45
+ if result.is_STRUCTURED():
46
+ for item in result.results:
47
+ print(
48
+ f"[{item.score:.2f}] ({item.layout_type or 'line'} #{item.region_id}) {item.text}"
49
+ )
50
+
51
+ # Reconstructed 2D spatial text layout
52
+ spatial = engine.detect_text("invoice.png").as_spatial().run()
53
+ if spatial.is_SPATIAL():
54
+ print(spatial.text)
55
+ ```
56
+
57
+ You can also manage the engine lifecycle explicitly without a `with` block:
58
+
59
+ ```python
60
+ from rusto import InitializeConfig, RustO
61
+
62
+ engine = RustO.initialize(InitializeConfig.indra())
63
+ try:
64
+ result = engine.detect_text("invoice.png").as_words().run()
65
+ if result.is_STRUCTURED():
66
+ for word in result.results:
67
+ print(word.text, word.frame)
68
+ finally:
69
+ engine.close()
70
+ ```
71
+
72
+ ## Custom Configuration & Offline Models (.mnn / .rten)
73
+
74
+ Select canonical model tiers (`"indraocr"`, `"ppocrv6-tiny"`, `"ppocrv6-small"`, `"ppocrv5-mobile"`, `"ppocrv4-mobile"`), languages, or local model paths:
75
+
76
+ ```python
77
+ from rusto import (
78
+ DetectionConfig,
79
+ InitializeConfig,
80
+ LayoutConfig,
81
+ RecognitionConfig,
82
+ RustO,
83
+ UnwarpConfig,
84
+ )
85
+
86
+ # Preset by canonical model + language (auto-downloaded to cache)
87
+ cfg = InitializeConfig.for_model("ppocrv6-tiny", lang="latin")
88
+ engine = RustO.initialize(cfg)
89
+ engine.close()
90
+
91
+ # Explicit local assets for offline environments
92
+ offline_cfg = InitializeConfig(
93
+ template="indra",
94
+ enable_reading_order=True,
95
+ detection=DetectionConfig(enabled=True, model_path="./models/indra_det.mnn"),
96
+ recognition=RecognitionConfig(
97
+ enabled=True,
98
+ model_path="./models/indra_rec.mnn",
99
+ dict_path="./models/indra_meta.json",
100
+ ),
101
+ unwarp=UnwarpConfig(enabled=True, model_path="./models/uvdoc.mnn"),
102
+ layout=LayoutConfig(enabled=True, model_path="./models/layout_cdla.mnn"),
103
+ )
104
+ with RustO.initialize(offline_cfg) as offline_engine:
105
+ res = offline_engine.detect_text("scan.png").with_auto_unwarp().as_lines().run()
106
+ ```
107
+
108
+ Pre-download models into a target cache directory ahead of time (e.g., during Docker image build):
109
+
110
+ ```python
111
+ from rusto import download_model
112
+
113
+ paths = download_model(model="indraocr", lang="latin", cache_dir="./models-cache")
114
+ ```
115
+
116
+ ## Input Sources & Raw RGB Buffers
117
+
118
+ Pass a file path (`str` or `Path`), encoded image `bytes`, `ImageSource`, or raw interleaved 24-bit RGB pixels:
119
+
120
+ ```python
121
+ from pathlib import Path
122
+ import numpy as np
123
+ from rusto import RustO
124
+
125
+ with RustO.initialize() as engine:
126
+ # 1. Encoded PNG/JPEG bytes
127
+ png_bytes = Path("invoice.png").read_bytes()
128
+ res_bytes = engine.detect_text(png_bytes).as_lines().run()
129
+
130
+ # 2. Raw HxWx3 uint8 RGB array (e.g. from Pillow / imageio)
131
+ rgb_array = np.zeros((720, 1280, 3), dtype=np.uint8)
132
+ height, width, _ = rgb_array.shape
133
+ stride = width * 3
134
+
135
+ res_rgb = (
136
+ engine.detect_text()
137
+ .rgb(rgb_array.tobytes(), width, height, stride)
138
+ .as_lines()
139
+ .run()
140
+ )
141
+ ```
142
+
143
+ ## 6-Phase Pipeline Options
144
+
145
+ Customize every phase of OCR execution per request:
146
+
147
+ ```python
148
+ from rusto import (
149
+ DetectionRunOptions,
150
+ OutputGranularity,
151
+ PostDetectionOptions,
152
+ PostRecognitionOptions,
153
+ PreDetectionOptions,
154
+ PreRecognitionOptions,
155
+ RecognitionRunOptions,
156
+ )
157
+
158
+ result = (
159
+ engine.detect_text("document.jpg")
160
+ .with_orientation_detection()
161
+ .with_auto_unwarp()
162
+ .with_layout_reading()
163
+ .with_pre_detection(PreDetectionOptions(descreen_strength=0.3, target_max_side=1280))
164
+ .with_detection(DetectionRunOptions(limit_side_len=960, limit_type="max"))
165
+ .with_post_detection(PostDetectionOptions(threshold=0.3, box_threshold=0.6, unclip_ratio=1.6))
166
+ .with_pre_recognition(PreRecognitionOptions(line_y_threshold=0.5, word_x_threshold=0.4))
167
+ .with_recognition(RecognitionRunOptions(batch_size=8))
168
+ .with_post_recognition(PostRecognitionOptions(score_threshold=0.5))
169
+ .with_output(OutputGranularity.LINES)
170
+ .run()
171
+ )
172
+ ```
173
+
174
+ ## Result Reference
175
+
176
+ `DetectTextResult` is a tagged union returned by `.run()`:
177
+
178
+ - `result.is_STRUCTURED()` -> `True` for `.as_lines()` and `.as_words()`. Access `result.results` (`list[TextResult]`):
179
+ - `item.text` (`str`): Recognized text string.
180
+ - `item.score` (`float`): Confidence score (`0.0` – `1.0`).
181
+ - `item.box_points` (`list[Point]`): 4 polygon vertices (`x`, `y`).
182
+ - `item.frame` (`Frame`): Axis-aligned bounding box (`width`, `height`, `top`, `left`).
183
+ - `item.region_id` (`int | None`): Layout region index when `with_layout_reading()` is active.
184
+ - `item.layout_type` (`LayoutType | None`): Semantic region category (`TEXT`, `TITLE`, `TABLE`, `HEADER`, `FOOTER`, `FIGURE`, etc.).
185
+ - `result.is_SPATIAL()` -> `True` for `.as_spatial()`. Access `result.text` (`str`).
186
+
187
+ ## License
188
+
189
+ Apache-2.0 OR MIT
rusto-0.4.0/README.md ADDED
@@ -0,0 +1,178 @@
1
+ # rusto (Python SDK)
2
+
3
+ Official Python bindings for **RustO!** — a high-performance, pure-Rust OCR engine powered by Indra OCR, PaddleOCR, and the pure-Rust MNN (`rusto-nn`) inference runtime via UniFFI.
4
+
5
+ ## Features
6
+
7
+ - **Zero-Config Indra OCR**: `RustO.initialize()` automatically downloads and caches the default `indraocr` models on first run from Hugging Face Hub.
8
+ - **Context Manager Support**: Deterministic native resource cleanup with `with RustO.initialize() as engine:` or `engine.close()`.
9
+ - **Full Document Pipeline**: Neural document unwarping (`with_auto_unwarp()`), page orientation detection (`with_orientation_detection()`), semantic layout analysis, and reading-order recovery (`with_layout_reading()`).
10
+ - **Fluent Builder API**: Chain `.as_lines()`, `.as_words()`, `.as_spatial()`, `.as_tsv()`, or `.with_output(...)` into a single `.run()` terminal method.
11
+ - **Zero-Copy Raw RGB Support**: Feed NumPy / OpenCV / Pillow RGB8 buffers directly via `.rgb(pixels, width, height, stride)`.
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ pip install rusto
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ```python
22
+ from rusto import RustO
23
+
24
+ # Zero-config initialization (auto-downloads Indra OCR models from Hugging Face Hub if not cached)
25
+ with RustO.initialize() as engine:
26
+ result = (
27
+ engine.detect_text("invoice.png")
28
+ .with_auto_unwarp()
29
+ .with_layout_reading()
30
+ .as_lines()
31
+ .run()
32
+ )
33
+
34
+ if result.is_STRUCTURED():
35
+ for item in result.results:
36
+ print(
37
+ f"[{item.score:.2f}] ({item.layout_type or 'line'} #{item.region_id}) {item.text}"
38
+ )
39
+
40
+ # Reconstructed 2D spatial text layout
41
+ spatial = engine.detect_text("invoice.png").as_spatial().run()
42
+ if spatial.is_SPATIAL():
43
+ print(spatial.text)
44
+ ```
45
+
46
+ You can also manage the engine lifecycle explicitly without a `with` block:
47
+
48
+ ```python
49
+ from rusto import InitializeConfig, RustO
50
+
51
+ engine = RustO.initialize(InitializeConfig.indra())
52
+ try:
53
+ result = engine.detect_text("invoice.png").as_words().run()
54
+ if result.is_STRUCTURED():
55
+ for word in result.results:
56
+ print(word.text, word.frame)
57
+ finally:
58
+ engine.close()
59
+ ```
60
+
61
+ ## Custom Configuration & Offline Models (.mnn / .rten)
62
+
63
+ Select canonical model tiers (`"indraocr"`, `"ppocrv6-tiny"`, `"ppocrv6-small"`, `"ppocrv5-mobile"`, `"ppocrv4-mobile"`), languages, or local model paths:
64
+
65
+ ```python
66
+ from rusto import (
67
+ DetectionConfig,
68
+ InitializeConfig,
69
+ LayoutConfig,
70
+ RecognitionConfig,
71
+ RustO,
72
+ UnwarpConfig,
73
+ )
74
+
75
+ # Preset by canonical model + language (auto-downloaded to cache)
76
+ cfg = InitializeConfig.for_model("ppocrv6-tiny", lang="latin")
77
+ engine = RustO.initialize(cfg)
78
+ engine.close()
79
+
80
+ # Explicit local assets for offline environments
81
+ offline_cfg = InitializeConfig(
82
+ template="indra",
83
+ enable_reading_order=True,
84
+ detection=DetectionConfig(enabled=True, model_path="./models/indra_det.mnn"),
85
+ recognition=RecognitionConfig(
86
+ enabled=True,
87
+ model_path="./models/indra_rec.mnn",
88
+ dict_path="./models/indra_meta.json",
89
+ ),
90
+ unwarp=UnwarpConfig(enabled=True, model_path="./models/uvdoc.mnn"),
91
+ layout=LayoutConfig(enabled=True, model_path="./models/layout_cdla.mnn"),
92
+ )
93
+ with RustO.initialize(offline_cfg) as offline_engine:
94
+ res = offline_engine.detect_text("scan.png").with_auto_unwarp().as_lines().run()
95
+ ```
96
+
97
+ Pre-download models into a target cache directory ahead of time (e.g., during Docker image build):
98
+
99
+ ```python
100
+ from rusto import download_model
101
+
102
+ paths = download_model(model="indraocr", lang="latin", cache_dir="./models-cache")
103
+ ```
104
+
105
+ ## Input Sources & Raw RGB Buffers
106
+
107
+ Pass a file path (`str` or `Path`), encoded image `bytes`, `ImageSource`, or raw interleaved 24-bit RGB pixels:
108
+
109
+ ```python
110
+ from pathlib import Path
111
+ import numpy as np
112
+ from rusto import RustO
113
+
114
+ with RustO.initialize() as engine:
115
+ # 1. Encoded PNG/JPEG bytes
116
+ png_bytes = Path("invoice.png").read_bytes()
117
+ res_bytes = engine.detect_text(png_bytes).as_lines().run()
118
+
119
+ # 2. Raw HxWx3 uint8 RGB array (e.g. from Pillow / imageio)
120
+ rgb_array = np.zeros((720, 1280, 3), dtype=np.uint8)
121
+ height, width, _ = rgb_array.shape
122
+ stride = width * 3
123
+
124
+ res_rgb = (
125
+ engine.detect_text()
126
+ .rgb(rgb_array.tobytes(), width, height, stride)
127
+ .as_lines()
128
+ .run()
129
+ )
130
+ ```
131
+
132
+ ## 6-Phase Pipeline Options
133
+
134
+ Customize every phase of OCR execution per request:
135
+
136
+ ```python
137
+ from rusto import (
138
+ DetectionRunOptions,
139
+ OutputGranularity,
140
+ PostDetectionOptions,
141
+ PostRecognitionOptions,
142
+ PreDetectionOptions,
143
+ PreRecognitionOptions,
144
+ RecognitionRunOptions,
145
+ )
146
+
147
+ result = (
148
+ engine.detect_text("document.jpg")
149
+ .with_orientation_detection()
150
+ .with_auto_unwarp()
151
+ .with_layout_reading()
152
+ .with_pre_detection(PreDetectionOptions(descreen_strength=0.3, target_max_side=1280))
153
+ .with_detection(DetectionRunOptions(limit_side_len=960, limit_type="max"))
154
+ .with_post_detection(PostDetectionOptions(threshold=0.3, box_threshold=0.6, unclip_ratio=1.6))
155
+ .with_pre_recognition(PreRecognitionOptions(line_y_threshold=0.5, word_x_threshold=0.4))
156
+ .with_recognition(RecognitionRunOptions(batch_size=8))
157
+ .with_post_recognition(PostRecognitionOptions(score_threshold=0.5))
158
+ .with_output(OutputGranularity.LINES)
159
+ .run()
160
+ )
161
+ ```
162
+
163
+ ## Result Reference
164
+
165
+ `DetectTextResult` is a tagged union returned by `.run()`:
166
+
167
+ - `result.is_STRUCTURED()` -> `True` for `.as_lines()` and `.as_words()`. Access `result.results` (`list[TextResult]`):
168
+ - `item.text` (`str`): Recognized text string.
169
+ - `item.score` (`float`): Confidence score (`0.0` – `1.0`).
170
+ - `item.box_points` (`list[Point]`): 4 polygon vertices (`x`, `y`).
171
+ - `item.frame` (`Frame`): Axis-aligned bounding box (`width`, `height`, `top`, `left`).
172
+ - `item.region_id` (`int | None`): Layout region index when `with_layout_reading()` is active.
173
+ - `item.layout_type` (`LayoutType | None`): Semantic region category (`TEXT`, `TITLE`, `TABLE`, `HEADER`, `FOOTER`, `FIGURE`, etc.).
174
+ - `result.is_SPATIAL()` -> `True` for `.as_spatial()`. Access `result.text` (`str`).
175
+
176
+ ## License
177
+
178
+ Apache-2.0 OR MIT
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "rusto"
7
- version = "0.3.2"
8
- description = "Pure Rust OCR library for Python based on RapidOCR and PaddleOCR"
7
+ version = "0.4.0"
8
+ description = "Pure Rust OCR library for Python based on RapidOCR, Indra OCR, and pure-Rust MNN (rusto-nn)"
9
9
  readme = "README.md"
10
10
  authors = [{ name = "RustO Contributors", email = "contact@rusto.dev" }]
11
11
  license = "MIT"