@camstack/addon-vision 0.1.2 → 0.1.3

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 (110) hide show
  1. package/dist/addons/animal-classifier/index.js +999 -822
  2. package/dist/addons/animal-classifier/index.js.map +1 -1
  3. package/dist/addons/animal-classifier/index.mjs +242 -7
  4. package/dist/addons/animal-classifier/index.mjs.map +1 -1
  5. package/dist/addons/audio-classification/index.js +501 -378
  6. package/dist/addons/audio-classification/index.js.map +1 -1
  7. package/dist/addons/audio-classification/index.mjs +224 -4
  8. package/dist/addons/audio-classification/index.mjs.map +1 -1
  9. package/dist/addons/bird-global-classifier/index.js +1002 -825
  10. package/dist/addons/bird-global-classifier/index.js.map +1 -1
  11. package/dist/addons/bird-global-classifier/index.mjs +248 -7
  12. package/dist/addons/bird-global-classifier/index.mjs.map +1 -1
  13. package/dist/addons/bird-nabirds-classifier/index.js +1002 -825
  14. package/dist/addons/bird-nabirds-classifier/index.js.map +1 -1
  15. package/dist/addons/bird-nabirds-classifier/index.mjs +289 -7
  16. package/dist/addons/bird-nabirds-classifier/index.mjs.map +1 -1
  17. package/dist/addons/face-detection/index.js +1196 -934
  18. package/dist/addons/face-detection/index.js.map +1 -1
  19. package/dist/addons/face-detection/index.mjs +227 -7
  20. package/dist/addons/face-detection/index.mjs.map +1 -1
  21. package/dist/addons/face-recognition/index.js +1003 -807
  22. package/dist/addons/face-recognition/index.js.map +1 -1
  23. package/dist/addons/face-recognition/index.mjs +197 -6
  24. package/dist/addons/face-recognition/index.mjs.map +1 -1
  25. package/dist/addons/motion-detection/index.js +214 -111
  26. package/dist/addons/motion-detection/index.js.map +1 -1
  27. package/dist/addons/motion-detection/index.mjs +12 -9
  28. package/dist/addons/motion-detection/index.mjs.map +1 -1
  29. package/dist/addons/object-detection/index.js +1287 -1082
  30. package/dist/addons/object-detection/index.js.map +1 -1
  31. package/dist/addons/object-detection/index.mjs +373 -7
  32. package/dist/addons/object-detection/index.mjs.map +1 -1
  33. package/dist/addons/plate-detection/index.js +1075 -868
  34. package/dist/addons/plate-detection/index.js.map +1 -1
  35. package/dist/addons/plate-detection/index.mjs +230 -7
  36. package/dist/addons/plate-detection/index.mjs.map +1 -1
  37. package/dist/addons/plate-recognition/index.js +684 -505
  38. package/dist/addons/plate-recognition/index.js.map +1 -1
  39. package/dist/addons/plate-recognition/index.mjs +244 -5
  40. package/dist/addons/plate-recognition/index.mjs.map +1 -1
  41. package/dist/addons/segmentation-refiner/index.js +967 -790
  42. package/dist/addons/segmentation-refiner/index.js.map +1 -1
  43. package/dist/addons/segmentation-refiner/index.mjs +21 -17
  44. package/dist/addons/segmentation-refiner/index.mjs.map +1 -1
  45. package/dist/addons/vehicle-classifier/index.js +581 -410
  46. package/dist/addons/vehicle-classifier/index.js.map +1 -1
  47. package/dist/addons/vehicle-classifier/index.mjs +20 -16
  48. package/dist/addons/vehicle-classifier/index.mjs.map +1 -1
  49. package/dist/chunk-2YMA6QOV.mjs +193 -0
  50. package/dist/chunk-2YMA6QOV.mjs.map +1 -0
  51. package/dist/chunk-3IIFBJCD.mjs +45 -0
  52. package/dist/chunk-BS4DKYGN.mjs +48 -0
  53. package/dist/{chunk-7DYHXUPZ.mjs.map → chunk-BS4DKYGN.mjs.map} +1 -1
  54. package/dist/chunk-DE7I3VHO.mjs +106 -0
  55. package/dist/{chunk-KUO2BVFY.mjs.map → chunk-DE7I3VHO.mjs.map} +1 -1
  56. package/dist/chunk-F6D2OZ36.mjs +89 -0
  57. package/dist/chunk-F6D2OZ36.mjs.map +1 -0
  58. package/dist/chunk-GAOIFQDX.mjs +59 -0
  59. package/dist/chunk-GAOIFQDX.mjs.map +1 -0
  60. package/dist/chunk-HUIX2XVR.mjs +159 -0
  61. package/dist/chunk-HUIX2XVR.mjs.map +1 -0
  62. package/dist/chunk-K36R6HWY.mjs +51 -0
  63. package/dist/{chunk-XZ6ZMXXU.mjs.map → chunk-K36R6HWY.mjs.map} +1 -1
  64. package/dist/chunk-MBTAI3WE.mjs +78 -0
  65. package/dist/chunk-MBTAI3WE.mjs.map +1 -0
  66. package/dist/chunk-MGT6RUVX.mjs +423 -0
  67. package/dist/{chunk-BP7H4NFS.mjs.map → chunk-MGT6RUVX.mjs.map} +1 -1
  68. package/dist/chunk-PIFS7AIT.mjs +446 -0
  69. package/dist/{chunk-2IOKI4ES.mjs.map → chunk-PIFS7AIT.mjs.map} +1 -1
  70. package/dist/chunk-WG66JYYW.mjs +116 -0
  71. package/dist/{chunk-22BHCDT5.mjs.map → chunk-WG66JYYW.mjs.map} +1 -1
  72. package/dist/chunk-XD7WGXHZ.mjs +82 -0
  73. package/dist/{chunk-DUN6XU3N.mjs.map → chunk-XD7WGXHZ.mjs.map} +1 -1
  74. package/dist/chunk-YYDM6V2F.mjs +113 -0
  75. package/dist/{chunk-BR2FPGOX.mjs.map → chunk-YYDM6V2F.mjs.map} +1 -1
  76. package/dist/chunk-ZK7P3TZN.mjs +286 -0
  77. package/dist/chunk-ZK7P3TZN.mjs.map +1 -0
  78. package/dist/index.js +4443 -3924
  79. package/dist/index.js.map +1 -1
  80. package/dist/index.mjs +2698 -250
  81. package/dist/index.mjs.map +1 -1
  82. package/package.json +1 -1
  83. package/dist/chunk-22BHCDT5.mjs +0 -101
  84. package/dist/chunk-2IOKI4ES.mjs +0 -335
  85. package/dist/chunk-7DYHXUPZ.mjs +0 -36
  86. package/dist/chunk-BJTO5JO5.mjs +0 -11
  87. package/dist/chunk-BP7H4NFS.mjs +0 -412
  88. package/dist/chunk-BR2FPGOX.mjs +0 -98
  89. package/dist/chunk-D6WEHN33.mjs +0 -276
  90. package/dist/chunk-D6WEHN33.mjs.map +0 -1
  91. package/dist/chunk-DRYFGARD.mjs +0 -289
  92. package/dist/chunk-DRYFGARD.mjs.map +0 -1
  93. package/dist/chunk-DUN6XU3N.mjs +0 -72
  94. package/dist/chunk-ESLHNWWE.mjs +0 -387
  95. package/dist/chunk-ESLHNWWE.mjs.map +0 -1
  96. package/dist/chunk-JUQEW6ON.mjs +0 -256
  97. package/dist/chunk-JUQEW6ON.mjs.map +0 -1
  98. package/dist/chunk-KUO2BVFY.mjs +0 -90
  99. package/dist/chunk-R5J3WAUI.mjs +0 -645
  100. package/dist/chunk-R5J3WAUI.mjs.map +0 -1
  101. package/dist/chunk-XZ6ZMXXU.mjs +0 -39
  102. package/dist/chunk-YPU4WTXZ.mjs +0 -269
  103. package/dist/chunk-YPU4WTXZ.mjs.map +0 -1
  104. package/dist/chunk-YUCD2TFH.mjs +0 -242
  105. package/dist/chunk-YUCD2TFH.mjs.map +0 -1
  106. package/dist/chunk-ZTJENCFC.mjs +0 -379
  107. package/dist/chunk-ZTJENCFC.mjs.map +0 -1
  108. package/dist/chunk-ZWYXXCXP.mjs +0 -248
  109. package/dist/chunk-ZWYXXCXP.mjs.map +0 -1
  110. /package/dist/{chunk-BJTO5JO5.mjs.map → chunk-3IIFBJCD.mjs.map} +0 -0
