@camstack/addon-pipeline 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1955,215 +1955,6 @@ function getDefaultModelForFormat(stepId, format) {
1955
1955
  })[0].id;
1956
1956
  }
1957
1957
  //#endregion
1958
- //#region src/detection-pipeline/engine/node-engine-manager.ts
1959
- var NodeEngineManager = class {
1960
- backend;
1961
- resolveModelPath;
1962
- createEngine;
1963
- engines = /* @__PURE__ */ new Map();
1964
- log;
1965
- constructor(backend, resolveModelPath, createEngine, logger) {
1966
- this.backend = backend;
1967
- this.resolveModelPath = resolveModelPath;
1968
- this.createEngine = createEngine;
1969
- this.log = logger;
1970
- }
1971
- /**
1972
- * Apply a new pipeline configuration.
1973
- * Loads/unloads engines for steps that changed.
1974
- */
1975
- async applyConfig(newSteps) {
1976
- const enabledSteps = flattenEnabledVideoSteps(newSteps);
1977
- const desiredMap = /* @__PURE__ */ new Map();
1978
- for (const step of enabledSteps) desiredMap.set(step.addonId, step);
1979
- for (const [stepId, loaded] of this.engines) if (!desiredMap.has(stepId)) {
1980
- this.log.info("Unloading ONNX engine for step", { meta: { step: stepId } });
1981
- await loaded.engine.dispose();
1982
- this.engines.delete(stepId);
1983
- }
1984
- for (const [stepId, step] of desiredMap) {
1985
- const existing = this.engines.get(stepId);
1986
- if (existing && existing.modelId === step.modelId) continue;
1987
- if (existing) {
1988
- this.log.info("Replacing ONNX engine for step", { meta: {
1989
- step: stepId,
1990
- fromModelId: existing.modelId,
1991
- toModelId: step.modelId
1992
- } });
1993
- await existing.engine.dispose();
1994
- } else this.log.info("Loading ONNX engine for step", { meta: {
1995
- step: stepId,
1996
- modelId: step.modelId
1997
- } });
1998
- const modelEntry = getStepDefinition(stepId).models.find((m) => m.id === step.modelId);
1999
- if (!modelEntry) throw new Error(`Model "${step.modelId}" not found in step "${stepId}" catalog`);
2000
- const modelPath = this.resolveModelPath(stepId, step.modelId);
2001
- const meta = {
2002
- inputSize: modelEntry.inputSize,
2003
- inputNormalization: modelEntry.inputNormalization ?? "zero-one",
2004
- inputLayout: modelEntry.inputLayout ?? "nchw",
2005
- preprocessMode: modelEntry.preprocessMode ?? "letterbox"
2006
- };
2007
- const engine = await this.createEngine(modelPath, this.backend, meta, this.log.child(stepId));
2008
- this.engines.set(stepId, {
2009
- stepId,
2010
- modelId: step.modelId,
2011
- engine
2012
- });
2013
- }
2014
- }
2015
- /**
2016
- * Get an IInferenceEngine for a step.
2017
- * @throws if the step is not loaded.
2018
- */
2019
- getEngine(stepId) {
2020
- const loaded = this.engines.get(stepId);
2021
- if (!loaded) throw new Error(`ONNX engine for step "${stepId}" is not loaded`);
2022
- return loaded.engine;
2023
- }
2024
- isLoaded(stepId) {
2025
- return this.engines.has(stepId);
2026
- }
2027
- isLoadedWithModel(stepId, modelId) {
2028
- const loaded = this.engines.get(stepId);
2029
- return loaded !== void 0 && loaded.modelId === modelId;
2030
- }
2031
- async loadAdditional(steps) {
2032
- const enabledSteps = flattenEnabledVideoSteps(steps);
2033
- for (const step of enabledSteps) {
2034
- const existing = this.engines.get(step.addonId);
2035
- if (existing && existing.modelId === step.modelId) continue;
2036
- if (existing) {
2037
- this.log.info("Replacing ONNX engine for step", { meta: {
2038
- step: step.addonId,
2039
- fromModelId: existing.modelId,
2040
- toModelId: step.modelId
2041
- } });
2042
- await existing.engine.dispose();
2043
- } else this.log.info("Loading additional ONNX engine for step", { meta: {
2044
- step: step.addonId,
2045
- modelId: step.modelId
2046
- } });
2047
- const modelEntry = getStepDefinition(step.addonId).models.find((m) => m.id === step.modelId);
2048
- if (!modelEntry) throw new Error(`Model "${step.modelId}" not found in step "${step.addonId}" catalog`);
2049
- const modelPath = this.resolveModelPath(step.addonId, step.modelId);
2050
- const meta = {
2051
- inputSize: modelEntry.inputSize,
2052
- inputNormalization: modelEntry.inputNormalization ?? "zero-one",
2053
- inputLayout: modelEntry.inputLayout ?? "nchw",
2054
- preprocessMode: modelEntry.preprocessMode ?? "letterbox"
2055
- };
2056
- const engine = await this.createEngine(modelPath, this.backend, meta, this.log.child(step.addonId));
2057
- this.engines.set(step.addonId, {
2058
- stepId: step.addonId,
2059
- modelId: step.modelId,
2060
- engine
2061
- });
2062
- }
2063
- }
2064
- listLoaded() {
2065
- return [...this.engines.values()].map((l) => ({
2066
- stepId: l.stepId,
2067
- modelId: l.modelId
2068
- }));
2069
- }
2070
- async disposeAll() {
2071
- for (const [, loaded] of this.engines) await loaded.engine.dispose();
2072
- this.engines.clear();
2073
- }
2074
- };
2075
- //#endregion
2076
- //#region src/detection-pipeline/engine/model-shape-validator.ts
2077
- /**
2078
- * Runtime input-shape validator for ONNX models.
2079
- *
2080
- * Reads the actual graph input dimensions from a locally-downloaded
2081
- * ONNX model and compares them against the catalog declaration. Used
2082
- * by the engine factory at load time so a converter regression or a
2083
- * stale catalog entry surfaces as a one-line warning rather than
2084
- * silent incorrect inference (preprocess uses one size, the model
2085
- * expects another → garbage detections).
2086
- *
2087
- * Only ONNX is validated here. CoreML and OpenVINO converters in our
2088
- * pipeline derive shape from the same source ONNX, so a passing ONNX
2089
- * check covers all three formats. If they ever diverge, extend with a
2090
- * format-specific reader (Manifest.json for .mlpackage, root <input>
2091
- * tag for OpenVINO XML).
2092
- */
2093
- /**
2094
- * Probe an ONNX file for its first input's shape. Returns null if the
2095
- * file is missing or unparseable — callers should treat null as
2096
- * "validation skipped" (not a mismatch).
2097
- *
2098
- * Implementation: uses `onnxruntime-node` to create a session and read
2099
- * `inputMetadata`. The session is released immediately after probing.
2100
- */
2101
- async function readOnnxInputShape(onnxPath) {
2102
- if (!fs.existsSync(onnxPath)) return null;
2103
- try {
2104
- const session = await (await import("onnxruntime-node")).InferenceSession.create(onnxPath);
2105
- const firstInputName = session.inputNames[0];
2106
- if (!firstInputName) return null;
2107
- const numeric = (session.inputMetadata?.[firstInputName]?.dimensions ?? []).map((d) => typeof d === "number" ? d : null);
2108
- let height = null;
2109
- let width = null;
2110
- if (numeric.length === 4) {
2111
- const candidates = numeric.map((v, i) => ({
2112
- v,
2113
- i
2114
- })).filter((e) => typeof e.v === "number" && e.v > 4).toSorted((a, b) => b.v - a.v);
2115
- if (candidates.length >= 2) {
2116
- const sorted = candidates.slice(0, 2).toSorted((a, b) => a.i - b.i);
2117
- height = sorted[0]?.v ?? null;
2118
- width = sorted[1]?.v ?? null;
2119
- }
2120
- }
2121
- if (typeof session.release === "function") await session.release();
2122
- return {
2123
- height,
2124
- width
2125
- };
2126
- } catch {
2127
- return null;
2128
- }
2129
- }
2130
- /**
2131
- * Check the catalog `expected` size against the actual ONNX input shape.
2132
- * Returns a ShapeMismatch when the actual shape is known and disagrees;
2133
- * returns null when the file is missing, unparseable, or matches.
2134
- */
2135
- async function validateOnnxInputShape(opts) {
2136
- const actual = await readOnnxInputShape(opts.modelPath);
2137
- if (!actual) return null;
2138
- const matchesH = actual.height === null || actual.height === opts.expected.height;
2139
- const matchesW = actual.width === null || actual.width === opts.expected.width;
2140
- if (matchesH && matchesW) return null;
2141
- return {
2142
- modelId: opts.modelId,
2143
- modelPath: opts.modelPath,
2144
- expected: opts.expected,
2145
- actual
2146
- };
2147
- }
2148
- /**
2149
- * Convenience wrapper: validate, log on mismatch via the supplied
2150
- * logger. Returns true when validation passed (or was skipped) so
2151
- * callers can keep loading; mismatches do not throw — they warn.
2152
- */
2153
- async function checkAndLogModelShape(opts, logger) {
2154
- const mismatch = await validateOnnxInputShape(opts);
2155
- if (!mismatch) return true;
2156
- logger.warn("Model input shape mismatch — catalog declaration disagrees with model file", { meta: {
2157
- modelId: mismatch.modelId,
2158
- expectedWidth: mismatch.expected.width,
2159
- expectedHeight: mismatch.expected.height,
2160
- actualWidth: mismatch.actual.width,
2161
- actualHeight: mismatch.actual.height,
2162
- modelPath: mismatch.modelPath
2163
- } });
2164
- return false;
2165
- }
2166
- //#endregion
2167
1958
  //#region src/detection-pipeline/engine/engine-factory.ts
