@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
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { n as __require } from "../chunk-DnnnRqeS.mjs";
|
|
2
|
-
import { $ as
|
|
3
|
-
import { a as
|
|
2
|
+
import { $ as pickClusterStepSettings, At as nodePin, D as YAMNET_TO_MACRO, Et as hydrateSchema, G as evaluateZoneRules, Gt as union, Ht as object, I as defaultDeviceFor$1, It as array, Kt as EventCategory, Pt as sleep, Q as pickClusterStepModels, Tt as createEvent, V as detectionPipelineCapability, W as enumerateInferenceDevices, Wt as string, X as overlayClusterStepSettings, c as DEFAULT_CLUSTER_STEP_MODELS, ct as resolvePoolMemoryPolicy, ht as errMsg, jt as parseJsonUnknown, l as DEFAULT_CLUSTER_STEP_SETTINGS, nt as pipelineExecutorCapability, ot as resolveClusterStepModelId, p as DEVICE_BACKEND_TO_FORMAT, pt as supportedRuntimes$1, t as APPLE_SA_TO_MACRO, ut as runtimeDevices$1, x as PoolMemoryWatchdog, xt as BaseAddon } from "../dist-DGQkkWc6.mjs";
|
|
3
|
+
import { a as ALL_PIPELINE_STEPS, c as getDefaultModelForFormatFromDef, d as resolveModelForFormat, f as landmarkPrecisionVerdict, l as getStep, n as startEventLoopStallMonitor, o as ALL_STEPS, r as localFrameRegistry, s as getDefaultModelForFormat, u as getStepDefinition } from "../event-loop-stall-monitor-D5jK5v4Z.mjs";
|
|
4
4
|
import { t as getSharp } from "../lazy-sharp-6oymT_yf.mjs";
|
|
5
|
-
import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-
|
|
6
|
-
import { a as ensureModel, o as isModelDownloaded, r as deleteModelFromDisk } from "../addon-utils-
|
|
5
|
+
import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-BtT7WfbJ.mjs";
|
|
6
|
+
import { a as ensureModel, o as isModelDownloaded, r as deleteModelFromDisk } from "../addon-utils-CgBCF-mE.mjs";
|
|
7
7
|
import sharp from "sharp";
|
|
8
8
|
import { spawn } from "node:child_process";
|
|
9
9
|
import * as path$1 from "node:path";
|
|
@@ -257,7 +257,13 @@ var OBJECT_DETECTION_STEP_ID = "object-detection";
|
|
|
257
257
|
* `null` → the caller substitutes the step's own `defaultModelId` (`yolo26n`).
|
|
258
258
|
* INTEL NPU + iGPU default to OUR YOLOv9 (int8 @320): yolo26 does NOT compile on
|
|
259
259
|
* the Intel NPU (arch incompat → 0 frames), while yolov9 runs on it (~298 fps
|
|
260
|
-
* measured). Apple ANE
|
|
260
|
+
* measured). Apple ANE uses the CoreML yolov9 @320 build.
|
|
261
|
+
*
|
|
262
|
+
* Do **not** promote these ids to `yolov9m-640` / `*-640`. The controlled
|
|
263
|
+
* evaluation recovered 0/3 misses at the current 0.50 threshold and failed the
|
|
264
|
+
* false-positive and capacity gates — see
|
|
265
|
+
* `docs/benchmarks/pipeline-frame-model-eval.md`. 640 remains an explicit
|
|
266
|
+
* operator pick, not a hardware-aware default.
|
|
261
267
|
*/
|
|
262
268
|
var MODEL_BY_CLASS = {
|
|
263
269
|
"apple-ane": "yolov9m-320",
|
|
@@ -1367,7 +1373,7 @@ function macroOfMinConfidenceKey(key) {
|
|
|
1367
1373
|
*/
|
|
1368
1374
|
function reachableMacros(def, entry) {
|
|
1369
1375
|
if (entry.labels.length === 0) return void 0;
|
|
1370
|
-
const map = def.classMap;
|
|
1376
|
+
const map = entry.classMap ?? def.classMap;
|
|
1371
1377
|
if (!map) return new Set(entry.labels.map((l) => l.id));
|
|
1372
1378
|
if (map.preserveOriginal) return void 0;
|
|
1373
1379
|
const macros = /* @__PURE__ */ new Set();
|
|
@@ -1387,7 +1393,7 @@ function reachableMacros(def, entry) {
|
|
|
1387
1393
|
*/
|
|
1388
1394
|
function collectClassMapDropWarning(def, entry) {
|
|
1389
1395
|
if (entry.labels.length === 0) return null;
|
|
1390
|
-
const map = def.classMap;
|
|
1396
|
+
const map = entry.classMap ?? def.classMap;
|
|
1391
1397
|
if (!map || map.preserveOriginal) return null;
|
|
1392
1398
|
const unmapped = entry.labels.filter((l) => map.mapping[l.id] === void 0).map((l) => l.id);
|
|
1393
1399
|
if (unmapped.length === 0) return null;
|
|
@@ -4163,7 +4169,7 @@ function applyChildOutput(parent, childStep, output, stepLatencyMs, ctx) {
|
|
|
4163
4169
|
switch (output.kind) {
|
|
4164
4170
|
case "detections":
|
|
4165
4171
|
if (childStep.definition.slot === "refiner") {
|
|
4166
|
-
const classMap = childStep.
|
|
4172
|
+
const classMap = childStep.effectiveClassMap?.mapping;
|
|
4167
4173
|
const parentMacro = parent.macroClass;
|
|
4168
4174
|
const best = output.detections.filter((d) => {
|
|
4169
4175
|
if (d.mask === void 0) return false;
|
|
@@ -4503,6 +4509,29 @@ function reprojectCropZoneDetections(output, cropOrigin) {
|
|
|
4503
4509
|
}))
|
|
4504
4510
|
};
|
|
4505
4511
|
}
|
|
4512
|
+
function reprojectViewDetections(output, geometry) {
|
|
4513
|
+
const mapPoint = (x, y) => ({
|
|
4514
|
+
x: geometry.sourceCrop.left + x / geometry.scale.x,
|
|
4515
|
+
y: geometry.sourceCrop.top + y / geometry.scale.y
|
|
4516
|
+
});
|
|
4517
|
+
return {
|
|
4518
|
+
kind: "detections",
|
|
4519
|
+
detections: output.detections.map((det) => {
|
|
4520
|
+
const origin = mapPoint(det.bbox[0], det.bbox[1]);
|
|
4521
|
+
const end = mapPoint(det.bbox[2], det.bbox[3]);
|
|
4522
|
+
return {
|
|
4523
|
+
...det,
|
|
4524
|
+
bbox: [
|
|
4525
|
+
origin.x,
|
|
4526
|
+
origin.y,
|
|
4527
|
+
end.x,
|
|
4528
|
+
end.y
|
|
4529
|
+
],
|
|
4530
|
+
...det.landmarks ? { landmarks: det.landmarks.map((landmark) => mapPoint(landmark.x, landmark.y)) } : {}
|
|
4531
|
+
};
|
|
4532
|
+
})
|
|
4533
|
+
};
|
|
4534
|
+
}
|
|
4506
4535
|
var PipelineExecutor = class {
|
|
4507
4536
|
opts;
|
|
4508
4537
|
/** Bounds the full-frame-guard drop log: first example per (device,
|
|
@@ -4564,7 +4593,7 @@ var PipelineExecutor = class {
|
|
|
4564
4593
|
*
|
|
4565
4594
|
* @returns FrameResult + optional trace
|
|
4566
4595
|
*/
|
|
4567
|
-
async run(tree, rootInput, fullFrameJpegProvider, imageWidth, imageHeight, deviceId, runOpts, nativeCropProvider, cropZoneBbox) {
|
|
4596
|
+
async run(tree, rootInput, fullFrameJpegProvider, imageWidth, imageHeight, deviceId, runOpts, nativeCropProvider, cropZoneBbox, rootInputViewProvider) {
|
|
4568
4597
|
const startMs = Date.now();
|
|
4569
4598
|
const verbosity = runOpts?.traceVerbosity ?? "off";
|
|
4570
4599
|
const traceBuilder = new ExecutionTraceBuilder(verbosity, deviceId, imageWidth, imageHeight, this.opts.engineRuntime);
|
|
@@ -4612,18 +4641,20 @@ var PipelineExecutor = class {
|
|
|
4612
4641
|
};
|
|
4613
4642
|
for (const rootStep of tree.roots) {
|
|
4614
4643
|
if (debug) console.log(`[executor] rootStep=${rootStep.stepId} settings=${JSON.stringify(rootStep.settings ?? {})}`);
|
|
4615
|
-
const
|
|
4644
|
+
const rootCrop = rootStep.definition.extractMode === "crop-zone" ? cropZoneBbox : void 0;
|
|
4645
|
+
const rootView = rootInputViewProvider ? await rootInputViewProvider(rootStep, rootCrop) : null;
|
|
4646
|
+
const cropPrep = !rootView && rootCrop !== void 0 ? await this.prepareCropZoneInput(rootCrop, fullFrameJpegProvider, imageWidth, imageHeight, deviceId) : null;
|
|
4616
4647
|
const rootStart = Date.now();
|
|
4617
|
-
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);
|
|
4648
|
+
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);
|
|
4618
4649
|
const rootMs = Date.now() - rootStart;
|
|
4619
4650
|
if (rawRootOutput === null) continue;
|
|
4620
|
-
const rootOutput = cropPrep && rawRootOutput.kind === "detections" ? reprojectCropZoneDetections(rawRootOutput, cropPrep.origin) : rawRootOutput;
|
|
4651
|
+
const rootOutput = rootView && rawRootOutput.kind === "detections" ? reprojectViewDetections(rawRootOutput, rootView.geometry) : cropPrep && rawRootOutput.kind === "detections" ? reprojectCropZoneDetections(rawRootOutput, cropPrep.origin) : rawRootOutput;
|
|
4621
4652
|
if (rootOutput.kind !== "detections") {
|
|
4622
4653
|
if (isEnrichmentOutput(rootOutput)) {
|
|
4623
4654
|
const mutable = this.synthesizeRootDetection(rootOutput, rootStep, idGen, rootMs, imageWidth, imageHeight);
|
|
4624
4655
|
applyChildOutput(mutable, rootStep, rootOutput, rootMs, ctx);
|
|
4625
4656
|
try {
|
|
4626
|
-
await this.executeChildren(rootStep.children, mutable, fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg, runOpts?.plane, deviceId, nativeCropProvider);
|
|
4657
|
+
await this.executeChildren(rootStep.children, mutable, rootView?.jpegProvider ?? fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg, runOpts?.plane, deviceId, nativeCropProvider);
|
|
4627
4658
|
} catch (err) {
|
|
4628
4659
|
this.opts.logger?.warn("Pipeline child execution failed — keeping parent detection", {
|
|
4629
4660
|
tags: { deviceId },
|
|
@@ -4641,12 +4672,12 @@ var PipelineExecutor = class {
|
|
|
4641
4672
|
}
|
|
4642
4673
|
for (const det of rootOutput.detections) {
|
|
4643
4674
|
const mutable = toMutableRootDetection(det, rootStep, idGen, rootMs);
|
|
4644
|
-
if (rootStep.
|
|
4645
|
-
const mapped = rootStep.
|
|
4675
|
+
if (rootStep.effectiveClassMap) {
|
|
4676
|
+
const mapped = rootStep.effectiveClassMap.mapping[det.class];
|
|
4646
4677
|
if (mapped) {
|
|
4647
4678
|
mutable.originalClass = det.class;
|
|
4648
4679
|
mutable.macroClass = mapped;
|
|
4649
|
-
} else if (!rootStep.
|
|
4680
|
+
} else if (!rootStep.effectiveClassMap.preserveOriginal) {
|
|
4650
4681
|
(discarded ??= []).push({
|
|
4651
4682
|
bbox: [
|
|
4652
4683
|
mutable.bbox[0],
|
|
@@ -4728,7 +4759,7 @@ var PipelineExecutor = class {
|
|
|
4728
4759
|
}
|
|
4729
4760
|
});
|
|
4730
4761
|
try {
|
|
4731
|
-
await this.executeChildren(rootStep.children, mutable, fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg, runOpts?.plane, deviceId, nativeCropProvider);
|
|
4762
|
+
await this.executeChildren(rootStep.children, mutable, rootView?.jpegProvider ?? fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg, runOpts?.plane, deviceId, nativeCropProvider);
|
|
4732
4763
|
} catch (err) {
|
|
4733
4764
|
this.opts.logger?.warn("Pipeline child execution failed — keeping parent detection", {
|
|
4734
4765
|
tags: { deviceId },
|
|
@@ -5148,6 +5179,59 @@ function capitalize(s) {
|
|
|
5148
5179
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
5149
5180
|
}
|
|
5150
5181
|
//#endregion
|
|
5182
|
+
//#region src/session-decode/frame-view-payload.ts
|
|
5183
|
+
var FRAME_VIEW_PAYLOAD_POLICY = "jpeg";
|
|
5184
|
+
//#endregion
|
|
5185
|
+
//#region src/detection-pipeline/root-frame-view.ts
|
|
5186
|
+
/** Resolve the pre-padding content requested from the decode worker for one root. */
|
|
5187
|
+
function resolveRootFrameViewSpec(model, source, crop, format = FRAME_VIEW_PAYLOAD_POLICY) {
|
|
5188
|
+
const sourceWidth = crop?.width ?? source.width;
|
|
5189
|
+
const sourceHeight = crop?.height ?? source.height;
|
|
5190
|
+
if (model.preprocessMode !== "letterbox") return {
|
|
5191
|
+
...crop ? { crop } : {},
|
|
5192
|
+
content: {
|
|
5193
|
+
width: model.inputSize.width,
|
|
5194
|
+
height: model.inputSize.height
|
|
5195
|
+
},
|
|
5196
|
+
fit: "stretch",
|
|
5197
|
+
format
|
|
5198
|
+
};
|
|
5199
|
+
const scale = Math.min(model.inputSize.width / sourceWidth, model.inputSize.height / sourceHeight);
|
|
5200
|
+
return {
|
|
5201
|
+
...crop ? { crop } : {},
|
|
5202
|
+
content: {
|
|
5203
|
+
width: Math.max(1, Math.round(sourceWidth * scale)),
|
|
5204
|
+
height: Math.max(1, Math.round(sourceHeight * scale))
|
|
5205
|
+
},
|
|
5206
|
+
fit: "contain",
|
|
5207
|
+
format
|
|
5208
|
+
};
|
|
5209
|
+
}
|
|
5210
|
+
//#endregion
|
|
5211
|
+
//#region src/detection-pipeline/frame-ref-view-provider.ts
|
|
5212
|
+
var LocalFrameRefMissError = class extends Error {
|
|
5213
|
+
reason;
|
|
5214
|
+
constructor(reason) {
|
|
5215
|
+
super(`local frameRef miss: ${reason}`);
|
|
5216
|
+
this.reason = reason;
|
|
5217
|
+
this.name = "LocalFrameRefMissError";
|
|
5218
|
+
}
|
|
5219
|
+
};
|
|
5220
|
+
/** Bind one registry lease for all heterogeneous roots of a pipeline invocation. */
|
|
5221
|
+
function createRootFrameViewResolver(registry, ref) {
|
|
5222
|
+
const lease = registry.acquire(ref);
|
|
5223
|
+
if (!lease) throw new LocalFrameRefMissError(ref.registryId === registry.registryId ? "stale-ref" : "foreign-registry");
|
|
5224
|
+
const resolve = async (root, crop) => {
|
|
5225
|
+
const model = root.definition.models.find((candidate) => candidate.id === root.modelId);
|
|
5226
|
+
if (!model) throw new Error(`frame view model not found: ${root.modelId}`);
|
|
5227
|
+
const spec = resolveRootFrameViewSpec(model, ref, crop);
|
|
5228
|
+
const result = await lease.resolve(spec);
|
|
5229
|
+
if (result.kind === "miss") throw new LocalFrameRefMissError(result.reason);
|
|
5230
|
+
return result;
|
|
5231
|
+
};
|
|
5232
|
+
return Object.assign(resolve, { release: (reason) => lease.release(reason) });
|
|
5233
|
+
}
|
|
5234
|
+
//#endregion
|
|
5151
5235
|
//#region src/detection-pipeline/pipeline/native-crop-compose.ts
|
|
5152
5236
|
/** Clamp `v` into `[lo, hi]`. */
|
|
5153
5237
|
function clamp(v, lo, hi) {
|
|
@@ -5187,23 +5271,32 @@ function composeCropRoiToFrameNorm(roi, cropFrameSpace, frameWidth, frameHeight)
|
|
|
5187
5271
|
//#endregion
|
|
5188
5272
|
//#region src/detection-pipeline/pipeline/tree-builder.ts
|
|
5189
5273
|
/**
|
|
5274
|
+
* Effective class map for `(definition, modelId)` without writing back to the
|
|
5275
|
+
* shared StepDefinition. Custom models missing from `definition.models` are
|
|
5276
|
+
* resolved through the optional registry callback.
|
|
5277
|
+
*/
|
|
5278
|
+
function resolveEffectiveClassMap(definition, modelId, resolveModel) {
|
|
5279
|
+
return (definition.models.find((model) => model.id === modelId) ?? resolveModel?.(definition.id, modelId))?.classMap ?? definition.classMap;
|
|
5280
|
+
}
|
|
5281
|
+
/**
|
|
5190
5282
|
* Build an executable tree from user config.
|
|
5191
5283
|
*
|
|
5192
5284
|
* @param steps - User-configured pipeline steps (from PipelineDefaultStep[])
|
|
5193
5285
|
* @param getEngine - Function that returns an IInferenceEngine for a step ID.
|
|
5194
5286
|
* Throws if step not loaded.
|
|
5195
5287
|
*/
|
|
5196
|
-
function buildExecutableTree(steps, getEngine) {
|
|
5197
|
-
return { roots: steps.filter((s) => s.enabled).filter((s) => s.slot !== "audio-classifier").map((s) => buildNode(s, getEngine)) };
|
|
5288
|
+
function buildExecutableTree(steps, getEngine, resolveModel) {
|
|
5289
|
+
return { roots: steps.filter((s) => s.enabled).filter((s) => s.slot !== "audio-classifier").map((s) => buildNode(s, getEngine, resolveModel)) };
|
|
5198
5290
|
}
|
|
5199
|
-
function buildNode(step, getEngine) {
|
|
5291
|
+
function buildNode(step, getEngine, resolveModel) {
|
|
5200
5292
|
const definition = getStepDefinition(step.addonId);
|
|
5201
5293
|
const engine = getEngine(step.addonId);
|
|
5202
|
-
const children = (step.children ?? []).filter((c) => c.enabled).map((c) => buildNode(c, getEngine));
|
|
5294
|
+
const children = (step.children ?? []).filter((c) => c.enabled).map((c) => buildNode(c, getEngine, resolveModel));
|
|
5203
5295
|
const mergedSettings = {
|
|
5204
5296
|
...collectSchemaDefaults(step.addonId),
|
|
5205
5297
|
...step.settings
|
|
5206
5298
|
};
|
|
5299
|
+
const effectiveClassMap = resolveEffectiveClassMap(definition, step.modelId, resolveModel);
|
|
5207
5300
|
return {
|
|
5208
5301
|
stepId: step.addonId,
|
|
5209
5302
|
definition,
|
|
@@ -5212,7 +5305,8 @@ function buildNode(step, getEngine) {
|
|
|
5212
5305
|
inputClasses: definition.inputClasses ?? [],
|
|
5213
5306
|
enabled: step.enabled,
|
|
5214
5307
|
children,
|
|
5215
|
-
...Object.keys(mergedSettings).length > 0 ? { settings: mergedSettings } : {}
|
|
5308
|
+
...Object.keys(mergedSettings).length > 0 ? { settings: mergedSettings } : {},
|
|
5309
|
+
...effectiveClassMap !== void 0 ? { effectiveClassMap } : {}
|
|
5216
5310
|
};
|
|
5217
5311
|
}
|
|
5218
5312
|
/**
|
|
@@ -5447,7 +5541,7 @@ function collectUnknownAddonIssues(steps, getStepDef = getStepDefinition) {
|
|
|
5447
5541
|
* `diagnostics.substitutions` instead of happening silently. The caller
|
|
5448
5542
|
* (the provider) owns logging + dedup for both.
|
|
5449
5543
|
*/
|
|
5450
|
-
function resolveInputSteps(steps, format, engine, clusterModels) {
|
|
5544
|
+
function resolveInputSteps(steps, format, engine, clusterModels, clusterSettings) {
|
|
5451
5545
|
const resolvedSteps = [];
|
|
5452
5546
|
const unknownAddonIds = [];
|
|
5453
5547
|
const substitutions = [];
|
|
@@ -5469,12 +5563,13 @@ function resolveInputSteps(steps, format, engine, clusterModels) {
|
|
|
5469
5563
|
format: verdict.format,
|
|
5470
5564
|
formatsShipped: verdict.formatsShipped
|
|
5471
5565
|
});
|
|
5472
|
-
const childResult = s.children ? resolveInputSteps(s.children, format, engine, clusterModels) : null;
|
|
5566
|
+
const childResult = s.children ? resolveInputSteps(s.children, format, engine, clusterModels, clusterSettings) : null;
|
|
5473
5567
|
if (childResult) {
|
|
5474
5568
|
unknownAddonIds.push(...childResult.diagnostics.unknownAddonIds);
|
|
5475
5569
|
substitutions.push(...childResult.diagnostics.substitutions);
|
|
5476
5570
|
clusterRefusals.push(...childResult.diagnostics.clusterRefusals);
|
|
5477
5571
|
}
|
|
5572
|
+
const settings = overlayClusterStepSettings(s.addonId, s.settings, clusterSettings ?? {});
|
|
5478
5573
|
resolvedSteps.push({
|
|
5479
5574
|
addonId: s.addonId,
|
|
5480
5575
|
addonName: def.name,
|
|
@@ -5484,7 +5579,7 @@ function resolveInputSteps(steps, format, engine, clusterModels) {
|
|
|
5484
5579
|
enabled: s.enabled,
|
|
5485
5580
|
modelId: verdict.modelId,
|
|
5486
5581
|
children: childResult ? childResult.steps : [],
|
|
5487
|
-
...
|
|
5582
|
+
...settings ? { settings } : {}
|
|
5488
5583
|
});
|
|
5489
5584
|
continue;
|
|
5490
5585
|
}
|
|
@@ -5497,12 +5592,13 @@ function resolveInputSteps(steps, format, engine, clusterModels) {
|
|
|
5497
5592
|
running: runningModelId,
|
|
5498
5593
|
format
|
|
5499
5594
|
});
|
|
5500
|
-
const childResult = s.children ? resolveInputSteps(s.children, format, engine, clusterModels) : null;
|
|
5595
|
+
const childResult = s.children ? resolveInputSteps(s.children, format, engine, clusterModels, clusterSettings) : null;
|
|
5501
5596
|
if (childResult) {
|
|
5502
5597
|
unknownAddonIds.push(...childResult.diagnostics.unknownAddonIds);
|
|
5503
5598
|
substitutions.push(...childResult.diagnostics.substitutions);
|
|
5504
5599
|
clusterRefusals.push(...childResult.diagnostics.clusterRefusals);
|
|
5505
5600
|
}
|
|
5601
|
+
const settings = overlayClusterStepSettings(s.addonId, s.settings, clusterSettings ?? {});
|
|
5506
5602
|
resolvedSteps.push({
|
|
5507
5603
|
addonId: s.addonId,
|
|
5508
5604
|
addonName: def.name,
|
|
@@ -5512,7 +5608,7 @@ function resolveInputSteps(steps, format, engine, clusterModels) {
|
|
|
5512
5608
|
enabled: s.enabled,
|
|
5513
5609
|
modelId: runningModelId,
|
|
5514
5610
|
children: childResult ? childResult.steps : [],
|
|
5515
|
-
...
|
|
5611
|
+
...settings ? { settings } : {}
|
|
5516
5612
|
});
|
|
5517
5613
|
}
|
|
5518
5614
|
return {
|
|
@@ -5601,6 +5697,7 @@ var CLUSTER_MODEL_OWNER_ADDON_ID = "pipeline-orchestrator";
|
|
|
5601
5697
|
/** TTL-cached read of the cluster model row. */
|
|
5602
5698
|
var ClusterModelSource = class {
|
|
5603
5699
|
models = DEFAULT_CLUSTER_STEP_MODELS;
|
|
5700
|
+
settings = DEFAULT_CLUSTER_STEP_SETTINGS;
|
|
5604
5701
|
lastReadAtMs = Number.NEGATIVE_INFINITY;
|
|
5605
5702
|
inFlight = null;
|
|
5606
5703
|
logger;
|
|
@@ -5615,6 +5712,10 @@ var ClusterModelSource = class {
|
|
|
5615
5712
|
current() {
|
|
5616
5713
|
return this.models;
|
|
5617
5714
|
}
|
|
5715
|
+
/** Cluster-scoped step knobs in force right now (admission floors, …). */
|
|
5716
|
+
currentSettings() {
|
|
5717
|
+
return this.settings;
|
|
5718
|
+
}
|
|
5618
5719
|
/**
|
|
5619
5720
|
* Re-read if the cached row has expired. Concurrent callers share one
|
|
5620
5721
|
* in-flight read; a failure keeps the LAST KNOWN row.
|
|
@@ -5630,9 +5731,16 @@ var ClusterModelSource = class {
|
|
|
5630
5731
|
}
|
|
5631
5732
|
async read(api) {
|
|
5632
5733
|
try {
|
|
5633
|
-
const
|
|
5734
|
+
const view = await api.addonSettings.getGlobalSettings.query({ addonId: CLUSTER_MODEL_OWNER_ADDON_ID });
|
|
5735
|
+
const next = pickClusterStepModels(view);
|
|
5736
|
+
const nextSettings = pickClusterStepSettings(view);
|
|
5634
5737
|
this.lastReadAtMs = this.now();
|
|
5635
5738
|
const changed = Object.keys(next).filter((stepId) => next[stepId] !== this.models[stepId]);
|
|
5739
|
+
const settingsChanged = Object.keys(nextSettings).some((stepId) => {
|
|
5740
|
+
const from = this.settings[stepId] ?? {};
|
|
5741
|
+
const to = nextSettings[stepId] ?? {};
|
|
5742
|
+
return [...new Set([...Object.keys(from), ...Object.keys(to)])].some((key) => from[key] !== to[key]);
|
|
5743
|
+
});
|
|
5636
5744
|
if (changed.length > 0) {
|
|
5637
5745
|
this.logger.info("cluster step model changed — vectors already stored by the previous model need a re-embed pass", { meta: { changed: changed.map((stepId) => ({
|
|
5638
5746
|
stepId,
|
|
@@ -5641,6 +5749,13 @@ var ClusterModelSource = class {
|
|
|
5641
5749
|
})) } });
|
|
5642
5750
|
this.models = next;
|
|
5643
5751
|
}
|
|
5752
|
+
if (settingsChanged) {
|
|
5753
|
+
this.logger.info("cluster step settings changed", { meta: {
|
|
5754
|
+
from: { ...this.settings },
|
|
5755
|
+
to: { ...nextSettings }
|
|
5756
|
+
} });
|
|
5757
|
+
this.settings = nextSettings;
|
|
5758
|
+
}
|
|
5644
5759
|
} catch (err) {
|
|
5645
5760
|
this.logger.warn("cluster step model read failed — keeping the last known row", { meta: {
|
|
5646
5761
|
owner: CLUSTER_MODEL_OWNER_ADDON_ID,
|
|
@@ -7070,17 +7185,30 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
7070
7185
|
let jpegProvider;
|
|
7071
7186
|
const sources = [
|
|
7072
7187
|
input.frame ? "frame" : null,
|
|
7188
|
+
input.frameRef ? "frameRef" : null,
|
|
7073
7189
|
input.frameHandle ? "frameHandle" : null,
|
|
7074
7190
|
input.image ? "image" : null,
|
|
7075
7191
|
input.imageBase64 ? "imageBase64" : null,
|
|
7076
7192
|
input.referenceImage ? "referenceImage" : null
|
|
7077
7193
|
].filter((s) => s !== null);
|
|
7078
|
-
if (sources.length === 0) throw new Error("runPipeline requires exactly one of: frame, frameHandle, image, imageBase64, referenceImage");
|
|
7194
|
+
if (sources.length === 0) throw new Error("runPipeline requires exactly one of: frame, frameRef, frameHandle, image, imageBase64, referenceImage");
|
|
7079
7195
|
if (sources.length > 1) throw new Error(`runPipeline received conflicting image sources: ${sources.join(", ")}`);
|
|
7080
7196
|
if (input.frameHandle) return this.emptyFrameHandleResult(input);
|
|
7081
7197
|
const runtimeFrame = input.frame ?? void 0;
|
|
7198
|
+
const runtimeFrameRef = input.frameRef;
|
|
7082
7199
|
const decodeT0 = performance.now();
|
|
7083
|
-
if (
|
|
7200
|
+
if (runtimeFrameRef) {
|
|
7201
|
+
imageWidth = runtimeFrameRef.width;
|
|
7202
|
+
imageHeight = runtimeFrameRef.height;
|
|
7203
|
+
rootInput = {
|
|
7204
|
+
kind: "jpeg",
|
|
7205
|
+
data: Buffer.alloc(0)
|
|
7206
|
+
};
|
|
7207
|
+
jpegProvider = async () => {
|
|
7208
|
+
throw new Error("frameRef root view was requested before model resolution");
|
|
7209
|
+
};
|
|
7210
|
+
emit(`FrameRef: ${imageWidth}×${imageHeight} (${runtimeFrameRef.format})`);
|
|
7211
|
+
} else if (runtimeFrame) {
|
|
7084
7212
|
const frame = runtimeFrame;
|
|
7085
7213
|
imageWidth = frame.width;
|
|
7086
7214
|
imageHeight = frame.height;
|
|
@@ -7280,9 +7408,9 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
7280
7408
|
emit(`All models loaded`);
|
|
7281
7409
|
}
|
|
7282
7410
|
emit("Running inference...");
|
|
7283
|
-
const tree = buildExecutableTree(benchmarkSteps, (stepId) => dispatchFactory.getEngine(stepId));
|
|
7411
|
+
const tree = buildExecutableTree(benchmarkSteps, (stepId) => dispatchFactory.getEngine(stepId), this.customModelResolver);
|
|
7284
7412
|
setupMs = performance.now() - wallT0 - decodeMs;
|
|
7285
|
-
const isRuntime = Boolean(runtimeFrame);
|
|
7413
|
+
const isRuntime = Boolean(runtimeFrame || runtimeFrameRef);
|
|
7286
7414
|
const effectiveDeviceId = input.deviceId ?? 0;
|
|
7287
7415
|
const deviceOverrides = effectiveDeviceId > 0 ? await this.readDeviceStore(effectiveDeviceId) : {};
|
|
7288
7416
|
const effectiveTree = Object.keys(deviceOverrides).length > 0 ? applyDeviceOverridesToTree(tree, "object-detection", deviceOverrides) : tree;
|
|
@@ -7293,10 +7421,42 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
7293
7421
|
const proxy = this.deviceProxies.get(effectiveDeviceId);
|
|
7294
7422
|
if (proxy) cropZoneBbox = resolvePackageCropBbox(proxy.state.zones.value?.zones ?? [], proxy.state.zoneRules.value?.package ?? [], imageWidth, imageHeight) ?? void 0;
|
|
7295
7423
|
}
|
|
7296
|
-
|
|
7297
|
-
|
|
7298
|
-
|
|
7299
|
-
|
|
7424
|
+
let frameViewResolver;
|
|
7425
|
+
let rootInputViewProvider;
|
|
7426
|
+
if (runtimeFrameRef) {
|
|
7427
|
+
frameViewResolver = createRootFrameViewResolver(localFrameRegistry, runtimeFrameRef);
|
|
7428
|
+
rootInputViewProvider = async (root, crop) => {
|
|
7429
|
+
const view = await frameViewResolver(root, crop ? {
|
|
7430
|
+
left: crop[0],
|
|
7431
|
+
top: crop[1],
|
|
7432
|
+
width: crop[2] - crop[0],
|
|
7433
|
+
height: crop[3] - crop[1]
|
|
7434
|
+
} : void 0);
|
|
7435
|
+
const data = Buffer.from(view.data.buffer, view.data.byteOffset, view.data.byteLength);
|
|
7436
|
+
return {
|
|
7437
|
+
input: {
|
|
7438
|
+
kind: "jpeg",
|
|
7439
|
+
data
|
|
7440
|
+
},
|
|
7441
|
+
jpegProvider: async () => data,
|
|
7442
|
+
width: view.width,
|
|
7443
|
+
height: view.height,
|
|
7444
|
+
geometry: view.geometry
|
|
7445
|
+
};
|
|
7446
|
+
};
|
|
7447
|
+
}
|
|
7448
|
+
let executionSucceeded = false;
|
|
7449
|
+
let execution;
|
|
7450
|
+
try {
|
|
7451
|
+
execution = await executor.run(effectiveTree, rootInput, jpegProvider, imageWidth, imageHeight, effectiveDeviceId, {
|
|
7452
|
+
traceVerbosity: isRuntime ? this.eventBus ? "summary" : "off" : "full",
|
|
7453
|
+
plane: input.plane
|
|
7454
|
+
}, nativeCropProvider, cropZoneBbox, rootInputViewProvider);
|
|
7455
|
+
executionSucceeded = true;
|
|
7456
|
+
} finally {
|
|
7457
|
+
frameViewResolver?.release(executionSucceeded ? "success" : "error");
|
|
7458
|
+
}
|
|
7459
|
+
const { result, trace } = execution;
|
|
7300
7460
|
if (isRuntime) {
|
|
7301
7461
|
if (trace && this.eventBus) this.eventBus.emit(createEvent(EventCategory.PipelineTrace, {
|
|
7302
7462
|
type: "device",
|
|
@@ -7497,7 +7657,7 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
7497
7657
|
backend: this.currentEngine.backend,
|
|
7498
7658
|
device: this.currentEngine.device ?? null
|
|
7499
7659
|
}, clusterRefusalsOut) {
|
|
7500
|
-
const { steps: resolvedSteps, diagnostics } = resolveInputSteps(steps, format, engine, this.clusterModels.current());
|
|
7660
|
+
const { steps: resolvedSteps, diagnostics } = resolveInputSteps(steps, format, engine, this.clusterModels.current(), this.clusterModels.currentSettings());
|
|
7501
7661
|
if (clusterRefusalsOut) clusterRefusalsOut.push(...diagnostics.clusterRefusals);
|
|
7502
7662
|
for (const addonId of diagnostics.unknownAddonIds) this.logLiveDispatchIssueOnce(`unknown:${addonId}`, () => this.log.warn("Live pipeline step references an unknown addon — dropping step", { meta: { addonId } }));
|
|
7503
7663
|
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: {
|