@camstack/addon-pipeline 1.2.106 → 1.2.115
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{addon-utils-BEzVJ0xg.js → addon-utils-C0ht2KPO.js} +51 -15
- package/dist/{addon-utils-A2S9D7pu.mjs → addon-utils-CgBCF-mE.mjs} +50 -14
- package/dist/audio-analyzer/index.js +3 -3
- package/dist/audio-analyzer/index.mjs +3 -3
- package/dist/detection-pipeline/index.js +198 -38
- package/dist/detection-pipeline/index.mjs +197 -37
- package/dist/{dist-BSeR_hVv.js → dist-BqIbYW1A.js} +290 -17
- package/dist/{dist-lITI1Bn5.mjs → dist-DGQkkWc6.mjs} +273 -18
- package/dist/{event-loop-stall-monitor-0VvjTRDP.mjs → event-loop-stall-monitor-D5jK5v4Z.mjs} +223 -2
- package/dist/{event-loop-stall-monitor-BNsp9k8r.js → event-loop-stall-monitor-ylMGpz48.js} +234 -1
- package/dist/{lazy-sharp-CBohM8D8.js → lazy-sharp-cOsy7l_P.js} +1 -1
- package/dist/motion-wasm/index.js +2 -2
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/pipeline-runner/index.js +915 -107
- package/dist/pipeline-runner/index.mjs +914 -106
- package/dist/{process-memory-C33u3tQz.js → process-memory-45juuHpN.js} +1 -1
- package/dist/{process-memory-CEKVKfwg.mjs → process-memory-BtT7WfbJ.mjs} +1 -1
- package/dist/recorder/index.js +187 -47
- package/dist/recorder/index.mjs +187 -47
- package/dist/session-decode/decode-worker-child.js +30 -10
- package/dist/session-decode/decode-worker-child.mjs +29 -9
- package/dist/stream-broker/_stub.js +2 -2
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-w2XLD3uI.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-C_SFFNGT.mjs} +3 -3
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-B1LDFHY9.mjs +26 -0
- package/dist/stream-broker/{_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DsIi4G5Q.mjs → _virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BAMyzCWw.mjs} +1 -1
- package/dist/stream-broker/{hostInit-B-h24cDy.mjs → hostInit-CG28NvlV.mjs} +3 -3
- package/dist/stream-broker/index.js +279 -198
- package/dist/stream-broker/index.mjs +279 -198
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/dist/{worker-protocol-CiKfal2P.js → worker-protocol-CIrqGbpG.js} +6 -3
- package/dist/{worker-protocol-BDiL8TBm.mjs → worker-protocol-DyocTIx_.mjs} +6 -3
- package/package.json +1 -1
- package/python/inference_pool.py +4 -1
- package/python/test_inference_pool_preprocess.py +87 -16
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DvZWLWk1.mjs +0 -26
|
@@ -2,11 +2,11 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_dist = require("../dist-
|
|
6
|
-
const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-
|
|
7
|
-
const require_lazy_sharp = require("../lazy-sharp-
|
|
8
|
-
const require_process_memory = require("../process-memory-
|
|
9
|
-
const require_addon_utils = require("../addon-utils-
|
|
5
|
+
const require_dist = require("../dist-BqIbYW1A.js");
|
|
6
|
+
const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-ylMGpz48.js");
|
|
7
|
+
const require_lazy_sharp = require("../lazy-sharp-cOsy7l_P.js");
|
|
8
|
+
const require_process_memory = require("../process-memory-45juuHpN.js");
|
|
9
|
+
const require_addon_utils = require("../addon-utils-C0ht2KPO.js");
|
|
10
10
|
let sharp = require("sharp");
|
|
11
11
|
sharp = require_dist.__toESM(sharp);
|
|
12
12
|
let node_child_process = require("node:child_process");
|
|
@@ -264,7 +264,13 @@ var OBJECT_DETECTION_STEP_ID = "object-detection";
|
|
|
264
264
|
* `null` → the caller substitutes the step's own `defaultModelId` (`yolo26n`).
|
|
265
265
|
* INTEL NPU + iGPU default to OUR YOLOv9 (int8 @320): yolo26 does NOT compile on
|
|
266
266
|
* the Intel NPU (arch incompat → 0 frames), while yolov9 runs on it (~298 fps
|
|
267
|
-
* measured). Apple ANE
|
|
267
|
+
* measured). Apple ANE uses the CoreML yolov9 @320 build.
|
|
268
|
+
*
|
|
269
|
+
* Do **not** promote these ids to `yolov9m-640` / `*-640`. The controlled
|
|
270
|
+
* evaluation recovered 0/3 misses at the current 0.50 threshold and failed the
|
|
271
|
+
* false-positive and capacity gates — see
|
|
272
|
+
* `docs/benchmarks/pipeline-frame-model-eval.md`. 640 remains an explicit
|
|
273
|
+
* operator pick, not a hardware-aware default.
|
|
268
274
|
*/
|
|
269
275
|
var MODEL_BY_CLASS = {
|
|
270
276
|
"apple-ane": "yolov9m-320",
|
|
@@ -1374,7 +1380,7 @@ function macroOfMinConfidenceKey(key) {
|
|
|
1374
1380
|
*/
|
|
1375
1381
|
function reachableMacros(def, entry) {
|
|
1376
1382
|
if (entry.labels.length === 0) return void 0;
|
|
1377
|
-
const map = def.classMap;
|
|
1383
|
+
const map = entry.classMap ?? def.classMap;
|
|
1378
1384
|
if (!map) return new Set(entry.labels.map((l) => l.id));
|
|
1379
1385
|
if (map.preserveOriginal) return void 0;
|
|
1380
1386
|
const macros = /* @__PURE__ */ new Set();
|
|
@@ -1394,7 +1400,7 @@ function reachableMacros(def, entry) {
|
|
|
1394
1400
|
*/
|
|
1395
1401
|
function collectClassMapDropWarning(def, entry) {
|
|
1396
1402
|
if (entry.labels.length === 0) return null;
|
|
1397
|
-
const map = def.classMap;
|
|
1403
|
+
const map = entry.classMap ?? def.classMap;
|
|
1398
1404
|
if (!map || map.preserveOriginal) return null;
|
|
1399
1405
|
const unmapped = entry.labels.filter((l) => map.mapping[l.id] === void 0).map((l) => l.id);
|
|
1400
1406
|
if (unmapped.length === 0) return null;
|
|
@@ -4170,7 +4176,7 @@ function applyChildOutput(parent, childStep, output, stepLatencyMs, ctx) {
|
|
|
4170
4176
|
switch (output.kind) {
|
|
4171
4177
|
case "detections":
|
|
4172
4178
|
if (childStep.definition.slot === "refiner") {
|
|
4173
|
-
const classMap = childStep.
|
|
4179
|
+
const classMap = childStep.effectiveClassMap?.mapping;
|
|
4174
4180
|
const parentMacro = parent.macroClass;
|
|
4175
4181
|
const best = output.detections.filter((d) => {
|
|
4176
4182
|
if (d.mask === void 0) return false;
|
|
@@ -4510,6 +4516,29 @@ function reprojectCropZoneDetections(output, cropOrigin) {
|
|
|
4510
4516
|
}))
|
|
4511
4517
|
};
|
|
4512
4518
|
}
|
|
4519
|
+
function reprojectViewDetections(output, geometry) {
|
|
4520
|
+
const mapPoint = (x, y) => ({
|
|
4521
|
+
x: geometry.sourceCrop.left + x / geometry.scale.x,
|
|
4522
|
+
y: geometry.sourceCrop.top + y / geometry.scale.y
|
|
4523
|
+
});
|
|
4524
|
+
return {
|
|
4525
|
+
kind: "detections",
|
|
4526
|
+
detections: output.detections.map((det) => {
|
|
4527
|
+
const origin = mapPoint(det.bbox[0], det.bbox[1]);
|
|
4528
|
+
const end = mapPoint(det.bbox[2], det.bbox[3]);
|
|
4529
|
+
return {
|
|
4530
|
+
...det,
|
|
4531
|
+
bbox: [
|
|
4532
|
+
origin.x,
|
|
4533
|
+
origin.y,
|
|
4534
|
+
end.x,
|
|
4535
|
+
end.y
|
|
4536
|
+
],
|
|
4537
|
+
...det.landmarks ? { landmarks: det.landmarks.map((landmark) => mapPoint(landmark.x, landmark.y)) } : {}
|
|
4538
|
+
};
|
|
4539
|
+
})
|
|
4540
|
+
};
|
|
4541
|
+
}
|
|
4513
4542
|
var PipelineExecutor = class {
|
|
4514
4543
|
opts;
|
|
4515
4544
|
/** Bounds the full-frame-guard drop log: first example per (device,
|
|
@@ -4571,7 +4600,7 @@ var PipelineExecutor = class {
|
|
|
4571
4600
|
*
|
|
4572
4601
|
* @returns FrameResult + optional trace
|
|
4573
4602
|
*/
|
|
4574
|
-
async run(tree, rootInput, fullFrameJpegProvider, imageWidth, imageHeight, deviceId, runOpts, nativeCropProvider, cropZoneBbox) {
|
|
4603
|
+
async run(tree, rootInput, fullFrameJpegProvider, imageWidth, imageHeight, deviceId, runOpts, nativeCropProvider, cropZoneBbox, rootInputViewProvider) {
|
|
4575
4604
|
const startMs = Date.now();
|
|
4576
4605
|
const verbosity = runOpts?.traceVerbosity ?? "off";
|
|
4577
4606
|
const traceBuilder = new ExecutionTraceBuilder(verbosity, deviceId, imageWidth, imageHeight, this.opts.engineRuntime);
|
|
@@ -4619,18 +4648,20 @@ var PipelineExecutor = class {
|
|
|
4619
4648
|
};
|
|
4620
4649
|
for (const rootStep of tree.roots) {
|
|
4621
4650
|
if (debug) console.log(`[executor] rootStep=${rootStep.stepId} settings=${JSON.stringify(rootStep.settings ?? {})}`);
|
|
4622
|
-
const
|
|
4651
|
+
const rootCrop = rootStep.definition.extractMode === "crop-zone" ? cropZoneBbox : void 0;
|
|
4652
|
+
const rootView = rootInputViewProvider ? await rootInputViewProvider(rootStep, rootCrop) : null;
|
|
4653
|
+
const cropPrep = !rootView && rootCrop !== void 0 ? await this.prepareCropZoneInput(rootCrop, fullFrameJpegProvider, imageWidth, imageHeight, deviceId) : null;
|
|
4623
4654
|
const rootStart = Date.now();
|
|
4624
|
-
const rawRootOutput = await this.executeStep(rootStep, cropPrep?.input ?? withInferenceDeviceId(rootInput, deviceId), cropPrep?.width ?? imageWidth, cropPrep?.height ?? imageHeight, "full-frame", void 0, void 0, traceBuilder, stepTimings, poolAgg, rootShed);
|
|
4655
|
+
const rawRootOutput = await this.executeStep(rootStep, rootView?.input ?? cropPrep?.input ?? withInferenceDeviceId(rootInput, deviceId), rootView?.width ?? cropPrep?.width ?? imageWidth, rootView?.height ?? cropPrep?.height ?? imageHeight, "full-frame", void 0, void 0, traceBuilder, stepTimings, poolAgg, rootShed);
|
|
4625
4656
|
const rootMs = Date.now() - rootStart;
|
|
4626
4657
|
if (rawRootOutput === null) continue;
|
|
4627
|
-
const rootOutput = cropPrep && rawRootOutput.kind === "detections" ? reprojectCropZoneDetections(rawRootOutput, cropPrep.origin) : rawRootOutput;
|
|
4658
|
+
const rootOutput = rootView && rawRootOutput.kind === "detections" ? reprojectViewDetections(rawRootOutput, rootView.geometry) : cropPrep && rawRootOutput.kind === "detections" ? reprojectCropZoneDetections(rawRootOutput, cropPrep.origin) : rawRootOutput;
|
|
4628
4659
|
if (rootOutput.kind !== "detections") {
|
|
4629
4660
|
if (isEnrichmentOutput(rootOutput)) {
|
|
4630
4661
|
const mutable = this.synthesizeRootDetection(rootOutput, rootStep, idGen, rootMs, imageWidth, imageHeight);
|
|
4631
4662
|
applyChildOutput(mutable, rootStep, rootOutput, rootMs, ctx);
|
|
4632
4663
|
try {
|
|
4633
|
-
await this.executeChildren(rootStep.children, mutable, fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg, runOpts?.plane, deviceId, nativeCropProvider);
|
|
4664
|
+
await this.executeChildren(rootStep.children, mutable, rootView?.jpegProvider ?? fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg, runOpts?.plane, deviceId, nativeCropProvider);
|
|
4634
4665
|
} catch (err) {
|
|
4635
4666
|
this.opts.logger?.warn("Pipeline child execution failed — keeping parent detection", {
|
|
4636
4667
|
tags: { deviceId },
|
|
@@ -4648,12 +4679,12 @@ var PipelineExecutor = class {
|
|
|
4648
4679
|
}
|
|
4649
4680
|
for (const det of rootOutput.detections) {
|
|
4650
4681
|
const mutable = toMutableRootDetection(det, rootStep, idGen, rootMs);
|
|
4651
|
-
if (rootStep.
|
|
4652
|
-
const mapped = rootStep.
|
|
4682
|
+
if (rootStep.effectiveClassMap) {
|
|
4683
|
+
const mapped = rootStep.effectiveClassMap.mapping[det.class];
|
|
4653
4684
|
if (mapped) {
|
|
4654
4685
|
mutable.originalClass = det.class;
|
|
4655
4686
|
mutable.macroClass = mapped;
|
|
4656
|
-
} else if (!rootStep.
|
|
4687
|
+
} else if (!rootStep.effectiveClassMap.preserveOriginal) {
|
|
4657
4688
|
(discarded ??= []).push({
|
|
4658
4689
|
bbox: [
|
|
4659
4690
|
mutable.bbox[0],
|
|
@@ -4735,7 +4766,7 @@ var PipelineExecutor = class {
|
|
|
4735
4766
|
}
|
|
4736
4767
|
});
|
|
4737
4768
|
try {
|
|
4738
|
-
await this.executeChildren(rootStep.children, mutable, fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg, runOpts?.plane, deviceId, nativeCropProvider);
|
|
4769
|
+
await this.executeChildren(rootStep.children, mutable, rootView?.jpegProvider ?? fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg, runOpts?.plane, deviceId, nativeCropProvider);
|
|
4739
4770
|
} catch (err) {
|
|
4740
4771
|
this.opts.logger?.warn("Pipeline child execution failed — keeping parent detection", {
|
|
4741
4772
|
tags: { deviceId },
|
|
@@ -5155,6 +5186,59 @@ function capitalize(s) {
|
|
|
5155
5186
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
5156
5187
|
}
|
|
5157
5188
|
//#endregion
|
|
5189
|
+
//#region src/session-decode/frame-view-payload.ts
|
|
5190
|
+
var FRAME_VIEW_PAYLOAD_POLICY = "jpeg";
|
|
5191
|
+
//#endregion
|
|
5192
|
+
//#region src/detection-pipeline/root-frame-view.ts
|
|
5193
|
+
/** Resolve the pre-padding content requested from the decode worker for one root. */
|
|
5194
|
+
function resolveRootFrameViewSpec(model, source, crop, format = FRAME_VIEW_PAYLOAD_POLICY) {
|
|
5195
|
+
const sourceWidth = crop?.width ?? source.width;
|
|
5196
|
+
const sourceHeight = crop?.height ?? source.height;
|
|
5197
|
+
if (model.preprocessMode !== "letterbox") return {
|
|
5198
|
+
...crop ? { crop } : {},
|
|
5199
|
+
content: {
|
|
5200
|
+
width: model.inputSize.width,
|
|
5201
|
+
height: model.inputSize.height
|
|
5202
|
+
},
|
|
5203
|
+
fit: "stretch",
|
|
5204
|
+
format
|
|
5205
|
+
};
|
|
5206
|
+
const scale = Math.min(model.inputSize.width / sourceWidth, model.inputSize.height / sourceHeight);
|
|
5207
|
+
return {
|
|
5208
|
+
...crop ? { crop } : {},
|
|
5209
|
+
content: {
|
|
5210
|
+
width: Math.max(1, Math.round(sourceWidth * scale)),
|
|
5211
|
+
height: Math.max(1, Math.round(sourceHeight * scale))
|
|
5212
|
+
},
|
|
5213
|
+
fit: "contain",
|
|
5214
|
+
format
|
|
5215
|
+
};
|
|
5216
|
+
}
|
|
5217
|
+
//#endregion
|
|
5218
|
+
//#region src/detection-pipeline/frame-ref-view-provider.ts
|
|
5219
|
+
var LocalFrameRefMissError = class extends Error {
|
|
5220
|
+
reason;
|
|
5221
|
+
constructor(reason) {
|
|
5222
|
+
super(`local frameRef miss: ${reason}`);
|
|
5223
|
+
this.reason = reason;
|
|
5224
|
+
this.name = "LocalFrameRefMissError";
|
|
5225
|
+
}
|
|
5226
|
+
};
|
|
5227
|
+
/** Bind one registry lease for all heterogeneous roots of a pipeline invocation. */
|
|
5228
|
+
function createRootFrameViewResolver(registry, ref) {
|
|
5229
|
+
const lease = registry.acquire(ref);
|
|
5230
|
+
if (!lease) throw new LocalFrameRefMissError(ref.registryId === registry.registryId ? "stale-ref" : "foreign-registry");
|
|
5231
|
+
const resolve = async (root, crop) => {
|
|
5232
|
+
const model = root.definition.models.find((candidate) => candidate.id === root.modelId);
|
|
5233
|
+
if (!model) throw new Error(`frame view model not found: ${root.modelId}`);
|
|
5234
|
+
const spec = resolveRootFrameViewSpec(model, ref, crop);
|
|
5235
|
+
const result = await lease.resolve(spec);
|
|
5236
|
+
if (result.kind === "miss") throw new LocalFrameRefMissError(result.reason);
|
|
5237
|
+
return result;
|
|
5238
|
+
};
|
|
5239
|
+
return Object.assign(resolve, { release: (reason) => lease.release(reason) });
|
|
5240
|
+
}
|
|
5241
|
+
//#endregion
|
|
5158
5242
|
//#region src/detection-pipeline/pipeline/native-crop-compose.ts
|
|
5159
5243
|
/** Clamp `v` into `[lo, hi]`. */
|
|
5160
5244
|
function clamp(v, lo, hi) {
|
|
@@ -5194,23 +5278,32 @@ function composeCropRoiToFrameNorm(roi, cropFrameSpace, frameWidth, frameHeight)
|
|
|
5194
5278
|
//#endregion
|
|
5195
5279
|
//#region src/detection-pipeline/pipeline/tree-builder.ts
|
|
5196
5280
|
/**
|
|
5281
|
+
* Effective class map for `(definition, modelId)` without writing back to the
|
|
5282
|
+
* shared StepDefinition. Custom models missing from `definition.models` are
|
|
5283
|
+
* resolved through the optional registry callback.
|
|
5284
|
+
*/
|
|
5285
|
+
function resolveEffectiveClassMap(definition, modelId, resolveModel) {
|
|
5286
|
+
return (definition.models.find((model) => model.id === modelId) ?? resolveModel?.(definition.id, modelId))?.classMap ?? definition.classMap;
|
|
5287
|
+
}
|
|
5288
|
+
/**
|
|
5197
5289
|
* Build an executable tree from user config.
|
|
5198
5290
|
*
|
|
5199
5291
|
* @param steps - User-configured pipeline steps (from PipelineDefaultStep[])
|
|
5200
5292
|
* @param getEngine - Function that returns an IInferenceEngine for a step ID.
|
|
5201
5293
|
* Throws if step not loaded.
|
|
5202
5294
|
*/
|
|
5203
|
-
function buildExecutableTree(steps, getEngine) {
|
|
5204
|
-
return { roots: steps.filter((s) => s.enabled).filter((s) => s.slot !== "audio-classifier").map((s) => buildNode(s, getEngine)) };
|
|
5295
|
+
function buildExecutableTree(steps, getEngine, resolveModel) {
|
|
5296
|
+
return { roots: steps.filter((s) => s.enabled).filter((s) => s.slot !== "audio-classifier").map((s) => buildNode(s, getEngine, resolveModel)) };
|
|
5205
5297
|
}
|
|
5206
|
-
function buildNode(step, getEngine) {
|
|
5298
|
+
function buildNode(step, getEngine, resolveModel) {
|
|
5207
5299
|
const definition = require_event_loop_stall_monitor.getStepDefinition(step.addonId);
|
|
5208
5300
|
const engine = getEngine(step.addonId);
|
|
5209
|
-
const children = (step.children ?? []).filter((c) => c.enabled).map((c) => buildNode(c, getEngine));
|
|
5301
|
+
const children = (step.children ?? []).filter((c) => c.enabled).map((c) => buildNode(c, getEngine, resolveModel));
|
|
5210
5302
|
const mergedSettings = {
|
|
5211
5303
|
...collectSchemaDefaults(step.addonId),
|
|
5212
5304
|
...step.settings
|
|
5213
5305
|
};
|
|
5306
|
+
const effectiveClassMap = resolveEffectiveClassMap(definition, step.modelId, resolveModel);
|
|
5214
5307
|
return {
|
|
5215
5308
|
stepId: step.addonId,
|
|
5216
5309
|
definition,
|
|
@@ -5219,7 +5312,8 @@ function buildNode(step, getEngine) {
|
|
|
5219
5312
|
inputClasses: definition.inputClasses ?? [],
|
|
5220
5313
|
enabled: step.enabled,
|
|
5221
5314
|
children,
|
|
5222
|
-
...Object.keys(mergedSettings).length > 0 ? { settings: mergedSettings } : {}
|
|
5315
|
+
...Object.keys(mergedSettings).length > 0 ? { settings: mergedSettings } : {},
|
|
5316
|
+
...effectiveClassMap !== void 0 ? { effectiveClassMap } : {}
|
|
5223
5317
|
};
|
|
5224
5318
|
}
|
|
5225
5319
|
/**
|
|
@@ -5454,7 +5548,7 @@ function collectUnknownAddonIssues(steps, getStepDef = require_event_loop_stall_
|
|
|
5454
5548
|
* `diagnostics.substitutions` instead of happening silently. The caller
|
|
5455
5549
|
* (the provider) owns logging + dedup for both.
|
|
5456
5550
|
*/
|
|
5457
|
-
function resolveInputSteps(steps, format, engine, clusterModels) {
|
|
5551
|
+
function resolveInputSteps(steps, format, engine, clusterModels, clusterSettings) {
|
|
5458
5552
|
const resolvedSteps = [];
|
|
5459
5553
|
const unknownAddonIds = [];
|
|
5460
5554
|
const substitutions = [];
|
|
@@ -5476,12 +5570,13 @@ function resolveInputSteps(steps, format, engine, clusterModels) {
|
|
|
5476
5570
|
format: verdict.format,
|
|
5477
5571
|
formatsShipped: verdict.formatsShipped
|
|
5478
5572
|
});
|
|
5479
|
-
const childResult = s.children ? resolveInputSteps(s.children, format, engine, clusterModels) : null;
|
|
5573
|
+
const childResult = s.children ? resolveInputSteps(s.children, format, engine, clusterModels, clusterSettings) : null;
|
|
5480
5574
|
if (childResult) {
|
|
5481
5575
|
unknownAddonIds.push(...childResult.diagnostics.unknownAddonIds);
|
|
5482
5576
|
substitutions.push(...childResult.diagnostics.substitutions);
|
|
5483
5577
|
clusterRefusals.push(...childResult.diagnostics.clusterRefusals);
|
|
5484
5578
|
}
|
|
5579
|
+
const settings = require_dist.overlayClusterStepSettings(s.addonId, s.settings, clusterSettings ?? {});
|
|
5485
5580
|
resolvedSteps.push({
|
|
5486
5581
|
addonId: s.addonId,
|
|
5487
5582
|
addonName: def.name,
|
|
@@ -5491,7 +5586,7 @@ function resolveInputSteps(steps, format, engine, clusterModels) {
|
|
|
5491
5586
|
enabled: s.enabled,
|
|
5492
5587
|
modelId: verdict.modelId,
|
|
5493
5588
|
children: childResult ? childResult.steps : [],
|
|
5494
|
-
...
|
|
5589
|
+
...settings ? { settings } : {}
|
|
5495
5590
|
});
|
|
5496
5591
|
continue;
|
|
5497
5592
|
}
|
|
@@ -5504,12 +5599,13 @@ function resolveInputSteps(steps, format, engine, clusterModels) {
|
|
|
5504
5599
|
running: runningModelId,
|
|
5505
5600
|
format
|
|
5506
5601
|
});
|
|
5507
|
-
const childResult = s.children ? resolveInputSteps(s.children, format, engine, clusterModels) : null;
|
|
5602
|
+
const childResult = s.children ? resolveInputSteps(s.children, format, engine, clusterModels, clusterSettings) : null;
|
|
5508
5603
|
if (childResult) {
|
|
5509
5604
|
unknownAddonIds.push(...childResult.diagnostics.unknownAddonIds);
|
|
5510
5605
|
substitutions.push(...childResult.diagnostics.substitutions);
|
|
5511
5606
|
clusterRefusals.push(...childResult.diagnostics.clusterRefusals);
|
|
5512
5607
|
}
|
|
5608
|
+
const settings = require_dist.overlayClusterStepSettings(s.addonId, s.settings, clusterSettings ?? {});
|
|
5513
5609
|
resolvedSteps.push({
|
|
5514
5610
|
addonId: s.addonId,
|
|
5515
5611
|
addonName: def.name,
|
|
@@ -5519,7 +5615,7 @@ function resolveInputSteps(steps, format, engine, clusterModels) {
|
|
|
5519
5615
|
enabled: s.enabled,
|
|
5520
5616
|
modelId: runningModelId,
|
|
5521
5617
|
children: childResult ? childResult.steps : [],
|
|
5522
|
-
...
|
|
5618
|
+
...settings ? { settings } : {}
|
|
5523
5619
|
});
|
|
5524
5620
|
}
|
|
5525
5621
|
return {
|
|
@@ -5608,6 +5704,7 @@ var CLUSTER_MODEL_OWNER_ADDON_ID = "pipeline-orchestrator";
|
|
|
5608
5704
|
/** TTL-cached read of the cluster model row. */
|
|
5609
5705
|
var ClusterModelSource = class {
|
|
5610
5706
|
models = require_dist.DEFAULT_CLUSTER_STEP_MODELS;
|
|
5707
|
+
settings = require_dist.DEFAULT_CLUSTER_STEP_SETTINGS;
|
|
5611
5708
|
lastReadAtMs = Number.NEGATIVE_INFINITY;
|
|
5612
5709
|
inFlight = null;
|
|
5613
5710
|
logger;
|
|
@@ -5622,6 +5719,10 @@ var ClusterModelSource = class {
|
|
|
5622
5719
|
current() {
|
|
5623
5720
|
return this.models;
|
|
5624
5721
|
}
|
|
5722
|
+
/** Cluster-scoped step knobs in force right now (admission floors, …). */
|
|
5723
|
+
currentSettings() {
|
|
5724
|
+
return this.settings;
|
|
5725
|
+
}
|
|
5625
5726
|
/**
|
|
5626
5727
|
* Re-read if the cached row has expired. Concurrent callers share one
|
|
5627
5728
|
* in-flight read; a failure keeps the LAST KNOWN row.
|
|
@@ -5637,9 +5738,16 @@ var ClusterModelSource = class {
|
|
|
5637
5738
|
}
|
|
5638
5739
|
async read(api) {
|
|
5639
5740
|
try {
|
|
5640
|
-
const
|
|
5741
|
+
const view = await api.addonSettings.getGlobalSettings.query({ addonId: CLUSTER_MODEL_OWNER_ADDON_ID });
|
|
5742
|
+
const next = require_dist.pickClusterStepModels(view);
|
|
5743
|
+
const nextSettings = require_dist.pickClusterStepSettings(view);
|
|
5641
5744
|
this.lastReadAtMs = this.now();
|
|
5642
5745
|
const changed = Object.keys(next).filter((stepId) => next[stepId] !== this.models[stepId]);
|
|
5746
|
+
const settingsChanged = Object.keys(nextSettings).some((stepId) => {
|
|
5747
|
+
const from = this.settings[stepId] ?? {};
|
|
5748
|
+
const to = nextSettings[stepId] ?? {};
|
|
5749
|
+
return [...new Set([...Object.keys(from), ...Object.keys(to)])].some((key) => from[key] !== to[key]);
|
|
5750
|
+
});
|
|
5643
5751
|
if (changed.length > 0) {
|
|
5644
5752
|
this.logger.info("cluster step model changed — vectors already stored by the previous model need a re-embed pass", { meta: { changed: changed.map((stepId) => ({
|
|
5645
5753
|
stepId,
|
|
@@ -5648,6 +5756,13 @@ var ClusterModelSource = class {
|
|
|
5648
5756
|
})) } });
|
|
5649
5757
|
this.models = next;
|
|
5650
5758
|
}
|
|
5759
|
+
if (settingsChanged) {
|
|
5760
|
+
this.logger.info("cluster step settings changed", { meta: {
|
|
5761
|
+
from: { ...this.settings },
|
|
5762
|
+
to: { ...nextSettings }
|
|
5763
|
+
} });
|
|
5764
|
+
this.settings = nextSettings;
|
|
5765
|
+
}
|
|
5651
5766
|
} catch (err) {
|
|
5652
5767
|
this.logger.warn("cluster step model read failed — keeping the last known row", { meta: {
|
|
5653
5768
|
owner: CLUSTER_MODEL_OWNER_ADDON_ID,
|
|
@@ -7077,17 +7192,30 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
7077
7192
|
let jpegProvider;
|
|
7078
7193
|
const sources = [
|
|
7079
7194
|
input.frame ? "frame" : null,
|
|
7195
|
+
input.frameRef ? "frameRef" : null,
|
|
7080
7196
|
input.frameHandle ? "frameHandle" : null,
|
|
7081
7197
|
input.image ? "image" : null,
|
|
7082
7198
|
input.imageBase64 ? "imageBase64" : null,
|
|
7083
7199
|
input.referenceImage ? "referenceImage" : null
|
|
7084
7200
|
].filter((s) => s !== null);
|
|
7085
|
-
if (sources.length === 0) throw new Error("runPipeline requires exactly one of: frame, frameHandle, image, imageBase64, referenceImage");
|
|
7201
|
+
if (sources.length === 0) throw new Error("runPipeline requires exactly one of: frame, frameRef, frameHandle, image, imageBase64, referenceImage");
|
|
7086
7202
|
if (sources.length > 1) throw new Error(`runPipeline received conflicting image sources: ${sources.join(", ")}`);
|
|
7087
7203
|
if (input.frameHandle) return this.emptyFrameHandleResult(input);
|
|
7088
7204
|
const runtimeFrame = input.frame ?? void 0;
|
|
7205
|
+
const runtimeFrameRef = input.frameRef;
|
|
7089
7206
|
const decodeT0 = performance.now();
|
|
7090
|
-
if (
|
|
7207
|
+
if (runtimeFrameRef) {
|
|
7208
|
+
imageWidth = runtimeFrameRef.width;
|
|
7209
|
+
imageHeight = runtimeFrameRef.height;
|
|
7210
|
+
rootInput = {
|
|
7211
|
+
kind: "jpeg",
|
|
7212
|
+
data: Buffer.alloc(0)
|
|
7213
|
+
};
|
|
7214
|
+
jpegProvider = async () => {
|
|
7215
|
+
throw new Error("frameRef root view was requested before model resolution");
|
|
7216
|
+
};
|
|
7217
|
+
emit(`FrameRef: ${imageWidth}×${imageHeight} (${runtimeFrameRef.format})`);
|
|
7218
|
+
} else if (runtimeFrame) {
|
|
7091
7219
|
const frame = runtimeFrame;
|
|
7092
7220
|
imageWidth = frame.width;
|
|
7093
7221
|
imageHeight = frame.height;
|
|
@@ -7287,9 +7415,9 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
7287
7415
|
emit(`All models loaded`);
|
|
7288
7416
|
}
|
|
7289
7417
|
emit("Running inference...");
|
|
7290
|
-
const tree = buildExecutableTree(benchmarkSteps, (stepId) => dispatchFactory.getEngine(stepId));
|
|
7418
|
+
const tree = buildExecutableTree(benchmarkSteps, (stepId) => dispatchFactory.getEngine(stepId), this.customModelResolver);
|
|
7291
7419
|
setupMs = performance.now() - wallT0 - decodeMs;
|
|
7292
|
-
const isRuntime = Boolean(runtimeFrame);
|
|
7420
|
+
const isRuntime = Boolean(runtimeFrame || runtimeFrameRef);
|
|
7293
7421
|
const effectiveDeviceId = input.deviceId ?? 0;
|
|
7294
7422
|
const deviceOverrides = effectiveDeviceId > 0 ? await this.readDeviceStore(effectiveDeviceId) : {};
|
|
7295
7423
|
const effectiveTree = Object.keys(deviceOverrides).length > 0 ? applyDeviceOverridesToTree(tree, "object-detection", deviceOverrides) : tree;
|
|
@@ -7300,10 +7428,42 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
7300
7428
|
const proxy = this.deviceProxies.get(effectiveDeviceId);
|
|
7301
7429
|
if (proxy) cropZoneBbox = resolvePackageCropBbox(proxy.state.zones.value?.zones ?? [], proxy.state.zoneRules.value?.package ?? [], imageWidth, imageHeight) ?? void 0;
|
|
7302
7430
|
}
|
|
7303
|
-
|
|
7304
|
-
|
|
7305
|
-
|
|
7306
|
-
|
|
7431
|
+
let frameViewResolver;
|
|
7432
|
+
let rootInputViewProvider;
|
|
7433
|
+
if (runtimeFrameRef) {
|
|
7434
|
+
frameViewResolver = createRootFrameViewResolver(require_event_loop_stall_monitor.localFrameRegistry, runtimeFrameRef);
|
|
7435
|
+
rootInputViewProvider = async (root, crop) => {
|
|
7436
|
+
const view = await frameViewResolver(root, crop ? {
|
|
7437
|
+
left: crop[0],
|
|
7438
|
+
top: crop[1],
|
|
7439
|
+
width: crop[2] - crop[0],
|
|
7440
|
+
height: crop[3] - crop[1]
|
|
7441
|
+
} : void 0);
|
|
7442
|
+
const data = Buffer.from(view.data.buffer, view.data.byteOffset, view.data.byteLength);
|
|
7443
|
+
return {
|
|
7444
|
+
input: {
|
|
7445
|
+
kind: "jpeg",
|
|
7446
|
+
data
|
|
7447
|
+
},
|
|
7448
|
+
jpegProvider: async () => data,
|
|
7449
|
+
width: view.width,
|
|
7450
|
+
height: view.height,
|
|
7451
|
+
geometry: view.geometry
|
|
7452
|
+
};
|
|
7453
|
+
};
|
|
7454
|
+
}
|
|
7455
|
+
let executionSucceeded = false;
|
|
7456
|
+
let execution;
|
|
7457
|
+
try {
|
|
7458
|
+
execution = await executor.run(effectiveTree, rootInput, jpegProvider, imageWidth, imageHeight, effectiveDeviceId, {
|
|
7459
|
+
traceVerbosity: isRuntime ? this.eventBus ? "summary" : "off" : "full",
|
|
7460
|
+
plane: input.plane
|
|
7461
|
+
}, nativeCropProvider, cropZoneBbox, rootInputViewProvider);
|
|
7462
|
+
executionSucceeded = true;
|
|
7463
|
+
} finally {
|
|
7464
|
+
frameViewResolver?.release(executionSucceeded ? "success" : "error");
|
|
7465
|
+
}
|
|
7466
|
+
const { result, trace } = execution;
|
|
7307
7467
|
if (isRuntime) {
|
|
7308
7468
|
if (trace && this.eventBus) this.eventBus.emit(require_dist.createEvent(require_dist.EventCategory.PipelineTrace, {
|
|
7309
7469
|
type: "device",
|
|
@@ -7504,7 +7664,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
7504
7664
|
backend: this.currentEngine.backend,
|
|
7505
7665
|
device: this.currentEngine.device ?? null
|
|
7506
7666
|
}, clusterRefusalsOut) {
|
|
7507
|
-
const { steps: resolvedSteps, diagnostics } = resolveInputSteps(steps, format, engine, this.clusterModels.current());
|
|
7667
|
+
const { steps: resolvedSteps, diagnostics } = resolveInputSteps(steps, format, engine, this.clusterModels.current(), this.clusterModels.currentSettings());
|
|
7508
7668
|
if (clusterRefusalsOut) clusterRefusalsOut.push(...diagnostics.clusterRefusals);
|
|
7509
7669
|
for (const addonId of diagnostics.unknownAddonIds) this.logLiveDispatchIssueOnce(`unknown:${addonId}`, () => this.log.warn("Live pipeline step references an unknown addon — dropping step", { meta: { addonId } }));
|
|
7510
7670
|
for (const sub of diagnostics.substitutions) this.logLiveDispatchIssueOnce(`${sub.addonId}|${sub.chosen}|${sub.running}|${sub.format}`, () => this.log.info("Live pipeline step model substituted for engine format (node-local)", { meta: {
|