2168
1959
  var BACKEND_TO_POOL_RUNTIME = {
2169
1960
  coreml: "coreml",
@@ -2180,32 +1971,29 @@ var RUNTIME_TO_FORMAT = {
2180
1971
  var EngineFactory = class {
2181
1972
  pool = null;
2182
1973
  poolManager = null;
2183
- nodeManager = null;
2184
1974
  log;
2185
1975
  opts;
2186
1976
  constructor(opts) {
2187
1977
  this.opts = opts;
2188
1978
  this.log = opts.logger;
2189
1979
  }
2190
- /** Whether this factory uses a Python pool (vs Node.js ONNX). */
1980
+ /** Detection always uses the Python pool. */
2191
1981
  get usesPythonPool() {
2192
- return this.opts.engine.runtime === "python";
1982
+ return true;
2193
1983
  }
2194
1984
  /**
2195
1985
  * Initialize the engine layer and apply initial pipeline config.
2196
1986
  */
2197
1987
  async initialize(steps) {
2198
- if (this.usesPythonPool) await this.initPythonPool(steps);
2199
- else await this.initNodeEngines(steps);
1988
+ await this.initPythonPool(steps);
2200
1989
  }
2201
1990
  /**
2202
1991
  * Apply a new pipeline config (hot swap).
2203
1992
  * Only loads/unloads models that changed.
2204
1993
  */
2205
1994
  async applyConfig(steps) {
2206
- if (this.poolManager) await this.poolManager.applyConfig(steps);
2207
- else if (this.nodeManager) await this.nodeManager.applyConfig(steps);
2208
- else throw new Error("EngineFactory not initialized");
1995
+ if (!this.poolManager) throw new Error("EngineFactory not initialized");
1996
+ await this.poolManager.applyConfig(steps);
2209
1997
  }
2210
1998
  /**
2211
1999
  * Get an IInferenceEngine for a pipeline step. Without `modelId`,
@@ -2216,49 +2004,35 @@ var EngineFactory = class {
2216
2004
  * @throws if step not loaded with the requested (or active) model.
2217
2005
  */
2218
2006
  getEngine(stepId, modelId) {
2219
- if (this.poolManager) return this.poolManager.getHandle(stepId, modelId);
2220
- if (this.nodeManager) return this.nodeManager.getEngine(stepId);
2221
- throw new Error("EngineFactory not initialized");
2007
+ if (!this.poolManager) throw new Error("EngineFactory not initialized");
2008
+ return this.poolManager.getHandle(stepId, modelId);
2222
2009
  }
2223
2010
  /** Check if a step is loaded (any variant). */
2224
2011
  isLoaded(stepId) {
2225
- if (this.poolManager) return this.poolManager.isLoaded(stepId);
2226
- if (this.nodeManager) return this.nodeManager.isLoaded(stepId);
2227
- return false;
2012
+ return this.poolManager?.isLoaded(stepId) ?? false;
2228
2013
  }
2229
2014
  /** Check if a specific (stepId, modelId) variant is resident. */
2230
2015
  isLoadedWithModel(stepId, modelId) {
2231
- if (this.poolManager) return this.poolManager.isLoadedWithModel(stepId, modelId);
2232
- if (this.nodeManager) return this.nodeManager.isLoadedWithModel(stepId, modelId);
2233
- return false;
2016
+ return this.poolManager?.isLoadedWithModel(stepId, modelId) ?? false;
2234
2017
  }
2235
2018
  /**
2236
- * List every loaded (stepId, modelId) variant — the pool path
2237
- * surfaces each warm slot independently (including bench overrides);
2238
- * the Node path surfaces just the active model per step.
2019
+ * List every loaded (stepId, modelId) variant — the pool surfaces each
2020
+ * warm slot independently (including bench overrides).
2239
2021
  */
2240
2022
  listLoaded() {
2241
- if (this.poolManager) return this.poolManager.getLoadedSteps().map((l) => ({
2023
+ if (!this.poolManager) return [];
2024
+ return this.poolManager.getLoadedSteps().map((l) => ({
2242
2025
  stepId: l.stepId,
2243
2026
  modelId: l.modelId,
2244
2027
  active: l.active
2245
2028
  }));
2246
- if (this.nodeManager) return this.nodeManager.listLoaded().map((l) => ({
2247
- ...l,
2248
- active: true
2249
- }));
2250
- return [];
2251
2029
  }
2252
2030
  /** Native pid of the underlying Python pool, if any. */
2253
2031
  getPoolPid() {
2254
2032
  return this.pool?.getPid() ?? null;
2255
2033
  }
2256
2034
  /**
2257
- * Whether this factory exposes the batched fast path
2258
- * (`batchInferRaw`). Only the Python pool path supports it today —
2259
- * Node.js ONNX engines run one inference per call with their own
2260
- * thread pool inside InferenceSession, so batching at this layer
2261
- * would just queue serially.
2035
+ * Whether this factory exposes the batched fast path (`batchInferRaw`).
2262
2036
  */
2263
2037
  supportsBatch() {
2264
2038
  return this.poolManager !== null;
@@ -2272,7 +2046,7 @@ var EngineFactory = class {
2272
2046
  * in one IPC round-trip, amortising the per-call envelope overhead.
2273
2047
  */
2274
2048
  async batchInferRaw(stepId, items, modelId) {
2275
- if (!this.poolManager) throw new Error("EngineFactory.batchInferRaw: pool path not available (Node ONNX factory)");
2049
+ if (!this.poolManager) throw new Error("EngineFactory.batchInferRaw: pool not initialized");
2276
2050
  const idx = this.poolManager.getPoolIndex(stepId, modelId);
2277
2051
  if (idx === null) throw new Error(`EngineFactory.batchInferRaw: step "${stepId}"${modelId ? ` (model "${modelId}")` : ""} is not loaded`);
2278
2052
  return this.poolManager.getPool().inferBatch(idx, items);
@@ -2294,7 +2068,6 @@ var EngineFactory = class {
2294
2068
  /** Load additional models without unloading existing ones (for benchmark/test). */
2295
2069
  async loadAdditional(steps) {
2296
2070
  if (this.poolManager) await this.poolManager.loadAdditional(steps);
2297
- else if (this.nodeManager) await this.nodeManager.loadAdditional(steps);
2298
2071
  }
2299
2072
  /** Shut down all engines and the pool process. */
2300
2073
  async dispose() {
@@ -2303,14 +2076,10 @@ var EngineFactory = class {
2303
2076
  this.pool = null;
2304
2077
  this.poolManager = null;
2305
2078
  }
2306
- if (this.nodeManager) {
2307
- await this.nodeManager.disposeAll();
2308
- this.nodeManager = null;
2309
- }
2310
2079
  }
2311
2080
  async initPythonPool(steps) {
2312
2081
  const pythonPath = this.opts.pythonPath;
2313
- if (!pythonPath) throw new Error("EngineFactory: pythonPath is required for runtime=\"python\" — the addon must call ctx.deps.ensurePython() and pass the result. The embedded portable Python download likely failed; check the addon logs for the download error.");
2082
+ if (!pythonPath) throw new Error("EngineFactory: pythonPath is required — the addon must call ctx.deps.ensurePython() and pass the result. The embedded portable Python download likely failed; check the addon logs for the download error.");
2314
2083
  const poolRuntime = BACKEND_TO_POOL_RUNTIME[this.opts.engine.backend];
2315
2084
  if (!poolRuntime) throw new Error(`No pool runtime mapping for backend "${this.opts.engine.backend}"`);
2316
2085
  const concurrency = this.opts.concurrency ?? {
@@ -2361,16 +2130,6 @@ var EngineFactory = class {
2361
2130
  const filename = urlParts[urlParts.length - 1] ?? `${modelId}.${format}`;
2362
2131
  const modelPath = `${this.opts.modelsDir}/${filename}`;
2363
2132
  const inputSize = Math.max(modelEntry.inputSize.width, modelEntry.inputSize.height);
2364
- const onnxEntry = modelEntry.formats.onnx;
2365
- if (onnxEntry) {
2366
- const onnxUrlParts = onnxEntry.url.split("/");
2367
- const onnxFilename = onnxUrlParts[onnxUrlParts.length - 1] ?? `${modelId}.onnx`;
2368
- checkAndLogModelShape({
2369
- modelId,
2370
- modelPath: `${this.opts.modelsDir}/${onnxFilename}`,
2371
- expected: modelEntry.inputSize
2372
- }, this.log);
2373
- }
2374
2133
  let labels = def.labels;
2375
2134
  if (!labels && modelEntry.extraFiles) {
2376
2135
  const labelsFile = modelEntry.extraFiles.find((f) => f.filename.endsWith("-labels.json"));
@@ -2397,20 +2156,6 @@ var EngineFactory = class {
2397
2156
  device: this.opts.engine.device ?? (poolRuntime === "coreml" ? "all" : void 0)
2398
2157
  };
2399
2158
  }
2400
- async initNodeEngines(steps) {
2401
- if (!this.opts.createNodeEngine) throw new Error("createNodeEngine function required for nodejs+onnx backend");
2402
- this.nodeManager = new NodeEngineManager(this.opts.engine.backend, (stepId, modelId) => this.resolveOnnxModelPath(stepId, modelId), this.opts.createNodeEngine, this.log.child("onnx-mgr"));
2403
- await this.nodeManager.applyConfig(steps);
2404
- }
2405
- resolveOnnxModelPath(stepId, modelId) {
2406
- const modelEntry = getStepDefinition(stepId).models.find((m) => m.id === modelId);
2407
- if (!modelEntry) throw new Error(`Model "${modelId}" not found in step "${stepId}" catalog`);
2408
- const onnxFormat = modelEntry.formats["onnx"];
2409
- if (!onnxFormat) throw new Error(`Model "${modelId}" has no ONNX format`);
2410
- const urlParts = onnxFormat.url.split("/");
2411
- const filename = urlParts[urlParts.length - 1] ?? `${modelId}.onnx`;
2412
- return `${this.opts.modelsDir}/${filename}`;
2413
- }
2414
2159
  };
2415
2160
  //#endregion
2416
2161
  //#region src/detection-pipeline/postprocess/dispatch.ts
@@ -4121,9 +3866,10 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
4121
3866
  };
4122
3867
  } catch {}
4123
3868
  return {
4124
- runtime: "node",
4125
- backend: "cpu",
4126
- format: "onnx"
3869
+ runtime: "python",
3870
+ backend: "onnx",
3871
+ format: "onnx",
3872
+ device: "cpu"
4127
3873
  };
4128
3874
  }
4129
3875
  /** Store the addon context. ctx.api is a lazy getter resolved at call time. */
@@ -4144,18 +3890,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
4144
3890
  return this.getAvailableEnginesWithDevices().map((e) => e.engine);
4145
3891
  }
4146
3892
  getAvailableEnginesWithDevices() {
4147
- const engines = [{
4148
- engine: {
4149
- runtime: "node",
4150
- backend: "cpu",
4151
- format: "onnx"
4152
- },
4153
- devices: [{
4154
- id: "cpu",
4155
- label: "CPU"
4156
- }],
4157
- defaultDevice: "cpu"
4158
- }];
3893
+ const engines = [];
4159
3894
  if (process.platform === "darwin") engines.push({
4160
3895
  engine: {
4161
3896
  runtime: "python",
@@ -4208,11 +3943,11 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
4208
3943
  if (audioDef.models.some((m) => m.formats[format])) {
4209
3944
  const modelId = getDefaultModelForFormat("audio-classifier", format);
4210
3945
  const audioEngine = modelId === "apple-soundanalysis" ? {
4211
- runtime: "node",
3946
+ runtime: "python",
4212
3947
  backend: "coreml",
4213
3948
  format: "coreml"
4214
3949
  } : {
4215
- runtime: "node",
3950
+ runtime: "python",
4216
3951
  backend: "cpu",
4217
3952
  format: "onnx"
4218
3953
  };
@@ -5381,18 +5116,19 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
5381
5116
  if (typeof runtime === "string" && typeof backend === "string" && runtime && backend) {
5382
5117
  const storedDevice = typeof store["engineDevice"] === "string" ? String(store["engineDevice"]) : "";
5383
5118
  const detected = DetectionPipelineProvider.detectBestEngine();
5384
- if (runtime === "python" && !DetectionPipelineProvider.isPythonBackendAvailable(backend)) {
5119
+ if (runtime === "python" && !DetectionPipelineProvider.isPythonBackendAvailable(backend, this.executorOptions.pythonPath ?? "")) {
5385
5120
  this.log.warn("Stored engine backend unavailable on this node — falling back to detected best", { meta: {
5386
5121
  stored: `${runtime}/${backend}`,
5387
5122
  fallback: `${detected.runtime}/${detected.backend}`
5388
5123
  } });
5389
5124
  return detected;
5390
5125
  }
5126
+ const migratedBackend = runtime === "node" && backend === "cpu" ? "onnx" : backend;
5391
5127
  const device = storedDevice || detected.device;
5392
5128
  return {
5393
- runtime: runtime === "node" ? "node" : "python",
5394
- backend,
5395
- format: backendToFormat(backend),
5129
+ runtime: "python",
5130
+ backend: migratedBackend,
5131
+ format: backendToFormat(migratedBackend),
5396
5132
  ...device ? { device } : {}
5397
5133
  };
5398
5134
  }
@@ -5401,13 +5137,21 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
5401
5137
  }
5402
5138
  /**
5403
5139
  * Synchronous availability probe for a Python inference backend. Runs a
5404
- * short `python3 -c "import <mod>"` with a 3s timeout. Used at
5140
+ * short `<python> -c "import <mod>"` with a 3s timeout. Used at
5405
5141
  * `loadEngine` time to reject a persisted backend choice the Python
5406
5142
  * interpreter on this host can't actually import — without this the
5407
5143
  * detection-pipeline child process exits with code 1 the moment
5408
5144
  * `inference_pool.py` hits its `from openvino.runtime import Core`.
5145
+ *
5146
+ * MUST probe the EMBEDDED portable interpreter (`pythonPath`, resolved via
5147
+ * `ctx.deps.ensurePython()`) — that's where `installPythonRequirements`
5148
+ * puts the backend packages and what `SharedInferencePool` actually spawns.
5149
+ * Probing the system `python3` checks the wrong site-packages (and on a
5150
+ * slim container there is no system python3 at all → every backend would
5151
+ * be reported unavailable, silently disabling ML). Falls back to `python3`
5152
+ * only when no embedded interpreter is resolved.
5409
5153
  */
5410
- static isPythonBackendAvailable(backend) {
5154
+ static isPythonBackendAvailable(backend, pythonPath) {
5411
5155
  const mod = {
5412
5156
  coreml: "coremltools",
5413
5157
  openvino: "openvino.runtime",
@@ -5417,7 +5161,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
5417
5161
  if (!mod) return false;
5418
5162
  try {
5419
5163
  const { execFileSync } = __require("node:child_process");
5420
- execFileSync("python3", ["-c", `import ${mod}`], {
5164
+ execFileSync(pythonPath || "python3", ["-c", `import ${mod}`], {
5421
5165
  timeout: 3e3,
5422
5166
  stdio: "pipe"
5423
5167
  });
@@ -5808,11 +5552,11 @@ function buildDefaultStepTree(format) {
5808
5552
  makeStep("instance-segmentation", [], { enabled: false })
5809
5553
  ].filter((s) => s !== null));
5810
5554
  const audioEngine = getDefaultModelForFormat("audio-classifier", format) === "apple-soundanalysis" ? {
5811
- runtime: "node",
5555
+ runtime: "python",
5812
5556
  backend: "coreml",
5813
5557
  format: "coreml"
5814
5558
  } : {
5815
- runtime: "node",
5559
+ runtime: "python",
5816
5560
  backend: "cpu",
5817
5561
  format: "onnx"
5818
5562
  };
@@ -5952,30 +5696,21 @@ function resolveAddonPythonDir() {
5952
5696
  var RUNTIMES = [{
5953
5697
  value: "python",
5954
5698
  label: "Python (CoreML / OpenVINO / ONNX Runtime)"
5955
- }, {
5956
- value: "node",
5957
- label: "Node.js (onnxruntime-node)"
5958
5699
  }];
5959
- var BACKENDS_BY_RUNTIME = {
5960
- python: [
5961
- {
5962
- value: "coreml",
5963
- label: "CoreML"
5964
- },
5965
- {
5966
- value: "openvino",
5967
- label: "OpenVINO"
5968
- },
5969
- {
5970
- value: "onnx",
5971
- label: "ONNX Runtime"
5972
- }
5973
- ],
5974
- node: [{
5975
- value: "cpu",
5976
- label: "CPU (onnxruntime-node)"
5977
- }]
5978
- };
5700
+ var BACKENDS_BY_RUNTIME = { python: [
5701
+ {
5702
+ value: "coreml",
5703
+ label: "CoreML"
5704
+ },
5705
+ {
5706
+ value: "openvino",
5707
+ label: "OpenVINO"
5708
+ },
5709
+ {
5710
+ value: "onnx",
5711
+ label: "ONNX Runtime"
5712
+ }
5713
+ ] };
5979
5714
  var DEVICES_BY_BACKEND = {
5980
5715
  coreml: [
5981
5716
  {
@@ -6327,7 +6062,7 @@ var DetectionPipelineAddon = class extends BaseAddon {
6327
6062
  ...stored,
6328
6063
  ...overlay
6329
6064
  } : stored;
6330
- const runtime = merged.engineRuntime === "node" ? "node" : "python";
6065
+ const runtime = "python";
6331
6066
  const availableBackends = await this.resolveAvailableBackends(ctx, runtime);
6332
6067
  const runtimeBackends = availableBackends.length > 0 ? BACKENDS_BY_RUNTIME[runtime].filter((b) => availableBackends.includes(b.value)) : BACKENDS_BY_RUNTIME[runtime];
6333
6068
  const storedBackend = typeof merged.engineBackend === "string" ? merged.engineBackend : "";
@@ -3,7 +3,7 @@ import "./dist-CYZr2fwk.mjs";
3
3
  var e = {
4
4
  "@camstack/sdk": {
5
5
  name: "@camstack/sdk",
6
- version: "1.0.0",
6
+ version: "1.0.1",
7
7
  scope: ["default"],
8
8
  loaded: !1,
9
9
  from: "addon_stream_broker_widgets",
@@ -18,7 +18,7 @@ var e = {
18
18
  },
19
19
  "@camstack/types": {
20
20
  name: "@camstack/types",
21
- version: "1.0.0",
21
+ version: "1.0.1",
22
22
  scope: ["default"],
23
23
  loaded: !1,
24
24
  from: "addon_stream_broker_widgets",
@@ -33,7 +33,7 @@ var e = {
33
33
  },
34
34
  "@camstack/ui-library": {
35
35
  name: "@camstack/ui-library",
36
- version: "1.0.0",
36
+ version: "1.0.1",
37
37
  scope: ["default"],
38
38
  loaded: !1,
39
39
  from: "addon_stream_broker_widgets",
@@ -36,7 +36,7 @@ async function r() {
36
36
  }
37
37
  },
38
38
  "@camstack/types": {
39
- version: "1.0.0",
39
+ version: "1.0.1",
40
40
  scope: "default",
41
41
  shareConfig: {
42
42
  singleton: !0,
@@ -45,7 +45,7 @@ async function r() {
45
45
  }
46
46
  },
47
47
  "@camstack/sdk": {
48
- version: "1.0.0",
48
+ version: "1.0.1",
49
49
  scope: "default",
50
50
  shareConfig: {
51
51
  singleton: !0,
@@ -81,7 +81,7 @@ async function r() {
81
81
  }
82
82
  },
83
83
  "@camstack/ui-library": {
84
- version: "1.0.0",
84
+ version: "1.0.1",
85
85
  scope: "default",
86
86
  shareConfig: {
87
87
  singleton: !0,
@@ -14289,7 +14289,7 @@ function getNodeAv$1() {
14289
14289
  return _navPromise$1 ??= import("node-av");
14290
14290
  }
14291
14291
  function getConstants$1() {
14292
- return _constsPromise$1 ??= Promise.resolve().then(() => require("../constants-D65v6yp6.js"));
14292
+ return _constsPromise$1 ??= import("node-av/constants");
14293
14293
  }
14294
14294
  /** Convert a presentation timestamp in stream ticks to milliseconds. */
14295
14295
  function ticksToMs$1(ptsTicks, timeBase) {
@@ -14665,7 +14665,7 @@ var AV_NOPTS_VALUE = -9223372036854775808n;
14665
14665
  var _navPromise = null;
14666
14666
  var _constsPromise = null;
14667
14667
  var getNodeAv = () => _navPromise ??= import("node-av");
14668
- var getConstants = () => _constsPromise ??= Promise.resolve().then(() => require("../constants-D65v6yp6.js"));
14668
+ var getConstants = () => _constsPromise ??= import("node-av/constants");
14669
14669
  function ticksToMs(pts, tb) {
14670
14670
  return Math.round(Number(pts) * 1e3 * tb.num / tb.den);
14671
14671
  }
@@ -14284,7 +14284,7 @@ function getNodeAv$1() {
14284
14284
  return _navPromise$1 ??= import("node-av");
14285
14285
  }
14286
14286
  function getConstants$1() {
14287
- return _constsPromise$1 ??= import("../constants-B_b0a-6h.mjs");
14287
+ return _constsPromise$1 ??= import("node-av/constants");
14288
14288
  }
14289
14289
  /** Convert a presentation timestamp in stream ticks to milliseconds. */
14290
14290
  function ticksToMs$1(ptsTicks, timeBase) {
@@ -14660,7 +14660,7 @@ var AV_NOPTS_VALUE = -9223372036854775808n;
14660
14660
  var _navPromise = null;
14661
14661
  var _constsPromise = null;
14662
14662
  var getNodeAv = () => _navPromise ??= import("node-av");
14663
- var getConstants = () => _constsPromise ??= import("../constants-B_b0a-6h.mjs");
14663
+ var getConstants = () => _constsPromise ??= import("node-av/constants");
14664
14664
  function ticksToMs(pts, tb) {
14665
14665
  return Math.round(Number(pts) * 1e3 * tb.num / tb.den);
14666
14666
  }
@@ -30,7 +30,7 @@ async function d(e) {
30
30
  }
31
31
  }
32
32
  async function f() {
33
- return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-Bak8zYXf.mjs")).catch((e) => {
33
+ return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-qX99--rF.mjs")).catch((e) => {
34
34
  throw l = void 0, e;
35
35
  }), l;
36
36
  }