@camstack/addon-vision 0.1.7 → 0.1.9

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.
Files changed (136) hide show
  1. package/dist/addons/animal-classifier/index.d.mts +30 -0
  2. package/dist/addons/animal-classifier/index.d.ts +30 -0
  3. package/dist/addons/animal-classifier/index.js +822 -999
  4. package/dist/addons/animal-classifier/index.js.map +1 -1
  5. package/dist/addons/animal-classifier/index.mjs +7 -242
  6. package/dist/addons/animal-classifier/index.mjs.map +1 -1
  7. package/dist/addons/audio-classification/index.d.mts +36 -0
  8. package/dist/addons/audio-classification/index.d.ts +36 -0
  9. package/dist/addons/audio-classification/index.js +378 -501
  10. package/dist/addons/audio-classification/index.js.map +1 -1
  11. package/dist/addons/audio-classification/index.mjs +4 -224
  12. package/dist/addons/audio-classification/index.mjs.map +1 -1
  13. package/dist/addons/bird-global-classifier/index.d.mts +31 -0
  14. package/dist/addons/bird-global-classifier/index.d.ts +31 -0
  15. package/dist/addons/bird-global-classifier/index.js +825 -1002
  16. package/dist/addons/bird-global-classifier/index.js.map +1 -1
  17. package/dist/addons/bird-global-classifier/index.mjs +7 -248
  18. package/dist/addons/bird-global-classifier/index.mjs.map +1 -1
  19. package/dist/addons/bird-nabirds-classifier/index.d.mts +33 -0
  20. package/dist/addons/bird-nabirds-classifier/index.d.ts +33 -0
  21. package/dist/addons/bird-nabirds-classifier/index.js +825 -1002
  22. package/dist/addons/bird-nabirds-classifier/index.js.map +1 -1
  23. package/dist/addons/bird-nabirds-classifier/index.mjs +7 -289
  24. package/dist/addons/bird-nabirds-classifier/index.mjs.map +1 -1
  25. package/dist/addons/face-detection/index.d.mts +29 -0
  26. package/dist/addons/face-detection/index.d.ts +29 -0
  27. package/dist/addons/face-detection/index.js +934 -1196
  28. package/dist/addons/face-detection/index.js.map +1 -1
  29. package/dist/addons/face-detection/index.mjs +7 -227
  30. package/dist/addons/face-detection/index.mjs.map +1 -1
  31. package/dist/addons/face-recognition/index.d.mts +29 -0
  32. package/dist/addons/face-recognition/index.d.ts +29 -0
  33. package/dist/addons/face-recognition/index.js +807 -1003
  34. package/dist/addons/face-recognition/index.js.map +1 -1
  35. package/dist/addons/face-recognition/index.mjs +6 -197
  36. package/dist/addons/face-recognition/index.mjs.map +1 -1
  37. package/dist/addons/motion-detection/index.d.mts +28 -0
  38. package/dist/addons/motion-detection/index.d.ts +28 -0
  39. package/dist/addons/motion-detection/index.js +111 -214
  40. package/dist/addons/motion-detection/index.js.map +1 -1
  41. package/dist/addons/motion-detection/index.mjs +9 -12
  42. package/dist/addons/motion-detection/index.mjs.map +1 -1
  43. package/dist/addons/object-detection/index.d.mts +31 -0
  44. package/dist/addons/object-detection/index.d.ts +31 -0
  45. package/dist/addons/object-detection/index.js +1082 -1287
  46. package/dist/addons/object-detection/index.js.map +1 -1
  47. package/dist/addons/object-detection/index.mjs +7 -373
  48. package/dist/addons/object-detection/index.mjs.map +1 -1
  49. package/dist/addons/plate-detection/index.d.mts +30 -0
  50. package/dist/addons/plate-detection/index.d.ts +30 -0
  51. package/dist/addons/plate-detection/index.js +868 -1075
  52. package/dist/addons/plate-detection/index.js.map +1 -1
  53. package/dist/addons/plate-detection/index.mjs +7 -230
  54. package/dist/addons/plate-detection/index.mjs.map +1 -1
  55. package/dist/addons/plate-recognition/index.d.mts +31 -0
  56. package/dist/addons/plate-recognition/index.d.ts +31 -0
  57. package/dist/addons/plate-recognition/index.js +505 -684
  58. package/dist/addons/plate-recognition/index.js.map +1 -1
  59. package/dist/addons/plate-recognition/index.mjs +5 -244
  60. package/dist/addons/plate-recognition/index.mjs.map +1 -1
  61. package/dist/addons/segmentation-refiner/index.d.mts +30 -0
  62. package/dist/addons/segmentation-refiner/index.d.ts +30 -0
  63. package/dist/addons/segmentation-refiner/index.js +790 -967
  64. package/dist/addons/segmentation-refiner/index.js.map +1 -1
  65. package/dist/addons/segmentation-refiner/index.mjs +17 -21
  66. package/dist/addons/segmentation-refiner/index.mjs.map +1 -1
  67. package/dist/addons/vehicle-classifier/index.d.mts +31 -0
  68. package/dist/addons/vehicle-classifier/index.d.ts +31 -0
  69. package/dist/addons/vehicle-classifier/index.js +410 -581
  70. package/dist/addons/vehicle-classifier/index.js.map +1 -1
  71. package/dist/addons/vehicle-classifier/index.mjs +16 -20
  72. package/dist/addons/vehicle-classifier/index.mjs.map +1 -1
  73. package/dist/chunk-22BHCDT5.mjs +101 -0
  74. package/dist/{chunk-WG66JYYW.mjs.map → chunk-22BHCDT5.mjs.map} +1 -1
  75. package/dist/chunk-2IOKI4ES.mjs +335 -0
  76. package/dist/{chunk-PIFS7AIT.mjs.map → chunk-2IOKI4ES.mjs.map} +1 -1
  77. package/dist/chunk-7DYHXUPZ.mjs +36 -0
  78. package/dist/{chunk-BS4DKYGN.mjs.map → chunk-7DYHXUPZ.mjs.map} +1 -1
  79. package/dist/chunk-BJTO5JO5.mjs +11 -0
  80. package/dist/chunk-BP7H4NFS.mjs +412 -0
  81. package/dist/{chunk-MGT6RUVX.mjs.map → chunk-BP7H4NFS.mjs.map} +1 -1
  82. package/dist/chunk-BR2FPGOX.mjs +98 -0
  83. package/dist/{chunk-YYDM6V2F.mjs.map → chunk-BR2FPGOX.mjs.map} +1 -1
  84. package/dist/chunk-D6WEHN33.mjs +276 -0
  85. package/dist/chunk-D6WEHN33.mjs.map +1 -0
  86. package/dist/chunk-DRYFGARD.mjs +289 -0
  87. package/dist/chunk-DRYFGARD.mjs.map +1 -0
  88. package/dist/chunk-DUN6XU3N.mjs +72 -0
  89. package/dist/{chunk-XD7WGXHZ.mjs.map → chunk-DUN6XU3N.mjs.map} +1 -1
  90. package/dist/chunk-ESLHNWWE.mjs +387 -0
  91. package/dist/chunk-ESLHNWWE.mjs.map +1 -0
  92. package/dist/chunk-JUQEW6ON.mjs +256 -0
  93. package/dist/chunk-JUQEW6ON.mjs.map +1 -0
  94. package/dist/chunk-KUO2BVFY.mjs +90 -0
  95. package/dist/{chunk-DE7I3VHO.mjs.map → chunk-KUO2BVFY.mjs.map} +1 -1
  96. package/dist/chunk-R5J3WAUI.mjs +645 -0
  97. package/dist/chunk-R5J3WAUI.mjs.map +1 -0
  98. package/dist/chunk-XZ6ZMXXU.mjs +39 -0
  99. package/dist/{chunk-K36R6HWY.mjs.map → chunk-XZ6ZMXXU.mjs.map} +1 -1
  100. package/dist/chunk-YPU4WTXZ.mjs +269 -0
  101. package/dist/chunk-YPU4WTXZ.mjs.map +1 -0
  102. package/dist/chunk-YUCD2TFH.mjs +242 -0
  103. package/dist/chunk-YUCD2TFH.mjs.map +1 -0
  104. package/dist/chunk-ZTJENCFC.mjs +379 -0
  105. package/dist/chunk-ZTJENCFC.mjs.map +1 -0
  106. package/dist/chunk-ZWYXXCXP.mjs +248 -0
  107. package/dist/chunk-ZWYXXCXP.mjs.map +1 -0
  108. package/dist/index.d.mts +183 -0
  109. package/dist/index.d.ts +183 -0
  110. package/dist/index.js +3930 -4449
  111. package/dist/index.js.map +1 -1
  112. package/dist/index.mjs +250 -2698
  113. package/dist/index.mjs.map +1 -1
  114. package/package.json +5 -5
  115. package/dist/chunk-2YMA6QOV.mjs +0 -193
  116. package/dist/chunk-2YMA6QOV.mjs.map +0 -1
  117. package/dist/chunk-3IIFBJCD.mjs +0 -45
  118. package/dist/chunk-BS4DKYGN.mjs +0 -48
  119. package/dist/chunk-DE7I3VHO.mjs +0 -106
  120. package/dist/chunk-F6D2OZ36.mjs +0 -89
  121. package/dist/chunk-F6D2OZ36.mjs.map +0 -1
  122. package/dist/chunk-GAOIFQDX.mjs +0 -59
  123. package/dist/chunk-GAOIFQDX.mjs.map +0 -1
  124. package/dist/chunk-HUIX2XVR.mjs +0 -159
  125. package/dist/chunk-HUIX2XVR.mjs.map +0 -1
  126. package/dist/chunk-K36R6HWY.mjs +0 -51
  127. package/dist/chunk-MBTAI3WE.mjs +0 -78
  128. package/dist/chunk-MBTAI3WE.mjs.map +0 -1
  129. package/dist/chunk-MGT6RUVX.mjs +0 -423
  130. package/dist/chunk-PIFS7AIT.mjs +0 -446
  131. package/dist/chunk-WG66JYYW.mjs +0 -116
  132. package/dist/chunk-XD7WGXHZ.mjs +0 -82
  133. package/dist/chunk-YYDM6V2F.mjs +0 -113
  134. package/dist/chunk-ZK7P3TZN.mjs +0 -286
  135. package/dist/chunk-ZK7P3TZN.mjs.map +0 -1
  136. /package/dist/{chunk-3IIFBJCD.mjs.map → chunk-BJTO5JO5.mjs.map} +0 -0
@@ -5,9 +5,6 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __commonJS = (cb, mod) => function __require() {
9
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
- };
11
8
  var __export = (target, all) => {
12
9
  for (var name in all)
13
10
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -30,1119 +27,915 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
30
27
  ));
31
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
29
 
