mathcraft-ocr 0.2.8__tar.gz → 0.2.9__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.
Potentially problematic release.
This version of mathcraft-ocr might be problematic. Click here for more details.
- {mathcraft_ocr-0.2.8/mathcraft_ocr.egg-info → mathcraft_ocr-0.2.9}/PKG-INFO +59 -12
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/README_MATHCRAFT_OCR.md +47 -4
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/__init__.py +7 -1
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/adapters/common.py +33 -12
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/adapters/text_recognizer.py +12 -60
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/cli.py +7 -4
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/doctor.py +4 -2
- mathcraft_ocr-0.2.9/mathcraft_ocr/providers.py +279 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/runtime.py +5 -1
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/serialization.py +4 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/worker.py +4 -1
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9/mathcraft_ocr.egg-info}/PKG-INFO +59 -12
- mathcraft_ocr-0.2.9/mathcraft_ocr.egg-info/requires.txt +33 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/pyproject.toml +15 -8
- mathcraft_ocr-0.2.8/mathcraft_ocr/providers.py +0 -128
- mathcraft_ocr-0.2.8/mathcraft_ocr.egg-info/requires.txt +0 -30
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/LICENSE +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/MANIFEST.in +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/__main__.py +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/adapters/__init__.py +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/adapters/formula_detector.py +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/adapters/formula_recognizer.py +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/adapters/text_detector.py +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/api.py +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/cache.py +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/debug_blocks.py +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/devices.py +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/downloader.py +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/error_patterns.py +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/errors.py +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/formula_lines.py +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/hardware.py +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/image.py +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/latex_alignment.py +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/latex_quality.py +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/layout.py +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/manifest.py +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/manifests/models.v1.json +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/profiles.py +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr/results.py +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr.egg-info/SOURCES.txt +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr.egg-info/dependency_links.txt +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr.egg-info/entry_points.txt +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/mathcraft_ocr.egg-info/top_level.txt +0 -0
- {mathcraft_ocr-0.2.8 → mathcraft_ocr-0.2.9}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mathcraft-ocr
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.9
|
|
4
4
|
Summary: ONNX-only OCR runtime for mathematical documents
|
|
5
5
|
Author: SakuraMathcraft
|
|
6
6
|
License-Expression: GPL-3.0-only
|
|
@@ -21,21 +21,25 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.13
|
|
22
22
|
Classifier: Topic :: Scientific/Engineering :: Image Recognition
|
|
23
23
|
Classifier: Topic :: Text Processing
|
|
24
|
-
Requires-Python:
|
|
24
|
+
Requires-Python: <3.14,>=3.10
|
|
25
25
|
Description-Content-Type: text/markdown
|
|
26
26
|
License-File: LICENSE
|
|
27
|
-
Requires-Dist: numpy<3,>=
|
|
28
|
-
Requires-Dist: pillow<12
|
|
27
|
+
Requires-Dist: numpy<3,>=2
|
|
28
|
+
Requires-Dist: pillow<13,>=12
|
|
29
29
|
Requires-Dist: opencv-python<5,>=4.10
|
|
30
30
|
Requires-Dist: rapidocr==3.5.0
|
|
31
31
|
Requires-Dist: transformers==4.55.4
|
|
32
32
|
Requires-Dist: tokenizers==0.21.4
|
|
33
33
|
Provides-Extra: cpu
|
|
34
|
-
Requires-Dist: onnxruntime<1.
|
|
35
|
-
Requires-Dist: onnxruntime<1.26,>=1.20; python_version >= "3.13" and extra == "cpu"
|
|
34
|
+
Requires-Dist: onnxruntime<1.30,>=1.20; extra == "cpu"
|
|
36
35
|
Provides-Extra: gpu
|
|
37
|
-
Requires-Dist: onnxruntime-gpu<1.
|
|
38
|
-
|
|
36
|
+
Requires-Dist: onnxruntime-gpu<1.30,>=1.27; extra == "gpu"
|
|
37
|
+
Provides-Extra: gpu-cu12
|
|
38
|
+
Requires-Dist: onnxruntime-gpu<1.27,>=1.21; extra == "gpu-cu12"
|
|
39
|
+
Provides-Extra: directml
|
|
40
|
+
Requires-Dist: onnxruntime-directml<1.30,>=1.20; platform_system == "Windows" and extra == "directml"
|
|
41
|
+
Provides-Extra: openvino
|
|
42
|
+
Requires-Dist: onnxruntime-openvino<1.30,>=1.20; (platform_system == "Windows" or platform_system == "Linux") and extra == "openvino"
|
|
39
43
|
Provides-Extra: dev
|
|
40
44
|
Requires-Dist: ruff>=0.8; extra == "dev"
|
|
41
45
|
Requires-Dist: build>=1.2; extra == "dev"
|
|
@@ -76,9 +80,27 @@ GPU backend:
|
|
|
76
80
|
pip install "mathcraft-ocr[gpu]"
|
|
77
81
|
```
|
|
78
82
|
|
|
79
|
-
|
|
83
|
+
CUDA 12 backend:
|
|
80
84
|
|
|
81
|
-
|
|
85
|
+
```powershell
|
|
86
|
+
pip install "mathcraft-ocr[gpu-cu12]"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Windows DirectML backend:
|
|
90
|
+
|
|
91
|
+
```powershell
|
|
92
|
+
pip install "mathcraft-ocr[directml]"
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Intel OpenVINO backend on Windows or Linux:
|
|
96
|
+
|
|
97
|
+
```powershell
|
|
98
|
+
pip install "mathcraft-ocr[openvino]"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Install only one backend extra in a clean environment. The CPU, CUDA/TensorRT, DirectML, and OpenVINO ONNX Runtime distributions must not be mixed in the same environment. The standard `onnxruntime` macOS wheel includes CoreML EP support.
|
|
102
|
+
|
|
103
|
+
LaTeXSnipper's dependency wizard selects the ONNX Runtime GPU line from the detected CUDA toolkit: CUDA 11.x uses ONNX Runtime 1.20 from the official CUDA 11 feed, CUDA 12.x uses ONNX Runtime 1.21-1.26 from PyPI, and CUDA 13.x uses ONNX Runtime 1.27-1.29 from PyPI. The static `mathcraft-ocr[gpu]` extra follows the current PyPI default (CUDA 13 and Python 3.11+); use `gpu-cu12` for CUDA 12. CUDA 11 installations must also select the official CUDA 11 package feed, so LaTeXSnipper's dependency wizard is recommended for that configuration.
|
|
82
104
|
|
|
83
105
|
## Quick Start
|
|
84
106
|
|
|
@@ -190,9 +212,34 @@ Model artifacts are downloaded from the MathCraft-Models release assets declared
|
|
|
190
212
|
|
|
191
213
|
`provider_preference` accepts:
|
|
192
214
|
|
|
193
|
-
- `auto`: prefer CUDA
|
|
215
|
+
- `auto`: prefer CUDA, then a platform accelerator, and finally CPU; TensorRT remains explicit because of its first-use engine build cost.
|
|
194
216
|
- `cpu`: force CPU.
|
|
195
|
-
- `gpu`: request
|
|
217
|
+
- `gpu`: request the first available supported accelerator.
|
|
218
|
+
- `cuda`: request CUDA.
|
|
219
|
+
- `tensorrt` or `trt`: request TensorRT, followed by CUDA and CPU for unsupported nodes.
|
|
220
|
+
- `directml` or `dml`: request DirectML.
|
|
221
|
+
- `coreml`: request CoreML.
|
|
222
|
+
- `openvino`: request OpenVINO.
|
|
223
|
+
|
|
224
|
+
Advanced callers can pass an explicit ordered provider list and provider options:
|
|
225
|
+
|
|
226
|
+
```python
|
|
227
|
+
runtime = MathCraftRuntime(
|
|
228
|
+
providers=[
|
|
229
|
+
(
|
|
230
|
+
"TensorrtExecutionProvider",
|
|
231
|
+
{
|
|
232
|
+
"device_id": 0,
|
|
233
|
+
"trt_engine_cache_enable": True,
|
|
234
|
+
"trt_engine_cache_path": "./trt-cache",
|
|
235
|
+
},
|
|
236
|
+
),
|
|
237
|
+
("CUDAExecutionProvider", {"device_id": 0}),
|
|
238
|
+
]
|
|
239
|
+
)
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
`auto` deliberately prefers CUDA over TensorRT because TensorRT can spend substantial time building an engine on first use. Select `tensorrt` explicitly when its native runtime is installed; enable its engine cache for repeated startup performance.
|
|
196
243
|
|
|
197
244
|
The actual provider is available on recognition results through the `provider` field. Doctor and warmup reports also expose `device_id`, `device_name`, `device_uuid`, and `device_verified` under `provider_info`. GPU sessions bind the reported `device_id` explicitly; `device_verified` becomes true only after the runtime confirms the device used by initialized inference sessions.
|
|
198
245
|
|
|
@@ -30,9 +30,27 @@ GPU backend:
|
|
|
30
30
|
pip install "mathcraft-ocr[gpu]"
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
CUDA 12 backend:
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
```powershell
|
|
36
|
+
pip install "mathcraft-ocr[gpu-cu12]"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Windows DirectML backend:
|
|
40
|
+
|
|
41
|
+
```powershell
|
|
42
|
+
pip install "mathcraft-ocr[directml]"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Intel OpenVINO backend on Windows or Linux:
|
|
46
|
+
|
|
47
|
+
```powershell
|
|
48
|
+
pip install "mathcraft-ocr[openvino]"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Install only one backend extra in a clean environment. The CPU, CUDA/TensorRT, DirectML, and OpenVINO ONNX Runtime distributions must not be mixed in the same environment. The standard `onnxruntime` macOS wheel includes CoreML EP support.
|
|
52
|
+
|
|
53
|
+
LaTeXSnipper's dependency wizard selects the ONNX Runtime GPU line from the detected CUDA toolkit: CUDA 11.x uses ONNX Runtime 1.20 from the official CUDA 11 feed, CUDA 12.x uses ONNX Runtime 1.21-1.26 from PyPI, and CUDA 13.x uses ONNX Runtime 1.27-1.29 from PyPI. The static `mathcraft-ocr[gpu]` extra follows the current PyPI default (CUDA 13 and Python 3.11+); use `gpu-cu12` for CUDA 12. CUDA 11 installations must also select the official CUDA 11 package feed, so LaTeXSnipper's dependency wizard is recommended for that configuration.
|
|
36
54
|
|
|
37
55
|
## Quick Start
|
|
38
56
|
|
|
@@ -144,9 +162,34 @@ Model artifacts are downloaded from the MathCraft-Models release assets declared
|
|
|
144
162
|
|
|
145
163
|
`provider_preference` accepts:
|
|
146
164
|
|
|
147
|
-
- `auto`: prefer CUDA
|
|
165
|
+
- `auto`: prefer CUDA, then a platform accelerator, and finally CPU; TensorRT remains explicit because of its first-use engine build cost.
|
|
148
166
|
- `cpu`: force CPU.
|
|
149
|
-
- `gpu`: request
|
|
167
|
+
- `gpu`: request the first available supported accelerator.
|
|
168
|
+
- `cuda`: request CUDA.
|
|
169
|
+
- `tensorrt` or `trt`: request TensorRT, followed by CUDA and CPU for unsupported nodes.
|
|
170
|
+
- `directml` or `dml`: request DirectML.
|
|
171
|
+
- `coreml`: request CoreML.
|
|
172
|
+
- `openvino`: request OpenVINO.
|
|
173
|
+
|
|
174
|
+
Advanced callers can pass an explicit ordered provider list and provider options:
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
runtime = MathCraftRuntime(
|
|
178
|
+
providers=[
|
|
179
|
+
(
|
|
180
|
+
"TensorrtExecutionProvider",
|
|
181
|
+
{
|
|
182
|
+
"device_id": 0,
|
|
183
|
+
"trt_engine_cache_enable": True,
|
|
184
|
+
"trt_engine_cache_path": "./trt-cache",
|
|
185
|
+
},
|
|
186
|
+
),
|
|
187
|
+
("CUDAExecutionProvider", {"device_id": 0}),
|
|
188
|
+
]
|
|
189
|
+
)
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
`auto` deliberately prefers CUDA over TensorRT because TensorRT can spend substantial time building an engine on first use. Select `tensorrt` explicitly when its native runtime is installed; enable its engine cache for repeated startup performance.
|
|
150
193
|
|
|
151
194
|
The actual provider is available on recognition results through the `provider` field. Doctor and warmup reports also expose `device_id`, `device_name`, `device_uuid`, and `device_verified` under `provider_info`. GPU sessions bind the reported `device_id` explicitly; `device_verified` becomes true only after the runtime confirms the device used by initialized inference sessions.
|
|
152
195
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
__version__ = "0.2.
|
|
5
|
+
__version__ = "0.2.9"
|
|
6
6
|
|
|
7
7
|
__all__ = [
|
|
8
8
|
"DoctorReport",
|
|
@@ -12,6 +12,8 @@ __all__ = [
|
|
|
12
12
|
"MathCraftRuntime",
|
|
13
13
|
"MixedRecognitionResult",
|
|
14
14
|
"OCRRegion",
|
|
15
|
+
"ProviderInfo",
|
|
16
|
+
"ProviderSpec",
|
|
15
17
|
"__version__",
|
|
16
18
|
"run_doctor",
|
|
17
19
|
]
|
|
@@ -32,6 +34,10 @@ def __getattr__(name: str) -> object:
|
|
|
32
34
|
from . import doctor
|
|
33
35
|
|
|
34
36
|
return getattr(doctor, name)
|
|
37
|
+
if name in {"ProviderInfo", "ProviderSpec"}:
|
|
38
|
+
from . import providers
|
|
39
|
+
|
|
40
|
+
return getattr(providers, name)
|
|
35
41
|
if name == "MathCraftError":
|
|
36
42
|
from .errors import MathCraftError
|
|
37
43
|
|
|
@@ -6,7 +6,7 @@ import importlib
|
|
|
6
6
|
from functools import lru_cache
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
|
-
from ..providers import
|
|
9
|
+
from ..providers import ACCELERATOR_PROVIDER_NAMES, ProviderInfo
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
ProviderOptions = tuple[tuple[str, str], ...]
|
|
@@ -17,12 +17,14 @@ def _ort():
|
|
|
17
17
|
return importlib.import_module("onnxruntime")
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
def session_providers(provider_info: ProviderInfo) -> list[str | tuple[str, dict[str,
|
|
20
|
+
def session_providers(provider_info: ProviderInfo) -> list[str | tuple[str, dict[str, object]]]:
|
|
21
|
+
if provider_info.provider_specs:
|
|
22
|
+
return [spec.as_ort_provider() for spec in provider_info.provider_specs]
|
|
21
23
|
available = list(provider_info.available_providers)
|
|
22
24
|
active = provider_info.active_provider
|
|
23
|
-
if active and active in
|
|
25
|
+
if active and active in ACCELERATOR_PROVIDER_NAMES and "CPUExecutionProvider" in available:
|
|
24
26
|
return [(active, {"device_id": int(provider_info.device_id or 0)}), "CPUExecutionProvider"]
|
|
25
|
-
if active and active in
|
|
27
|
+
if active and active in ACCELERATOR_PROVIDER_NAMES:
|
|
26
28
|
return [(active, {"device_id": int(provider_info.device_id or 0)})]
|
|
27
29
|
if "CPUExecutionProvider" in available:
|
|
28
30
|
return ["CPUExecutionProvider"]
|
|
@@ -44,15 +46,34 @@ def _create_session_cached(model_path: str, providers: tuple[ProviderConfig, ...
|
|
|
44
46
|
(name, {key: value for key, value in options}) if options else name
|
|
45
47
|
for name, options in providers
|
|
46
48
|
]
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
)
|
|
49
|
+
kwargs = {
|
|
50
|
+
"providers": configured,
|
|
51
|
+
"enable_fallback": False,
|
|
52
|
+
}
|
|
53
|
+
session_options = _session_options(ort, providers)
|
|
54
|
+
if session_options is not None:
|
|
55
|
+
kwargs["sess_options"] = session_options
|
|
56
|
+
return ort.InferenceSession(model_path, **kwargs)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _session_options(ort, providers: tuple[ProviderConfig, ...]):
|
|
60
|
+
create_options = getattr(ort, "SessionOptions", None)
|
|
61
|
+
if not callable(create_options):
|
|
62
|
+
return None
|
|
63
|
+
session_options = create_options()
|
|
64
|
+
session_options.log_severity_level = 4
|
|
65
|
+
names = {name for name, _options in providers}
|
|
66
|
+
if "DmlExecutionProvider" not in names:
|
|
67
|
+
return session_options
|
|
68
|
+
session_options.enable_mem_pattern = False
|
|
69
|
+
execution_mode = getattr(getattr(ort, "ExecutionMode", None), "ORT_SEQUENTIAL", None)
|
|
70
|
+
if execution_mode is not None:
|
|
71
|
+
session_options.execution_mode = execution_mode
|
|
72
|
+
return session_options
|
|
52
73
|
|
|
53
74
|
|
|
54
75
|
def _freeze_provider_config(
|
|
55
|
-
providers: list[str | tuple[str, dict[str,
|
|
76
|
+
providers: list[str | tuple[str, dict[str, object]]],
|
|
56
77
|
) -> tuple[ProviderConfig, ...]:
|
|
57
78
|
frozen: list[ProviderConfig] = []
|
|
58
79
|
for item in providers:
|
|
@@ -82,12 +103,12 @@ def validate_session_provider(
|
|
|
82
103
|
actual = list(session.get_providers() or [])
|
|
83
104
|
active = str(active_provider or "")
|
|
84
105
|
if not actual or actual[0] != active:
|
|
85
|
-
provider_kind = "ONNX
|
|
106
|
+
provider_kind = "ONNX accelerator provider" if active in ACCELERATOR_PROVIDER_NAMES else "ONNX provider"
|
|
86
107
|
raise RuntimeError(
|
|
87
108
|
f"requested {provider_kind} {active or '<none>'}, "
|
|
88
109
|
f"but {runtime_name} session providers are {actual}"
|
|
89
110
|
)
|
|
90
|
-
if active in
|
|
111
|
+
if active in {"CUDAExecutionProvider", "TensorrtExecutionProvider", "DmlExecutionProvider"}:
|
|
91
112
|
get_options = getattr(session, "get_provider_options", None)
|
|
92
113
|
if callable(get_options):
|
|
93
114
|
options_by_provider = get_options() or {}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import logging
|
|
5
6
|
from functools import lru_cache
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
|
|
@@ -10,7 +11,11 @@ from rapidocr import EngineType, LangRec, ModelType, OCRVersion
|
|
|
10
11
|
from rapidocr.ch_ppocr_rec import TextRecInput, TextRecognizer
|
|
11
12
|
from rapidocr.utils.typings import TaskType
|
|
12
13
|
|
|
13
|
-
from .common import
|
|
14
|
+
from .common import create_session
|
|
15
|
+
from ..providers import ProviderInfo
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
logging.getLogger("RapidOCR").setLevel(logging.WARNING)
|
|
14
19
|
|
|
15
20
|
|
|
16
21
|
class _Config(dict):
|
|
@@ -56,26 +61,13 @@ def recognize_pp_text_lines(
|
|
|
56
61
|
|
|
57
62
|
def _create_pp_text_recognizer(model_dir: Path, provider_info) -> TextRecognizer:
|
|
58
63
|
model_dir = model_dir.resolve()
|
|
59
|
-
|
|
60
|
-
device_id = int(getattr(provider_info, "device_id", 0) or 0)
|
|
61
|
-
use_cuda = active_provider in {"CUDAExecutionProvider", "TensorrtExecutionProvider"}
|
|
62
|
-
use_dml = active_provider == "DmlExecutionProvider"
|
|
63
|
-
return _create_pp_text_recognizer_cached(
|
|
64
|
-
str(model_dir),
|
|
65
|
-
active_provider,
|
|
66
|
-
device_id,
|
|
67
|
-
use_cuda,
|
|
68
|
-
use_dml,
|
|
69
|
-
)
|
|
64
|
+
return _create_pp_text_recognizer_cached(str(model_dir), provider_info)
|
|
70
65
|
|
|
71
66
|
|
|
72
67
|
@lru_cache(maxsize=8)
|
|
73
68
|
def _create_pp_text_recognizer_cached(
|
|
74
69
|
model_dir: str,
|
|
75
|
-
|
|
76
|
-
device_id: int,
|
|
77
|
-
use_cuda: bool,
|
|
78
|
-
use_dml: bool,
|
|
70
|
+
provider_info: ProviderInfo,
|
|
79
71
|
) -> TextRecognizer:
|
|
80
72
|
model_dir = Path(model_dir)
|
|
81
73
|
model_candidates = sorted(model_dir.glob("**/*rec*.onnx"))
|
|
@@ -89,6 +81,7 @@ def _create_pp_text_recognizer_cached(
|
|
|
89
81
|
is_server = "server" in model_name or "server" in model_dir.name
|
|
90
82
|
is_v5 = "v5" in model_name or "v5" in model_dir.name
|
|
91
83
|
is_english = dict_path.name == "en_dict.txt"
|
|
84
|
+
session = create_session(model_path, provider_info)
|
|
92
85
|
config = _Config({
|
|
93
86
|
"engine_type": EngineType.ONNXRUNTIME,
|
|
94
87
|
"lang_type": LangRec.EN if is_english else LangRec.CH,
|
|
@@ -101,51 +94,10 @@ def _create_pp_text_recognizer_cached(
|
|
|
101
94
|
"rec_img_shape": [3, 48, 320],
|
|
102
95
|
"rec_batch_num": 6,
|
|
103
96
|
"font_path": None,
|
|
104
|
-
"
|
|
105
|
-
|
|
106
|
-
"inter_op_num_threads": -1,
|
|
107
|
-
"enable_cpu_mem_arena": False,
|
|
108
|
-
"cpu_ep_cfg": {"arena_extend_strategy": "kSameAsRequested"},
|
|
109
|
-
"use_cuda": use_cuda,
|
|
110
|
-
"cuda_ep_cfg": {
|
|
111
|
-
"device_id": device_id,
|
|
112
|
-
"arena_extend_strategy": "kNextPowerOfTwo",
|
|
113
|
-
"cudnn_conv_algo_search": "EXHAUSTIVE",
|
|
114
|
-
"do_copy_in_default_stream": True,
|
|
115
|
-
},
|
|
116
|
-
"use_dml": use_dml,
|
|
117
|
-
"dm_ep_cfg": {"device_id": device_id},
|
|
118
|
-
"use_cann": False,
|
|
119
|
-
"cann_ep_cfg": {
|
|
120
|
-
"device_id": 0,
|
|
121
|
-
"arena_extend_strategy": "kNextPowerOfTwo",
|
|
122
|
-
"npu_mem_limit": 21474836480,
|
|
123
|
-
"op_select_impl_mode": "high_performance",
|
|
124
|
-
"optypelist_for_implmode": "Gelu",
|
|
125
|
-
"enable_cann_graph": True,
|
|
126
|
-
},
|
|
127
|
-
},
|
|
97
|
+
"session": session,
|
|
98
|
+
"engine_cfg": {},
|
|
128
99
|
})
|
|
129
|
-
|
|
130
|
-
_enforce_strict_provider(recognizer, active_provider, device_id)
|
|
131
|
-
return recognizer
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
def _enforce_strict_provider(
|
|
135
|
-
recognizer: TextRecognizer,
|
|
136
|
-
active_provider: str,
|
|
137
|
-
device_id: int = 0,
|
|
138
|
-
) -> None:
|
|
139
|
-
engine = getattr(recognizer, "session", None)
|
|
140
|
-
session = getattr(engine, "session", None)
|
|
141
|
-
if session is None:
|
|
142
|
-
raise RuntimeError("RapidOCR did not expose its ONNX Runtime session")
|
|
143
|
-
validate_session_provider(
|
|
144
|
-
session,
|
|
145
|
-
active_provider,
|
|
146
|
-
device_id,
|
|
147
|
-
runtime_name="RapidOCR",
|
|
148
|
-
)
|
|
100
|
+
return TextRecognizer(config)
|
|
149
101
|
|
|
150
102
|
|
|
151
103
|
def clear_text_recognizer_cache() -> None:
|
|
@@ -16,6 +16,9 @@ from .serialization import (
|
|
|
16
16
|
)
|
|
17
17
|
|
|
18
18
|
|
|
19
|
+
_PROVIDER_HELP = "auto, cpu, gpu, cuda, tensorrt, directml, coreml, or openvino"
|
|
20
|
+
|
|
21
|
+
|
|
19
22
|
def _resolve_ocr_output_path(args: argparse.Namespace) -> Path | None:
|
|
20
23
|
output = str(getattr(args, "output", "") or "").strip()
|
|
21
24
|
output_dir = str(getattr(args, "output_dir", "") or "").strip()
|
|
@@ -45,22 +48,22 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
45
48
|
models_sub.add_parser("check")
|
|
46
49
|
|
|
47
50
|
doctor = sub.add_parser("doctor")
|
|
48
|
-
doctor.add_argument("--provider", default="auto")
|
|
51
|
+
doctor.add_argument("--provider", default="auto", help=_PROVIDER_HELP)
|
|
49
52
|
|
|
50
53
|
warmup = sub.add_parser("warmup")
|
|
51
54
|
warmup.add_argument("--profile", default="formula")
|
|
52
|
-
warmup.add_argument("--provider", default="auto")
|
|
55
|
+
warmup.add_argument("--provider", default="auto", help=_PROVIDER_HELP)
|
|
53
56
|
|
|
54
57
|
ocr = sub.add_parser("ocr")
|
|
55
58
|
ocr.add_argument("image")
|
|
56
59
|
ocr.add_argument("--profile", choices=("formula", "text", "mixed"), default="mixed")
|
|
57
|
-
ocr.add_argument("--provider", default="auto")
|
|
60
|
+
ocr.add_argument("--provider", default="auto", help=_PROVIDER_HELP)
|
|
58
61
|
ocr.add_argument("--output", "-o", default="")
|
|
59
62
|
ocr.add_argument("--output-dir", default="")
|
|
60
63
|
ocr.add_argument("--json", action="store_true", dest="as_json")
|
|
61
64
|
|
|
62
65
|
worker = sub.add_parser("worker")
|
|
63
|
-
worker.add_argument("--provider", default="auto")
|
|
66
|
+
worker.add_argument("--provider", default="auto", help=_PROVIDER_HELP)
|
|
64
67
|
return parser
|
|
65
68
|
|
|
66
69
|
|
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import sys
|
|
6
|
+
from collections.abc import Sequence
|
|
6
7
|
from dataclasses import dataclass
|
|
7
8
|
from pathlib import Path
|
|
8
9
|
|
|
9
10
|
from .cache import inspect_manifest_roots, resolve_model_roots, resolve_user_models_dir
|
|
10
11
|
from .manifest import Manifest, load_manifest
|
|
11
|
-
from .providers import ProviderInfo, detect_providers
|
|
12
|
+
from .providers import ProviderInfo, ProviderRequest, detect_providers
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
@dataclass(frozen=True)
|
|
@@ -28,6 +29,7 @@ def run_doctor(
|
|
|
28
29
|
bundled_models_dir: str | Path | None = None,
|
|
29
30
|
manifest: Manifest | None = None,
|
|
30
31
|
provider_preference: str = "auto",
|
|
32
|
+
providers: Sequence[ProviderRequest] | None = None,
|
|
31
33
|
include_optional: bool = True,
|
|
32
34
|
) -> DoctorReport:
|
|
33
35
|
manifest_obj = manifest or load_manifest()
|
|
@@ -36,7 +38,7 @@ def run_doctor(
|
|
|
36
38
|
states = inspect_manifest_roots(
|
|
37
39
|
model_roots, manifest_obj, include_optional=include_optional
|
|
38
40
|
)
|
|
39
|
-
provider_info = detect_providers(prefer=provider_preference)
|
|
41
|
+
provider_info = detect_providers(prefer=provider_preference, providers=providers)
|
|
40
42
|
return DoctorReport(
|
|
41
43
|
python_executable=sys.executable,
|
|
42
44
|
cache_dir=cache_root,
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import importlib
|
|
6
|
+
from collections.abc import Mapping, Sequence
|
|
7
|
+
from dataclasses import dataclass, replace
|
|
8
|
+
|
|
9
|
+
from .devices import confirm_device_identity, resolve_device_identity
|
|
10
|
+
from .errors import ProviderError
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
MAIN_PROVIDER_NAMES = (
|
|
14
|
+
"CPUExecutionProvider",
|
|
15
|
+
"CUDAExecutionProvider",
|
|
16
|
+
"TensorrtExecutionProvider",
|
|
17
|
+
"DmlExecutionProvider",
|
|
18
|
+
"CoreMLExecutionProvider",
|
|
19
|
+
"OpenVINOExecutionProvider",
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
ACCELERATOR_PROVIDER_NAMES = tuple(
|
|
23
|
+
name for name in MAIN_PROVIDER_NAMES if name != "CPUExecutionProvider"
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
# Kept as a compatibility alias for integrations importing the old name.
|
|
27
|
+
GPU_PROVIDER_NAMES = ACCELERATOR_PROVIDER_NAMES
|
|
28
|
+
|
|
29
|
+
_PROVIDER_ALIASES = {
|
|
30
|
+
"cpu": "CPUExecutionProvider",
|
|
31
|
+
"cuda": "CUDAExecutionProvider",
|
|
32
|
+
"tensorrt": "TensorrtExecutionProvider",
|
|
33
|
+
"trt": "TensorrtExecutionProvider",
|
|
34
|
+
"directml": "DmlExecutionProvider",
|
|
35
|
+
"dml": "DmlExecutionProvider",
|
|
36
|
+
"coreml": "CoreMLExecutionProvider",
|
|
37
|
+
"openvino": "OpenVINOExecutionProvider",
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
_AUTO_PRIORITY = (
|
|
41
|
+
"CUDAExecutionProvider",
|
|
42
|
+
"DmlExecutionProvider",
|
|
43
|
+
"CoreMLExecutionProvider",
|
|
44
|
+
"OpenVINOExecutionProvider",
|
|
45
|
+
"CPUExecutionProvider",
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
_ACCELERATOR_PRIORITY = (
|
|
49
|
+
"CUDAExecutionProvider",
|
|
50
|
+
"TensorrtExecutionProvider",
|
|
51
|
+
"DmlExecutionProvider",
|
|
52
|
+
"CoreMLExecutionProvider",
|
|
53
|
+
"OpenVINOExecutionProvider",
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
ProviderRequest = str | tuple[str, Mapping[str, object]]
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@dataclass(frozen=True)
|
|
60
|
+
class ProviderSpec:
|
|
61
|
+
name: str
|
|
62
|
+
options: tuple[tuple[str, str], ...] = ()
|
|
63
|
+
|
|
64
|
+
def as_ort_provider(self) -> str | tuple[str, dict[str, str]]:
|
|
65
|
+
if not self.options:
|
|
66
|
+
return self.name
|
|
67
|
+
return self.name, dict(self.options)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@dataclass(frozen=True)
|
|
71
|
+
class ProviderInfo:
|
|
72
|
+
available_providers: tuple[str, ...]
|
|
73
|
+
active_provider: str | None
|
|
74
|
+
device: str
|
|
75
|
+
gpu_requested: bool
|
|
76
|
+
gpu_runtime_ok: bool
|
|
77
|
+
device_id: int | None = None
|
|
78
|
+
device_name: str = ""
|
|
79
|
+
device_uuid: str = ""
|
|
80
|
+
device_verified: bool = False
|
|
81
|
+
provider_specs: tuple[ProviderSpec, ...] = ()
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def use_cuda(self) -> bool:
|
|
85
|
+
return self.active_provider in {"CUDAExecutionProvider", "TensorrtExecutionProvider"}
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def use_dml(self) -> bool:
|
|
89
|
+
return self.active_provider == "DmlExecutionProvider"
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def use_tensorrt(self) -> bool:
|
|
93
|
+
return self.active_provider == "TensorrtExecutionProvider"
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def use_coreml(self) -> bool:
|
|
97
|
+
return self.active_provider == "CoreMLExecutionProvider"
|
|
98
|
+
|
|
99
|
+
@property
|
|
100
|
+
def use_openvino(self) -> bool:
|
|
101
|
+
return self.active_provider == "OpenVINOExecutionProvider"
|
|
102
|
+
|
|
103
|
+
@property
|
|
104
|
+
def requested_providers(self) -> tuple[str, ...]:
|
|
105
|
+
if self.provider_specs:
|
|
106
|
+
return tuple(spec.name for spec in self.provider_specs)
|
|
107
|
+
return (self.active_provider,) if self.active_provider else ()
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def detect_providers(
|
|
111
|
+
prefer: str = "auto",
|
|
112
|
+
providers: Sequence[ProviderRequest] | None = None,
|
|
113
|
+
) -> ProviderInfo:
|
|
114
|
+
prefer_norm = (prefer or "auto").strip().lower()
|
|
115
|
+
if providers is None and prefer_norm not in {"auto", "cpu", "gpu", *_PROVIDER_ALIASES}:
|
|
116
|
+
raise ProviderError(f"unsupported provider preference: {prefer}")
|
|
117
|
+
try:
|
|
118
|
+
ort = importlib.import_module("onnxruntime")
|
|
119
|
+
except Exception as exc: # pragma: no cover - import environment dependent
|
|
120
|
+
raise ProviderError(f"failed to import onnxruntime: {exc}") from exc
|
|
121
|
+
|
|
122
|
+
get_available_providers = getattr(ort, "get_available_providers", None)
|
|
123
|
+
if not callable(get_available_providers):
|
|
124
|
+
origin = getattr(ort, "__file__", None) or "<namespace package>"
|
|
125
|
+
raise ProviderError(
|
|
126
|
+
"onnxruntime dependency is incomplete: missing get_available_providers "
|
|
127
|
+
f"(origin={origin})"
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
try:
|
|
131
|
+
available = tuple(get_available_providers())
|
|
132
|
+
except Exception as exc: # pragma: no cover - runtime environment dependent
|
|
133
|
+
raise ProviderError(f"failed to query ONNX providers: {exc}") from exc
|
|
134
|
+
|
|
135
|
+
specs = _resolve_provider_specs(prefer_norm, providers, available)
|
|
136
|
+
active = specs[0].name
|
|
137
|
+
accelerated = active in ACCELERATOR_PROVIDER_NAMES
|
|
138
|
+
device = (
|
|
139
|
+
"gpu"
|
|
140
|
+
if active in {"CUDAExecutionProvider", "TensorrtExecutionProvider", "DmlExecutionProvider"}
|
|
141
|
+
else "accelerator"
|
|
142
|
+
if accelerated
|
|
143
|
+
else "cpu"
|
|
144
|
+
)
|
|
145
|
+
return _provider_info(
|
|
146
|
+
available_providers=available,
|
|
147
|
+
active_provider=active,
|
|
148
|
+
device=device,
|
|
149
|
+
gpu_requested=accelerated,
|
|
150
|
+
gpu_runtime_ok=accelerated,
|
|
151
|
+
provider_specs=specs,
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _resolve_provider_specs(
|
|
156
|
+
prefer: str,
|
|
157
|
+
providers: Sequence[ProviderRequest] | None,
|
|
158
|
+
available: tuple[str, ...],
|
|
159
|
+
) -> tuple[ProviderSpec, ...]:
|
|
160
|
+
if providers is not None:
|
|
161
|
+
if isinstance(providers, (str, bytes)) or not providers:
|
|
162
|
+
raise ProviderError("providers must be a non-empty sequence")
|
|
163
|
+
specs = tuple(_normalize_provider_request(item) for item in providers)
|
|
164
|
+
_ensure_available(specs, available)
|
|
165
|
+
return specs
|
|
166
|
+
|
|
167
|
+
if prefer == "auto":
|
|
168
|
+
active = next((name for name in _AUTO_PRIORITY if name in available), None)
|
|
169
|
+
if active is None:
|
|
170
|
+
raise ProviderError(f"no supported ONNX execution provider is available: {available}")
|
|
171
|
+
return _default_provider_chain(active, available)
|
|
172
|
+
|
|
173
|
+
if prefer == "gpu":
|
|
174
|
+
active = next((name for name in _ACCELERATOR_PRIORITY if name in available), None)
|
|
175
|
+
if active is None:
|
|
176
|
+
raise ProviderError(f"GPU provider was requested but none is available: {available}")
|
|
177
|
+
return _default_provider_chain(active, available)
|
|
178
|
+
|
|
179
|
+
active = _PROVIDER_ALIASES[prefer]
|
|
180
|
+
if active not in available:
|
|
181
|
+
raise ProviderError(f"requested ONNX provider {active} is unavailable: {available}")
|
|
182
|
+
return _default_provider_chain(active, available)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def _normalize_provider_request(request: ProviderRequest) -> ProviderSpec:
|
|
186
|
+
if isinstance(request, str):
|
|
187
|
+
raw_name = request
|
|
188
|
+
options: Mapping[str, object] = {}
|
|
189
|
+
elif isinstance(request, tuple) and len(request) == 2 and isinstance(request[1], Mapping):
|
|
190
|
+
raw_name, options = request
|
|
191
|
+
else:
|
|
192
|
+
raise ProviderError(f"invalid provider specification: {request!r}")
|
|
193
|
+
name = _canonical_provider_name(str(raw_name))
|
|
194
|
+
if name not in MAIN_PROVIDER_NAMES:
|
|
195
|
+
raise ProviderError(f"unsupported ONNX provider: {raw_name}")
|
|
196
|
+
frozen_options = tuple(sorted((str(key), str(value)) for key, value in options.items()))
|
|
197
|
+
return ProviderSpec(name=name, options=frozen_options)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def _canonical_provider_name(name: str) -> str:
|
|
201
|
+
stripped = name.strip()
|
|
202
|
+
return _PROVIDER_ALIASES.get(stripped.lower(), stripped)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def _ensure_available(specs: tuple[ProviderSpec, ...], available: tuple[str, ...]) -> None:
|
|
206
|
+
unavailable = tuple(spec.name for spec in specs if spec.name not in available)
|
|
207
|
+
if unavailable:
|
|
208
|
+
raise ProviderError(
|
|
209
|
+
f"requested ONNX providers are unavailable: {unavailable}; available={available}"
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def _default_provider_chain(active: str, available: tuple[str, ...]) -> tuple[ProviderSpec, ...]:
|
|
214
|
+
names = [active]
|
|
215
|
+
if active == "TensorrtExecutionProvider" and "CUDAExecutionProvider" in available:
|
|
216
|
+
names.append("CUDAExecutionProvider")
|
|
217
|
+
if active != "CPUExecutionProvider" and "CPUExecutionProvider" in available:
|
|
218
|
+
names.append("CPUExecutionProvider")
|
|
219
|
+
return tuple(ProviderSpec(name=name, options=_default_options(name)) for name in names)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def _default_options(name: str) -> tuple[tuple[str, str], ...]:
|
|
223
|
+
if name in {"CUDAExecutionProvider", "TensorrtExecutionProvider", "DmlExecutionProvider"}:
|
|
224
|
+
return (("device_id", "0"),)
|
|
225
|
+
return ()
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def _provider_info(
|
|
229
|
+
*,
|
|
230
|
+
available_providers: tuple[str, ...],
|
|
231
|
+
active_provider: str,
|
|
232
|
+
device: str,
|
|
233
|
+
gpu_requested: bool,
|
|
234
|
+
gpu_runtime_ok: bool,
|
|
235
|
+
provider_specs: tuple[ProviderSpec, ...] = (),
|
|
236
|
+
) -> ProviderInfo:
|
|
237
|
+
active_spec = next((spec for spec in provider_specs if spec.name == active_provider), None)
|
|
238
|
+
active_options = dict(active_spec.options) if active_spec else {}
|
|
239
|
+
device_id = (
|
|
240
|
+
int(active_options.get("device_id", 0))
|
|
241
|
+
if active_provider in {"CUDAExecutionProvider", "TensorrtExecutionProvider", "DmlExecutionProvider"}
|
|
242
|
+
else None
|
|
243
|
+
)
|
|
244
|
+
identity = resolve_device_identity(active_provider, device_id)
|
|
245
|
+
return ProviderInfo(
|
|
246
|
+
available_providers=available_providers,
|
|
247
|
+
active_provider=active_provider,
|
|
248
|
+
device=device,
|
|
249
|
+
gpu_requested=gpu_requested,
|
|
250
|
+
gpu_runtime_ok=gpu_runtime_ok,
|
|
251
|
+
device_id=identity.device_id,
|
|
252
|
+
device_name=identity.name,
|
|
253
|
+
device_uuid=identity.uuid,
|
|
254
|
+
device_verified=identity.verified,
|
|
255
|
+
provider_specs=provider_specs,
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def confirm_provider_device(provider_info: ProviderInfo) -> ProviderInfo:
|
|
260
|
+
identity = confirm_device_identity(provider_info.active_provider, provider_info.device_id)
|
|
261
|
+
return replace(
|
|
262
|
+
provider_info,
|
|
263
|
+
device_id=identity.device_id,
|
|
264
|
+
device_name=identity.name,
|
|
265
|
+
device_uuid=identity.uuid,
|
|
266
|
+
device_verified=identity.verified,
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
__all__ = [
|
|
271
|
+
"ACCELERATOR_PROVIDER_NAMES",
|
|
272
|
+
"GPU_PROVIDER_NAMES",
|
|
273
|
+
"MAIN_PROVIDER_NAMES",
|
|
274
|
+
"ProviderInfo",
|
|
275
|
+
"ProviderRequest",
|
|
276
|
+
"ProviderSpec",
|
|
277
|
+
"confirm_provider_device",
|
|
278
|
+
"detect_providers",
|
|
279
|
+
]
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
from collections.abc import Sequence
|
|
5
6
|
from dataclasses import dataclass
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
import sys
|
|
@@ -56,7 +57,7 @@ from .profiles import (
|
|
|
56
57
|
TEXT_DETECTOR_ID,
|
|
57
58
|
TEXT_RECOGNIZER_ID,
|
|
58
59
|
)
|
|
59
|
-
from .providers import ProviderInfo, confirm_provider_device
|
|
60
|
+
from .providers import ProviderInfo, ProviderRequest, confirm_provider_device
|
|
60
61
|
from .results import Box4P, FormulaRecognitionResult, MathCraftBlock, MixedRecognitionResult, OCRRegion
|
|
61
62
|
|
|
62
63
|
|
|
@@ -98,6 +99,7 @@ class MathCraftRuntime:
|
|
|
98
99
|
*,
|
|
99
100
|
cache_dir: str | Path | None = None,
|
|
100
101
|
provider_preference: str = "auto",
|
|
102
|
+
providers: Sequence[ProviderRequest] | None = None,
|
|
101
103
|
manifest: Manifest | None = None,
|
|
102
104
|
bundled_models_dir: str | Path | None = None,
|
|
103
105
|
auto_download: bool = True,
|
|
@@ -106,6 +108,7 @@ class MathCraftRuntime:
|
|
|
106
108
|
self.bundled_models_dir = Path(bundled_models_dir) if bundled_models_dir else None
|
|
107
109
|
self.model_roots = resolve_model_roots(cache_dir, bundled_models_dir)
|
|
108
110
|
self.provider_preference = provider_preference
|
|
111
|
+
self.providers = tuple(providers) if providers is not None else None
|
|
109
112
|
self.manifest = manifest or load_manifest()
|
|
110
113
|
self.auto_download = auto_download
|
|
111
114
|
self._warmup_cache: dict[str, WarmupPlan] = {}
|
|
@@ -131,6 +134,7 @@ class MathCraftRuntime:
|
|
|
131
134
|
bundled_models_dir=self.bundled_models_dir,
|
|
132
135
|
manifest=self.manifest,
|
|
133
136
|
provider_preference=self.provider_preference,
|
|
137
|
+
providers=self.providers,
|
|
134
138
|
)
|
|
135
139
|
|
|
136
140
|
def doctor(self) -> DoctorReport:
|
|
@@ -67,6 +67,7 @@ def mixed_result_to_json(result: MixedRecognitionResult) -> dict:
|
|
|
67
67
|
def provider_info_to_json(provider_info) -> dict:
|
|
68
68
|
return {
|
|
69
69
|
"available_providers": list(provider_info.available_providers),
|
|
70
|
+
"requested_providers": list(provider_info.requested_providers),
|
|
70
71
|
"active_provider": provider_info.active_provider,
|
|
71
72
|
"device": provider_info.device,
|
|
72
73
|
"device_id": provider_info.device_id,
|
|
@@ -77,6 +78,9 @@ def provider_info_to_json(provider_info) -> dict:
|
|
|
77
78
|
"gpu_runtime_ok": provider_info.gpu_runtime_ok,
|
|
78
79
|
"use_cuda": provider_info.use_cuda,
|
|
79
80
|
"use_dml": provider_info.use_dml,
|
|
81
|
+
"use_tensorrt": provider_info.use_tensorrt,
|
|
82
|
+
"use_coreml": provider_info.use_coreml,
|
|
83
|
+
"use_openvino": provider_info.use_openvino,
|
|
80
84
|
}
|
|
81
85
|
|
|
82
86
|
|
|
@@ -12,6 +12,9 @@ from .runtime import FORMULA_MAX_NEW_TOKENS, MathCraftRuntime
|
|
|
12
12
|
from .serialization import doctor_report_to_json, formula_result_to_json, mixed_result_to_json, warmup_plan_to_json
|
|
13
13
|
|
|
14
14
|
|
|
15
|
+
_PROVIDER_HELP = "auto, cpu, gpu, cuda, tensorrt, directml, coreml, or openvino"
|
|
16
|
+
|
|
17
|
+
|
|
15
18
|
class MathCraftWorker:
|
|
16
19
|
def __init__(
|
|
17
20
|
self,
|
|
@@ -113,7 +116,7 @@ def serve_jsonl(
|
|
|
113
116
|
|
|
114
117
|
def build_parser() -> argparse.ArgumentParser:
|
|
115
118
|
parser = argparse.ArgumentParser(prog="mathcraft-worker")
|
|
116
|
-
parser.add_argument("--provider", default="auto")
|
|
119
|
+
parser.add_argument("--provider", default="auto", help=_PROVIDER_HELP)
|
|
117
120
|
return parser
|
|
118
121
|
|
|
119
122
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mathcraft-ocr
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.9
|
|
4
4
|
Summary: ONNX-only OCR runtime for mathematical documents
|
|
5
5
|
Author: SakuraMathcraft
|
|
6
6
|
License-Expression: GPL-3.0-only
|
|
@@ -21,21 +21,25 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.13
|
|
22
22
|
Classifier: Topic :: Scientific/Engineering :: Image Recognition
|
|
23
23
|
Classifier: Topic :: Text Processing
|
|
24
|
-
Requires-Python:
|
|
24
|
+
Requires-Python: <3.14,>=3.10
|
|
25
25
|
Description-Content-Type: text/markdown
|
|
26
26
|
License-File: LICENSE
|
|
27
|
-
Requires-Dist: numpy<3,>=
|
|
28
|
-
Requires-Dist: pillow<12
|
|
27
|
+
Requires-Dist: numpy<3,>=2
|
|
28
|
+
Requires-Dist: pillow<13,>=12
|
|
29
29
|
Requires-Dist: opencv-python<5,>=4.10
|
|
30
30
|
Requires-Dist: rapidocr==3.5.0
|
|
31
31
|
Requires-Dist: transformers==4.55.4
|
|
32
32
|
Requires-Dist: tokenizers==0.21.4
|
|
33
33
|
Provides-Extra: cpu
|
|
34
|
-
Requires-Dist: onnxruntime<1.
|
|
35
|
-
Requires-Dist: onnxruntime<1.26,>=1.20; python_version >= "3.13" and extra == "cpu"
|
|
34
|
+
Requires-Dist: onnxruntime<1.30,>=1.20; extra == "cpu"
|
|
36
35
|
Provides-Extra: gpu
|
|
37
|
-
Requires-Dist: onnxruntime-gpu<1.
|
|
38
|
-
|
|
36
|
+
Requires-Dist: onnxruntime-gpu<1.30,>=1.27; extra == "gpu"
|
|
37
|
+
Provides-Extra: gpu-cu12
|
|
38
|
+
Requires-Dist: onnxruntime-gpu<1.27,>=1.21; extra == "gpu-cu12"
|
|
39
|
+
Provides-Extra: directml
|
|
40
|
+
Requires-Dist: onnxruntime-directml<1.30,>=1.20; platform_system == "Windows" and extra == "directml"
|
|
41
|
+
Provides-Extra: openvino
|
|
42
|
+
Requires-Dist: onnxruntime-openvino<1.30,>=1.20; (platform_system == "Windows" or platform_system == "Linux") and extra == "openvino"
|
|
39
43
|
Provides-Extra: dev
|
|
40
44
|
Requires-Dist: ruff>=0.8; extra == "dev"
|
|
41
45
|
Requires-Dist: build>=1.2; extra == "dev"
|
|
@@ -76,9 +80,27 @@ GPU backend:
|
|
|
76
80
|
pip install "mathcraft-ocr[gpu]"
|
|
77
81
|
```
|
|
78
82
|
|
|
79
|
-
|
|
83
|
+
CUDA 12 backend:
|
|
80
84
|
|
|
81
|
-
|
|
85
|
+
```powershell
|
|
86
|
+
pip install "mathcraft-ocr[gpu-cu12]"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Windows DirectML backend:
|
|
90
|
+
|
|
91
|
+
```powershell
|
|
92
|
+
pip install "mathcraft-ocr[directml]"
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Intel OpenVINO backend on Windows or Linux:
|
|
96
|
+
|
|
97
|
+
```powershell
|
|
98
|
+
pip install "mathcraft-ocr[openvino]"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Install only one backend extra in a clean environment. The CPU, CUDA/TensorRT, DirectML, and OpenVINO ONNX Runtime distributions must not be mixed in the same environment. The standard `onnxruntime` macOS wheel includes CoreML EP support.
|
|
102
|
+
|
|
103
|
+
LaTeXSnipper's dependency wizard selects the ONNX Runtime GPU line from the detected CUDA toolkit: CUDA 11.x uses ONNX Runtime 1.20 from the official CUDA 11 feed, CUDA 12.x uses ONNX Runtime 1.21-1.26 from PyPI, and CUDA 13.x uses ONNX Runtime 1.27-1.29 from PyPI. The static `mathcraft-ocr[gpu]` extra follows the current PyPI default (CUDA 13 and Python 3.11+); use `gpu-cu12` for CUDA 12. CUDA 11 installations must also select the official CUDA 11 package feed, so LaTeXSnipper's dependency wizard is recommended for that configuration.
|
|
82
104
|
|
|
83
105
|
## Quick Start
|
|
84
106
|
|
|
@@ -190,9 +212,34 @@ Model artifacts are downloaded from the MathCraft-Models release assets declared
|
|
|
190
212
|
|
|
191
213
|
`provider_preference` accepts:
|
|
192
214
|
|
|
193
|
-
- `auto`: prefer CUDA
|
|
215
|
+
- `auto`: prefer CUDA, then a platform accelerator, and finally CPU; TensorRT remains explicit because of its first-use engine build cost.
|
|
194
216
|
- `cpu`: force CPU.
|
|
195
|
-
- `gpu`: request
|
|
217
|
+
- `gpu`: request the first available supported accelerator.
|
|
218
|
+
- `cuda`: request CUDA.
|
|
219
|
+
- `tensorrt` or `trt`: request TensorRT, followed by CUDA and CPU for unsupported nodes.
|
|
220
|
+
- `directml` or `dml`: request DirectML.
|
|
221
|
+
- `coreml`: request CoreML.
|
|
222
|
+
- `openvino`: request OpenVINO.
|
|
223
|
+
|
|
224
|
+
Advanced callers can pass an explicit ordered provider list and provider options:
|
|
225
|
+
|
|
226
|
+
```python
|
|
227
|
+
runtime = MathCraftRuntime(
|
|
228
|
+
providers=[
|
|
229
|
+
(
|
|
230
|
+
"TensorrtExecutionProvider",
|
|
231
|
+
{
|
|
232
|
+
"device_id": 0,
|
|
233
|
+
"trt_engine_cache_enable": True,
|
|
234
|
+
"trt_engine_cache_path": "./trt-cache",
|
|
235
|
+
},
|
|
236
|
+
),
|
|
237
|
+
("CUDAExecutionProvider", {"device_id": 0}),
|
|
238
|
+
]
|
|
239
|
+
)
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
`auto` deliberately prefers CUDA over TensorRT because TensorRT can spend substantial time building an engine on first use. Select `tensorrt` explicitly when its native runtime is installed; enable its engine cache for repeated startup performance.
|
|
196
243
|
|
|
197
244
|
The actual provider is available on recognition results through the `provider` field. Doctor and warmup reports also expose `device_id`, `device_name`, `device_uuid`, and `device_verified` under `provider_info`. GPU sessions bind the reported `device_id` explicitly; `device_verified` becomes true only after the runtime confirms the device used by initialized inference sessions.
|
|
198
245
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
numpy<3,>=2
|
|
2
|
+
pillow<13,>=12
|
|
3
|
+
opencv-python<5,>=4.10
|
|
4
|
+
rapidocr==3.5.0
|
|
5
|
+
transformers==4.55.4
|
|
6
|
+
tokenizers==0.21.4
|
|
7
|
+
|
|
8
|
+
[cpu]
|
|
9
|
+
onnxruntime<1.30,>=1.20
|
|
10
|
+
|
|
11
|
+
[dev]
|
|
12
|
+
ruff>=0.8
|
|
13
|
+
build>=1.2
|
|
14
|
+
twine>=5.0
|
|
15
|
+
|
|
16
|
+
[directml]
|
|
17
|
+
|
|
18
|
+
[directml:platform_system == "Windows"]
|
|
19
|
+
onnxruntime-directml<1.30,>=1.20
|
|
20
|
+
|
|
21
|
+
[gpu]
|
|
22
|
+
onnxruntime-gpu<1.30,>=1.27
|
|
23
|
+
|
|
24
|
+
[gpu-cu12]
|
|
25
|
+
onnxruntime-gpu<1.27,>=1.21
|
|
26
|
+
|
|
27
|
+
[openvino]
|
|
28
|
+
|
|
29
|
+
[openvino:platform_system == "Windows" or platform_system == "Linux"]
|
|
30
|
+
onnxruntime-openvino<1.30,>=1.20
|
|
31
|
+
|
|
32
|
+
[pandoc]
|
|
33
|
+
pypandoc>=1.15
|
|
@@ -4,10 +4,10 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "mathcraft-ocr"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.9"
|
|
8
8
|
description = "ONNX-only OCR runtime for mathematical documents"
|
|
9
9
|
readme = "README_MATHCRAFT_OCR.md"
|
|
10
|
-
requires-python = ">=3.10"
|
|
10
|
+
requires-python = ">=3.10,<3.14"
|
|
11
11
|
license = "GPL-3.0-only"
|
|
12
12
|
license-files = ["LICENSE"]
|
|
13
13
|
authors = [
|
|
@@ -37,8 +37,8 @@ classifiers = [
|
|
|
37
37
|
"Topic :: Text Processing"
|
|
38
38
|
]
|
|
39
39
|
dependencies = [
|
|
40
|
-
"numpy>=
|
|
41
|
-
"pillow>=
|
|
40
|
+
"numpy>=2,<3",
|
|
41
|
+
"pillow>=12,<13",
|
|
42
42
|
"opencv-python>=4.10,<5",
|
|
43
43
|
"rapidocr==3.5.0",
|
|
44
44
|
"transformers==4.55.4",
|
|
@@ -47,12 +47,19 @@ dependencies = [
|
|
|
47
47
|
|
|
48
48
|
[project.optional-dependencies]
|
|
49
49
|
cpu = [
|
|
50
|
-
"onnxruntime>=1.
|
|
51
|
-
"onnxruntime>=1.20,<1.26; python_version >= '3.13'",
|
|
50
|
+
"onnxruntime>=1.20,<1.30",
|
|
52
51
|
]
|
|
53
52
|
gpu = [
|
|
54
|
-
"onnxruntime-gpu>=1.
|
|
55
|
-
|
|
53
|
+
"onnxruntime-gpu>=1.27,<1.30",
|
|
54
|
+
]
|
|
55
|
+
gpu-cu12 = [
|
|
56
|
+
"onnxruntime-gpu>=1.21,<1.27",
|
|
57
|
+
]
|
|
58
|
+
directml = [
|
|
59
|
+
"onnxruntime-directml>=1.20,<1.30; platform_system == 'Windows'",
|
|
60
|
+
]
|
|
61
|
+
openvino = [
|
|
62
|
+
"onnxruntime-openvino>=1.20,<1.30; platform_system == 'Windows' or platform_system == 'Linux'",
|
|
56
63
|
]
|
|
57
64
|
dev = [
|
|
58
65
|
"ruff>=0.8",
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
# coding: utf-8
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import importlib
|
|
6
|
-
from dataclasses import dataclass, replace
|
|
7
|
-
|
|
8
|
-
from .devices import confirm_device_identity, resolve_device_identity
|
|
9
|
-
from .errors import ProviderError
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
GPU_PROVIDER_NAMES = (
|
|
13
|
-
"CUDAExecutionProvider",
|
|
14
|
-
"TensorrtExecutionProvider",
|
|
15
|
-
"DmlExecutionProvider",
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
@dataclass(frozen=True)
|
|
20
|
-
class ProviderInfo:
|
|
21
|
-
available_providers: tuple[str, ...]
|
|
22
|
-
active_provider: str | None
|
|
23
|
-
device: str
|
|
24
|
-
gpu_requested: bool
|
|
25
|
-
gpu_runtime_ok: bool
|
|
26
|
-
device_id: int | None = None
|
|
27
|
-
device_name: str = ""
|
|
28
|
-
device_uuid: str = ""
|
|
29
|
-
device_verified: bool = False
|
|
30
|
-
|
|
31
|
-
@property
|
|
32
|
-
def use_cuda(self) -> bool:
|
|
33
|
-
return self.active_provider in {"CUDAExecutionProvider", "TensorrtExecutionProvider"}
|
|
34
|
-
|
|
35
|
-
@property
|
|
36
|
-
def use_dml(self) -> bool:
|
|
37
|
-
return self.active_provider == "DmlExecutionProvider"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def detect_providers(prefer: str = "auto") -> ProviderInfo:
|
|
41
|
-
prefer_norm = (prefer or "auto").strip().lower()
|
|
42
|
-
if prefer_norm not in {"auto", "cpu", "gpu"}:
|
|
43
|
-
raise ProviderError(f"unsupported provider preference: {prefer}")
|
|
44
|
-
try:
|
|
45
|
-
ort = importlib.import_module("onnxruntime")
|
|
46
|
-
except Exception as exc: # pragma: no cover - import environment dependent
|
|
47
|
-
raise ProviderError(f"failed to import onnxruntime: {exc}") from exc
|
|
48
|
-
|
|
49
|
-
get_available_providers = getattr(ort, "get_available_providers", None)
|
|
50
|
-
if not callable(get_available_providers):
|
|
51
|
-
origin = getattr(ort, "__file__", None) or "<namespace package>"
|
|
52
|
-
raise ProviderError(
|
|
53
|
-
"onnxruntime dependency is incomplete: missing get_available_providers "
|
|
54
|
-
f"(origin={origin})"
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
try:
|
|
58
|
-
available = tuple(get_available_providers())
|
|
59
|
-
except Exception as exc: # pragma: no cover - runtime environment dependent
|
|
60
|
-
raise ProviderError(f"failed to query ONNX providers: {exc}") from exc
|
|
61
|
-
|
|
62
|
-
gpu_candidates = tuple(name for name in GPU_PROVIDER_NAMES if name in available)
|
|
63
|
-
gpu_visible = bool(gpu_candidates)
|
|
64
|
-
if prefer_norm == "cpu":
|
|
65
|
-
if "CPUExecutionProvider" not in available:
|
|
66
|
-
raise ProviderError(f"CPUExecutionProvider unavailable: {available}")
|
|
67
|
-
return _provider_info(
|
|
68
|
-
available_providers=available,
|
|
69
|
-
active_provider="CPUExecutionProvider",
|
|
70
|
-
device="cpu",
|
|
71
|
-
gpu_requested=False,
|
|
72
|
-
gpu_runtime_ok=False,
|
|
73
|
-
)
|
|
74
|
-
if gpu_visible:
|
|
75
|
-
return _provider_info(
|
|
76
|
-
available_providers=available,
|
|
77
|
-
active_provider=gpu_candidates[0],
|
|
78
|
-
device="gpu",
|
|
79
|
-
gpu_requested=True,
|
|
80
|
-
gpu_runtime_ok=True,
|
|
81
|
-
)
|
|
82
|
-
if prefer_norm == "gpu":
|
|
83
|
-
raise ProviderError(
|
|
84
|
-
f"GPU provider was requested but none is available: {available}"
|
|
85
|
-
)
|
|
86
|
-
if "CPUExecutionProvider" not in available:
|
|
87
|
-
raise ProviderError(f"no supported ONNX execution provider is available: {available}")
|
|
88
|
-
return _provider_info(
|
|
89
|
-
available_providers=available,
|
|
90
|
-
active_provider="CPUExecutionProvider",
|
|
91
|
-
device="cpu",
|
|
92
|
-
gpu_requested=False,
|
|
93
|
-
gpu_runtime_ok=False,
|
|
94
|
-
)
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
def _provider_info(
|
|
98
|
-
*,
|
|
99
|
-
available_providers: tuple[str, ...],
|
|
100
|
-
active_provider: str,
|
|
101
|
-
device: str,
|
|
102
|
-
gpu_requested: bool,
|
|
103
|
-
gpu_runtime_ok: bool,
|
|
104
|
-
) -> ProviderInfo:
|
|
105
|
-
device_id = 0 if active_provider in GPU_PROVIDER_NAMES else None
|
|
106
|
-
identity = resolve_device_identity(active_provider, device_id)
|
|
107
|
-
return ProviderInfo(
|
|
108
|
-
available_providers=available_providers,
|
|
109
|
-
active_provider=active_provider,
|
|
110
|
-
device=device,
|
|
111
|
-
gpu_requested=gpu_requested,
|
|
112
|
-
gpu_runtime_ok=gpu_runtime_ok,
|
|
113
|
-
device_id=identity.device_id,
|
|
114
|
-
device_name=identity.name,
|
|
115
|
-
device_uuid=identity.uuid,
|
|
116
|
-
device_verified=identity.verified,
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
def confirm_provider_device(provider_info: ProviderInfo) -> ProviderInfo:
|
|
121
|
-
identity = confirm_device_identity(provider_info.active_provider, provider_info.device_id)
|
|
122
|
-
return replace(
|
|
123
|
-
provider_info,
|
|
124
|
-
device_id=identity.device_id,
|
|
125
|
-
device_name=identity.name,
|
|
126
|
-
device_uuid=identity.uuid,
|
|
127
|
-
device_verified=identity.verified,
|
|
128
|
-
)
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
numpy<3,>=1.26
|
|
2
|
-
pillow<12,>=10
|
|
3
|
-
opencv-python<5,>=4.10
|
|
4
|
-
rapidocr==3.5.0
|
|
5
|
-
transformers==4.55.4
|
|
6
|
-
tokenizers==0.21.4
|
|
7
|
-
|
|
8
|
-
[cpu]
|
|
9
|
-
|
|
10
|
-
[cpu:python_version < "3.13"]
|
|
11
|
-
onnxruntime<1.26,>=1.19.2
|
|
12
|
-
|
|
13
|
-
[cpu:python_version >= "3.13"]
|
|
14
|
-
onnxruntime<1.26,>=1.20
|
|
15
|
-
|
|
16
|
-
[dev]
|
|
17
|
-
ruff>=0.8
|
|
18
|
-
build>=1.2
|
|
19
|
-
twine>=5.0
|
|
20
|
-
|
|
21
|
-
[gpu]
|
|
22
|
-
|
|
23
|
-
[gpu:python_version < "3.13"]
|
|
24
|
-
onnxruntime-gpu<1.26,>=1.19.2
|
|
25
|
-
|
|
26
|
-
[gpu:python_version >= "3.13"]
|
|
27
|
-
onnxruntime-gpu<1.26,>=1.20
|
|
28
|
-
|
|
29
|
-
[pandoc]
|
|
30
|
-
pypandoc>=1.15
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|