@qvac/ocr-ggml 0.24.3 → 0.25.1
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.
- package/README.md +23 -0
- package/index.d.ts +10 -0
- package/index.js +17 -0
- package/lib/main-gpu.d.ts +2 -0
- package/lib/main-gpu.js +5 -0
- package/package.json +11 -5
- package/prebuilds/android-arm64/qvac__ocr-ggml.bare +0 -0
- package/prebuilds/darwin-arm64/qvac__ocr-ggml.bare +0 -0
- package/prebuilds/darwin-arm64/qvac__ocr-ggml.bare.exports +2 -2
- package/prebuilds/darwin-x64/qvac__ocr-ggml.bare +0 -0
- package/prebuilds/darwin-x64/qvac__ocr-ggml.bare.exports +2 -2
- package/prebuilds/ios-arm64/qvac__ocr-ggml.bare +0 -0
- package/prebuilds/ios-arm64/qvac__ocr-ggml.bare.exports +2 -2
- package/prebuilds/ios-arm64-simulator/qvac__ocr-ggml.bare +0 -0
- package/prebuilds/ios-arm64-simulator/qvac__ocr-ggml.bare.exports +2 -2
- package/prebuilds/ios-x64-simulator/qvac__ocr-ggml.bare +0 -0
- package/prebuilds/ios-x64-simulator/qvac__ocr-ggml.bare.exports +2 -2
- package/prebuilds/linux-arm64/qvac__ocr-ggml.bare +0 -0
- package/prebuilds/linux-x64/qvac__ocr-ggml.bare +0 -0
- package/prebuilds/win32-x64/qvac__ocr-ggml.bare +0 -0
- package/prebuilds/win32-x64/qvac__ocr-ggml.bare.exports +0 -0
- package/test/integration/backend-device.test.js +97 -0
- package/test/integration/full-coverage.test.js +5 -3
- package/test/integration/utils.js +5 -3
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# @qvac/ocr-ggml
|
|
2
2
|
|
|
3
3
|
GGML-backed OCR addon for [QVAC](https://github.com/tetherto/qvac).
|
|
4
|
+
|
|
5
|
+
EasyOCR model loading rejects detector output shapes, recognizer class counts, malformed prediction bias vectors, and convolution bias sizes that do not match the expected tensors.
|
|
4
6
|
Provides two inference pipelines on **`ggml` / `.gguf`** — no Python, no
|
|
5
7
|
PyTorch, and no ONNX Runtime at runtime:
|
|
6
8
|
|
|
@@ -149,6 +151,7 @@ bare examples/backend-device.js --backend metal
|
|
|
149
151
|
| `params.nThreads` | `number` | | `0` (auto) | CPU thread count for GGML; `<0` leaves the GGML default |
|
|
150
152
|
| `params.backendsDir` | `string` | | `<package>/prebuilds` | directory holding `libggml-*.so` backend shared libs |
|
|
151
153
|
| `params.backendDevice` | `'cpu'` \| `'vulkan'` \| `'metal'` \| `'opencl'` | | `'cpu'` | ggml backend device. `'vulkan'` (Linux/Windows/Android), `'metal'` (Apple) and `'opencl'` (Android/Adreno) opt in to GPU inference with transparent CPU fallback — see [Backend device](#backend-device-cpu--vulkan--metal--opencl) |
|
|
154
|
+
| `params.main-gpu` / `params.main_gpu` | `number` \| `string` | | _prefer dedicated_ | Raw ggml registry index or strict GPU class; requires GPU `backendDevice`. See below. |
|
|
152
155
|
| `params.gpuDevice` | `number` | | _prefer discrete_ | 0-based index into the matching GPU/iGPU devices for `'vulkan'`/`'metal'`/`'opencl'`; out-of-range → CPU fallback — see [Selecting a specific GPU](#selecting-a-specific-gpu-gpudevice) |
|
|
153
156
|
| `opts.stats` | `boolean` | | `false` | emit timing stats on `finish` |
|
|
154
157
|
| `logger` | `Object` | | `null` | optional `{ info, warn, error, debug }` — receives C++ log lines |
|
|
@@ -278,6 +281,26 @@ Behaviour and expectations:
|
|
|
278
281
|
with identical output. Other GPUs (Adreno OpenCL, Apple Metal, NVIDIA/Intel
|
|
279
282
|
Vulkan) keep full-GPU detection.
|
|
280
283
|
|
|
284
|
+
### Shared GPU selection (`main-gpu`)
|
|
285
|
+
|
|
286
|
+
With a GPU `backendDevice`, set `'main-gpu': N` (or `main_gpu: N`) to select
|
|
287
|
+
that **raw ggml registry index before backend filtering**. For example, with
|
|
288
|
+
`[ROCm0, Vulkan0]`, `'main-gpu': 0` and `backendDevice: 'vulkan'` falls back to
|
|
289
|
+
CPU; it never renumbers Vulkan0 to index 0. An in-range CPU, unsupported,
|
|
290
|
+
or safety-excluded target also falls back to CPU. An out-of-range integer
|
|
291
|
+
(including negative values) emits a warning and uses normal selection.
|
|
292
|
+
|
|
293
|
+
`'dedicated'` selects only a dedicated GPU; `'integrated'` selects only an
|
|
294
|
+
integrated GPU. If that class is unavailable, selection falls back to CPU.
|
|
295
|
+
Without a selector, GPU selection prefers dedicated devices. Adreno Vulkan
|
|
296
|
+
and required OCR-op safety checks apply to all `main-gpu` requests.
|
|
297
|
+
`backendDevice: 'cpu'` (the default) remains CPU, regardless of this selector.
|
|
298
|
+
|
|
299
|
+
Use only one of `main-gpu`, `main_gpu`, or legacy `gpuDevice`. The new selector
|
|
300
|
+
accepts signed 32-bit integer numbers or integer strings, and case-insensitive
|
|
301
|
+
class strings. Null, booleans, fractions, overflow, and other strings are rejected.
|
|
302
|
+
`gpuDevice` retains its existing index into the filtered backend list.
|
|
303
|
+
|
|
281
304
|
### Selecting a specific GPU (`gpuDevice`)
|
|
282
305
|
|
|
283
306
|
On a host with more than one GPU (e.g. a discrete GPU plus an integrated GPU,
|
package/index.d.ts
CHANGED
|
@@ -97,6 +97,16 @@ export interface OcrGgmlParams {
|
|
|
97
97
|
* the README).
|
|
98
98
|
*/
|
|
99
99
|
gpuDevice?: number;
|
|
100
|
+
/**
|
|
101
|
+
* Raw ggml registry index (integer number/string), or a GPU class (case-insensitive).
|
|
102
|
+
* An unavailable/excluded in-range device or absent class falls back to CPU.
|
|
103
|
+
* Out-of-range indices warn and use the default dedicated-first selection.
|
|
104
|
+
* Requires a GPU backendDevice; CPU remains the default. Cannot be combined
|
|
105
|
+
* with gpuDevice or main_gpu. Adreno Vulkan safety checks still apply.
|
|
106
|
+
*/
|
|
107
|
+
"main-gpu"?: number | string;
|
|
108
|
+
/** Alias for main-gpu; provide only one spelling. */
|
|
109
|
+
main_gpu?: number | string;
|
|
100
110
|
}
|
|
101
111
|
export type { BackendInfo, OcrGgmlRunOptions };
|
|
102
112
|
export interface OcrGgmlArgs {
|
package/index.js
CHANGED
|
@@ -11,6 +11,7 @@ const ocr_ggml_1 = require("./ocr-ggml");
|
|
|
11
11
|
const error_1 = require("./lib/error");
|
|
12
12
|
Object.defineProperty(exports, "QvacErrorAddonOcrGgml", { enumerable: true, get: function () { return error_1.QvacErrorAddonOcrGgml; } });
|
|
13
13
|
Object.defineProperty(exports, "ERR_CODES", { enumerable: true, get: function () { return error_1.ERR_CODES; } });
|
|
14
|
+
const main_gpu_1 = require("./lib/main-gpu");
|
|
14
15
|
const DOCTR_INTERNAL_LANG_LIST = ["en"];
|
|
15
16
|
/**
|
|
16
17
|
* Native language-validation failure messages (see the EasyOCR pipeline's
|
|
@@ -139,6 +140,20 @@ class OcrGgml {
|
|
|
139
140
|
adds: "langList (non-empty array)",
|
|
140
141
|
});
|
|
141
142
|
}
|
|
143
|
+
const selectors = ["main-gpu", "main_gpu", "gpuDevice"];
|
|
144
|
+
if (selectors.filter((key) => this.params[key] !== undefined).length > 1) {
|
|
145
|
+
throw new TypeError("Use only one of main-gpu, main_gpu, or gpuDevice");
|
|
146
|
+
}
|
|
147
|
+
const rawMainGpu = this.params["main-gpu"] !== undefined
|
|
148
|
+
? this.params["main-gpu"] : this.params.main_gpu;
|
|
149
|
+
const mainGpu = typeof rawMainGpu === "string"
|
|
150
|
+
? (/^[+-]?\d+$/.test(rawMainGpu) ? Number(rawMainGpu) : rawMainGpu.toLowerCase())
|
|
151
|
+
: rawMainGpu;
|
|
152
|
+
if (mainGpu !== undefined && mainGpu !== "dedicated" && mainGpu !== "integrated" &&
|
|
153
|
+
!(typeof mainGpu === "number" && Number.isInteger(mainGpu) &&
|
|
154
|
+
mainGpu >= main_gpu_1.MIN_MAIN_GPU_INDEX && mainGpu <= main_gpu_1.MAX_MAIN_GPU_INDEX)) {
|
|
155
|
+
throw new TypeError("main-gpu must be a 32-bit integer registry index, 'dedicated', or 'integrated'");
|
|
156
|
+
}
|
|
142
157
|
const configurationParams = {
|
|
143
158
|
pathDetector: this.params.pathDetector,
|
|
144
159
|
pathRecognizer: this.params.pathRecognizer,
|
|
@@ -157,6 +172,8 @@ class OcrGgml {
|
|
|
157
172
|
"pipelineType",
|
|
158
173
|
"backendDevice",
|
|
159
174
|
"gpuDevice",
|
|
175
|
+
"main-gpu",
|
|
176
|
+
"main_gpu",
|
|
160
177
|
];
|
|
161
178
|
for (const field of optionalFields) {
|
|
162
179
|
if (this.params[field] !== undefined) {
|
package/lib/main-gpu.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qvac/ocr-ggml",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.1",
|
|
4
4
|
"description": "GGML-backed OCR addon for qvac (EasyOCR and DocTR pipelines on GGUF weights)",
|
|
5
5
|
"addon": true,
|
|
6
6
|
"engines": {
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"test": "npm run lint && npm run test:types && npm run test:unit && npm run test:integration",
|
|
34
34
|
"test:types": "npm run typecheck && npm run check:generated",
|
|
35
35
|
"test:dts": "npm run test:types",
|
|
36
|
-
"test:cpp:build": "bare-make generate -D BUILD_TESTING=ON && bare-make build --target addon-test",
|
|
37
|
-
"test:cpp:run": "cd build/addon/tests/ && ./addon-test --gtest_output=xml:cpp-test-results.xml",
|
|
36
|
+
"test:cpp:build": "bare-make generate -D BUILD_TESTING=ON && bare-make build --target addon-test ocr-prediction-bias-gguf-test",
|
|
37
|
+
"test:cpp:run": "cd build/addon/tests/ && ./addon-test --gtest_output=xml:cpp-test-results.xml && ./ocr-prediction-bias-gguf-test --gtest_output=xml:prediction-bias-gguf-test-results.xml",
|
|
38
38
|
"test:cpp": "npm run test:cpp:build && npm run test:cpp:run",
|
|
39
39
|
"setup:venv": "bash scripts/setup-venv.sh",
|
|
40
40
|
"convert-model": "bash scripts/convert-model.sh",
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
},
|
|
96
96
|
"dependencies": {
|
|
97
97
|
"@qvac/error": "^0.1.0",
|
|
98
|
-
"@qvac/fabric": "^0.
|
|
98
|
+
"@qvac/fabric": "^0.17.0",
|
|
99
99
|
"@qvac/infer-base": "^0.6.2",
|
|
100
100
|
"@qvac/logging": "^0.1.0",
|
|
101
101
|
"bare-fetch": "^3.0.1",
|
|
@@ -116,7 +116,13 @@
|
|
|
116
116
|
"types": "./addonLogging.d.ts",
|
|
117
117
|
"default": "./addonLogging.js"
|
|
118
118
|
},
|
|
119
|
-
"./addonLogging.js": "./addonLogging.js"
|
|
119
|
+
"./addonLogging.js": "./addonLogging.js",
|
|
120
|
+
"./lib/main-gpu": {
|
|
121
|
+
"types": "./lib/main-gpu.d.ts",
|
|
122
|
+
"default": "./lib/main-gpu.js"
|
|
123
|
+
},
|
|
124
|
+
"./binding": "./binding.js",
|
|
125
|
+
"./binding.js": "./binding.js"
|
|
120
126
|
},
|
|
121
127
|
"types": "index.d.ts"
|
|
122
128
|
}
|
|
Binary file
|
|
Binary file
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
],
|
|
8
8
|
"current_versions": [
|
|
9
9
|
{
|
|
10
|
-
"version": "0.
|
|
10
|
+
"version": "0.25.1"
|
|
11
11
|
}
|
|
12
12
|
],
|
|
13
13
|
"exported_symbols": [
|
|
@@ -2543,7 +2543,6 @@
|
|
|
2543
2543
|
"_png_write_bKGD",
|
|
2544
2544
|
"_png_set_hIST",
|
|
2545
2545
|
"__ZN2cv3MatC2ENS_5Size_IiEEi",
|
|
2546
|
-
"__ZN23qvac_lib_infer_ocr_ggml21ocr_backend_selection19selectBackendDeviceENS_13BackendDeviceENSt3__18optionalIiEE",
|
|
2547
2546
|
"__ZN2cv15ImageCollection4Impl3endEPS0_",
|
|
2548
2547
|
"_png_get_copyright",
|
|
2549
2548
|
"__Z6cvCeilRKN2cv9softfloatE",
|
|
@@ -2628,6 +2627,7 @@
|
|
|
2628
2627
|
"__ZN2cv15ImageCollection8iteratorppEi",
|
|
2629
2628
|
"_cvGetReal1D",
|
|
2630
2629
|
"__ZN2cv3MatC1Ev",
|
|
2630
|
+
"__ZN23qvac_lib_infer_ocr_ggml21ocr_backend_selection19selectBackendDeviceENS_13BackendDeviceENSt3__18optionalIiEENS3_INS2_7variantIJiNS_12MainGpuClassEEEEEE",
|
|
2631
2631
|
"_png_check_fp_string",
|
|
2632
2632
|
"__ZN2cv11linearPolarERKNS_11_InputArrayERKNS_12_OutputArrayENS_6Point_IfEEdi",
|
|
2633
2633
|
"__ZN2cv3LDAC1ERKNS_11_InputArrayES3_i",
|
|
Binary file
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
],
|
|
8
8
|
"current_versions": [
|
|
9
9
|
{
|
|
10
|
-
"version": "0.
|
|
10
|
+
"version": "0.25.1"
|
|
11
11
|
}
|
|
12
12
|
],
|
|
13
13
|
"exported_symbols": [
|
|
@@ -2597,7 +2597,6 @@
|
|
|
2597
2597
|
"_png_write_bKGD",
|
|
2598
2598
|
"_png_set_hIST",
|
|
2599
2599
|
"__ZN2cv3MatC2ENS_5Size_IiEEi",
|
|
2600
|
-
"__ZN23qvac_lib_infer_ocr_ggml21ocr_backend_selection19selectBackendDeviceENS_13BackendDeviceENSt3__18optionalIiEE",
|
|
2601
2600
|
"__ZN2cv15ImageCollection4Impl3endEPS0_",
|
|
2602
2601
|
"_png_get_copyright",
|
|
2603
2602
|
"__Z6cvCeilRKN2cv9softfloatE",
|
|
@@ -2680,6 +2679,7 @@
|
|
|
2680
2679
|
"__ZN2cv15ImageCollection8iteratorppEi",
|
|
2681
2680
|
"_cvGetReal1D",
|
|
2682
2681
|
"__ZN2cv3MatC1Ev",
|
|
2682
|
+
"__ZN23qvac_lib_infer_ocr_ggml21ocr_backend_selection19selectBackendDeviceENS_13BackendDeviceENSt3__18optionalIiEENS3_INS2_7variantIJiNS_12MainGpuClassEEEEEE",
|
|
2683
2683
|
"_png_check_fp_string",
|
|
2684
2684
|
"__ZN2cv11linearPolarERKNS_11_InputArrayERKNS_12_OutputArrayENS_6Point_IfEEdi",
|
|
2685
2685
|
"__ZN2cv3LDAC1ERKNS_11_InputArrayES3_i",
|
|
Binary file
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
],
|
|
8
8
|
"current_versions": [
|
|
9
9
|
{
|
|
10
|
-
"version": "0.
|
|
10
|
+
"version": "0.25.1"
|
|
11
11
|
}
|
|
12
12
|
],
|
|
13
13
|
"exported_symbols": [
|
|
@@ -2533,7 +2533,6 @@
|
|
|
2533
2533
|
"_png_write_bKGD",
|
|
2534
2534
|
"_png_set_hIST",
|
|
2535
2535
|
"__ZN2cv3MatC2ENS_5Size_IiEEi",
|
|
2536
|
-
"__ZN23qvac_lib_infer_ocr_ggml21ocr_backend_selection19selectBackendDeviceENS_13BackendDeviceENSt3__18optionalIiEE",
|
|
2537
2536
|
"__ZN2cv15ImageCollection4Impl3endEPS0_",
|
|
2538
2537
|
"_png_get_copyright",
|
|
2539
2538
|
"__Z6cvCeilRKN2cv9softfloatE",
|
|
@@ -2618,6 +2617,7 @@
|
|
|
2618
2617
|
"__ZN2cv15ImageCollection8iteratorppEi",
|
|
2619
2618
|
"_cvGetReal1D",
|
|
2620
2619
|
"__ZN2cv3MatC1Ev",
|
|
2620
|
+
"__ZN23qvac_lib_infer_ocr_ggml21ocr_backend_selection19selectBackendDeviceENS_13BackendDeviceENSt3__18optionalIiEENS3_INS2_7variantIJiNS_12MainGpuClassEEEEEE",
|
|
2621
2621
|
"_png_check_fp_string",
|
|
2622
2622
|
"__ZN2cv11linearPolarERKNS_11_InputArrayERKNS_12_OutputArrayENS_6Point_IfEEdi",
|
|
2623
2623
|
"__ZN2cv3LDAC1ERKNS_11_InputArrayES3_i",
|
|
Binary file
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
],
|
|
8
8
|
"current_versions": [
|
|
9
9
|
{
|
|
10
|
-
"version": "0.
|
|
10
|
+
"version": "0.25.1"
|
|
11
11
|
}
|
|
12
12
|
],
|
|
13
13
|
"exported_symbols": [
|
|
@@ -2533,7 +2533,6 @@
|
|
|
2533
2533
|
"_png_write_bKGD",
|
|
2534
2534
|
"_png_set_hIST",
|
|
2535
2535
|
"__ZN2cv3MatC2ENS_5Size_IiEEi",
|
|
2536
|
-
"__ZN23qvac_lib_infer_ocr_ggml21ocr_backend_selection19selectBackendDeviceENS_13BackendDeviceENSt3__18optionalIiEE",
|
|
2537
2536
|
"__ZN2cv15ImageCollection4Impl3endEPS0_",
|
|
2538
2537
|
"_png_get_copyright",
|
|
2539
2538
|
"__Z6cvCeilRKN2cv9softfloatE",
|
|
@@ -2618,6 +2617,7 @@
|
|
|
2618
2617
|
"__ZN2cv15ImageCollection8iteratorppEi",
|
|
2619
2618
|
"_cvGetReal1D",
|
|
2620
2619
|
"__ZN2cv3MatC1Ev",
|
|
2620
|
+
"__ZN23qvac_lib_infer_ocr_ggml21ocr_backend_selection19selectBackendDeviceENS_13BackendDeviceENSt3__18optionalIiEENS3_INS2_7variantIJiNS_12MainGpuClassEEEEEE",
|
|
2621
2621
|
"_png_check_fp_string",
|
|
2622
2622
|
"__ZN2cv11linearPolarERKNS_11_InputArrayERKNS_12_OutputArrayENS_6Point_IfEEdi",
|
|
2623
2623
|
"__ZN2cv3LDAC1ERKNS_11_InputArrayES3_i",
|
|
Binary file
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
],
|
|
8
8
|
"current_versions": [
|
|
9
9
|
{
|
|
10
|
-
"version": "0.
|
|
10
|
+
"version": "0.25.1"
|
|
11
11
|
}
|
|
12
12
|
],
|
|
13
13
|
"exported_symbols": [
|
|
@@ -2592,7 +2592,6 @@
|
|
|
2592
2592
|
"_png_write_bKGD",
|
|
2593
2593
|
"_png_set_hIST",
|
|
2594
2594
|
"__ZN2cv3MatC2ENS_5Size_IiEEi",
|
|
2595
|
-
"__ZN23qvac_lib_infer_ocr_ggml21ocr_backend_selection19selectBackendDeviceENS_13BackendDeviceENSt3__18optionalIiEE",
|
|
2596
2595
|
"__ZN2cv15ImageCollection4Impl3endEPS0_",
|
|
2597
2596
|
"_png_get_copyright",
|
|
2598
2597
|
"__Z6cvCeilRKN2cv9softfloatE",
|
|
@@ -2674,6 +2673,7 @@
|
|
|
2674
2673
|
"__ZN2cv15ImageCollection8iteratorppEi",
|
|
2675
2674
|
"_cvGetReal1D",
|
|
2676
2675
|
"__ZN2cv3MatC1Ev",
|
|
2676
|
+
"__ZN23qvac_lib_infer_ocr_ggml21ocr_backend_selection19selectBackendDeviceENS_13BackendDeviceENSt3__18optionalIiEENS3_INS2_7variantIJiNS_12MainGpuClassEEEEEE",
|
|
2677
2677
|
"_png_check_fp_string",
|
|
2678
2678
|
"__ZN2cv11linearPolarERKNS_11_InputArrayERKNS_12_OutputArrayENS_6Point_IfEEdi",
|
|
2679
2679
|
"__ZN2cv3LDAC1ERKNS_11_InputArrayES3_i",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const { OcrGgml } = require('../..')
|
|
4
4
|
const test = require('brittle')
|
|
5
|
+
const path = require('bare-path')
|
|
6
|
+
const { MIN_MAIN_GPU_INDEX, MAX_MAIN_GPU_INDEX } = require('@qvac/ocr-ggml/lib/main-gpu')
|
|
5
7
|
const {
|
|
6
8
|
isMobile,
|
|
7
9
|
platform,
|
|
@@ -33,6 +35,101 @@ const vulkanBackendLib = findVulkanBackendLib(PREBUILDS_DIR)
|
|
|
33
35
|
// host that did not ship a Vulkan backend lib.
|
|
34
36
|
const shouldSkip = isMobile || !vulkanBackendLib
|
|
35
37
|
|
|
38
|
+
function nativeBackendsDir() {
|
|
39
|
+
if (isMobile) return PREBUILDS_DIR
|
|
40
|
+
return path.join(path.dirname(require.resolve('@qvac/fabric/package')), 'prebuilds')
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
for (const key of ['main-gpu', 'main_gpu']) {
|
|
44
|
+
for (const value of [0, '+0', 'DEDICATED', 'Integrated']) {
|
|
45
|
+
test(
|
|
46
|
+
`native createInstance: ${key}=${value} resolves the requested device`,
|
|
47
|
+
{ timeout: TEST_TIMEOUT },
|
|
48
|
+
async function (t) {
|
|
49
|
+
const binding = require('../../binding')
|
|
50
|
+
const pathDetector = await ensureModelPath('detector_craft')
|
|
51
|
+
const pathRecognizer = await ensureModelPath('recognizer_latin')
|
|
52
|
+
const backendDevice = platform === 'darwin' || platform === 'ios' ? 'metal' : 'vulkan'
|
|
53
|
+
const handle = binding.createInstance(
|
|
54
|
+
{},
|
|
55
|
+
{
|
|
56
|
+
pathDetector,
|
|
57
|
+
pathRecognizer,
|
|
58
|
+
langList: ['en'],
|
|
59
|
+
backendDevice,
|
|
60
|
+
backendsDir: nativeBackendsDir(),
|
|
61
|
+
[key]: value
|
|
62
|
+
},
|
|
63
|
+
() => {}
|
|
64
|
+
)
|
|
65
|
+
try {
|
|
66
|
+
const info = binding.getBackendInfo(handle)
|
|
67
|
+
t.is(info.requested, backendDevice, 'native backend request is preserved')
|
|
68
|
+
const numeric = value === 0 || value === '+0'
|
|
69
|
+
if (info.backendDevice === 'CPU') {
|
|
70
|
+
t.is(info.deviceIndex, -1, 'fallback selects CPU')
|
|
71
|
+
const selectorReason = numeric
|
|
72
|
+
? 'main-gpu registry index 0 is not an eligible'
|
|
73
|
+
: 'main-gpu requested GPU class is unavailable'
|
|
74
|
+
t.ok(
|
|
75
|
+
info.fallbackReason.includes(selectorReason) ||
|
|
76
|
+
info.fallbackReason.includes('does not implement the OCR vision ops'),
|
|
77
|
+
'fallback identifies the parsed selector or the OCR safety check'
|
|
78
|
+
)
|
|
79
|
+
} else {
|
|
80
|
+
t.is(info.fallbackReason, '', 'selected GPU needs no fallback')
|
|
81
|
+
t.ok(info.deviceIndex >= 0, 'selected GPU has a registry index')
|
|
82
|
+
t.ok(
|
|
83
|
+
backendDevice === 'metal'
|
|
84
|
+
? /metal|mtl/i.test(info.backendName)
|
|
85
|
+
: /vulkan/i.test(info.backendName),
|
|
86
|
+
'resolved device belongs to the requested backend'
|
|
87
|
+
)
|
|
88
|
+
if (numeric) {
|
|
89
|
+
t.is(info.deviceIndex, 0, 'numeric selector preserves raw registry identity')
|
|
90
|
+
} else {
|
|
91
|
+
t.is(
|
|
92
|
+
info.backendDevice,
|
|
93
|
+
value.toLowerCase() === 'integrated' ? 'IGPU' : 'GPU',
|
|
94
|
+
'class selector is parsed case-insensitively and applied strictly'
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
} finally {
|
|
99
|
+
binding.destroyInstance(handle)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
test(`native createInstance: ${key} rejects invalid indices before model loading`, (t) => {
|
|
106
|
+
const binding = require('../../binding')
|
|
107
|
+
for (const value of [
|
|
108
|
+
0.5,
|
|
109
|
+
NaN,
|
|
110
|
+
Infinity,
|
|
111
|
+
MAX_MAIN_GPU_INDEX + 1,
|
|
112
|
+
MIN_MAIN_GPU_INDEX - 1,
|
|
113
|
+
String(MAX_MAIN_GPU_INDEX + 1),
|
|
114
|
+
String(MIN_MAIN_GPU_INDEX - 1),
|
|
115
|
+
'+-1',
|
|
116
|
+
'1junk',
|
|
117
|
+
' 1'
|
|
118
|
+
]) {
|
|
119
|
+
t.exception(
|
|
120
|
+
() =>
|
|
121
|
+
binding.createInstance(
|
|
122
|
+
{},
|
|
123
|
+
{ pathDetector: 'unused', pathRecognizer: 'unused', langList: ['en'], [key]: value },
|
|
124
|
+
() => {}
|
|
125
|
+
),
|
|
126
|
+
/main-gpu must be a 32-bit integer registry index/,
|
|
127
|
+
`${key}=${value} is rejected by native validation`
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
})
|
|
131
|
+
}
|
|
132
|
+
|
|
36
133
|
test(
|
|
37
134
|
'backendDevice vulkan: selects Vulkan or reports an explicit CPU fallback',
|
|
38
135
|
{ timeout: TEST_TIMEOUT, skip: shouldSkip },
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { OcrGgml, QvacErrorAddonOcrGgml, ERR_CODES, binding } = require('../..')
|
|
4
4
|
const test = require('brittle')
|
|
5
|
-
const { isMobile, ensureModelPath, getImagePath } = require('./utils')
|
|
5
|
+
const { isMobile, ensureModelPath, getImagePath, OCR_TEST_THREADS } = require('./utils')
|
|
6
6
|
|
|
7
7
|
const MOBILE_TIMEOUT = 600 * 1000
|
|
8
8
|
const DESKTOP_TIMEOUT = 120 * 1000
|
|
@@ -26,7 +26,8 @@ async function loadOcr() {
|
|
|
26
26
|
params: {
|
|
27
27
|
pathDetector: detectorPath,
|
|
28
28
|
pathRecognizer: recognizerPath,
|
|
29
|
-
langList: ['en']
|
|
29
|
+
langList: ['en'],
|
|
30
|
+
nThreads: OCR_TEST_THREADS
|
|
30
31
|
}
|
|
31
32
|
})
|
|
32
33
|
|
|
@@ -164,7 +165,8 @@ test(
|
|
|
164
165
|
pathRecognizer: recognizerPath,
|
|
165
166
|
langList: ['en'],
|
|
166
167
|
defaultRotationAngles: [90, 180, 270],
|
|
167
|
-
contrastRetry: true
|
|
168
|
+
contrastRetry: true,
|
|
169
|
+
nThreads: OCR_TEST_THREADS
|
|
168
170
|
}
|
|
169
171
|
})
|
|
170
172
|
|
|
@@ -352,6 +352,7 @@ try {
|
|
|
352
352
|
const platform = os.platform()
|
|
353
353
|
const isMobile = platform === 'ios' || platform === 'android'
|
|
354
354
|
const isWindows = platform === 'win32'
|
|
355
|
+
const OCR_TEST_THREADS = 4
|
|
355
356
|
|
|
356
357
|
function _envInt(key, fallback) {
|
|
357
358
|
let raw = ''
|
|
@@ -488,7 +489,7 @@ function getBackendDevice() {
|
|
|
488
489
|
function createOcrGgml(params = {}, opts) {
|
|
489
490
|
const { OcrGgml } = require('../..')
|
|
490
491
|
const instance = new OcrGgml({
|
|
491
|
-
params: { backendDevice: getBackendDevice(), ...params },
|
|
492
|
+
params: { backendDevice: getBackendDevice(), nThreads: OCR_TEST_THREADS, ...params },
|
|
492
493
|
opts
|
|
493
494
|
})
|
|
494
495
|
// After load() resolves the backend, record the actual GPU/backend name on
|
|
@@ -1063,7 +1064,7 @@ async function runDoctrOCR(t, params, imagePath) {
|
|
|
1063
1064
|
params: {
|
|
1064
1065
|
langList: ['en'],
|
|
1065
1066
|
pipelineType: 'doctr',
|
|
1066
|
-
nThreads:
|
|
1067
|
+
nThreads: OCR_TEST_THREADS,
|
|
1067
1068
|
backendDevice: getBackendDevice(),
|
|
1068
1069
|
...params
|
|
1069
1070
|
},
|
|
@@ -1351,7 +1352,7 @@ async function runDoctrWarmProfile(t, cfg) {
|
|
|
1351
1352
|
params: {
|
|
1352
1353
|
langList: ['en'],
|
|
1353
1354
|
pipelineType: 'doctr',
|
|
1354
|
-
nThreads:
|
|
1355
|
+
nThreads: OCR_TEST_THREADS,
|
|
1355
1356
|
backendDevice: 'vulkan',
|
|
1356
1357
|
...params
|
|
1357
1358
|
},
|
|
@@ -1439,6 +1440,7 @@ module.exports = {
|
|
|
1439
1440
|
runDoctrWarmProfile,
|
|
1440
1441
|
isWindows,
|
|
1441
1442
|
platform,
|
|
1443
|
+
OCR_TEST_THREADS,
|
|
1442
1444
|
PERF_RUNS,
|
|
1443
1445
|
PREBUILDS_DIR,
|
|
1444
1446
|
findVulkanBackendLib,
|