33
- // src/catalogs/object-detection-models.js
34
- var require_object_detection_models = __commonJS({
35
- "src/catalogs/object-detection-models.js"(exports2) {
36
- "use strict";
37
- Object.defineProperty(exports2, "__esModule", { value: true });
38
- exports2.OBJECT_DETECTION_MODELS = exports2.MLPACKAGE_FILES = void 0;
39
- var types_1 = require("@camstack/types");
40
- var HF_REPO = "camstack/camstack-models";
41
- exports2.MLPACKAGE_FILES = [
42
- "Manifest.json",
43
- "Data/com.apple.CoreML/model.mlmodel",
44
- "Data/com.apple.CoreML/weights/weight.bin"
45
- ];
46
- exports2.OBJECT_DETECTION_MODELS = [
47
- // ── YOLOv8 ──────────────────────────────────────────────────────
48
- {
49
- id: "yolov8n",
50
- name: "YOLOv8 Nano",
51
- description: "YOLOv8 Nano \u2014 fastest, smallest object detection model",
52
- inputSize: { width: 640, height: 640 },
53
- labels: types_1.COCO_80_LABELS,
54
- formats: {
55
- onnx: {
56
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov8/onnx/camstack-yolov8n.onnx"),
57
- sizeMB: 12
58
- },
59
- coreml: {
60
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov8/coreml/camstack-yolov8n.mlpackage"),
61
- sizeMB: 6,
62
- isDirectory: true,
63
- files: exports2.MLPACKAGE_FILES,
64
- runtimes: ["python"]
65
- },
66
- openvino: {
67
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov8/openvino/camstack-yolov8n.xml"),
68
- sizeMB: 7,
69
- runtimes: ["python"]
70
- },
71
- tflite: {
72
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov8/tflite/camstack-yolov8n_float32.tflite"),
73
- sizeMB: 12,
74
- runtimes: ["python"]
75
- }
76
- }
30
+ // src/addons/plate-detection/index.ts
31
+ var plate_detection_exports = {};
32
+ __export(plate_detection_exports, {
33
+ default: () => PlateDetectionAddon
34
+ });
35
+ module.exports = __toCommonJS(plate_detection_exports);
36
+
37
+ // src/catalogs/plate-detection-models.ts
38
+ var import_types2 = require("@camstack/types");
39
+
40
+ // src/catalogs/object-detection-models.ts
41
+ var import_types = require("@camstack/types");
42
+ var HF_REPO = "camstack/camstack-models";
43
+ var MLPACKAGE_FILES = [
44
+ "Manifest.json",
45
+ "Data/com.apple.CoreML/model.mlmodel",
46
+ "Data/com.apple.CoreML/weights/weight.bin"
47
+ ];
48
+ var OBJECT_DETECTION_MODELS = [
49
+ // ── YOLOv8 ──────────────────────────────────────────────────────
50
+ {
51
+ id: "yolov8n",
52
+ name: "YOLOv8 Nano",
53
+ description: "YOLOv8 Nano \u2014 fastest, smallest object detection model",
54
+ inputSize: { width: 640, height: 640 },
55
+ labels: import_types.COCO_80_LABELS,
56
+ formats: {
57
+ onnx: {
58
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/onnx/camstack-yolov8n.onnx"),
59
+ sizeMB: 12
77
60
  },
78
- {
79
- id: "yolov8s",
80
- name: "YOLOv8 Small",
81
- description: "YOLOv8 Small \u2014 balanced speed and accuracy",
82
- inputSize: { width: 640, height: 640 },
83
- labels: types_1.COCO_80_LABELS,
84
- formats: {
85
- onnx: {
86
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov8/onnx/camstack-yolov8s.onnx"),
87
- sizeMB: 43
88
- },
89
- coreml: {
90
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov8/coreml/camstack-yolov8s.mlpackage"),
91
- sizeMB: 21,
92
- isDirectory: true,
93
- files: exports2.MLPACKAGE_FILES,
94
- runtimes: ["python"]
95
- },
96
- openvino: {
97
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov8/openvino/camstack-yolov8s.xml"),
98
- sizeMB: 22,
99
- runtimes: ["python"]
100
- },
101
- tflite: {
102
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov8/tflite/camstack-yolov8s_float32.tflite"),
103
- sizeMB: 43,
104
- runtimes: ["python"]
105
- }
106
- }
61
+ coreml: {
62
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/coreml/camstack-yolov8n.mlpackage"),
63
+ sizeMB: 6,
64
+ isDirectory: true,
65
+ files: MLPACKAGE_FILES,
66
+ runtimes: ["python"]
107
67
  },
108
- {
109
- id: "yolov8s-relu",
110
- name: "YOLOv8 Small ReLU",
111
- description: "YOLOv8 Small with ReLU activation \u2014 better hardware compatibility",
112
- inputSize: { width: 640, height: 640 },
113
- labels: types_1.COCO_80_LABELS,
114
- formats: {
115
- onnx: {
116
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov8/onnx/camstack-yolov8s-relu.onnx"),
117
- sizeMB: 43
118
- }
119
- }
68
+ openvino: {
69
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/openvino/camstack-yolov8n.xml"),
70
+ sizeMB: 7,
71
+ runtimes: ["python"]
120
72
  },
121
- {
122
- id: "yolov8m",
123
- name: "YOLOv8 Medium",
124
- description: "YOLOv8 Medium \u2014 higher accuracy, moderate size",
125
- inputSize: { width: 640, height: 640 },
126
- labels: types_1.COCO_80_LABELS,
127
- formats: {
128
- onnx: {
129
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov8/onnx/camstack-yolov8m.onnx"),
130
- sizeMB: 99
131
- },
132
- coreml: {
133
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov8/coreml/camstack-yolov8m.mlpackage"),
134
- sizeMB: 49,
135
- isDirectory: true,
136
- files: exports2.MLPACKAGE_FILES,
137
- runtimes: ["python"]
138
- },
139
- openvino: {
140
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov8/openvino/camstack-yolov8m.xml"),
141
- sizeMB: 50,
142
- runtimes: ["python"]
143
- },
144
- tflite: {
145
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov8/tflite/camstack-yolov8m_float32.tflite"),
146
- sizeMB: 99,
147
- runtimes: ["python"]
148
- }
149
- }
73
+ tflite: {
74
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/tflite/camstack-yolov8n_float32.tflite"),
75
+ sizeMB: 12,
76
+ runtimes: ["python"]
77
+ }
78
+ }
79
+ },
80
+ {
81
+ id: "yolov8s",
82
+ name: "YOLOv8 Small",
83
+ description: "YOLOv8 Small \u2014 balanced speed and accuracy",
84
+ inputSize: { width: 640, height: 640 },
85
+ labels: import_types.COCO_80_LABELS,
86
+ formats: {
87
+ onnx: {
88
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/onnx/camstack-yolov8s.onnx"),
89
+ sizeMB: 43
150
90
  },
151
- {
152
- id: "yolov8l",
153
- name: "YOLOv8 Large",
154
- description: "YOLOv8 Large \u2014 high-accuracy large model",
155
- inputSize: { width: 640, height: 640 },
156
- labels: types_1.COCO_80_LABELS,
157
- formats: {
158
- onnx: {
159
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov8/onnx/camstack-yolov8l.onnx"),
160
- sizeMB: 167
161
- },
162
- coreml: {
163
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov8/coreml/camstack-yolov8l.mlpackage"),
164
- sizeMB: 83,
165
- isDirectory: true,
166
- files: exports2.MLPACKAGE_FILES,
167
- runtimes: ["python"]
168
- },
169
- openvino: {
170
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov8/openvino/camstack-yolov8l.xml"),
171
- sizeMB: 84,
172
- runtimes: ["python"]
173
- }
174
- }
91
+ coreml: {
92
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/coreml/camstack-yolov8s.mlpackage"),
93
+ sizeMB: 21,
94
+ isDirectory: true,
95
+ files: MLPACKAGE_FILES,
96
+ runtimes: ["python"]
175
97
  },
176
- {
177
- id: "yolov8x",
178
- name: "YOLOv8 Extra-Large",
179
- description: "YOLOv8 Extra-Large \u2014 maximum accuracy",
180
- inputSize: { width: 640, height: 640 },
181
- labels: types_1.COCO_80_LABELS,
182
- formats: {
183
- onnx: {
184
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov8/onnx/camstack-yolov8x.onnx"),
185
- sizeMB: 260
186
- },
187
- coreml: {
188
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov8/coreml/camstack-yolov8x.mlpackage"),
189
- sizeMB: 130,
190
- isDirectory: true,
191
- files: exports2.MLPACKAGE_FILES,
192
- runtimes: ["python"]
193
- },
194
- openvino: {
195
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov8/openvino/camstack-yolov8x.xml"),
196
- sizeMB: 131,
197
- runtimes: ["python"]
198
- }
199
- }
98
+ openvino: {
99
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/openvino/camstack-yolov8s.xml"),
100
+ sizeMB: 22,
101
+ runtimes: ["python"]
200
102
  },
201
- // ── YOLOv9 ──────────────────────────────────────────────────────
202
- {
203
- id: "yolov9t",
204
- name: "YOLOv9 Tiny",
205
- description: "YOLOv9 Tiny \u2014 ultra-lightweight next-gen detector",
206
- inputSize: { width: 640, height: 640 },
207
- labels: types_1.COCO_80_LABELS,
208
- formats: {
209
- onnx: {
210
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov9/onnx/camstack-yolov9t.onnx"),
211
- sizeMB: 8
212
- },
213
- coreml: {
214
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov9/coreml/camstack-yolov9t.mlpackage"),
215
- sizeMB: 4,
216
- isDirectory: true,
217
- files: exports2.MLPACKAGE_FILES,
218
- runtimes: ["python"]
219
- },
220
- openvino: {
221
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov9/openvino/camstack-yolov9t.xml"),
222
- sizeMB: 6,
223
- runtimes: ["python"]
224
- },
225
- tflite: {
226
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov9/tflite/camstack-yolov9t_float32.tflite"),
227
- sizeMB: 8,
228
- runtimes: ["python"]
229
- }
230
- }
103
+ tflite: {
104
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/tflite/camstack-yolov8s_float32.tflite"),
105
+ sizeMB: 43,
106
+ runtimes: ["python"]
107
+ }
108
+ }
109
+ },
110
+ {
111
+ id: "yolov8s-relu",
112
+ name: "YOLOv8 Small ReLU",
113
+ description: "YOLOv8 Small with ReLU activation \u2014 better hardware compatibility",
114
+ inputSize: { width: 640, height: 640 },
115
+ labels: import_types.COCO_80_LABELS,
116
+ formats: {
117
+ onnx: {
118
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/onnx/camstack-yolov8s-relu.onnx"),
119
+ sizeMB: 43
120
+ }
121
+ }
122
+ },
123
+ {
124
+ id: "yolov8m",
125
+ name: "YOLOv8 Medium",
126
+ description: "YOLOv8 Medium \u2014 higher accuracy, moderate size",
127
+ inputSize: { width: 640, height: 640 },
128
+ labels: import_types.COCO_80_LABELS,
129
+ formats: {
130
+ onnx: {
131
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/onnx/camstack-yolov8m.onnx"),
132
+ sizeMB: 99
231
133
  },
232
- {
233
- id: "yolov9s",
234
- name: "YOLOv9 Small",
235
- description: "YOLOv9 Small \u2014 improved efficiency over YOLOv8s",
236
- inputSize: { width: 640, height: 640 },
237
- labels: types_1.COCO_80_LABELS,
238
- formats: {
239
- onnx: {
240
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov9/onnx/camstack-yolov9s.onnx"),
241
- sizeMB: 28
242
- },
243
- coreml: {
244
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov9/coreml/camstack-yolov9s.mlpackage"),
245
- sizeMB: 14,
246
- isDirectory: true,
247
- files: exports2.MLPACKAGE_FILES,
248
- runtimes: ["python"]
249
- },
250
- openvino: {
251
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov9/openvino/camstack-yolov9s.xml"),
252
- sizeMB: 16,
253
- runtimes: ["python"]
254
- },
255
- tflite: {
256
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov9/tflite/camstack-yolov9s_float32.tflite"),
257
- sizeMB: 28,
258
- runtimes: ["python"]
259
- }
260
- }
134
+ coreml: {
135
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/coreml/camstack-yolov8m.mlpackage"),
136
+ sizeMB: 49,
137
+ isDirectory: true,
138
+ files: MLPACKAGE_FILES,
139
+ runtimes: ["python"]
261
140
  },
262
- {
263
- id: "yolov9c",
264
- name: "YOLOv9 C",
265
- description: "YOLOv9 C \u2014 high-accuracy compact model",
266
- inputSize: { width: 640, height: 640 },
267
- labels: types_1.COCO_80_LABELS,
268
- formats: {
269
- onnx: {
270
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov9/onnx/camstack-yolov9c.onnx"),
271
- sizeMB: 97
272
- },
273
- coreml: {
274
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov9/coreml/camstack-yolov9c.mlpackage"),
275
- sizeMB: 48,
276
- isDirectory: true,
277
- files: exports2.MLPACKAGE_FILES,
278
- runtimes: ["python"]
279
- },
280
- openvino: {
281
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov9/openvino/camstack-yolov9c.xml"),
282
- sizeMB: 49,
283
- runtimes: ["python"]
284
- },
285
- tflite: {
286
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolov9/tflite/camstack-yolov9c_float32.tflite"),
287
- sizeMB: 97,
288
- runtimes: ["python"]
289
- }
290
- }
141
+ openvino: {
142
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/openvino/camstack-yolov8m.xml"),
143
+ sizeMB: 50,
144
+ runtimes: ["python"]
291
145
  },
292
- // ── YOLO11 ────────────────────────────────────────────────────
293
- {
294
- id: "yolo11n",
295
- name: "YOLO11 Nano",
296
- description: "YOLO11 Nano \u2014 fastest, smallest YOLO11 detection model (mAP 39.5)",
297
- inputSize: { width: 640, height: 640 },
298
- labels: types_1.COCO_80_LABELS,
299
- formats: {
300
- onnx: {
301
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolo11/onnx/camstack-yolo11n.onnx"),
302
- sizeMB: 10
303
- },
304
- coreml: {
305
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolo11/coreml/camstack-yolo11n.mlpackage"),
306
- sizeMB: 5,
307
- isDirectory: true,
308
- files: exports2.MLPACKAGE_FILES,
309
- runtimes: ["python"]
310
- },
311
- openvino: {
312
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolo11/openvino/camstack-yolo11n.xml"),
313
- sizeMB: 5,
314
- runtimes: ["python"]
315
- },
316
- tflite: {
317
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolo11/tflite/camstack-yolo11n_float32.tflite"),
318
- sizeMB: 10,
319
- runtimes: ["python"]
320
- }
321
- }
146
+ tflite: {
147
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/tflite/camstack-yolov8m_float32.tflite"),
148
+ sizeMB: 99,
149
+ runtimes: ["python"]
150
+ }
151
+ }
152
+ },
153
+ {
154
+ id: "yolov8l",
155
+ name: "YOLOv8 Large",
156
+ description: "YOLOv8 Large \u2014 high-accuracy large model",
157
+ inputSize: { width: 640, height: 640 },
158
+ labels: import_types.COCO_80_LABELS,
159
+ formats: {
160
+ onnx: {
161
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/onnx/camstack-yolov8l.onnx"),
162
+ sizeMB: 167
322
163
  },
323
- {
324
- id: "yolo11s",
325
- name: "YOLO11 Small",
326
- description: "YOLO11 Small \u2014 balanced speed and accuracy (mAP 47.0)",
327
- inputSize: { width: 640, height: 640 },
328
- labels: types_1.COCO_80_LABELS,
329
- formats: {
330
- onnx: {
331
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolo11/onnx/camstack-yolo11s.onnx"),
332
- sizeMB: 36
333
- },
334
- coreml: {
335
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolo11/coreml/camstack-yolo11s.mlpackage"),
336
- sizeMB: 18,
337
- isDirectory: true,
338
- files: exports2.MLPACKAGE_FILES,
339
- runtimes: ["python"]
340
- },
341
- openvino: {
342
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolo11/openvino/camstack-yolo11s.xml"),
343
- sizeMB: 18,
344
- runtimes: ["python"]
345
- },
346
- tflite: {
347
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolo11/tflite/camstack-yolo11s_float32.tflite"),
348
- sizeMB: 36,
349
- runtimes: ["python"]
350
- }
351
- }
164
+ coreml: {
165
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/coreml/camstack-yolov8l.mlpackage"),
166
+ sizeMB: 83,
167
+ isDirectory: true,
168
+ files: MLPACKAGE_FILES,
169
+ runtimes: ["python"]
352
170
  },
353
- {
354
- id: "yolo11m",
355
- name: "YOLO11 Medium",
356
- description: "YOLO11 Medium \u2014 higher accuracy, moderate size (mAP 51.5)",
357
- inputSize: { width: 640, height: 640 },
358
- labels: types_1.COCO_80_LABELS,
359
- formats: {
360
- onnx: {
361
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolo11/onnx/camstack-yolo11m.onnx"),
362
- sizeMB: 77
363
- },
364
- coreml: {
365
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolo11/coreml/camstack-yolo11m.mlpackage"),
366
- sizeMB: 39,
367
- isDirectory: true,
368
- files: exports2.MLPACKAGE_FILES,
369
- runtimes: ["python"]
370
- },
371
- openvino: {
372
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolo11/openvino/camstack-yolo11m.xml"),
373
- sizeMB: 39,
374
- runtimes: ["python"]
375
- },
376
- tflite: {
377
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolo11/tflite/camstack-yolo11m_float32.tflite"),
378
- sizeMB: 77,
379
- runtimes: ["python"]
380
- }
381
- }
171
+ openvino: {
172
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/openvino/camstack-yolov8l.xml"),
173
+ sizeMB: 84,
174
+ runtimes: ["python"]
175
+ }
176
+ }
177
+ },
178
+ {
179
+ id: "yolov8x",
180
+ name: "YOLOv8 Extra-Large",
181
+ description: "YOLOv8 Extra-Large \u2014 maximum accuracy",
182
+ inputSize: { width: 640, height: 640 },
183
+ labels: import_types.COCO_80_LABELS,
184
+ formats: {
185
+ onnx: {
186
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/onnx/camstack-yolov8x.onnx"),
187
+ sizeMB: 260
382
188
  },
383
- {
384
- id: "yolo11l",
385
- name: "YOLO11 Large",
386
- description: "YOLO11 Large \u2014 high-accuracy large model (mAP 53.4)",
387
- inputSize: { width: 640, height: 640 },
388
- labels: types_1.COCO_80_LABELS,
389
- formats: {
390
- onnx: {
391
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolo11/onnx/camstack-yolo11l.onnx"),
392
- sizeMB: 97
393
- },
394
- coreml: {
395
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolo11/coreml/camstack-yolo11l.mlpackage"),
396
- sizeMB: 49,
397
- isDirectory: true,
398
- files: exports2.MLPACKAGE_FILES,
399
- runtimes: ["python"]
400
- },
401
- openvino: {
402
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolo11/openvino/camstack-yolo11l.xml"),
403
- sizeMB: 49,
404
- runtimes: ["python"]
405
- },
406
- tflite: {
407
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolo11/tflite/camstack-yolo11l_float32.tflite"),
408
- sizeMB: 97,
409
- runtimes: ["python"]
410
- }
411
- }
189
+ coreml: {
190
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/coreml/camstack-yolov8x.mlpackage"),
191
+ sizeMB: 130,
192
+ isDirectory: true,
193
+ files: MLPACKAGE_FILES,
194
+ runtimes: ["python"]
412
195
  },
413
- {
414
- id: "yolo11x",
415
- name: "YOLO11 Extra-Large",
416
- description: "YOLO11 Extra-Large \u2014 maximum accuracy (mAP 54.7)",
417
- inputSize: { width: 640, height: 640 },
418
- labels: types_1.COCO_80_LABELS,
419
- formats: {
420
- onnx: {
421
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolo11/onnx/camstack-yolo11x.onnx"),
422
- sizeMB: 218
423
- },
424
- coreml: {
425
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolo11/coreml/camstack-yolo11x.mlpackage"),
426
- sizeMB: 109,
427
- isDirectory: true,
428
- files: exports2.MLPACKAGE_FILES,
429
- runtimes: ["python"]
430
- },
431
- openvino: {
432
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolo11/openvino/camstack-yolo11x.xml"),
433
- sizeMB: 109,
434
- runtimes: ["python"]
435
- },
436
- tflite: {
437
- url: (0, types_1.hfModelUrl)(HF_REPO, "objectDetection/yolo11/tflite/camstack-yolo11x_float32.tflite"),
438
- sizeMB: 218,
439
- runtimes: ["python"]
440
- }
441
- }
196
+ openvino: {
197
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov8/openvino/camstack-yolov8x.xml"),
198
+ sizeMB: 131,
199
+ runtimes: ["python"]
442
200
  }
443
- ];
444
- }
445
- });
446
-
447
- // src/catalogs/plate-detection-models.js
448
- var require_plate_detection_models = __commonJS({
449
- "src/catalogs/plate-detection-models.js"(exports2) {
450
- "use strict";
451
- Object.defineProperty(exports2, "__esModule", { value: true });
452
- exports2.PLATE_DETECTION_MODELS = void 0;
453
- var types_1 = require("@camstack/types");
454
- var object_detection_models_js_1 = require_object_detection_models();
455
- var HF_REPO = "camstack/camstack-models";
456
- var PLATE_LABELS2 = [
457
- { id: "plate", name: "License Plate" }
458
- ];
459
- exports2.PLATE_DETECTION_MODELS = [
460
- {
461
- id: "yolov8n-plate",
462
- name: "YOLOv8 Nano \u2014 License Plate",
463
- description: "YOLOv8 Nano fine-tuned for license plate detection",
464
- inputSize: { width: 640, height: 640 },
465
- labels: PLATE_LABELS2,
466
- formats: {
467
- onnx: {
468
- url: (0, types_1.hfModelUrl)(HF_REPO, "plateDetection/yolov8-plate/onnx/camstack-yolov8n-plate.onnx"),
469
- sizeMB: 12
470
- },
471
- coreml: {
472
- url: (0, types_1.hfModelUrl)(HF_REPO, "plateDetection/yolov8-plate/coreml/camstack-yolov8n-plate.mlpackage"),
473
- sizeMB: 5.9,
474
- isDirectory: true,
475
- files: object_detection_models_js_1.MLPACKAGE_FILES,
476
- runtimes: ["python"]
477
- },
478
- openvino: {
479
- url: (0, types_1.hfModelUrl)(HF_REPO, "plateDetection/yolov8-plate/openvino/camstack-yolov8n-plate.xml"),
480
- sizeMB: 6.1,
481
- runtimes: ["python"]
482
- },
483
- tflite: {
484
- url: (0, types_1.hfModelUrl)(HF_REPO, "plateDetection/yolov8-plate/tflite/camstack-yolov8n-plate_float32.tflite"),
485
- sizeMB: 12,
486
- runtimes: ["python"]
487
- }
488
- }
201
+ }
202
+ },
203
+ // ── YOLOv9 ──────────────────────────────────────────────────────
204
+ {
205
+ id: "yolov9t",
206
+ name: "YOLOv9 Tiny",
207
+ description: "YOLOv9 Tiny \u2014 ultra-lightweight next-gen detector",
208
+ inputSize: { width: 640, height: 640 },
209
+ labels: import_types.COCO_80_LABELS,
210
+ formats: {
211
+ onnx: {
212
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov9/onnx/camstack-yolov9t.onnx"),
213
+ sizeMB: 8
214
+ },
215
+ coreml: {
216
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov9/coreml/camstack-yolov9t.mlpackage"),
217
+ sizeMB: 4,
218
+ isDirectory: true,
219
+ files: MLPACKAGE_FILES,
220
+ runtimes: ["python"]
221
+ },
222
+ openvino: {
223
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov9/openvino/camstack-yolov9t.xml"),
224
+ sizeMB: 6,
225
+ runtimes: ["python"]
226
+ },
227
+ tflite: {
228
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov9/tflite/camstack-yolov9t_float32.tflite"),
229
+ sizeMB: 8,
230
+ runtimes: ["python"]
489
231
  }
490
- ];
491
- }
492
- });
493
-
494
- // src/shared/image-utils.js
495
- var require_image_utils = __commonJS({
496
- "src/shared/image-utils.js"(exports2) {
497
- "use strict";
498
- var __importDefault = exports2 && exports2.__importDefault || function(mod) {
499
- return mod && mod.__esModule ? mod : { "default": mod };
500
- };
501
- Object.defineProperty(exports2, "__esModule", { value: true });
502
- exports2.jpegToRgb = jpegToRgb;
503
- exports2.cropRegion = cropRegion2;
504
- exports2.letterbox = letterbox2;
505
- exports2.resizeAndNormalize = resizeAndNormalize;
506
- exports2.rgbToGrayscale = rgbToGrayscale;
507
- var sharp_1 = __importDefault(require("sharp"));
508
- async function jpegToRgb(jpeg) {
509
- const { data, info } = await (0, sharp_1.default)(jpeg).removeAlpha().raw().toBuffer({ resolveWithObject: true });
510
- return { data, width: info.width, height: info.height };
511
232
  }
512
- async function cropRegion2(jpeg, roi) {
513
- return (0, sharp_1.default)(jpeg).extract({
514
- left: Math.round(roi.x),
515
- top: Math.round(roi.y),
516
- width: Math.round(roi.w),
517
- height: Math.round(roi.h)
518
- }).jpeg().toBuffer();
233
+ },
234
+ {
235
+ id: "yolov9s",
236
+ name: "YOLOv9 Small",
237
+ description: "YOLOv9 Small \u2014 improved efficiency over YOLOv8s",
238
+ inputSize: { width: 640, height: 640 },
239
+ labels: import_types.COCO_80_LABELS,
240
+ formats: {
241
+ onnx: {
242
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov9/onnx/camstack-yolov9s.onnx"),
243
+ sizeMB: 28
244
+ },
245
+ coreml: {
246
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov9/coreml/camstack-yolov9s.mlpackage"),
247
+ sizeMB: 14,
248
+ isDirectory: true,
249
+ files: MLPACKAGE_FILES,
250
+ runtimes: ["python"]
251
+ },
252
+ openvino: {
253
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov9/openvino/camstack-yolov9s.xml"),
254
+ sizeMB: 16,
255
+ runtimes: ["python"]
256
+ },
257
+ tflite: {
258
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov9/tflite/camstack-yolov9s_float32.tflite"),
259
+ sizeMB: 28,
260
+ runtimes: ["python"]
261
+ }
519
262
  }
520
- async function letterbox2(jpeg, targetSize) {
521
- const meta = await (0, sharp_1.default)(jpeg).metadata();
522
- const originalWidth = meta.width ?? 0;
523
- const originalHeight = meta.height ?? 0;
524
- const scale = Math.min(targetSize / originalWidth, targetSize / originalHeight);
525
- const scaledWidth = Math.round(originalWidth * scale);
526
- const scaledHeight = Math.round(originalHeight * scale);
527
- const padX = Math.floor((targetSize - scaledWidth) / 2);
528
- const padY = Math.floor((targetSize - scaledHeight) / 2);
529
- const { data } = await (0, sharp_1.default)(jpeg).resize(scaledWidth, scaledHeight).extend({
530
- top: padY,
531
- bottom: targetSize - scaledHeight - padY,
532
- left: padX,
533
- right: targetSize - scaledWidth - padX,
534
- background: { r: 114, g: 114, b: 114 }
535
- }).removeAlpha().raw().toBuffer({ resolveWithObject: true });
536
- const numPixels = targetSize * targetSize;
537
- const float32 = new Float32Array(3 * numPixels);
538
- for (let i = 0; i < numPixels; i++) {
539
- const srcBase = i * 3;
540
- float32[0 * numPixels + i] = data[srcBase] / 255;
541
- float32[1 * numPixels + i] = data[srcBase + 1] / 255;
542
- float32[2 * numPixels + i] = data[srcBase + 2] / 255;
263
+ },
264
+ {
265
+ id: "yolov9c",
266
+ name: "YOLOv9 C",
267
+ description: "YOLOv9 C \u2014 high-accuracy compact model",
268
+ inputSize: { width: 640, height: 640 },
269
+ labels: import_types.COCO_80_LABELS,
270
+ formats: {
271
+ onnx: {
272
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov9/onnx/camstack-yolov9c.onnx"),
273
+ sizeMB: 97
274
+ },
275
+ coreml: {
276
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov9/coreml/camstack-yolov9c.mlpackage"),
277
+ sizeMB: 48,
278
+ isDirectory: true,
279
+ files: MLPACKAGE_FILES,
280
+ runtimes: ["python"]
281
+ },
282
+ openvino: {
283
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov9/openvino/camstack-yolov9c.xml"),
284
+ sizeMB: 49,
285
+ runtimes: ["python"]
286
+ },
287
+ tflite: {
288
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolov9/tflite/camstack-yolov9c_float32.tflite"),
289
+ sizeMB: 97,
290
+ runtimes: ["python"]
543
291
  }
544
- return { data: float32, scale, padX, padY, originalWidth, originalHeight };
545
292
  }
546
- async function resizeAndNormalize(jpeg, targetWidth, targetHeight, normalization, layout) {
547
- const { data } = await (0, sharp_1.default)(jpeg).resize(targetWidth, targetHeight, { fit: "fill" }).removeAlpha().raw().toBuffer({ resolveWithObject: true });
548
- const numPixels = targetWidth * targetHeight;
549
- const float32 = new Float32Array(3 * numPixels);
550
- const mean = [0.485, 0.456, 0.406];
551
- const std = [0.229, 0.224, 0.225];
552
- if (layout === "nchw") {
553
- for (let i = 0; i < numPixels; i++) {
554
- const srcBase = i * 3;
555
- for (let c = 0; c < 3; c++) {
556
- const raw = data[srcBase + c] / 255;
557
- let val;
558
- if (normalization === "zero-one") {
559
- val = raw;
560
- } else if (normalization === "imagenet") {
561
- val = (raw - mean[c]) / std[c];
562
- } else {
563
- val = data[srcBase + c];
564
- }
565
- float32[c * numPixels + i] = val;
566
- }
567
- }
568
- } else {
569
- for (let i = 0; i < numPixels; i++) {
570
- const srcBase = i * 3;
571
- for (let c = 0; c < 3; c++) {
572
- const raw = data[srcBase + c] / 255;
573
- let val;
574
- if (normalization === "zero-one") {
575
- val = raw;
576
- } else if (normalization === "imagenet") {
577
- val = (raw - mean[c]) / std[c];
578
- } else {
579
- val = data[srcBase + c];
580
- }
581
- float32[i * 3 + c] = val;
582
- }
583
- }
293
+ },
294
+ // ── YOLO11 ────────────────────────────────────────────────────
295
+ {
296
+ id: "yolo11n",
297
+ name: "YOLO11 Nano",
298
+ description: "YOLO11 Nano \u2014 fastest, smallest YOLO11 detection model (mAP 39.5)",
299
+ inputSize: { width: 640, height: 640 },
300
+ labels: import_types.COCO_80_LABELS,
301
+ formats: {
302
+ onnx: {
303
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/onnx/camstack-yolo11n.onnx"),
304
+ sizeMB: 10
305
+ },
306
+ coreml: {
307
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/coreml/camstack-yolo11n.mlpackage"),
308
+ sizeMB: 5,
309
+ isDirectory: true,
310
+ files: MLPACKAGE_FILES,
311
+ runtimes: ["python"]
312
+ },
313
+ openvino: {
314
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/openvino/camstack-yolo11n.xml"),
315
+ sizeMB: 5,
316
+ runtimes: ["python"]
317
+ },
318
+ tflite: {
319
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/tflite/camstack-yolo11n_float32.tflite"),
320
+ sizeMB: 10,
321
+ runtimes: ["python"]
584
322
  }
585
- return float32;
586
323
  }
587
- function rgbToGrayscale(rgb, width, height) {
588
- const numPixels = width * height;
589
- const gray = new Uint8Array(numPixels);
590
- for (let i = 0; i < numPixels; i++) {
591
- const r = rgb[i * 3];
592
- const g = rgb[i * 3 + 1];
593
- const b = rgb[i * 3 + 2];
594
- gray[i] = Math.round(0.299 * r + 0.587 * g + 0.114 * b);
324
+ },
325
+ {
326
+ id: "yolo11s",
327
+ name: "YOLO11 Small",
328
+ description: "YOLO11 Small \u2014 balanced speed and accuracy (mAP 47.0)",
329
+ inputSize: { width: 640, height: 640 },
330
+ labels: import_types.COCO_80_LABELS,
331
+ formats: {
332
+ onnx: {
333
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/onnx/camstack-yolo11s.onnx"),
334
+ sizeMB: 36
335
+ },
336
+ coreml: {
337
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/coreml/camstack-yolo11s.mlpackage"),
338
+ sizeMB: 18,
339
+ isDirectory: true,
340
+ files: MLPACKAGE_FILES,
341
+ runtimes: ["python"]
342
+ },
343
+ openvino: {
344
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/openvino/camstack-yolo11s.xml"),
345
+ sizeMB: 18,
346
+ runtimes: ["python"]
347
+ },
348
+ tflite: {
349
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/tflite/camstack-yolo11s_float32.tflite"),
350
+ sizeMB: 36,
351
+ runtimes: ["python"]
595
352
  }
596
- return gray;
597
353
  }
598
- }
599
- });
600
-
601
- // src/shared/postprocess/yolo.js
602
- var require_yolo = __commonJS({
603
- "src/shared/postprocess/yolo.js"(exports2) {
604
- "use strict";
605
- Object.defineProperty(exports2, "__esModule", { value: true });
606
- exports2.iou = iou;
607
- exports2.nms = nms;
608
- exports2.yoloPostprocess = yoloPostprocess2;
609
- function iou(a, b) {
610
- const ax1 = a.x;
611
- const ay1 = a.y;
612
- const ax2 = a.x + a.w;
613
- const ay2 = a.y + a.h;
614
- const bx1 = b.x;
615
- const by1 = b.y;
616
- const bx2 = b.x + b.w;
617
- const by2 = b.y + b.h;
618
- const interX1 = Math.max(ax1, bx1);
619
- const interY1 = Math.max(ay1, by1);
620
- const interX2 = Math.min(ax2, bx2);
621
- const interY2 = Math.min(ay2, by2);
622
- const interW = Math.max(0, interX2 - interX1);
623
- const interH = Math.max(0, interY2 - interY1);
624
- const interArea = interW * interH;
625
- if (interArea === 0)
626
- return 0;
627
- const areaA = a.w * a.h;
628
- const areaB = b.w * b.h;
629
- const unionArea = areaA + areaB - interArea;
630
- return unionArea === 0 ? 0 : interArea / unionArea;
354
+ },
355
+ {
356
+ id: "yolo11m",
357
+ name: "YOLO11 Medium",
358
+ description: "YOLO11 Medium \u2014 higher accuracy, moderate size (mAP 51.5)",
359
+ inputSize: { width: 640, height: 640 },
360
+ labels: import_types.COCO_80_LABELS,
361
+ formats: {
362
+ onnx: {
363
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/onnx/camstack-yolo11m.onnx"),
364
+ sizeMB: 77
365
+ },
366
+ coreml: {
367
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/coreml/camstack-yolo11m.mlpackage"),
368
+ sizeMB: 39,
369
+ isDirectory: true,
370
+ files: MLPACKAGE_FILES,
371
+ runtimes: ["python"]
372
+ },
373
+ openvino: {
374
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/openvino/camstack-yolo11m.xml"),
375
+ sizeMB: 39,
376
+ runtimes: ["python"]
377
+ },
378
+ tflite: {
379
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/tflite/camstack-yolo11m_float32.tflite"),
380
+ sizeMB: 77,
381
+ runtimes: ["python"]
382
+ }
631
383
  }
632
- function nms(boxes, iouThreshold) {
633
- const indices = boxes.map((_, i) => i).sort((a, b) => boxes[b].score - boxes[a].score);
634
- const kept = [];
635
- const suppressed = /* @__PURE__ */ new Set();
636
- for (const idx of indices) {
637
- if (suppressed.has(idx))
638
- continue;
639
- kept.push(idx);
640
- for (const other of indices) {
641
- if (other === idx || suppressed.has(other))
642
- continue;
643
- if (iou(boxes[idx].bbox, boxes[other].bbox) > iouThreshold) {
644
- suppressed.add(other);
645
- }
646
- }
384
+ },
385
+ {
386
+ id: "yolo11l",
387
+ name: "YOLO11 Large",
388
+ description: "YOLO11 Large \u2014 high-accuracy large model (mAP 53.4)",
389
+ inputSize: { width: 640, height: 640 },
390
+ labels: import_types.COCO_80_LABELS,
391
+ formats: {
392
+ onnx: {
393
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/onnx/camstack-yolo11l.onnx"),
394
+ sizeMB: 97
395
+ },
396
+ coreml: {
397
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/coreml/camstack-yolo11l.mlpackage"),
398
+ sizeMB: 49,
399
+ isDirectory: true,
400
+ files: MLPACKAGE_FILES,
401
+ runtimes: ["python"]
402
+ },
403
+ openvino: {
404
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/openvino/camstack-yolo11l.xml"),
405
+ sizeMB: 49,
406
+ runtimes: ["python"]
407
+ },
408
+ tflite: {
409
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/tflite/camstack-yolo11l_float32.tflite"),
410
+ sizeMB: 97,
411
+ runtimes: ["python"]
647
412
  }
648
- return kept;
649
413
  }
650
- function yoloPostprocess2(output, numClasses, numBoxes, options) {
651
- const { confidence, iouThreshold, labels, scale, padX, padY, originalWidth, originalHeight } = options;
652
- const candidates = [];
653
- for (let i = 0; i < numBoxes; i++) {
654
- const cx = output[0 * numBoxes + i];
655
- const cy = output[1 * numBoxes + i];
656
- const w = output[2 * numBoxes + i];
657
- const h = output[3 * numBoxes + i];
658
- let bestScore = -Infinity;
659
- let bestClass = 0;
660
- for (let j = 0; j < numClasses; j++) {
661
- const score = output[(4 + j) * numBoxes + i];
662
- if (score > bestScore) {
663
- bestScore = score;
664
- bestClass = j;
665
- }
666
- }
667
- if (bestScore < confidence)
668
- continue;
669
- const bbox = {
670
- x: cx - w / 2,
671
- y: cy - h / 2,
672
- w,
673
- h
674
- };
675
- candidates.push({ bbox, score: bestScore, classIdx: bestClass });
414
+ },
415
+ {
416
+ id: "yolo11x",
417
+ name: "YOLO11 Extra-Large",
418
+ description: "YOLO11 Extra-Large \u2014 maximum accuracy (mAP 54.7)",
419
+ inputSize: { width: 640, height: 640 },
420
+ labels: import_types.COCO_80_LABELS,
421
+ formats: {
422
+ onnx: {
423
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/onnx/camstack-yolo11x.onnx"),
424
+ sizeMB: 218
425
+ },
426
+ coreml: {
427
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/coreml/camstack-yolo11x.mlpackage"),
428
+ sizeMB: 109,
429
+ isDirectory: true,
430
+ files: MLPACKAGE_FILES,
431
+ runtimes: ["python"]
432
+ },
433
+ openvino: {
434
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/openvino/camstack-yolo11x.xml"),
435
+ sizeMB: 109,
436
+ runtimes: ["python"]
437
+ },
438
+ tflite: {
439
+ url: (0, import_types.hfModelUrl)(HF_REPO, "objectDetection/yolo11/tflite/camstack-yolo11x_float32.tflite"),
440
+ sizeMB: 218,
441
+ runtimes: ["python"]
676
442
  }
677
- if (candidates.length === 0)
678
- return [];
679
- const keptIndices = nms(candidates, iouThreshold);
680
- return keptIndices.map((idx) => {
681
- const { bbox, score, classIdx } = candidates[idx];
682
- const label = labels[classIdx] ?? String(classIdx);
683
- const x = Math.max(0, Math.min(originalWidth, (bbox.x - padX) / scale));
684
- const y = Math.max(0, Math.min(originalHeight, (bbox.y - padY) / scale));
685
- const x2 = Math.max(0, Math.min(originalWidth, (bbox.x + bbox.w - padX) / scale));
686
- const y2 = Math.max(0, Math.min(originalHeight, (bbox.y + bbox.h - padY) / scale));
687
- const finalBbox = { x, y, w: x2 - x, h: y2 - y };
688
- return {
689
- class: label,
690
- originalClass: label,
691
- score,
692
- bbox: finalBbox
693
- };
694
- });
695
443
  }
696
444
  }
697
- });
445
+ ];
698
446
 
699
- // src/shared/node-engine.js
700
- var require_node_engine = __commonJS({
701
- "src/shared/node-engine.js"(exports2) {
702
- "use strict";
703
- var __createBinding = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {
704
- if (k2 === void 0) k2 = k;
705
- var desc = Object.getOwnPropertyDescriptor(m, k);
706
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
707
- desc = { enumerable: true, get: function() {
708
- return m[k];
709
- } };
710
- }
711
- Object.defineProperty(o, k2, desc);
712
- }) : (function(o, m, k, k2) {
713
- if (k2 === void 0) k2 = k;
714
- o[k2] = m[k];
715
- }));
716
- var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? (function(o, v) {
717
- Object.defineProperty(o, "default", { enumerable: true, value: v });
718
- }) : function(o, v) {
719
- o["default"] = v;
720
- });
721
- var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ (function() {
722
- var ownKeys = function(o) {
723
- ownKeys = Object.getOwnPropertyNames || function(o2) {
724
- var ar = [];
725
- for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
726
- return ar;
727
- };
728
- return ownKeys(o);
729
- };
730
- return function(mod) {
731
- if (mod && mod.__esModule) return mod;
732
- var result = {};
733
- if (mod != null) {
734
- for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
735
- }
736
- __setModuleDefault(result, mod);
737
- return result;
738
- };
739
- })();
740
- Object.defineProperty(exports2, "__esModule", { value: true });
741
- exports2.NodeInferenceEngine = void 0;
742
- var path = __importStar(require("path"));
743
- var BACKEND_TO_PROVIDER = {
744
- cpu: "cpu",
745
- coreml: "coreml",
746
- cuda: "cuda",
747
- tensorrt: "tensorrt",
748
- dml: "dml"
749
- };
750
- var BACKEND_TO_DEVICE = {
751
- cpu: "cpu",
752
- coreml: "gpu-mps",
753
- cuda: "gpu-cuda",
754
- tensorrt: "tensorrt"
755
- };
756
- var NodeInferenceEngine = class {
757
- modelPath;
758
- backend;
759
- runtime = "onnx";
760
- device;
761
- session = null;
762
- constructor(modelPath, backend) {
763
- this.modelPath = modelPath;
764
- this.backend = backend;
765
- this.device = BACKEND_TO_DEVICE[backend] ?? "cpu";
766
- }
767
- async initialize() {
768
- const ort = await Promise.resolve().then(() => __importStar(require("onnxruntime-node")));
769
- const provider = BACKEND_TO_PROVIDER[this.backend] ?? "cpu";
770
- const absModelPath = path.isAbsolute(this.modelPath) ? this.modelPath : path.resolve(process.cwd(), this.modelPath);
771
- const sessionOptions = {
772
- executionProviders: [provider]
773
- };
774
- this.session = await ort.InferenceSession.create(absModelPath, sessionOptions);
775
- }
776
- async run(input, inputShape) {
777
- if (!this.session) {
778
- throw new Error("NodeInferenceEngine: not initialized \u2014 call initialize() first");
779
- }
780
- const ort = await Promise.resolve().then(() => __importStar(require("onnxruntime-node")));
781
- const sess = this.session;
782
- const inputName = sess.inputNames[0];
783
- const tensor = new ort.Tensor("float32", input, [...inputShape]);
784
- const feeds = { [inputName]: tensor };
785
- const results = await sess.run(feeds);
786
- const outputName = sess.outputNames[0];
787
- const outputTensor = results[outputName];
788
- return outputTensor.data;
447
+ // src/catalogs/plate-detection-models.ts
448
+ var HF_REPO2 = "camstack/camstack-models";
449
+ var PLATE_LABELS = [
450
+ { id: "plate", name: "License Plate" }
451
+ ];
452
+ var PLATE_DETECTION_MODELS = [
453
+ {
454
+ id: "yolov8n-plate",
455
+ name: "YOLOv8 Nano \u2014 License Plate",
456
+ description: "YOLOv8 Nano fine-tuned for license plate detection",
457
+ inputSize: { width: 640, height: 640 },
458
+ labels: PLATE_LABELS,
459
+ formats: {
460
+ onnx: {
461
+ url: (0, import_types2.hfModelUrl)(HF_REPO2, "plateDetection/yolov8-plate/onnx/camstack-yolov8n-plate.onnx"),
462
+ sizeMB: 12
463
+ },
464
+ coreml: {
465
+ url: (0, import_types2.hfModelUrl)(HF_REPO2, "plateDetection/yolov8-plate/coreml/camstack-yolov8n-plate.mlpackage"),
466
+ sizeMB: 5.9,
467
+ isDirectory: true,
468
+ files: MLPACKAGE_FILES,
469
+ runtimes: ["python"]
470
+ },
471
+ openvino: {
472
+ url: (0, import_types2.hfModelUrl)(HF_REPO2, "plateDetection/yolov8-plate/openvino/camstack-yolov8n-plate.xml"),
473
+ sizeMB: 6.1,
474
+ runtimes: ["python"]
475
+ },
476
+ tflite: {
477
+ url: (0, import_types2.hfModelUrl)(HF_REPO2, "plateDetection/yolov8-plate/tflite/camstack-yolov8n-plate_float32.tflite"),
478
+ sizeMB: 12,
479
+ runtimes: ["python"]
789
480
  }
790
- async runMultiOutput(input, inputShape) {
791
- if (!this.session) {
792
- throw new Error("NodeInferenceEngine: not initialized \u2014 call initialize() first");
793
- }
794
- const ort = await Promise.resolve().then(() => __importStar(require("onnxruntime-node")));
795
- const sess = this.session;
796
- const inputName = sess.inputNames[0];
797
- const tensor = new ort.Tensor("float32", input, [...inputShape]);
798
- const feeds = { [inputName]: tensor };
799
- const results = await sess.run(feeds);
800
- const out = {};
801
- for (const name of sess.outputNames) {
802
- out[name] = results[name].data;
803
- }
804
- return out;
481
+ }
482
+ }
483
+ ];
484
+
485
+ // src/shared/image-utils.ts
486
+ var import_sharp = __toESM(require("sharp"));
487
+ async function cropRegion(jpeg, roi) {
488
+ return (0, import_sharp.default)(jpeg).extract({
489
+ left: Math.round(roi.x),
490
+ top: Math.round(roi.y),
491
+ width: Math.round(roi.w),
492
+ height: Math.round(roi.h)
493
+ }).jpeg().toBuffer();
494
+ }
495
+ async function letterbox(jpeg, targetSize) {
496
+ const meta = await (0, import_sharp.default)(jpeg).metadata();
497
+ const originalWidth = meta.width ?? 0;
498
+ const originalHeight = meta.height ?? 0;
499
+ const scale = Math.min(targetSize / originalWidth, targetSize / originalHeight);
500
+ const scaledWidth = Math.round(originalWidth * scale);
501
+ const scaledHeight = Math.round(originalHeight * scale);
502
+ const padX = Math.floor((targetSize - scaledWidth) / 2);
503
+ const padY = Math.floor((targetSize - scaledHeight) / 2);
504
+ const { data } = await (0, import_sharp.default)(jpeg).resize(scaledWidth, scaledHeight).extend({
505
+ top: padY,
506
+ bottom: targetSize - scaledHeight - padY,
507
+ left: padX,
508
+ right: targetSize - scaledWidth - padX,
509
+ background: { r: 114, g: 114, b: 114 }
510
+ }).removeAlpha().raw().toBuffer({ resolveWithObject: true });
511
+ const numPixels = targetSize * targetSize;
512
+ const float32 = new Float32Array(3 * numPixels);
513
+ for (let i = 0; i < numPixels; i++) {
514
+ const srcBase = i * 3;
515
+ float32[0 * numPixels + i] = data[srcBase] / 255;
516
+ float32[1 * numPixels + i] = data[srcBase + 1] / 255;
517
+ float32[2 * numPixels + i] = data[srcBase + 2] / 255;
518
+ }
519
+ return { data: float32, scale, padX, padY, originalWidth, originalHeight };
520
+ }
521
+
522
+ // src/shared/postprocess/yolo.ts
523
+ function iou(a, b) {
524
+ const ax1 = a.x;
525
+ const ay1 = a.y;
526
+ const ax2 = a.x + a.w;
527
+ const ay2 = a.y + a.h;
528
+ const bx1 = b.x;
529
+ const by1 = b.y;
530
+ const bx2 = b.x + b.w;
531
+ const by2 = b.y + b.h;
532
+ const interX1 = Math.max(ax1, bx1);
533
+ const interY1 = Math.max(ay1, by1);
534
+ const interX2 = Math.min(ax2, bx2);
535
+ const interY2 = Math.min(ay2, by2);
536
+ const interW = Math.max(0, interX2 - interX1);
537
+ const interH = Math.max(0, interY2 - interY1);
538
+ const interArea = interW * interH;
539
+ if (interArea === 0) return 0;
540
+ const areaA = a.w * a.h;
541
+ const areaB = b.w * b.h;
542
+ const unionArea = areaA + areaB - interArea;
543
+ return unionArea === 0 ? 0 : interArea / unionArea;
544
+ }
545
+ function nms(boxes, iouThreshold) {
546
+ const indices = boxes.map((_, i) => i).sort((a, b) => boxes[b].score - boxes[a].score);
547
+ const kept = [];
548
+ const suppressed = /* @__PURE__ */ new Set();
549
+ for (const idx of indices) {
550
+ if (suppressed.has(idx)) continue;
551
+ kept.push(idx);
552
+ for (const other of indices) {
553
+ if (other === idx || suppressed.has(other)) continue;
554
+ if (iou(boxes[idx].bbox, boxes[other].bbox) > iouThreshold) {
555
+ suppressed.add(other);
805
556
  }
806
- async dispose() {
807
- this.session = null;
557
+ }
558
+ }
559
+ return kept;
560
+ }
561
+ function yoloPostprocess(output, numClasses, numBoxes, options) {
562
+ const { confidence, iouThreshold, labels, scale, padX, padY, originalWidth, originalHeight } = options;
563
+ const candidates = [];
564
+ for (let i = 0; i < numBoxes; i++) {
565
+ const cx = output[0 * numBoxes + i];
566
+ const cy = output[1 * numBoxes + i];
567
+ const w = output[2 * numBoxes + i];
568
+ const h = output[3 * numBoxes + i];
569
+ let bestScore = -Infinity;
570
+ let bestClass = 0;
571
+ for (let j = 0; j < numClasses; j++) {
572
+ const score = output[(4 + j) * numBoxes + i];
573
+ if (score > bestScore) {
574
+ bestScore = score;
575
+ bestClass = j;
808
576
  }
577
+ }
578
+ if (bestScore < confidence) continue;
579
+ const bbox = {
580
+ x: cx - w / 2,
581
+ y: cy - h / 2,
582
+ w,
583
+ h
809
584
  };
810
- exports2.NodeInferenceEngine = NodeInferenceEngine;
585
+ candidates.push({ bbox, score: bestScore, classIdx: bestClass });
811
586
  }
812
- });
587
+ if (candidates.length === 0) return [];
588
+ const keptIndices = nms(candidates, iouThreshold);
589
+ return keptIndices.map((idx) => {
590
+ const { bbox, score, classIdx } = candidates[idx];
591
+ const label = labels[classIdx] ?? String(classIdx);
592
+ const x = Math.max(0, Math.min(originalWidth, (bbox.x - padX) / scale));
593
+ const y = Math.max(0, Math.min(originalHeight, (bbox.y - padY) / scale));
594
+ const x2 = Math.max(0, Math.min(originalWidth, (bbox.x + bbox.w - padX) / scale));
595
+ const y2 = Math.max(0, Math.min(originalHeight, (bbox.y + bbox.h - padY) / scale));
596
+ const finalBbox = { x, y, w: x2 - x, h: y2 - y };
597
+ return {
598
+ class: label,
599
+ originalClass: label,
600
+ score,
601
+ bbox: finalBbox
602
+ };
603
+ });
604
+ }
813
605
 
814
- // src/shared/python-engine.js
815
- var require_python_engine = __commonJS({
816
- "src/shared/python-engine.js"(exports2) {
817
- "use strict";
818
- Object.defineProperty(exports2, "__esModule", { value: true });
819
- exports2.PythonInferenceEngine = void 0;
820
- exports2.resolvePythonBinary = resolvePythonBinary;
821
- var node_child_process_1 = require("child_process");
822
- var PythonInferenceEngine = class {
823
- pythonPath;
824
- scriptPath;
825
- modelPath;
826
- extraArgs;
827
- runtime;
828
- device;
829
- process = null;
830
- receiveBuffer = Buffer.alloc(0);
831
- pendingResolve = null;
832
- pendingReject = null;
833
- constructor(pythonPath, scriptPath, runtime, modelPath, extraArgs = []) {
834
- this.pythonPath = pythonPath;
835
- this.scriptPath = scriptPath;
836
- this.modelPath = modelPath;
837
- this.extraArgs = extraArgs;
838
- this.runtime = runtime;
839
- const runtimeDeviceMap = {
840
- onnx: "cpu",
841
- coreml: "gpu-mps",
842
- pytorch: "cpu",
843
- openvino: "cpu",
844
- tflite: "cpu"
845
- };
846
- this.device = runtimeDeviceMap[runtime];
847
- }
848
- async initialize() {
849
- const args = [this.scriptPath, this.modelPath, ...this.extraArgs];
850
- this.process = (0, node_child_process_1.spawn)(this.pythonPath, args, {
851
- stdio: ["pipe", "pipe", "pipe"]
852
- });
853
- if (!this.process.stdout || !this.process.stdin) {
854
- throw new Error("PythonInferenceEngine: failed to create process pipes");
855
- }
856
- this.process.stderr?.on("data", (chunk) => {
857
- process.stderr.write(`[python-engine] ${chunk.toString()}`);
858
- });
859
- this.process.on("error", (err) => {
860
- this.pendingReject?.(err);
861
- this.pendingReject = null;
862
- this.pendingResolve = null;
863
- });
864
- this.process.on("exit", (code) => {
865
- if (code !== 0) {
866
- const err = new Error(`PythonInferenceEngine: process exited with code ${code}`);
867
- this.pendingReject?.(err);
868
- this.pendingReject = null;
869
- this.pendingResolve = null;
870
- }
871
- });
872
- this.process.stdout.on("data", (chunk) => {
873
- this.receiveBuffer = Buffer.concat([this.receiveBuffer, chunk]);
874
- this._tryReceive();
875
- });
876
- await new Promise((resolve, reject) => {
877
- const timeout = setTimeout(() => resolve(), 2e3);
878
- this.process?.on("error", (err) => {
879
- clearTimeout(timeout);
880
- reject(err);
881
- });
882
- this.process?.on("exit", (code) => {
883
- clearTimeout(timeout);
884
- if (code !== 0) {
885
- reject(new Error(`PythonInferenceEngine: process exited early with code ${code}`));
886
- }
887
- });
888
- });
889
- }
890
- _tryReceive() {
891
- if (this.receiveBuffer.length < 4)
892
- return;
893
- const length = this.receiveBuffer.readUInt32LE(0);
894
- if (this.receiveBuffer.length < 4 + length)
895
- return;
896
- const jsonBytes = this.receiveBuffer.subarray(4, 4 + length);
897
- this.receiveBuffer = this.receiveBuffer.subarray(4 + length);
898
- const resolve = this.pendingResolve;
899
- const reject = this.pendingReject;
900
- this.pendingResolve = null;
901
- this.pendingReject = null;
902
- if (!resolve)
903
- return;
904
- try {
905
- const parsed = JSON.parse(jsonBytes.toString("utf8"));
906
- resolve(parsed);
907
- } catch (err) {
908
- reject?.(err instanceof Error ? err : new Error(String(err)));
909
- }
910
- }
911
- /** Send JPEG buffer, receive JSON detection results */
912
- async runJpeg(jpeg) {
913
- if (!this.process?.stdin) {
914
- throw new Error("PythonInferenceEngine: process not initialized");
915
- }
916
- return new Promise((resolve, reject) => {
917
- this.pendingResolve = resolve;
918
- this.pendingReject = reject;
919
- const lengthBuf = Buffer.allocUnsafe(4);
920
- lengthBuf.writeUInt32LE(jpeg.length, 0);
921
- this.process.stdin.write(Buffer.concat([lengthBuf, jpeg]));
922
- });
923
- }
924
- /** IInferenceEngine.run — wraps runJpeg for compatibility */
925
- async run(_input, _inputShape) {
926
- throw new Error("PythonInferenceEngine: use runJpeg() directly \u2014 this engine operates on JPEG input");
927
- }
928
- /** IInferenceEngine.runMultiOutput — not supported by Python engine (operates on JPEG input) */
929
- async runMultiOutput(_input, _inputShape) {
930
- throw new Error("PythonInferenceEngine: runMultiOutput() is not supported \u2014 this engine operates on JPEG input");
931
- }
932
- async dispose() {
933
- if (this.process) {
934
- this.process.stdin?.end();
935
- this.process.kill("SIGTERM");
936
- this.process = null;
937
- }
938
- }
606
+ // src/shared/engine-resolver.ts
607
+ var fs = __toESM(require("fs"));
608
+ var path2 = __toESM(require("path"));
609
+
610
+ // src/shared/node-engine.ts
611
+ var path = __toESM(require("path"));
612
+ var BACKEND_TO_PROVIDER = {
613
+ cpu: "cpu",
614
+ coreml: "coreml",
615
+ cuda: "cuda",
616
+ tensorrt: "tensorrt",
617
+ dml: "dml"
618
+ };
619
+ var BACKEND_TO_DEVICE = {
620
+ cpu: "cpu",
621
+ coreml: "gpu-mps",
622
+ cuda: "gpu-cuda",
623
+ tensorrt: "tensorrt"
624
+ };
625
+ var NodeInferenceEngine = class {
626
+ constructor(modelPath, backend) {
627
+ this.modelPath = modelPath;
628
+ this.backend = backend;
629
+ this.device = BACKEND_TO_DEVICE[backend] ?? "cpu";
630
+ }
631
+ runtime = "onnx";
632
+ device;
633
+ session = null;
634
+ async initialize() {
635
+ const ort = await import("onnxruntime-node");
636
+ const provider = BACKEND_TO_PROVIDER[this.backend] ?? "cpu";
637
+ const absModelPath = path.isAbsolute(this.modelPath) ? this.modelPath : path.resolve(process.cwd(), this.modelPath);
638
+ const sessionOptions = {
639
+ executionProviders: [provider]
939
640
  };
940
- exports2.PythonInferenceEngine = PythonInferenceEngine;
941
- async function resolvePythonBinary(configPath, deps) {
942
- if (configPath)
943
- return configPath;
944
- return deps.ensurePython();
641
+ this.session = await ort.InferenceSession.create(absModelPath, sessionOptions);
642
+ }
643
+ async run(input, inputShape) {
644
+ if (!this.session) {
645
+ throw new Error("NodeInferenceEngine: not initialized \u2014 call initialize() first");
945
646
  }
647
+ const ort = await import("onnxruntime-node");
648
+ const sess = this.session;
649
+ const inputName = sess.inputNames[0];
650
+ const tensor = new ort.Tensor("float32", input, [...inputShape]);
651
+ const feeds = { [inputName]: tensor };
652
+ const results = await sess.run(feeds);
653
+ const outputName = sess.outputNames[0];
654
+ const outputTensor = results[outputName];
655
+ return outputTensor.data;
946
656
  }
947
- });
657
+ async runMultiOutput(input, inputShape) {
658
+ if (!this.session) {
659
+ throw new Error("NodeInferenceEngine: not initialized \u2014 call initialize() first");
660
+ }
661
+ const ort = await import("onnxruntime-node");
662
+ const sess = this.session;
663
+ const inputName = sess.inputNames[0];
664
+ const tensor = new ort.Tensor("float32", input, [...inputShape]);
665
+ const feeds = { [inputName]: tensor };
666
+ const results = await sess.run(feeds);
667
+ const out = {};
668
+ for (const name of sess.outputNames) {
669
+ out[name] = results[name].data;
670
+ }
671
+ return out;
672
+ }
673
+ async dispose() {
674
+ this.session = null;
675
+ }
676
+ };
948
677
 
949
- // src/shared/engine-resolver.js
950
- var require_engine_resolver = __commonJS({
951
- "src/shared/engine-resolver.js"(exports2) {
952
- "use strict";
953
- var __createBinding = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {
954
- if (k2 === void 0) k2 = k;
955
- var desc = Object.getOwnPropertyDescriptor(m, k);
956
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
957
- desc = { enumerable: true, get: function() {
958
- return m[k];
959
- } };
678
+ // src/shared/python-engine.ts
679
+ var import_node_child_process = require("child_process");
680
+ var PythonInferenceEngine = class {
681
+ constructor(pythonPath, scriptPath, runtime, modelPath, extraArgs = []) {
682
+ this.pythonPath = pythonPath;
683
+ this.scriptPath = scriptPath;
684
+ this.modelPath = modelPath;
685
+ this.extraArgs = extraArgs;
686
+ this.runtime = runtime;
687
+ const runtimeDeviceMap = {
688
+ onnx: "cpu",
689
+ coreml: "gpu-mps",
690
+ pytorch: "cpu",
691
+ openvino: "cpu",
692
+ tflite: "cpu"
693
+ };
694
+ this.device = runtimeDeviceMap[runtime];
695
+ }
696
+ runtime;
697
+ device;
698
+ process = null;
699
+ receiveBuffer = Buffer.alloc(0);
700
+ pendingResolve = null;
701
+ pendingReject = null;
702
+ async initialize() {
703
+ const args = [this.scriptPath, this.modelPath, ...this.extraArgs];
704
+ this.process = (0, import_node_child_process.spawn)(this.pythonPath, args, {
705
+ stdio: ["pipe", "pipe", "pipe"]
706
+ });
707
+ if (!this.process.stdout || !this.process.stdin) {
708
+ throw new Error("PythonInferenceEngine: failed to create process pipes");
709
+ }
710
+ this.process.stderr?.on("data", (chunk) => {
711
+ process.stderr.write(`[python-engine] ${chunk.toString()}`);
712
+ });
713
+ this.process.on("error", (err) => {
714
+ this.pendingReject?.(err);
715
+ this.pendingReject = null;
716
+ this.pendingResolve = null;
717
+ });
718
+ this.process.on("exit", (code) => {
719
+ if (code !== 0) {
720
+ const err = new Error(`PythonInferenceEngine: process exited with code ${code}`);
721
+ this.pendingReject?.(err);
722
+ this.pendingReject = null;
723
+ this.pendingResolve = null;
960
724
  }
961
- Object.defineProperty(o, k2, desc);
962
- }) : (function(o, m, k, k2) {
963
- if (k2 === void 0) k2 = k;
964
- o[k2] = m[k];
965
- }));
966
- var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? (function(o, v) {
967
- Object.defineProperty(o, "default", { enumerable: true, value: v });
968
- }) : function(o, v) {
969
- o["default"] = v;
970
725
  });
971
- var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ (function() {
972
- var ownKeys = function(o) {
973
- ownKeys = Object.getOwnPropertyNames || function(o2) {
974
- var ar = [];
975
- for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
976
- return ar;
977
- };
978
- return ownKeys(o);
979
- };
980
- return function(mod) {
981
- if (mod && mod.__esModule) return mod;
982
- var result = {};
983
- if (mod != null) {
984
- for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
726
+ this.process.stdout.on("data", (chunk) => {
727
+ this.receiveBuffer = Buffer.concat([this.receiveBuffer, chunk]);
728
+ this._tryReceive();
729
+ });
730
+ await new Promise((resolve2, reject) => {
731
+ const timeout = setTimeout(() => resolve2(), 2e3);
732
+ this.process?.on("error", (err) => {
733
+ clearTimeout(timeout);
734
+ reject(err);
735
+ });
736
+ this.process?.on("exit", (code) => {
737
+ clearTimeout(timeout);
738
+ if (code !== 0) {
739
+ reject(new Error(`PythonInferenceEngine: process exited early with code ${code}`));
985
740
  }
986
- __setModuleDefault(result, mod);
987
- return result;
988
- };
989
- })();
990
- Object.defineProperty(exports2, "__esModule", { value: true });
991
- exports2.resolveEngine = resolveEngine2;
992
- exports2.probeOnnxBackends = probeOnnxBackends;
993
- var fs = __importStar(require("fs"));
994
- var path = __importStar(require("path"));
995
- var node_engine_js_1 = require_node_engine();
996
- var python_engine_js_1 = require_python_engine();
997
- var AUTO_BACKEND_PRIORITY = ["coreml", "cuda", "tensorrt", "cpu"];
998
- var BACKEND_TO_FORMAT = {
999
- cpu: "onnx",
1000
- coreml: "onnx",
1001
- cuda: "onnx",
1002
- tensorrt: "onnx"
1003
- };
1004
- var RUNTIME_TO_FORMAT = {
1005
- onnx: "onnx",
1006
- coreml: "coreml",
1007
- openvino: "openvino",
1008
- tflite: "tflite",
1009
- pytorch: "pt"
1010
- };
1011
- function modelFilePath(modelsDir, modelEntry, format) {
1012
- const formatEntry = modelEntry.formats[format];
1013
- if (!formatEntry) {
1014
- throw new Error(`Model ${modelEntry.id} has no ${format} format`);
1015
- }
1016
- const urlParts = formatEntry.url.split("/");
1017
- const filename = urlParts[urlParts.length - 1] ?? `${modelEntry.id}.${format}`;
1018
- return path.join(modelsDir, filename);
741
+ });
742
+ });
743
+ }
744
+ _tryReceive() {
745
+ if (this.receiveBuffer.length < 4) return;
746
+ const length = this.receiveBuffer.readUInt32LE(0);
747
+ if (this.receiveBuffer.length < 4 + length) return;
748
+ const jsonBytes = this.receiveBuffer.subarray(4, 4 + length);
749
+ this.receiveBuffer = this.receiveBuffer.subarray(4 + length);
750
+ const resolve2 = this.pendingResolve;
751
+ const reject = this.pendingReject;
752
+ this.pendingResolve = null;
753
+ this.pendingReject = null;
754
+ if (!resolve2) return;
755
+ try {
756
+ const parsed = JSON.parse(jsonBytes.toString("utf8"));
757
+ resolve2(parsed);
758
+ } catch (err) {
759
+ reject?.(err instanceof Error ? err : new Error(String(err)));
1019
760
  }
1020
- function modelExists(filePath) {
1021
- try {
1022
- return fs.existsSync(filePath);
1023
- } catch {
1024
- return false;
1025
- }
761
+ }
762
+ /** Send JPEG buffer, receive JSON detection results */
763
+ async runJpeg(jpeg) {
764
+ if (!this.process?.stdin) {
765
+ throw new Error("PythonInferenceEngine: process not initialized");
1026
766
  }
1027
- async function resolveEngine2(options) {
1028
- const { runtime, backend, modelEntry, modelsDir, models } = options;
1029
- let selectedFormat;
1030
- let selectedBackend;
1031
- if (runtime === "auto") {
1032
- const available = await probeOnnxBackends();
1033
- let chosen = null;
1034
- for (const b of AUTO_BACKEND_PRIORITY) {
1035
- if (!available.includes(b))
1036
- continue;
1037
- const fmt = BACKEND_TO_FORMAT[b];
1038
- if (!fmt)
1039
- continue;
1040
- if (!modelEntry.formats[fmt])
1041
- continue;
1042
- chosen = { backend: b, format: fmt };
1043
- break;
1044
- }
1045
- if (!chosen) {
1046
- throw new Error(`resolveEngine: no compatible backend found for model ${modelEntry.id}. Available backends: ${available.join(", ")}`);
1047
- }
1048
- selectedFormat = chosen.format;
1049
- selectedBackend = chosen.backend;
1050
- } else {
1051
- const fmt = RUNTIME_TO_FORMAT[runtime];
1052
- if (!fmt) {
1053
- throw new Error(`resolveEngine: unsupported runtime "${runtime}"`);
1054
- }
1055
- if (!modelEntry.formats[fmt]) {
1056
- throw new Error(`resolveEngine: model ${modelEntry.id} has no ${fmt} format for runtime ${runtime}`);
1057
- }
1058
- selectedFormat = fmt;
1059
- selectedBackend = runtime === "onnx" ? backend || "cpu" : runtime;
1060
- }
1061
- let modelPath;
1062
- if (models) {
1063
- modelPath = await models.ensure(modelEntry.id, selectedFormat);
1064
- } else {
1065
- modelPath = modelFilePath(modelsDir, modelEntry, selectedFormat);
1066
- if (!modelExists(modelPath)) {
1067
- throw new Error(`resolveEngine: model file not found at ${modelPath} and no model service provided`);
1068
- }
1069
- }
1070
- if (selectedFormat === "onnx") {
1071
- const engine = new node_engine_js_1.NodeInferenceEngine(modelPath, selectedBackend);
1072
- await engine.initialize();
1073
- return { engine, format: selectedFormat, modelPath };
1074
- }
1075
- const { pythonPath } = options;
1076
- const PYTHON_SCRIPT_MAP = {
1077
- coreml: "coreml_inference.py",
1078
- pytorch: "pytorch_inference.py",
1079
- openvino: "openvino_inference.py"
1080
- };
1081
- const effectiveRuntime = runtime === "auto" ? selectedBackend : runtime;
1082
- const scriptName = PYTHON_SCRIPT_MAP[effectiveRuntime];
1083
- if (scriptName && pythonPath) {
1084
- const candidates = [
1085
- path.join(__dirname, "../../python", scriptName),
1086
- path.join(__dirname, "../python", scriptName),
1087
- path.join(__dirname, "../../../python", scriptName)
1088
- ];
1089
- const scriptPath = candidates.find((p) => fs.existsSync(p));
1090
- if (!scriptPath) {
1091
- throw new Error(`resolveEngine: Python script "${scriptName}" not found. Searched:
1092
- ${candidates.join("\n")}`);
1093
- }
1094
- const inputSize = Math.max(modelEntry.inputSize.width, modelEntry.inputSize.height);
1095
- const engine = new python_engine_js_1.PythonInferenceEngine(pythonPath, scriptPath, effectiveRuntime, modelPath, [
1096
- `--input-size=${inputSize}`,
1097
- `--confidence=0.25`
1098
- ]);
1099
- await engine.initialize();
1100
- return { engine, format: selectedFormat, modelPath };
1101
- }
1102
- const fallbackPath = modelFilePath(modelsDir, modelEntry, "onnx");
1103
- if (modelEntry.formats["onnx"] && modelExists(fallbackPath)) {
1104
- const engine = new node_engine_js_1.NodeInferenceEngine(fallbackPath, "cpu");
1105
- await engine.initialize();
1106
- return { engine, format: "onnx", modelPath: fallbackPath };
1107
- }
1108
- throw new Error(`resolveEngine: format ${selectedFormat} is not yet supported by NodeInferenceEngine, no Python runtime is available, and no ONNX fallback exists`);
767
+ return new Promise((resolve2, reject) => {
768
+ this.pendingResolve = resolve2;
769
+ this.pendingReject = reject;
770
+ const lengthBuf = Buffer.allocUnsafe(4);
771
+ lengthBuf.writeUInt32LE(jpeg.length, 0);
772
+ this.process.stdin.write(Buffer.concat([lengthBuf, jpeg]));
773
+ });
774
+ }
775
+ /** IInferenceEngine.run — wraps runJpeg for compatibility */
776
+ async run(_input, _inputShape) {
777
+ throw new Error(
778
+ "PythonInferenceEngine: use runJpeg() directly \u2014 this engine operates on JPEG input"
779
+ );
780
+ }
781
+ /** IInferenceEngine.runMultiOutput — not supported by Python engine (operates on JPEG input) */
782
+ async runMultiOutput(_input, _inputShape) {
783
+ throw new Error(
784
+ "PythonInferenceEngine: runMultiOutput() is not supported \u2014 this engine operates on JPEG input"
785
+ );
786
+ }
787
+ async dispose() {
788
+ if (this.process) {
789
+ this.process.stdin?.end();
790
+ this.process.kill("SIGTERM");
791
+ this.process = null;
1109
792
  }
1110
- async function probeOnnxBackends() {
1111
- const available = ["cpu"];
1112
- try {
1113
- const ort = await Promise.resolve().then(() => __importStar(require("onnxruntime-node")));
1114
- const providers = ort.env?.webgl?.disabled !== void 0 ? ort.InferenceSession?.getAvailableProviders?.() ?? [] : [];
1115
- for (const p of providers) {
1116
- const normalized = p.toLowerCase().replace("executionprovider", "");
1117
- if (normalized === "coreml")
1118
- available.push("coreml");
1119
- else if (normalized === "cuda")
1120
- available.push("cuda");
1121
- else if (normalized === "tensorrt")
1122
- available.push("tensorrt");
1123
- }
1124
- } catch {
1125
- }
1126
- if (process.platform === "darwin" && !available.includes("coreml")) {
1127
- available.push("coreml");
1128
- }
1129
- return [...new Set(available)];
793
+ }
794
+ };
795
+
796
+ // src/shared/engine-resolver.ts
797
+ var AUTO_BACKEND_PRIORITY = ["coreml", "cuda", "tensorrt", "cpu"];
798
+ var BACKEND_TO_FORMAT = {
799
+ cpu: "onnx",
800
+ coreml: "onnx",
801
+ cuda: "onnx",
802
+ tensorrt: "onnx"
803
+ };
804
+ var RUNTIME_TO_FORMAT = {
805
+ onnx: "onnx",
806
+ coreml: "coreml",
807
+ openvino: "openvino",
808
+ tflite: "tflite",
809
+ pytorch: "pt"
810
+ };
811
+ function modelFilePath(modelsDir, modelEntry, format) {
812
+ const formatEntry = modelEntry.formats[format];
813
+ if (!formatEntry) {
814
+ throw new Error(`Model ${modelEntry.id} has no ${format} format`);
815
+ }
816
+ const urlParts = formatEntry.url.split("/");
817
+ const filename = urlParts[urlParts.length - 1] ?? `${modelEntry.id}.${format}`;
818
+ return path2.join(modelsDir, filename);
819
+ }
820
+ function modelExists(filePath) {
821
+ try {
822
+ return fs.existsSync(filePath);
823
+ } catch {
824
+ return false;
825
+ }
826
+ }
827
+ async function resolveEngine(options) {
828
+ const { runtime, backend, modelEntry, modelsDir, models } = options;
829
+ let selectedFormat;
830
+ let selectedBackend;
831
+ if (runtime === "auto") {
832
+ const available = await probeOnnxBackends();
833
+ let chosen = null;
834
+ for (const b of AUTO_BACKEND_PRIORITY) {
835
+ if (!available.includes(b)) continue;
836
+ const fmt = BACKEND_TO_FORMAT[b];
837
+ if (!fmt) continue;
838
+ if (!modelEntry.formats[fmt]) continue;
839
+ chosen = { backend: b, format: fmt };
840
+ break;
841
+ }
842
+ if (!chosen) {
843
+ throw new Error(
844
+ `resolveEngine: no compatible backend found for model ${modelEntry.id}. Available backends: ${available.join(", ")}`
845
+ );
846
+ }
847
+ selectedFormat = chosen.format;
848
+ selectedBackend = chosen.backend;
849
+ } else {
850
+ const fmt = RUNTIME_TO_FORMAT[runtime];
851
+ if (!fmt) {
852
+ throw new Error(`resolveEngine: unsupported runtime "${runtime}"`);
1130
853
  }
854
+ if (!modelEntry.formats[fmt]) {
855
+ throw new Error(
856
+ `resolveEngine: model ${modelEntry.id} has no ${fmt} format for runtime ${runtime}`
857
+ );
858
+ }
859
+ selectedFormat = fmt;
860
+ selectedBackend = runtime === "onnx" ? backend || "cpu" : runtime;
1131
861
  }
1132
- });
862
+ let modelPath;
863
+ if (models) {
864
+ modelPath = await models.ensure(modelEntry.id, selectedFormat);
865
+ } else {
866
+ modelPath = modelFilePath(modelsDir, modelEntry, selectedFormat);
867
+ if (!modelExists(modelPath)) {
868
+ throw new Error(
869
+ `resolveEngine: model file not found at ${modelPath} and no model service provided`
870
+ );
871
+ }
872
+ }
873
+ if (selectedFormat === "onnx") {
874
+ const engine = new NodeInferenceEngine(modelPath, selectedBackend);
875
+ await engine.initialize();
876
+ return { engine, format: selectedFormat, modelPath };
877
+ }
878
+ const { pythonPath } = options;
879
+ const PYTHON_SCRIPT_MAP = {
880
+ coreml: "coreml_inference.py",
881
+ pytorch: "pytorch_inference.py",
882
+ openvino: "openvino_inference.py"
883
+ };
884
+ const effectiveRuntime = runtime === "auto" ? selectedBackend : runtime;
885
+ const scriptName = PYTHON_SCRIPT_MAP[effectiveRuntime];
886
+ if (scriptName && pythonPath) {
887
+ const candidates = [
888
+ path2.join(__dirname, "../../python", scriptName),
889
+ path2.join(__dirname, "../python", scriptName),
890
+ path2.join(__dirname, "../../../python", scriptName)
891
+ ];
892
+ const scriptPath = candidates.find((p) => fs.existsSync(p));
893
+ if (!scriptPath) {
894
+ throw new Error(
895
+ `resolveEngine: Python script "${scriptName}" not found. Searched:
896
+ ${candidates.join("\n")}`
897
+ );
898
+ }
899
+ const inputSize = Math.max(modelEntry.inputSize.width, modelEntry.inputSize.height);
900
+ const engine = new PythonInferenceEngine(pythonPath, scriptPath, effectiveRuntime, modelPath, [
901
+ `--input-size=${inputSize}`,
902
+ `--confidence=0.25`
903
+ ]);
904
+ await engine.initialize();
905
+ return { engine, format: selectedFormat, modelPath };
906
+ }
907
+ const fallbackPath = modelFilePath(modelsDir, modelEntry, "onnx");
908
+ if (modelEntry.formats["onnx"] && modelExists(fallbackPath)) {
909
+ const engine = new NodeInferenceEngine(fallbackPath, "cpu");
910
+ await engine.initialize();
911
+ return { engine, format: "onnx", modelPath: fallbackPath };
912
+ }
913
+ throw new Error(
914
+ `resolveEngine: format ${selectedFormat} is not yet supported by NodeInferenceEngine, no Python runtime is available, and no ONNX fallback exists`
915
+ );
916
+ }
917
+ async function probeOnnxBackends() {
918
+ const available = ["cpu"];
919
+ try {
920
+ const ort = await import("onnxruntime-node");
921
+ const providers = ort.env?.webgl?.disabled !== void 0 ? ort.InferenceSession?.getAvailableProviders?.() ?? [] : [];
922
+ for (const p of providers) {
923
+ const normalized = p.toLowerCase().replace("executionprovider", "");
924
+ if (normalized === "coreml") available.push("coreml");
925
+ else if (normalized === "cuda") available.push("cuda");
926
+ else if (normalized === "tensorrt") available.push("tensorrt");
927
+ }
928
+ } catch {
929
+ }
930
+ if (process.platform === "darwin" && !available.includes("coreml")) {
931
+ available.push("coreml");
932
+ }
933
+ return [...new Set(available)];
934
+ }
1133
935
 
1134
936
  // src/addons/plate-detection/index.ts
1135
- var plate_detection_exports = {};
1136
- __export(plate_detection_exports, {
1137
- default: () => PlateDetectionAddon
1138
- });
1139
- module.exports = __toCommonJS(plate_detection_exports);
1140
- var import_plate_detection_models = __toESM(require_plate_detection_models());
1141
- var import_image_utils = __toESM(require_image_utils());
1142
- var import_yolo = __toESM(require_yolo());
1143
- var import_engine_resolver = __toESM(require_engine_resolver());
1144
937
  var PLATE_LABEL = { id: "plate", name: "License Plate" };
1145
- var PLATE_LABELS = [PLATE_LABEL];
938
+ var PLATE_LABELS2 = [PLATE_LABEL];
1146
939
  var PLATE_CLASS_MAP = { mapping: {}, preserveOriginal: true };
1147
940
  var PlateDetectionAddon = class {
1148
941
  id = "plate-detection";
@@ -1175,7 +968,7 @@ var PlateDetectionAddon = class {
1175
968
  resolvedConfig = null;
1176
969
  ctx = null;
1177
970
  getModelRequirements() {
1178
- return import_plate_detection_models.PLATE_DETECTION_MODELS.map((m) => ({
971
+ return PLATE_DETECTION_MODELS.map((m) => ({
1179
972
  modelId: m.id,
1180
973
  name: m.name,
1181
974
  minRAM_MB: 80,
@@ -1192,7 +985,7 @@ var PlateDetectionAddon = class {
1192
985
  const modelId = cfg["modelId"] ?? this.resolvedConfig?.modelId ?? "yolov8n-plate";
1193
986
  this.confidence = cfg["confidence"] ?? 0.5;
1194
987
  this.iouThreshold = cfg["iouThreshold"] ?? 0.45;
1195
- const entry = import_plate_detection_models.PLATE_DETECTION_MODELS.find((m) => m.id === modelId);
988
+ const entry = PLATE_DETECTION_MODELS.find((m) => m.id === modelId);
1196
989
  if (!entry) {
1197
990
  throw new Error(`PlateDetectionAddon: unknown modelId "${modelId}"`);
1198
991
  }
@@ -1203,13 +996,13 @@ var PlateDetectionAddon = class {
1203
996
  const start = Date.now();
1204
997
  const { width: inputW, height: inputH } = this.modelEntry.inputSize;
1205
998
  const targetSize = Math.max(inputW, inputH);
1206
- const vehicleCrop = await (0, import_image_utils.cropRegion)(input.frame.data, input.roi);
1207
- const lb = await (0, import_image_utils.letterbox)(vehicleCrop, targetSize);
999
+ const vehicleCrop = await cropRegion(input.frame.data, input.roi);
1000
+ const lb = await letterbox(vehicleCrop, targetSize);
1208
1001
  const output = await this.engine.run(lb.data, [1, 3, targetSize, targetSize]);
1209
1002
  const numClasses = this.modelEntry.labels.length;
1210
1003
  const numBoxes = output.length / (4 + numClasses);
1211
1004
  const labels = this.modelEntry.labels.map((l) => l.id);
1212
- const plates = (0, import_yolo.yoloPostprocess)(output, numClasses, numBoxes, {
1005
+ const plates = yoloPostprocess(output, numClasses, numBoxes, {
1213
1006
  confidence: this.confidence,
1214
1007
  iouThreshold: this.iouThreshold,
1215
1008
  labels,
@@ -1232,13 +1025,13 @@ var PlateDetectionAddon = class {
1232
1025
  const runtime = config?.runtime === "python" ? "coreml" : config?.runtime === "node" ? "onnx" : "auto";
1233
1026
  const backend = config?.backend ?? "cpu";
1234
1027
  const format = config?.format ?? "onnx";
1235
- const entry = import_plate_detection_models.PLATE_DETECTION_MODELS.find((m) => m.id === modelId) ?? this.modelEntry;
1028
+ const entry = PLATE_DETECTION_MODELS.find((m) => m.id === modelId) ?? this.modelEntry;
1236
1029
  this.modelEntry = entry;
1237
1030
  const modelsDir = this.ctx.models?.getModelsDir() ?? this.ctx.locationPaths.models;
1238
1031
  if (this.ctx.models) {
1239
1032
  await this.ctx.models.ensure(modelId, format);
1240
1033
  }
1241
- const resolved = await (0, import_engine_resolver.resolveEngine)({
1034
+ const resolved = await resolveEngine({
1242
1035
  runtime,
1243
1036
  backend,
1244
1037
  modelEntry: entry,
@@ -1262,7 +1055,7 @@ var PlateDetectionAddon = class {
1262
1055
  key: "modelId",
1263
1056
  label: "Model",
1264
1057
  type: "model-selector",
1265
- catalog: [...import_plate_detection_models.PLATE_DETECTION_MODELS],
1058
+ catalog: [...PLATE_DETECTION_MODELS],
1266
1059
  allowCustom: false,
1267
1060
  allowConversion: false,
1268
1061
  acceptFormats: ["onnx", "coreml", "openvino"],
@@ -1333,13 +1126,13 @@ var PlateDetectionAddon = class {
1333
1126
  return PLATE_CLASS_MAP;
1334
1127
  }
1335
1128
  getModelCatalog() {
1336
- return [...import_plate_detection_models.PLATE_DETECTION_MODELS];
1129
+ return [...PLATE_DETECTION_MODELS];
1337
1130
  }
1338
1131
  getAvailableModels() {
1339
1132
  return [];
1340
1133
  }
1341
1134
  getActiveLabels() {
1342
- return PLATE_LABELS;
1135
+ return PLATE_LABELS2;
1343
1136
  }
1344
1137
  async probe() {
1345
1138
  return {