@@ -5,6 +5,9 @@ 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
+ };
8
11
  var __export = (target, all) => {
9
12
  for (var name in all)
10
13
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -27,433 +30,601 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
30
  ));
28
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
32
 
30
- // src/addons/vehicle-classifier/index.ts
31
- var vehicle_classifier_exports = {};
32
- __export(vehicle_classifier_exports, {
33
- default: () => VehicleClassifierAddon
34
- });
35
- module.exports = __toCommonJS(vehicle_classifier_exports);
36
-
37
- // src/catalogs/vehicle-classification-models.ts
38
- var import_types = require("@camstack/types");
39
- var HF_REPO = "camstack/camstack-models";
40
- var hf = (path4) => (0, import_types.hfModelUrl)(HF_REPO, path4);
41
- var VEHICLE_LABELS = [
42
- { id: "vehicle-type", name: "Vehicle Type" }
43
- ];
44
- var VEHICLE_TYPE_MODELS = [
45
- {
46
- id: "vehicle-type-efficientnet",
47
- name: "Vehicle Type (EfficientNet)",
48
- description: "EfficientNet-B4 vehicle make/model/year classifier \u2014 8,949 classes from VMMRdb",
49
- inputSize: { width: 380, height: 380 },
50
- inputNormalization: "imagenet",
51
- labels: VEHICLE_LABELS,
52
- formats: {
53
- onnx: { url: hf("vehicleClassification/efficientnet/onnx/camstack-vehicle-type-efficientnet.onnx"), sizeMB: 135 },
54
- coreml: {
55
- url: hf("vehicleClassification/efficientnet/coreml/camstack-vehicle-type-efficientnet.mlpackage"),
56
- sizeMB: 10,
57
- isDirectory: true,
58
- files: ["Manifest.json", "Data/com.apple.CoreML/model.mlmodel", "Data/com.apple.CoreML/weights/weight.bin"],
59
- runtimes: ["python"]
60
- }
61
- },
62
- extraFiles: [
33
+ // src/catalogs/vehicle-classification-models.js
34
+ var require_vehicle_classification_models = __commonJS({
35
+ "src/catalogs/vehicle-classification-models.js"(exports2) {
36
+ "use strict";
37
+ Object.defineProperty(exports2, "__esModule", { value: true });
38
+ exports2.VEHICLE_TYPE_MODELS = void 0;
39
+ var types_1 = require("@camstack/types");
40
+ var HF_REPO = "camstack/camstack-models";
41
+ var hf = (path2) => (0, types_1.hfModelUrl)(HF_REPO, path2);
42
+ var VEHICLE_LABELS = [
43
+ { id: "vehicle-type", name: "Vehicle Type" }
44
+ ];
45
+ exports2.VEHICLE_TYPE_MODELS = [
63
46
  {
64
- url: hf("vehicleClassification/efficientnet/camstack-vehicle-type-labels.json"),
65
- filename: "camstack-vehicle-type-labels.json",
66
- sizeMB: 0.2
47
+ id: "vehicle-type-efficientnet",
48
+ name: "Vehicle Type (EfficientNet)",
49
+ description: "EfficientNet-B4 vehicle make/model/year classifier \u2014 8,949 classes from VMMRdb",
50
+ inputSize: { width: 380, height: 380 },
51
+ inputNormalization: "imagenet",
52
+ labels: VEHICLE_LABELS,
53
+ formats: {
54
+ onnx: { url: hf("vehicleClassification/efficientnet/onnx/camstack-vehicle-type-efficientnet.onnx"), sizeMB: 135 },
55
+ coreml: {
56
+ url: hf("vehicleClassification/efficientnet/coreml/camstack-vehicle-type-efficientnet.mlpackage"),
57
+ sizeMB: 10,
58
+ isDirectory: true,
59
+ files: ["Manifest.json", "Data/com.apple.CoreML/model.mlmodel", "Data/com.apple.CoreML/weights/weight.bin"],
60
+ runtimes: ["python"]
61
+ }
62
+ },
63
+ extraFiles: [
64
+ {
65
+ url: hf("vehicleClassification/efficientnet/camstack-vehicle-type-labels.json"),
66
+ filename: "camstack-vehicle-type-labels.json",
67
+ sizeMB: 0.2
68
+ }
69
+ ]
67
70
  }
68
- ]
71
+ ];
69
72
  }
70
- ];
73
+ });
71
74
 
72
- // src/shared/image-utils.ts
73
- var import_sharp = __toESM(require("sharp"));
74
- async function cropRegion(jpeg, roi) {
75
- return (0, import_sharp.default)(jpeg).extract({
76
- left: Math.round(roi.x),
77
- top: Math.round(roi.y),
78
- width: Math.round(roi.w),
79
- height: Math.round(roi.h)
80
- }).jpeg().toBuffer();
81
- }
82
- async function resizeAndNormalize(jpeg, targetWidth, targetHeight, normalization, layout) {
83
- const { data } = await (0, import_sharp.default)(jpeg).resize(targetWidth, targetHeight, { fit: "fill" }).removeAlpha().raw().toBuffer({ resolveWithObject: true });
84
- const numPixels = targetWidth * targetHeight;
85
- const float32 = new Float32Array(3 * numPixels);
86
- const mean = [0.485, 0.456, 0.406];
87
- const std = [0.229, 0.224, 0.225];
88
- if (layout === "nchw") {
89
- for (let i = 0; i < numPixels; i++) {
90
- const srcBase = i * 3;
91
- for (let c = 0; c < 3; c++) {
92
- const raw = data[srcBase + c] / 255;
93
- let val;
94
- if (normalization === "zero-one") {
95
- val = raw;
96
- } else if (normalization === "imagenet") {
97
- val = (raw - mean[c]) / std[c];
98
- } else {
99
- val = data[srcBase + c];
100
- }
101
- float32[c * numPixels + i] = val;
75
+ // src/shared/image-utils.js
76
+ var require_image_utils = __commonJS({
77
+ "src/shared/image-utils.js"(exports2) {
78
+ "use strict";
79
+ var __importDefault = exports2 && exports2.__importDefault || function(mod) {
80
+ return mod && mod.__esModule ? mod : { "default": mod };
81
+ };
82
+ Object.defineProperty(exports2, "__esModule", { value: true });
83
+ exports2.jpegToRgb = jpegToRgb;
84
+ exports2.cropRegion = cropRegion2;
85
+ exports2.letterbox = letterbox;
86
+ exports2.resizeAndNormalize = resizeAndNormalize2;
87
+ exports2.rgbToGrayscale = rgbToGrayscale;
88
+ var sharp_1 = __importDefault(require("sharp"));
89
+ async function jpegToRgb(jpeg) {
90
+ const { data, info } = await (0, sharp_1.default)(jpeg).removeAlpha().raw().toBuffer({ resolveWithObject: true });
91
+ return { data, width: info.width, height: info.height };
92
+ }
93
+ async function cropRegion2(jpeg, roi) {
94
+ return (0, sharp_1.default)(jpeg).extract({
95
+ left: Math.round(roi.x),
96
+ top: Math.round(roi.y),
97
+ width: Math.round(roi.w),
98
+ height: Math.round(roi.h)
99
+ }).jpeg().toBuffer();
100
+ }
101
+ async function letterbox(jpeg, targetSize) {
102
+ const meta = await (0, sharp_1.default)(jpeg).metadata();
103
+ const originalWidth = meta.width ?? 0;
104
+ const originalHeight = meta.height ?? 0;
105
+ const scale = Math.min(targetSize / originalWidth, targetSize / originalHeight);
106
+ const scaledWidth = Math.round(originalWidth * scale);
107
+ const scaledHeight = Math.round(originalHeight * scale);
108
+ const padX = Math.floor((targetSize - scaledWidth) / 2);
109
+ const padY = Math.floor((targetSize - scaledHeight) / 2);
110
+ const { data } = await (0, sharp_1.default)(jpeg).resize(scaledWidth, scaledHeight).extend({
111
+ top: padY,
112
+ bottom: targetSize - scaledHeight - padY,
113
+ left: padX,
114
+ right: targetSize - scaledWidth - padX,
115
+ background: { r: 114, g: 114, b: 114 }
116
+ }).removeAlpha().raw().toBuffer({ resolveWithObject: true });
117
+ const numPixels = targetSize * targetSize;
118
+ const float32 = new Float32Array(3 * numPixels);
119
+ for (let i = 0; i < numPixels; i++) {
120
+ const srcBase = i * 3;
121
+ float32[0 * numPixels + i] = data[srcBase] / 255;
122
+ float32[1 * numPixels + i] = data[srcBase + 1] / 255;
123
+ float32[2 * numPixels + i] = data[srcBase + 2] / 255;
102
124
  }
125
+ return { data: float32, scale, padX, padY, originalWidth, originalHeight };
103
126
  }
104
- } else {
105
- for (let i = 0; i < numPixels; i++) {
106
- const srcBase = i * 3;
107
- for (let c = 0; c < 3; c++) {
108
- const raw = data[srcBase + c] / 255;
109
- let val;
110
- if (normalization === "zero-one") {
111
- val = raw;
112
- } else if (normalization === "imagenet") {
113
- val = (raw - mean[c]) / std[c];
114
- } else {
115
- val = data[srcBase + c];
127
+ async function resizeAndNormalize2(jpeg, targetWidth, targetHeight, normalization, layout) {
128
+ const { data } = await (0, sharp_1.default)(jpeg).resize(targetWidth, targetHeight, { fit: "fill" }).removeAlpha().raw().toBuffer({ resolveWithObject: true });
129
+ const numPixels = targetWidth * targetHeight;
130
+ const float32 = new Float32Array(3 * numPixels);
131
+ const mean = [0.485, 0.456, 0.406];
132
+ const std = [0.229, 0.224, 0.225];
133
+ if (layout === "nchw") {
134
+ for (let i = 0; i < numPixels; i++) {
135
+ const srcBase = i * 3;
136
+ for (let c = 0; c < 3; c++) {
137
+ const raw = data[srcBase + c] / 255;
138
+ let val;
139
+ if (normalization === "zero-one") {
140
+ val = raw;
141
+ } else if (normalization === "imagenet") {
142
+ val = (raw - mean[c]) / std[c];
143
+ } else {
144
+ val = data[srcBase + c];
145
+ }
146
+ float32[c * numPixels + i] = val;
147
+ }
148
+ }
149
+ } else {
150
+ for (let i = 0; i < numPixels; i++) {
151
+ const srcBase = i * 3;
152
+ for (let c = 0; c < 3; c++) {
153
+ const raw = data[srcBase + c] / 255;
154
+ let val;
155
+ if (normalization === "zero-one") {
156
+ val = raw;
157
+ } else if (normalization === "imagenet") {
158
+ val = (raw - mean[c]) / std[c];
159
+ } else {
160
+ val = data[srcBase + c];
161
+ }
162
+ float32[i * 3 + c] = val;
163
+ }
116
164
  }
117
- float32[i * 3 + c] = val;
118
165
  }
166
+ return float32;
119
167
  }
120
- }
121
- return float32;
122
- }
123
-
124
- // src/shared/engine-resolver.ts
125
- var fs = __toESM(require("fs"));
126
- var path2 = __toESM(require("path"));
127
-
128
- // src/shared/node-engine.ts
129
- var path = __toESM(require("path"));
130
- var BACKEND_TO_PROVIDER = {
131
- cpu: "cpu",
132
- coreml: "coreml",
133
- cuda: "cuda",
134
- tensorrt: "tensorrt",
135
- dml: "dml"
136
- };
137
- var BACKEND_TO_DEVICE = {
138
- cpu: "cpu",
139
- coreml: "gpu-mps",
140
- cuda: "gpu-cuda",
141
- tensorrt: "tensorrt"
142
- };
143
- var NodeInferenceEngine = class {
144
- constructor(modelPath, backend) {
145
- this.modelPath = modelPath;
146
- this.backend = backend;
147
- this.device = BACKEND_TO_DEVICE[backend] ?? "cpu";
148
- }
149
- runtime = "onnx";
150
- device;
151
- session = null;
152
- async initialize() {
153
- const ort = await import("onnxruntime-node");
154
- const provider = BACKEND_TO_PROVIDER[this.backend] ?? "cpu";
155
- const absModelPath = path.isAbsolute(this.modelPath) ? this.modelPath : path.resolve(process.cwd(), this.modelPath);
156
- const sessionOptions = {
157
- executionProviders: [provider]
158
- };
159
- this.session = await ort.InferenceSession.create(absModelPath, sessionOptions);
160
- }
161
- async run(input, inputShape) {
162
- if (!this.session) {
163
- throw new Error("NodeInferenceEngine: not initialized \u2014 call initialize() first");
164
- }
165
- const ort = await import("onnxruntime-node");
166
- const sess = this.session;
167
- const inputName = sess.inputNames[0];
168
- const tensor = new ort.Tensor("float32", input, [...inputShape]);
169
- const feeds = { [inputName]: tensor };
170
- const results = await sess.run(feeds);
171
- const outputName = sess.outputNames[0];
172
- const outputTensor = results[outputName];
173
- return outputTensor.data;
174
- }
175
- async runMultiOutput(input, inputShape) {
176
- if (!this.session) {
177
- throw new Error("NodeInferenceEngine: not initialized \u2014 call initialize() first");
178
- }
179
- const ort = await import("onnxruntime-node");
180
- const sess = this.session;
181
- const inputName = sess.inputNames[0];
182
- const tensor = new ort.Tensor("float32", input, [...inputShape]);
183
- const feeds = { [inputName]: tensor };
184
- const results = await sess.run(feeds);
185
- const out = {};
186
- for (const name of sess.outputNames) {
187
- out[name] = results[name].data;
168
+ function rgbToGrayscale(rgb, width, height) {
169
+ const numPixels = width * height;
170
+ const gray = new Uint8Array(numPixels);
171
+ for (let i = 0; i < numPixels; i++) {
172
+ const r = rgb[i * 3];
173
+ const g = rgb[i * 3 + 1];
174
+ const b = rgb[i * 3 + 2];
175
+ gray[i] = Math.round(0.299 * r + 0.587 * g + 0.114 * b);
176
+ }
177
+ return gray;
188
178
  }
189
- return out;
190
- }
191
- async dispose() {
192
- this.session = null;
193
179
  }
194
- };
180
+ });
195
181
 
196
- // src/shared/python-engine.ts
197
- var import_node_child_process = require("child_process");
198
- var PythonInferenceEngine = class {
199
- constructor(pythonPath, scriptPath, runtime, modelPath, extraArgs = []) {
200
- this.pythonPath = pythonPath;
201
- this.scriptPath = scriptPath;
202
- this.modelPath = modelPath;
203
- this.extraArgs = extraArgs;
204
- this.runtime = runtime;
205
- const runtimeDeviceMap = {
206
- onnx: "cpu",
182
+ // src/shared/node-engine.js
183
+ var require_node_engine = __commonJS({
184
+ "src/shared/node-engine.js"(exports2) {
185
+ "use strict";
186
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {
187
+ if (k2 === void 0) k2 = k;
188
+ var desc = Object.getOwnPropertyDescriptor(m, k);
189
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
190
+ desc = { enumerable: true, get: function() {
191
+ return m[k];
192
+ } };
193
+ }
194
+ Object.defineProperty(o, k2, desc);
195
+ }) : (function(o, m, k, k2) {
196
+ if (k2 === void 0) k2 = k;
197
+ o[k2] = m[k];
198
+ }));
199
+ var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? (function(o, v) {
200
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
201
+ }) : function(o, v) {
202
+ o["default"] = v;
203
+ });
204
+ var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ (function() {
205
+ var ownKeys = function(o) {
206
+ ownKeys = Object.getOwnPropertyNames || function(o2) {
207
+ var ar = [];
208
+ for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
209
+ return ar;
210
+ };
211
+ return ownKeys(o);
212
+ };
213
+ return function(mod) {
214
+ if (mod && mod.__esModule) return mod;
215
+ var result = {};
216
+ if (mod != null) {
217
+ for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
218
+ }
219
+ __setModuleDefault(result, mod);
220
+ return result;
221
+ };
222
+ })();
223
+ Object.defineProperty(exports2, "__esModule", { value: true });
224
+ exports2.NodeInferenceEngine = void 0;
225
+ var path2 = __importStar(require("path"));
226
+ var BACKEND_TO_PROVIDER = {
227
+ cpu: "cpu",
228
+ coreml: "coreml",
229
+ cuda: "cuda",
230
+ tensorrt: "tensorrt",
231
+ dml: "dml"
232
+ };
233
+ var BACKEND_TO_DEVICE = {
234
+ cpu: "cpu",
207
235
  coreml: "gpu-mps",
208
- pytorch: "cpu",
209
- openvino: "cpu",
210
- tflite: "cpu"
236
+ cuda: "gpu-cuda",
237
+ tensorrt: "tensorrt"
211
238
  };
212
- this.device = runtimeDeviceMap[runtime];
239
+ var NodeInferenceEngine = class {
240
+ modelPath;
241
+ backend;
242
+ runtime = "onnx";
243
+ device;
244
+ session = null;
245
+ constructor(modelPath, backend) {
246
+ this.modelPath = modelPath;
247
+ this.backend = backend;
248
+ this.device = BACKEND_TO_DEVICE[backend] ?? "cpu";
249
+ }
250
+ async initialize() {
251
+ const ort = await Promise.resolve().then(() => __importStar(require("onnxruntime-node")));
252
+ const provider = BACKEND_TO_PROVIDER[this.backend] ?? "cpu";
253
+ const absModelPath = path2.isAbsolute(this.modelPath) ? this.modelPath : path2.resolve(process.cwd(), this.modelPath);
254
+ const sessionOptions = {
255
+ executionProviders: [provider]
256
+ };
257
+ this.session = await ort.InferenceSession.create(absModelPath, sessionOptions);
258
+ }
259
+ async run(input, inputShape) {
260
+ if (!this.session) {
261
+ throw new Error("NodeInferenceEngine: not initialized \u2014 call initialize() first");
262
+ }
263
+ const ort = await Promise.resolve().then(() => __importStar(require("onnxruntime-node")));
264
+ const sess = this.session;
265
+ const inputName = sess.inputNames[0];
266
+ const tensor = new ort.Tensor("float32", input, [...inputShape]);
267
+ const feeds = { [inputName]: tensor };
268
+ const results = await sess.run(feeds);
269
+ const outputName = sess.outputNames[0];
270
+ const outputTensor = results[outputName];
271
+ return outputTensor.data;
272
+ }
273
+ async runMultiOutput(input, inputShape) {
274
+ if (!this.session) {
275
+ throw new Error("NodeInferenceEngine: not initialized \u2014 call initialize() first");
276
+ }
277
+ const ort = await Promise.resolve().then(() => __importStar(require("onnxruntime-node")));
278
+ const sess = this.session;
279
+ const inputName = sess.inputNames[0];
280
+ const tensor = new ort.Tensor("float32", input, [...inputShape]);
281
+ const feeds = { [inputName]: tensor };
282
+ const results = await sess.run(feeds);
283
+ const out = {};
284
+ for (const name of sess.outputNames) {
285
+ out[name] = results[name].data;
286
+ }
287
+ return out;
288
+ }
289
+ async dispose() {
290
+ this.session = null;
291
+ }
292
+ };
293
+ exports2.NodeInferenceEngine = NodeInferenceEngine;
213
294
  }
214
- runtime;
215
- device;
216
- process = null;
217
- receiveBuffer = Buffer.alloc(0);
218
- pendingResolve = null;
219
- pendingReject = null;
220
- async initialize() {
221
- const args = [this.scriptPath, this.modelPath, ...this.extraArgs];
222
- this.process = (0, import_node_child_process.spawn)(this.pythonPath, args, {
223
- stdio: ["pipe", "pipe", "pipe"]
224
- });
225
- if (!this.process.stdout || !this.process.stdin) {
226
- throw new Error("PythonInferenceEngine: failed to create process pipes");
227
- }
228
- this.process.stderr?.on("data", (chunk) => {
229
- process.stderr.write(`[python-engine] ${chunk.toString()}`);
230
- });
231
- this.process.on("error", (err) => {
232
- this.pendingReject?.(err);
233
- this.pendingReject = null;
234
- this.pendingResolve = null;
235
- });
236
- this.process.on("exit", (code) => {
237
- if (code !== 0) {
238
- const err = new Error(`PythonInferenceEngine: process exited with code ${code}`);
239
- this.pendingReject?.(err);
240
- this.pendingReject = null;
295
+ });
296
+
297
+ // src/shared/python-engine.js
298
+ var require_python_engine = __commonJS({
299
+ "src/shared/python-engine.js"(exports2) {
300
+ "use strict";
301
+ Object.defineProperty(exports2, "__esModule", { value: true });
302
+ exports2.PythonInferenceEngine = void 0;
303
+ exports2.resolvePythonBinary = resolvePythonBinary;
304
+ var node_child_process_1 = require("child_process");
305
+ var PythonInferenceEngine = class {
306
+ pythonPath;
307
+ scriptPath;
308
+ modelPath;
309
+ extraArgs;
310
+ runtime;
311
+ device;
312
+ process = null;
313
+ receiveBuffer = Buffer.alloc(0);
314
+ pendingResolve = null;
315
+ pendingReject = null;
316
+ constructor(pythonPath, scriptPath, runtime, modelPath, extraArgs = []) {
317
+ this.pythonPath = pythonPath;
318
+ this.scriptPath = scriptPath;
319
+ this.modelPath = modelPath;
320
+ this.extraArgs = extraArgs;
321
+ this.runtime = runtime;
322
+ const runtimeDeviceMap = {
323
+ onnx: "cpu",
324
+ coreml: "gpu-mps",
325
+ pytorch: "cpu",
326
+ openvino: "cpu",
327
+ tflite: "cpu"
328
+ };
329
+ this.device = runtimeDeviceMap[runtime];
330
+ }
331
+ async initialize() {
332
+ const args = [this.scriptPath, this.modelPath, ...this.extraArgs];
333
+ this.process = (0, node_child_process_1.spawn)(this.pythonPath, args, {
334
+ stdio: ["pipe", "pipe", "pipe"]
335
+ });
336
+ if (!this.process.stdout || !this.process.stdin) {
337
+ throw new Error("PythonInferenceEngine: failed to create process pipes");
338
+ }
339
+ this.process.stderr?.on("data", (chunk) => {
340
+ process.stderr.write(`[python-engine] ${chunk.toString()}`);
341
+ });
342
+ this.process.on("error", (err) => {
343
+ this.pendingReject?.(err);
344
+ this.pendingReject = null;
345
+ this.pendingResolve = null;
346
+ });
347
+ this.process.on("exit", (code) => {
348
+ if (code !== 0) {
349
+ const err = new Error(`PythonInferenceEngine: process exited with code ${code}`);
350
+ this.pendingReject?.(err);
351
+ this.pendingReject = null;
352
+ this.pendingResolve = null;
353
+ }
354
+ });
355
+ this.process.stdout.on("data", (chunk) => {
356
+ this.receiveBuffer = Buffer.concat([this.receiveBuffer, chunk]);
357
+ this._tryReceive();
358
+ });
359
+ await new Promise((resolve, reject) => {
360
+ const timeout = setTimeout(() => resolve(), 2e3);
361
+ this.process?.on("error", (err) => {
362
+ clearTimeout(timeout);
363
+ reject(err);
364
+ });
365
+ this.process?.on("exit", (code) => {
366
+ clearTimeout(timeout);
367
+ if (code !== 0) {
368
+ reject(new Error(`PythonInferenceEngine: process exited early with code ${code}`));
369
+ }
370
+ });
371
+ });
372
+ }
373
+ _tryReceive() {
374
+ if (this.receiveBuffer.length < 4)
375
+ return;
376
+ const length = this.receiveBuffer.readUInt32LE(0);
377
+ if (this.receiveBuffer.length < 4 + length)
378
+ return;
379
+ const jsonBytes = this.receiveBuffer.subarray(4, 4 + length);
380
+ this.receiveBuffer = this.receiveBuffer.subarray(4 + length);
381
+ const resolve = this.pendingResolve;
382
+ const reject = this.pendingReject;
241
383
  this.pendingResolve = null;
384
+ this.pendingReject = null;
385
+ if (!resolve)
386
+ return;
387
+ try {
388
+ const parsed = JSON.parse(jsonBytes.toString("utf8"));
389
+ resolve(parsed);
390
+ } catch (err) {
391
+ reject?.(err instanceof Error ? err : new Error(String(err)));
392
+ }
242
393
  }
243
- });
244
- this.process.stdout.on("data", (chunk) => {
245
- this.receiveBuffer = Buffer.concat([this.receiveBuffer, chunk]);
246
- this._tryReceive();
247
- });
248
- await new Promise((resolve2, reject) => {
249
- const timeout = setTimeout(() => resolve2(), 2e3);
250
- this.process?.on("error", (err) => {
251
- clearTimeout(timeout);
252
- reject(err);
253
- });
254
- this.process?.on("exit", (code) => {
255
- clearTimeout(timeout);
256
- if (code !== 0) {
257
- reject(new Error(`PythonInferenceEngine: process exited early with code ${code}`));
394
+ /** Send JPEG buffer, receive JSON detection results */
395
+ async runJpeg(jpeg) {
396
+ if (!this.process?.stdin) {
397
+ throw new Error("PythonInferenceEngine: process not initialized");
258
398
  }
259
- });
260
- });
261
- }
262
- _tryReceive() {
263
- if (this.receiveBuffer.length < 4) return;
264
- const length = this.receiveBuffer.readUInt32LE(0);
265
- if (this.receiveBuffer.length < 4 + length) return;
266
- const jsonBytes = this.receiveBuffer.subarray(4, 4 + length);
267
- this.receiveBuffer = this.receiveBuffer.subarray(4 + length);
268
- const resolve2 = this.pendingResolve;
269
- const reject = this.pendingReject;
270
- this.pendingResolve = null;
271
- this.pendingReject = null;
272
- if (!resolve2) return;
273
- try {
274
- const parsed = JSON.parse(jsonBytes.toString("utf8"));
275
- resolve2(parsed);
276
- } catch (err) {
277
- reject?.(err instanceof Error ? err : new Error(String(err)));
278
- }
279
- }
280
- /** Send JPEG buffer, receive JSON detection results */
281
- async runJpeg(jpeg) {
282
- if (!this.process?.stdin) {
283
- throw new Error("PythonInferenceEngine: process not initialized");
284
- }
285
- return new Promise((resolve2, reject) => {
286
- this.pendingResolve = resolve2;
287
- this.pendingReject = reject;
288
- const lengthBuf = Buffer.allocUnsafe(4);
289
- lengthBuf.writeUInt32LE(jpeg.length, 0);
290
- this.process.stdin.write(Buffer.concat([lengthBuf, jpeg]));
291
- });
292
- }
293
- /** IInferenceEngine.run — wraps runJpeg for compatibility */
294
- async run(_input, _inputShape) {
295
- throw new Error(
296
- "PythonInferenceEngine: use runJpeg() directly \u2014 this engine operates on JPEG input"
297
- );
298
- }
299
- /** IInferenceEngine.runMultiOutput — not supported by Python engine (operates on JPEG input) */
300
- async runMultiOutput(_input, _inputShape) {
301
- throw new Error(
302
- "PythonInferenceEngine: runMultiOutput() is not supported \u2014 this engine operates on JPEG input"
303
- );
304
- }
305
- async dispose() {
306
- if (this.process) {
307
- this.process.stdin?.end();
308
- this.process.kill("SIGTERM");
309
- this.process = null;
399
+ return new Promise((resolve, reject) => {
400
+ this.pendingResolve = resolve;
401
+ this.pendingReject = reject;
402
+ const lengthBuf = Buffer.allocUnsafe(4);
403
+ lengthBuf.writeUInt32LE(jpeg.length, 0);
404
+ this.process.stdin.write(Buffer.concat([lengthBuf, jpeg]));
405
+ });
406
+ }
407
+ /** IInferenceEngine.run wraps runJpeg for compatibility */
408
+ async run(_input, _inputShape) {
409
+ throw new Error("PythonInferenceEngine: use runJpeg() directly \u2014 this engine operates on JPEG input");
410
+ }
411
+ /** IInferenceEngine.runMultiOutput not supported by Python engine (operates on JPEG input) */
412
+ async runMultiOutput(_input, _inputShape) {
413
+ throw new Error("PythonInferenceEngine: runMultiOutput() is not supported \u2014 this engine operates on JPEG input");
414
+ }
415
+ async dispose() {
416
+ if (this.process) {
417
+ this.process.stdin?.end();
418
+ this.process.kill("SIGTERM");
419
+ this.process = null;
420
+ }
421
+ }
422
+ };
423
+ exports2.PythonInferenceEngine = PythonInferenceEngine;
424
+ async function resolvePythonBinary(configPath, deps) {
425
+ if (configPath)
426
+ return configPath;
427
+ return deps.ensurePython();
310
428
  }
311
429
  }
312
- };
430
+ });
313
431
 
314
- // src/shared/engine-resolver.ts
315
- var AUTO_BACKEND_PRIORITY = ["coreml", "cuda", "tensorrt", "cpu"];
316
- var BACKEND_TO_FORMAT = {
317
- cpu: "onnx",
318
- coreml: "onnx",
319
- cuda: "onnx",
320
- tensorrt: "onnx"
321
- };
322
- var RUNTIME_TO_FORMAT = {
323
- onnx: "onnx",
324
- coreml: "coreml",
325
- openvino: "openvino",
326
- tflite: "tflite",
327
- pytorch: "pt"
328
- };
329
- function modelFilePath(modelsDir, modelEntry, format) {
330
- const formatEntry = modelEntry.formats[format];
331
- if (!formatEntry) {
332
- throw new Error(`Model ${modelEntry.id} has no ${format} format`);
333
- }
334
- const urlParts = formatEntry.url.split("/");
335
- const filename = urlParts[urlParts.length - 1] ?? `${modelEntry.id}.${format}`;
336
- return path2.join(modelsDir, filename);
337
- }
338
- function modelExists(filePath) {
339
- try {
340
- return fs.existsSync(filePath);
341
- } catch {
342
- return false;
343
- }
344
- }
345
- async function resolveEngine(options) {
346
- const { runtime, backend, modelEntry, modelsDir, models } = options;
347
- let selectedFormat;
348
- let selectedBackend;
349
- if (runtime === "auto") {
350
- const available = await probeOnnxBackends();
351
- let chosen = null;
352
- for (const b of AUTO_BACKEND_PRIORITY) {
353
- if (!available.includes(b)) continue;
354
- const fmt = BACKEND_TO_FORMAT[b];
355
- if (!fmt) continue;
356
- if (!modelEntry.formats[fmt]) continue;
357
- chosen = { backend: b, format: fmt };
358
- break;
359
- }
360
- if (!chosen) {
361
- throw new Error(
362
- `resolveEngine: no compatible backend found for model ${modelEntry.id}. Available backends: ${available.join(", ")}`
363
- );
364
- }
365
- selectedFormat = chosen.format;
366
- selectedBackend = chosen.backend;
367
- } else {
368
- const fmt = RUNTIME_TO_FORMAT[runtime];
369
- if (!fmt) {
370
- throw new Error(`resolveEngine: unsupported runtime "${runtime}"`);
371
- }
372
- if (!modelEntry.formats[fmt]) {
373
- throw new Error(
374
- `resolveEngine: model ${modelEntry.id} has no ${fmt} format for runtime ${runtime}`
375
- );
432
+ // src/shared/engine-resolver.js
433
+ var require_engine_resolver = __commonJS({
434
+ "src/shared/engine-resolver.js"(exports2) {
435
+ "use strict";
436
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {
437
+ if (k2 === void 0) k2 = k;
438
+ var desc = Object.getOwnPropertyDescriptor(m, k);
439
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
440
+ desc = { enumerable: true, get: function() {
441
+ return m[k];
442
+ } };
443
+ }
444
+ Object.defineProperty(o, k2, desc);
445
+ }) : (function(o, m, k, k2) {
446
+ if (k2 === void 0) k2 = k;
447
+ o[k2] = m[k];
448
+ }));
449
+ var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? (function(o, v) {
450
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
451
+ }) : function(o, v) {
452
+ o["default"] = v;
453
+ });
454
+ var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ (function() {
455
+ var ownKeys = function(o) {
456
+ ownKeys = Object.getOwnPropertyNames || function(o2) {
457
+ var ar = [];
458
+ for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
459
+ return ar;
460
+ };
461
+ return ownKeys(o);
462
+ };
463
+ return function(mod) {
464
+ if (mod && mod.__esModule) return mod;
465
+ var result = {};
466
+ if (mod != null) {
467
+ for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
468
+ }
469
+ __setModuleDefault(result, mod);
470
+ return result;
471
+ };
472
+ })();
473
+ Object.defineProperty(exports2, "__esModule", { value: true });
474
+ exports2.resolveEngine = resolveEngine2;
475
+ exports2.probeOnnxBackends = probeOnnxBackends;
476
+ var fs2 = __importStar(require("fs"));
477
+ var path2 = __importStar(require("path"));
478
+ var node_engine_js_1 = require_node_engine();
479
+ var python_engine_js_1 = require_python_engine();
480
+ var AUTO_BACKEND_PRIORITY = ["coreml", "cuda", "tensorrt", "cpu"];
481
+ var BACKEND_TO_FORMAT = {
482
+ cpu: "onnx",
483
+ coreml: "onnx",
484
+ cuda: "onnx",
485
+ tensorrt: "onnx"
486
+ };
487
+ var RUNTIME_TO_FORMAT = {
488
+ onnx: "onnx",
489
+ coreml: "coreml",
490
+ openvino: "openvino",
491
+ tflite: "tflite",
492
+ pytorch: "pt"
493
+ };
494
+ function modelFilePath(modelsDir, modelEntry, format) {
495
+ const formatEntry = modelEntry.formats[format];
496
+ if (!formatEntry) {
497
+ throw new Error(`Model ${modelEntry.id} has no ${format} format`);
498
+ }
499
+ const urlParts = formatEntry.url.split("/");
500
+ const filename = urlParts[urlParts.length - 1] ?? `${modelEntry.id}.${format}`;
501
+ return path2.join(modelsDir, filename);
376
502
  }
377
- selectedFormat = fmt;
378
- selectedBackend = runtime === "onnx" ? backend || "cpu" : runtime;
379
- }
380
- let modelPath;
381
- if (models) {
382
- modelPath = await models.ensure(modelEntry.id, selectedFormat);
383
- } else {
384
- modelPath = modelFilePath(modelsDir, modelEntry, selectedFormat);
385
- if (!modelExists(modelPath)) {
386
- throw new Error(
387
- `resolveEngine: model file not found at ${modelPath} and no model service provided`
388
- );
503
+ function modelExists(filePath) {
504
+ try {
505
+ return fs2.existsSync(filePath);
506
+ } catch {
507
+ return false;
508
+ }
389
509
  }
390
- }
391
- if (selectedFormat === "onnx") {
392
- const engine = new NodeInferenceEngine(modelPath, selectedBackend);
393
- await engine.initialize();
394
- return { engine, format: selectedFormat, modelPath };
395
- }
396
- const { pythonPath } = options;
397
- const PYTHON_SCRIPT_MAP = {
398
- coreml: "coreml_inference.py",
399
- pytorch: "pytorch_inference.py",
400
- openvino: "openvino_inference.py"
401
- };
402
- const effectiveRuntime = runtime === "auto" ? selectedBackend : runtime;
403
- const scriptName = PYTHON_SCRIPT_MAP[effectiveRuntime];
404
- if (scriptName && pythonPath) {
405
- const candidates = [
406
- path2.join(__dirname, "../../python", scriptName),
407
- path2.join(__dirname, "../python", scriptName),
408
- path2.join(__dirname, "../../../python", scriptName)
409
- ];
410
- const scriptPath = candidates.find((p) => fs.existsSync(p));
411
- if (!scriptPath) {
412
- throw new Error(
413
- `resolveEngine: Python script "${scriptName}" not found. Searched:
414
- ${candidates.join("\n")}`
415
- );
510
+ async function resolveEngine2(options) {
511
+ const { runtime, backend, modelEntry, modelsDir, models } = options;
512
+ let selectedFormat;
513
+ let selectedBackend;
514
+ if (runtime === "auto") {
515
+ const available = await probeOnnxBackends();
516
+ let chosen = null;
517
+ for (const b of AUTO_BACKEND_PRIORITY) {
518
+ if (!available.includes(b))
519
+ continue;
520
+ const fmt = BACKEND_TO_FORMAT[b];
521
+ if (!fmt)
522
+ continue;
523
+ if (!modelEntry.formats[fmt])
524
+ continue;
525
+ chosen = { backend: b, format: fmt };
526
+ break;
527
+ }
528
+ if (!chosen) {
529
+ throw new Error(`resolveEngine: no compatible backend found for model ${modelEntry.id}. Available backends: ${available.join(", ")}`);
530
+ }
531
+ selectedFormat = chosen.format;
532
+ selectedBackend = chosen.backend;
533
+ } else {
534
+ const fmt = RUNTIME_TO_FORMAT[runtime];
535
+ if (!fmt) {
536
+ throw new Error(`resolveEngine: unsupported runtime "${runtime}"`);
537
+ }
538
+ if (!modelEntry.formats[fmt]) {
539
+ throw new Error(`resolveEngine: model ${modelEntry.id} has no ${fmt} format for runtime ${runtime}`);
540
+ }
541
+ selectedFormat = fmt;
542
+ selectedBackend = runtime === "onnx" ? backend || "cpu" : runtime;
543
+ }
544
+ let modelPath;
545
+ if (models) {
546
+ modelPath = await models.ensure(modelEntry.id, selectedFormat);
547
+ } else {
548
+ modelPath = modelFilePath(modelsDir, modelEntry, selectedFormat);
549
+ if (!modelExists(modelPath)) {
550
+ throw new Error(`resolveEngine: model file not found at ${modelPath} and no model service provided`);
551
+ }
552
+ }
553
+ if (selectedFormat === "onnx") {
554
+ const engine = new node_engine_js_1.NodeInferenceEngine(modelPath, selectedBackend);
555
+ await engine.initialize();
556
+ return { engine, format: selectedFormat, modelPath };
557
+ }
558
+ const { pythonPath } = options;
559
+ const PYTHON_SCRIPT_MAP = {
560
+ coreml: "coreml_inference.py",
561
+ pytorch: "pytorch_inference.py",
562
+ openvino: "openvino_inference.py"
563
+ };
564
+ const effectiveRuntime = runtime === "auto" ? selectedBackend : runtime;
565
+ const scriptName = PYTHON_SCRIPT_MAP[effectiveRuntime];
566
+ if (scriptName && pythonPath) {
567
+ const candidates = [
568
+ path2.join(__dirname, "../../python", scriptName),
569
+ path2.join(__dirname, "../python", scriptName),
570
+ path2.join(__dirname, "../../../python", scriptName)
571
+ ];
572
+ const scriptPath = candidates.find((p) => fs2.existsSync(p));
573
+ if (!scriptPath) {
574
+ throw new Error(`resolveEngine: Python script "${scriptName}" not found. Searched:
575
+ ${candidates.join("\n")}`);
576
+ }
577
+ const inputSize = Math.max(modelEntry.inputSize.width, modelEntry.inputSize.height);
578
+ const engine = new python_engine_js_1.PythonInferenceEngine(pythonPath, scriptPath, effectiveRuntime, modelPath, [
579
+ `--input-size=${inputSize}`,
580
+ `--confidence=0.25`
581
+ ]);
582
+ await engine.initialize();
583
+ return { engine, format: selectedFormat, modelPath };
584
+ }
585
+ const fallbackPath = modelFilePath(modelsDir, modelEntry, "onnx");
586
+ if (modelEntry.formats["onnx"] && modelExists(fallbackPath)) {
587
+ const engine = new node_engine_js_1.NodeInferenceEngine(fallbackPath, "cpu");
588
+ await engine.initialize();
589
+ return { engine, format: "onnx", modelPath: fallbackPath };
590
+ }
591
+ throw new Error(`resolveEngine: format ${selectedFormat} is not yet supported by NodeInferenceEngine, no Python runtime is available, and no ONNX fallback exists`);
416
592
  }
417
- const inputSize = Math.max(modelEntry.inputSize.width, modelEntry.inputSize.height);
418
- const engine = new PythonInferenceEngine(pythonPath, scriptPath, effectiveRuntime, modelPath, [
419
- `--input-size=${inputSize}`,
420
- `--confidence=0.25`
421
- ]);
422
- await engine.initialize();
423
- return { engine, format: selectedFormat, modelPath };
424
- }
425
- const fallbackPath = modelFilePath(modelsDir, modelEntry, "onnx");
426
- if (modelEntry.formats["onnx"] && modelExists(fallbackPath)) {
427
- const engine = new NodeInferenceEngine(fallbackPath, "cpu");
428
- await engine.initialize();
429
- return { engine, format: "onnx", modelPath: fallbackPath };
430
- }
431
- throw new Error(
432
- `resolveEngine: format ${selectedFormat} is not yet supported by NodeInferenceEngine, no Python runtime is available, and no ONNX fallback exists`
433
- );
434
- }
435
- async function probeOnnxBackends() {
436
- const available = ["cpu"];
437
- try {
438
- const ort = await import("onnxruntime-node");
439
- const providers = ort.env?.webgl?.disabled !== void 0 ? ort.InferenceSession?.getAvailableProviders?.() ?? [] : [];
440
- for (const p of providers) {
441
- const normalized = p.toLowerCase().replace("executionprovider", "");
442
- if (normalized === "coreml") available.push("coreml");
443
- else if (normalized === "cuda") available.push("cuda");
444
- else if (normalized === "tensorrt") available.push("tensorrt");
593
+ async function probeOnnxBackends() {
594
+ const available = ["cpu"];
595
+ try {
596
+ const ort = await Promise.resolve().then(() => __importStar(require("onnxruntime-node")));
597
+ const providers = ort.env?.webgl?.disabled !== void 0 ? ort.InferenceSession?.getAvailableProviders?.() ?? [] : [];
598
+ for (const p of providers) {
599
+ const normalized = p.toLowerCase().replace("executionprovider", "");
600
+ if (normalized === "coreml")
601
+ available.push("coreml");
602
+ else if (normalized === "cuda")
603
+ available.push("cuda");
604
+ else if (normalized === "tensorrt")
605
+ available.push("tensorrt");
606
+ }
607
+ } catch {
608
+ }
609
+ if (process.platform === "darwin" && !available.includes("coreml")) {
610
+ available.push("coreml");
611
+ }
612
+ return [...new Set(available)];
445
613
  }
446
- } catch {
447
614
  }
448
- if (process.platform === "darwin" && !available.includes("coreml")) {
449
- available.push("coreml");
450
- }
451
- return [...new Set(available)];
452
- }
615
+ });
453
616
 
454
617
  // src/addons/vehicle-classifier/index.ts
455
- var fs2 = __toESM(require("fs"));
456
- var path3 = __toESM(require("path"));
618
+ var vehicle_classifier_exports = {};
619
+ __export(vehicle_classifier_exports, {
620
+ default: () => VehicleClassifierAddon
621
+ });
622
+ module.exports = __toCommonJS(vehicle_classifier_exports);
623
+ var import_vehicle_classification_models = __toESM(require_vehicle_classification_models());
624
+ var import_image_utils = __toESM(require_image_utils());
625
+ var import_engine_resolver = __toESM(require_engine_resolver());
626
+ var fs = __toESM(require("fs"));
627
+ var path = __toESM(require("path"));
457
628
  var VEHICLE_TYPE_LABEL = { id: "vehicle-type", name: "Vehicle Type" };
458
629
  var VEHICLE_TYPE_LABELS = [VEHICLE_TYPE_LABEL];
459
630
  var VEHICLE_CLASS_MAP = { mapping: {}, preserveOriginal: true };
@@ -463,9 +634,9 @@ function loadLabels(modelsDir, modelId) {
463
634
  `camstack-vehicle-type-labels.json`
464
635
  ];
465
636
  for (const name of labelNames) {
466
- const labelPath = path3.join(modelsDir, name);
467
- if (fs2.existsSync(labelPath)) {
468
- const raw = fs2.readFileSync(labelPath, "utf-8");
637
+ const labelPath = path.join(modelsDir, name);
638
+ if (fs.existsSync(labelPath)) {
639
+ const raw = fs.readFileSync(labelPath, "utf-8");
469
640
  return JSON.parse(raw);
470
641
  }
471
642
  }
@@ -511,7 +682,7 @@ var VehicleClassifierAddon = class {
511
682
  resolvedConfig = null;
512
683
  ctx = null;
513
684
  getModelRequirements() {
514
- return VEHICLE_TYPE_MODELS.map((m) => ({
685
+ return import_vehicle_classification_models.VEHICLE_TYPE_MODELS.map((m) => ({
515
686
  modelId: m.id,
516
687
  name: m.name,
517
688
  minRAM_MB: 120,
@@ -527,7 +698,7 @@ var VehicleClassifierAddon = class {
527
698
  const cfg = ctx.addonConfig;
528
699
  const modelId = cfg["modelId"] ?? this.resolvedConfig?.modelId ?? "vehicle-type-efficientnet";
529
700
  this.minConfidence = cfg["minConfidence"] ?? 0.05;
530
- const entry = VEHICLE_TYPE_MODELS.find((m) => m.id === modelId);
701
+ const entry = import_vehicle_classification_models.VEHICLE_TYPE_MODELS.find((m) => m.id === modelId);
531
702
  if (!entry) {
532
703
  throw new Error(`VehicleClassifierAddon: unknown modelId "${modelId}"`);
533
704
  }
@@ -537,8 +708,8 @@ var VehicleClassifierAddon = class {
537
708
  if (!this.engine) await this.ensureEngine();
538
709
  const start = Date.now();
539
710
  const { width: inputW, height: inputH } = this.modelEntry.inputSize;
540
- const vehicleCrop = await cropRegion(input.frame.data, input.roi);
541
- const normalized = await resizeAndNormalize(vehicleCrop, inputW, inputH, "imagenet", "nchw");
711
+ const vehicleCrop = await (0, import_image_utils.cropRegion)(input.frame.data, input.roi);
712
+ const normalized = await (0, import_image_utils.resizeAndNormalize)(vehicleCrop, inputW, inputH, "imagenet", "nchw");
542
713
  const rawOutput = await this.engine.run(normalized, [1, 3, inputH, inputW]);
543
714
  console.log(`[VehicleClassifier] Output length: ${rawOutput.length}, labels: ${this.labels.length}, first 5 raw: [${Array.from(rawOutput.slice(0, 5)).map((v) => v.toFixed(3)).join(", ")}]`);
544
715
  const probs = softmax(rawOutput);
@@ -575,14 +746,14 @@ var VehicleClassifierAddon = class {
575
746
  const runtime = config?.runtime === "python" ? "coreml" : config?.runtime === "node" ? "onnx" : "auto";
576
747
  const backend = config?.backend ?? "cpu";
577
748
  const format = config?.format ?? "onnx";
578
- const entry = VEHICLE_TYPE_MODELS.find((m) => m.id === modelId) ?? this.modelEntry;
749
+ const entry = import_vehicle_classification_models.VEHICLE_TYPE_MODELS.find((m) => m.id === modelId) ?? this.modelEntry;
579
750
  this.modelEntry = entry;
580
751
  const modelsDir = this.ctx.models?.getModelsDir() ?? this.ctx.locationPaths.models;
581
752
  if (this.ctx.models) {
582
753
  await this.ctx.models.ensure(modelId, format);
583
754
  }
584
755
  this.labels = loadLabels(modelsDir, modelId);
585
- const resolved = await resolveEngine({
756
+ const resolved = await (0, import_engine_resolver.resolveEngine)({
586
757
  runtime,
587
758
  backend,
588
759
  modelEntry: entry,
@@ -606,7 +777,7 @@ var VehicleClassifierAddon = class {
606
777
  key: "modelId",
607
778
  label: "Model",
608
779
  type: "model-selector",
609
- catalog: [...VEHICLE_TYPE_MODELS],
780
+ catalog: [...import_vehicle_classification_models.VEHICLE_TYPE_MODELS],
610
781
  allowCustom: false,
611
782
  allowConversion: false,
612
783
  acceptFormats: ["onnx", "coreml", "openvino"],
@@ -668,7 +839,7 @@ var VehicleClassifierAddon = class {
668
839
  return VEHICLE_CLASS_MAP;
669
840
  }
670
841
  getModelCatalog() {
671
- return [...VEHICLE_TYPE_MODELS];
842
+ return [...import_vehicle_classification_models.VEHICLE_TYPE_MODELS];
672
843
  }
673
844
  getAvailableModels() {
674
845
  return [];