@camstack/addon-pipeline 1.2.43 → 1.2.44
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/audio-analyzer/index.js +1 -1
- package/dist/audio-analyzer/index.mjs +1 -1
- package/dist/detection-pipeline/index.js +157 -81
- package/dist/detection-pipeline/index.mjs +157 -81
- package/dist/{dist-UHbKZiSa.js → dist-BuFE5rOK.js} +724 -39
- package/dist/{dist-B-VVBzrL.mjs → dist-DOu93i_g.mjs} +659 -40
- package/dist/{event-loop-stall-monitor-DfKdC7G4.mjs → event-loop-stall-monitor-CShgQE6l.mjs} +40 -2
- package/dist/{event-loop-stall-monitor-C7_L6vHO.js → event-loop-stall-monitor-L08yG6bB.js} +40 -2
- package/dist/motion-wasm/index.js +1 -1
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/pipeline-runner/index.js +342 -69
- package/dist/pipeline-runner/index.mjs +342 -69
- package/dist/recorder/index.js +189 -6
- package/dist/recorder/index.mjs +189 -6
- package/dist/session-decode/decode-worker-child.js +197 -24
- package/dist/session-decode/decode-worker-child.mjs +197 -24
- package/dist/stream-broker/_stub.js +2 -2
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-D7iQbuKY.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DiXoZnou.mjs} +2 -2
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BRc-m6W-.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-54IklEep.mjs → _virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-B_hakWAb.mjs} +1 -1
- package/dist/stream-broker/{hostInit-CKYS9yZO.mjs → hostInit-khRXMnjl.mjs} +2 -2
- package/dist/stream-broker/index.js +3952 -1103
- package/dist/stream-broker/index.mjs +3953 -1104
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/dist/worker-protocol-BOXlUhWO.mjs +244 -0
- package/dist/worker-protocol-VURr0nUh.js +279 -0
- package/embed-dist/assets/{MaskShapeCanvas-DI4BY7W2-DxZ75vB8.js → MaskShapeCanvas-DI4BY7W2-DHZuYYjH.js} +1 -1
- package/embed-dist/assets/{MotionZonesSettings-NcxxQN8r-BBY2Ztz5.js → MotionZonesSettings-NcxxQN8r-jFDOzPCD.js} +1 -1
- package/embed-dist/assets/{PrivacyMaskSettings-APgPLF7p-BC-3QmHa.js → PrivacyMaskSettings-APgPLF7p-BPBXgIX8.js} +1 -1
- package/embed-dist/assets/{index-on1wyOnd.js → index-4CtQAybX.js} +12 -12
- package/embed-dist/assets/index-DC63og2c.css +2 -0
- package/embed-dist/index.html +2 -2
- package/package.json +1 -1
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CCC9fqHH.mjs +0 -26
- package/dist/worker-protocol-D7RzZIla.mjs +0 -77
- package/dist/worker-protocol-DextwlTX.js +0 -94
- package/embed-dist/assets/index-CGdwTcwE.css +0 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as __require } from "../chunk-DnnnRqeS.mjs";
|
|
2
|
-
import { A as
|
|
3
|
-
import { a as getDefaultModelForFormat, c as getStepDefinition, i as ALL_STEPS, l as resolveModelForFormat, n as startEventLoopStallMonitor, o as getDefaultModelForFormatFromDef, r as ALL_PIPELINE_STEPS, s as getStep } from "../event-loop-stall-monitor-
|
|
2
|
+
import { A as defaultDeviceFor$1, Dt as string, L as enumerateInferenceDevices, Ot as union, P as detectionPipelineCapability, Q as runtimeDevices$1, R as evaluateZoneRules, S as YAMNET_TO_MACRO, Tt as object, _t as sleep, ct as createEvent, it as BaseAddon, kt as EventCategory, lt as hydrateSchema, mt as parseJsonUnknown, pt as nodePin, q as pipelineExecutorCapability, rt as errMsg, t as APPLE_SA_TO_MACRO, tt as supportedRuntimes$1, u as DEVICE_BACKEND_TO_FORMAT, yt as array } from "../dist-DOu93i_g.mjs";
|
|
3
|
+
import { a as getDefaultModelForFormat, c as getStepDefinition, i as ALL_STEPS, l as resolveModelForFormat, n as startEventLoopStallMonitor, o as getDefaultModelForFormatFromDef, r as ALL_PIPELINE_STEPS, s as getStep } from "../event-loop-stall-monitor-CShgQE6l.mjs";
|
|
4
4
|
import { t as getSharp } from "../lazy-sharp-B-mb8uWx.mjs";
|
|
5
5
|
import { t as pickNodePlatformArch } from "../node-topology-platform-BkR_k6WT.mjs";
|
|
6
6
|
import { a as ensureModel, o as isModelDownloaded, r as deleteModelFromDisk } from "../model-download-service-D8B-4ktF-BB7oZL3y.mjs";
|
|
@@ -246,7 +246,7 @@ function normalizeEngineNodeId(rawNodeId) {
|
|
|
246
246
|
//#endregion
|
|
247
247
|
//#region src/detection-pipeline/default-detection-model.ts
|
|
248
248
|
/** The object-detection step id — the only slot this resolver applies to. */
|
|
249
|
-
var OBJECT_DETECTION_STEP_ID
|
|
249
|
+
var OBJECT_DETECTION_STEP_ID = "object-detection";
|
|
250
250
|
/**
|
|
251
251
|
* Balanced default object-detection model per accelerator class. `'cpu'` maps to
|
|
252
252
|
* `null` → the caller substitutes the step's own `defaultModelId` (`yolo26n`).
|
|
@@ -308,7 +308,7 @@ function classifyAccelerator(backend, device) {
|
|
|
308
308
|
function resolveDefaultDetectionModel(backend, device, format, getStepDef = getStepDefinition) {
|
|
309
309
|
let def;
|
|
310
310
|
try {
|
|
311
|
-
def = getStepDef(OBJECT_DETECTION_STEP_ID
|
|
311
|
+
def = getStepDef(OBJECT_DETECTION_STEP_ID);
|
|
312
312
|
} catch {
|
|
313
313
|
return "yolo26n";
|
|
314
314
|
}
|
|
@@ -434,7 +434,7 @@ var PoolHandle = class {
|
|
|
434
434
|
}
|
|
435
435
|
async infer(input) {
|
|
436
436
|
const start = performance.now();
|
|
437
|
-
return poolResultToEngineOutput(input.kind === "raw" ? await this.pool.inferRaw(this.modelIndex, input.data, input.width, input.height, input.format) : await this.pool.infer(this.modelIndex, input.data), performance.now() - start);
|
|
437
|
+
return poolResultToEngineOutput(input.kind === "raw" ? await this.pool.inferRaw(this.modelIndex, input.data, input.width, input.height, input.format, input.deviceId) : await this.pool.infer(this.modelIndex, input.data, input.deviceId), performance.now() - start);
|
|
438
438
|
}
|
|
439
439
|
/**
|
|
440
440
|
* Inference on a frame previously cached in the Python pool via
|
|
@@ -638,12 +638,12 @@ var PoolWorker = class {
|
|
|
638
638
|
});
|
|
639
639
|
});
|
|
640
640
|
}
|
|
641
|
-
async infer(modelByte, jpeg) {
|
|
641
|
+
async infer(modelByte, jpeg, deviceId) {
|
|
642
642
|
this.ensureReady();
|
|
643
643
|
const payload = Buffer.concat([Buffer.from([modelByte]), jpeg]);
|
|
644
|
-
return this.dispatch(MSG_INFER_JPEG, payload);
|
|
644
|
+
return this.dispatch(MSG_INFER_JPEG, payload, deviceId);
|
|
645
645
|
}
|
|
646
|
-
async inferRaw(modelByte, raw, width, height, format) {
|
|
646
|
+
async inferRaw(modelByte, raw, width, height, format, deviceId) {
|
|
647
647
|
this.ensureReady();
|
|
648
648
|
const fmtCode = RAW_FMT_CODE[format];
|
|
649
649
|
const rawHeader = Buffer.allocUnsafe(10);
|
|
@@ -651,7 +651,7 @@ var PoolWorker = class {
|
|
|
651
651
|
rawHeader.writeUInt32LE(width, 1);
|
|
652
652
|
rawHeader.writeUInt32LE(height, 5);
|
|
653
653
|
rawHeader[9] = fmtCode;
|
|
654
|
-
return this.dispatchMulti(MSG_INFER_RAW, rawHeader.length + raw.length, [rawHeader, raw]);
|
|
654
|
+
return this.dispatchMulti(MSG_INFER_RAW, rawHeader.length + raw.length, [rawHeader, raw], deviceId);
|
|
655
655
|
}
|
|
656
656
|
async inferBatch(modelByte, items, frameId = 0) {
|
|
657
657
|
this.ensureReady();
|
|
@@ -689,12 +689,12 @@ var PoolWorker = class {
|
|
|
689
689
|
const result = await this.dispatchMulti(MSG_CACHE_FRAME, payloadLen, [header, raw]);
|
|
690
690
|
if (result["error"]) throw new Error(String(result["error"]));
|
|
691
691
|
}
|
|
692
|
-
async inferCached(modelByte, frameId) {
|
|
692
|
+
async inferCached(modelByte, frameId, deviceId) {
|
|
693
693
|
this.ensureReady();
|
|
694
694
|
const payload = Buffer.allocUnsafe(5);
|
|
695
695
|
payload[0] = modelByte;
|
|
696
696
|
payload.writeUInt32LE(frameId, 1);
|
|
697
|
-
return this.dispatch(MSG_INFER_CACHED, payload);
|
|
697
|
+
return this.dispatch(MSG_INFER_CACHED, payload, deviceId);
|
|
698
698
|
}
|
|
699
699
|
async sendCommand(cmd) {
|
|
700
700
|
this.ensureReady();
|
|
@@ -718,7 +718,7 @@ var PoolWorker = class {
|
|
|
718
718
|
* raise — but logging none is how a camera went dark for 52 minutes looking
|
|
719
719
|
* like a quiet afternoon.
|
|
720
720
|
*/
|
|
721
|
-
shedIfSaturated(msgType) {
|
|
721
|
+
shedIfSaturated(msgType, deviceId) {
|
|
722
722
|
if (!SHEDDABLE_MSG_TYPES.has(msgType)) return null;
|
|
723
723
|
if (this.pending.size < POOL_MAX_IN_FLIGHT) {
|
|
724
724
|
this.shedding = false;
|
|
@@ -726,15 +726,18 @@ var PoolWorker = class {
|
|
|
726
726
|
}
|
|
727
727
|
if (!this.shedding) {
|
|
728
728
|
this.shedding = true;
|
|
729
|
-
this.log.warn("worker saturated — shedding inference until it catches up", {
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
729
|
+
this.log.warn("worker saturated — shedding inference until it catches up", {
|
|
730
|
+
...deviceId !== void 0 ? { tags: { deviceId } } : {},
|
|
731
|
+
meta: {
|
|
732
|
+
worker: this.opts.workerLabel,
|
|
733
|
+
pid: this.getPid(),
|
|
734
|
+
runtime: this.opts.poolRuntime,
|
|
735
|
+
device: this.opts.device ?? "default",
|
|
736
|
+
inFlight: this.pending.size,
|
|
737
|
+
cap: POOL_MAX_IN_FLIGHT,
|
|
738
|
+
deadlineMs: POOL_LIVE_INFER_TIMEOUT_MS
|
|
739
|
+
}
|
|
740
|
+
});
|
|
738
741
|
}
|
|
739
742
|
this.shedCount++;
|
|
740
743
|
return {
|
|
@@ -747,12 +750,12 @@ var PoolWorker = class {
|
|
|
747
750
|
deadlineFor(msgType) {
|
|
748
751
|
return SHEDDABLE_MSG_TYPES.has(msgType) ? POOL_LIVE_INFER_TIMEOUT_MS : POOL_INFER_TIMEOUT_MS;
|
|
749
752
|
}
|
|
750
|
-
dispatch(msgType, payload) {
|
|
751
|
-
const shed = this.shedIfSaturated(msgType);
|
|
753
|
+
dispatch(msgType, payload, deviceId) {
|
|
754
|
+
const shed = this.shedIfSaturated(msgType, deviceId);
|
|
752
755
|
if (shed) return Promise.resolve(shed);
|
|
753
756
|
const reqId = this.allocRequestId();
|
|
754
757
|
return new Promise((resolve, reject) => {
|
|
755
|
-
const timer = this.armRequestTimeout(reqId, reject, this.deadlineFor(msgType));
|
|
758
|
+
const timer = this.armRequestTimeout(reqId, reject, this.deadlineFor(msgType), deviceId);
|
|
756
759
|
this.pending.set(reqId, {
|
|
757
760
|
resolve,
|
|
758
761
|
reject,
|
|
@@ -772,30 +775,33 @@ var PoolWorker = class {
|
|
|
772
775
|
* `POOL_INFER_TIMEOUT_MS`. `unref` so it never keeps the event loop alive.
|
|
773
776
|
* The normal response + `rejectAll` paths clear it via `PendingRequest.timer`.
|
|
774
777
|
*/
|
|
775
|
-
armRequestTimeout(reqId, reject, timeoutMs) {
|
|
778
|
+
armRequestTimeout(reqId, reject, timeoutMs, deviceId) {
|
|
776
779
|
const timer = setTimeout(() => {
|
|
777
780
|
if (this.pending.delete(reqId)) {
|
|
778
|
-
this.log.error("inference request timed out", {
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
781
|
+
this.log.error("inference request timed out", {
|
|
782
|
+
...deviceId !== void 0 ? { tags: { deviceId } } : {},
|
|
783
|
+
meta: {
|
|
784
|
+
worker: this.opts.workerLabel,
|
|
785
|
+
pid: this.getPid(),
|
|
786
|
+
runtime: this.opts.poolRuntime,
|
|
787
|
+
device: this.opts.device ?? "default",
|
|
788
|
+
inFlight: this.pending.size,
|
|
789
|
+
reqId,
|
|
790
|
+
timeoutMs
|
|
791
|
+
}
|
|
792
|
+
});
|
|
787
793
|
reject(/* @__PURE__ */ new Error(`PoolWorker[${this.opts.workerLabel}]: inference request ${reqId} timed out after ${timeoutMs}ms (worker alive, no reply)`));
|
|
788
794
|
}
|
|
789
795
|
}, timeoutMs);
|
|
790
796
|
timer.unref?.();
|
|
791
797
|
return timer;
|
|
792
798
|
}
|
|
793
|
-
dispatchMulti(msgType, payloadLen, parts) {
|
|
794
|
-
const shed = this.shedIfSaturated(msgType);
|
|
799
|
+
dispatchMulti(msgType, payloadLen, parts, deviceId) {
|
|
800
|
+
const shed = this.shedIfSaturated(msgType, deviceId);
|
|
795
801
|
if (shed) return Promise.resolve(shed);
|
|
796
802
|
const reqId = this.allocRequestId();
|
|
797
803
|
return new Promise((resolve, reject) => {
|
|
798
|
-
const timer = this.armRequestTimeout(reqId, reject, this.deadlineFor(msgType));
|
|
804
|
+
const timer = this.armRequestTimeout(reqId, reject, this.deadlineFor(msgType), deviceId);
|
|
799
805
|
this.pending.set(reqId, {
|
|
800
806
|
resolve,
|
|
801
807
|
reject,
|
|
@@ -991,21 +997,21 @@ var SharedInferencePool = class {
|
|
|
991
997
|
workers: this.numWorkers
|
|
992
998
|
};
|
|
993
999
|
}
|
|
994
|
-
async infer(modelIndex, jpeg) {
|
|
1000
|
+
async infer(modelIndex, jpeg, deviceId) {
|
|
995
1001
|
const w = this.pickWorker();
|
|
996
|
-
return this.trackDroppedResponse(await w.infer(this.encodeModelByte(modelIndex), jpeg), modelIndex);
|
|
1002
|
+
return this.trackDroppedResponse(await w.infer(this.encodeModelByte(modelIndex), jpeg, deviceId), modelIndex);
|
|
997
1003
|
}
|
|
998
|
-
async inferRaw(modelIndex, raw, width, height, format) {
|
|
1004
|
+
async inferRaw(modelIndex, raw, width, height, format, deviceId) {
|
|
999
1005
|
const w = this.pickWorker();
|
|
1000
|
-
return this.trackDroppedResponse(await w.inferRaw(this.encodeModelByte(modelIndex), raw, width, height, format), modelIndex);
|
|
1006
|
+
return this.trackDroppedResponse(await w.inferRaw(this.encodeModelByte(modelIndex), raw, width, height, format, deviceId), modelIndex);
|
|
1001
1007
|
}
|
|
1002
1008
|
async inferBatch(modelIndex, items, frameId = 0) {
|
|
1003
1009
|
if (items.length > 255) throw new Error(`SharedInferencePool.inferBatch: max 255 items per call, got ${items.length}`);
|
|
1004
1010
|
return this.pickWorker().inferBatch(this.encodeModelByte(modelIndex), items, frameId);
|
|
1005
1011
|
}
|
|
1006
|
-
async inferCached(modelIndex, frameId) {
|
|
1012
|
+
async inferCached(modelIndex, frameId, deviceId) {
|
|
1007
1013
|
const w = this.pickWorker();
|
|
1008
|
-
return this.trackDroppedResponse(await w.inferCached(this.encodeModelByte(modelIndex), frameId), modelIndex);
|
|
1014
|
+
return this.trackDroppedResponse(await w.inferCached(this.encodeModelByte(modelIndex), frameId, deviceId), modelIndex);
|
|
1009
1015
|
}
|
|
1010
1016
|
/**
|
|
1011
1017
|
* Total `"dropped": true` responses seen from the Python pool — frames
|
|
@@ -1631,12 +1637,24 @@ var RUNTIME_TO_FORMAT = {
|
|
|
1631
1637
|
onnxruntime: "onnx",
|
|
1632
1638
|
edgetpu: "tflite"
|
|
1633
1639
|
};
|
|
1634
|
-
/** The step whose detections are re-filtered downstream by the executor's
|
|
1635
|
-
* per-macro `minConfidence*` sliders (`macroFilterVerdict`). Its pool-side
|
|
1636
|
-
* floor must stay BELOW those sliders or it silently pre-empts them. */
|
|
1637
|
-
var OBJECT_DETECTION_STEP_ID = "object-detection";
|
|
1638
1640
|
/**
|
|
1639
|
-
*
|
|
1641
|
+
* Steps whose detections are re-filtered downstream by the executor's per-macro
|
|
1642
|
+
* `minConfidence*` sliders (`macroFilterVerdict` runs on EVERY root, keyed by
|
|
1643
|
+
* the detection's macro class). Their pool-side floor must stay BELOW those
|
|
1644
|
+
* sliders or it silently pre-empts them.
|
|
1645
|
+
*
|
|
1646
|
+
* `package-detection` joined on 2026-08-07, when it gained a
|
|
1647
|
+
* `minConfidencePackage` slider: while it kept `defaultConfidence` (0.5) as its
|
|
1648
|
+
* pool floor, every sub-0.5 position of that brand-new slider was dead on
|
|
1649
|
+
* arrival — the same foot-gun this constant was introduced to remove for
|
|
1650
|
+
* object-detection. A step with NO operator-facing threshold keeps its own
|
|
1651
|
+
* `def.defaultConfidence`; adding one without adding the id here ships a
|
|
1652
|
+
* control that lies below its default.
|
|
1653
|
+
*/
|
|
1654
|
+
var PER_MACRO_REFILTERED_STEP_IDS = new Set(["object-detection", "package-detection"]);
|
|
1655
|
+
/**
|
|
1656
|
+
* Pool-side confidence FLOOR for a step the executor re-filters (#4 foot-gun
|
|
1657
|
+
* fix).
|
|
1640
1658
|
*
|
|
1641
1659
|
* The pool used to receive `def.defaultConfidence` (0.5) as its floor and drop
|
|
1642
1660
|
* every box < 0.5 BEFORE the executor's per-macro `minConfidence*` sliders run —
|
|
@@ -1644,17 +1662,17 @@ var OBJECT_DETECTION_STEP_ID = "object-detection";
|
|
|
1644
1662
|
* constant so the operator-visible per-macro sliders are the authoritative
|
|
1645
1663
|
* filter across their full 0–1 range. The per-macro slider DEFAULTS stay at 0.5
|
|
1646
1664
|
* (see `step-definitions.ts` getConfigSchema), so default UI behaviour is
|
|
1647
|
-
* unchanged; only sub-0.5 sliders start having an effect.
|
|
1648
|
-
|
|
1649
|
-
var OBJECT_DETECTION_POOL_CONFIDENCE_FLOOR = .05;
|
|
1665
|
+
* unchanged; only sub-0.5 sliders start having an effect. */
|
|
1666
|
+
var PER_MACRO_POOL_CONFIDENCE_FLOOR = .05;
|
|
1650
1667
|
/**
|
|
1651
|
-
* Resolve the pool-side confidence FLOOR for a step (#4).
|
|
1652
|
-
*
|
|
1653
|
-
* per-macro `minConfidence*`
|
|
1654
|
-
*
|
|
1668
|
+
* Resolve the pool-side confidence FLOOR for a step (#4). A step in
|
|
1669
|
+
* {@link PER_MACRO_REFILTERED_STEP_IDS} gets the small
|
|
1670
|
+
* {@link PER_MACRO_POOL_CONFIDENCE_FLOOR} so its per-macro `minConfidence*`
|
|
1671
|
+
* slider (applied downstream by the executor) is the authoritative filter;
|
|
1672
|
+
* every other step keeps its own `defaultConfidence`.
|
|
1655
1673
|
*/
|
|
1656
1674
|
function resolvePoolConfidenceFloor(stepId, defaultConfidence) {
|
|
1657
|
-
return stepId
|
|
1675
|
+
return PER_MACRO_REFILTERED_STEP_IDS.has(stepId) ? PER_MACRO_POOL_CONFIDENCE_FLOOR : defaultConfidence;
|
|
1658
1676
|
}
|
|
1659
1677
|
/**
|
|
1660
1678
|
* Load a model's runtime label list from its `-labels.json` extraFile, if any.
|
|
@@ -3482,6 +3500,21 @@ function isEnrichmentOutput(output) {
|
|
|
3482
3500
|
return output.kind === "classifications" || output.kind === "embedding" || output.kind === "text";
|
|
3483
3501
|
}
|
|
3484
3502
|
/**
|
|
3503
|
+
* Stamp the camera onto an inference input so a failure inside the SHARED pool
|
|
3504
|
+
* can name it (`InferenceInput.deviceId` — diagnostic only, it selects
|
|
3505
|
+
* nothing). Immutable, and a no-op for a caller with no real camera: the
|
|
3506
|
+
* benchmark and the reference runs pass `deviceId: 0`, and a fabricated `0` in
|
|
3507
|
+
* a log tag is worse than no tag.
|
|
3508
|
+
*/
|
|
3509
|
+
function withInferenceDeviceId(input, deviceId) {
|
|
3510
|
+
if (!Number.isFinite(deviceId) || deviceId <= 0) return input;
|
|
3511
|
+
if (input.deviceId === deviceId) return input;
|
|
3512
|
+
return {
|
|
3513
|
+
...input,
|
|
3514
|
+
deviceId
|
|
3515
|
+
};
|
|
3516
|
+
}
|
|
3517
|
+
/**
|
|
3485
3518
|
* Re-project a `crop-zone` root's detections from crop-relative coordinates
|
|
3486
3519
|
* back to full-frame image space by the crop's origin — the root analogue of
|
|
3487
3520
|
* the crop-roi child re-projection (`transformBboxToImageSpace`). Landmarks (if
|
|
@@ -3585,7 +3618,7 @@ var PipelineExecutor = class {
|
|
|
3585
3618
|
if (debug) console.log(`[executor] rootStep=${rootStep.stepId} settings=${JSON.stringify(rootStep.settings ?? {})}`);
|
|
3586
3619
|
const cropPrep = rootStep.definition.extractMode === "crop-zone" && cropZoneBbox !== void 0 ? await this.prepareCropZoneInput(cropZoneBbox, fullFrameJpegProvider, imageWidth, imageHeight, deviceId) : null;
|
|
3587
3620
|
const rootStart = Date.now();
|
|
3588
|
-
const rawRootOutput = await this.executeStep(rootStep, cropPrep?.input ?? rootInput, cropPrep?.width ?? imageWidth, cropPrep?.height ?? imageHeight, "full-frame", void 0, void 0, traceBuilder, stepTimings, poolAgg, rootShed);
|
|
3621
|
+
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);
|
|
3589
3622
|
const rootMs = Date.now() - rootStart;
|
|
3590
3623
|
if (rawRootOutput === null) continue;
|
|
3591
3624
|
const rootOutput = cropPrep && rawRootOutput.kind === "detections" ? reprojectCropZoneDetections(rawRootOutput, cropPrep.origin) : rawRootOutput;
|
|
@@ -3776,10 +3809,10 @@ var PipelineExecutor = class {
|
|
|
3776
3809
|
const ox = Math.max(0, Math.round(cropZoneBbox[0]));
|
|
3777
3810
|
const oy = Math.max(0, Math.round(cropZoneBbox[1]));
|
|
3778
3811
|
return {
|
|
3779
|
-
input: {
|
|
3812
|
+
input: withInferenceDeviceId({
|
|
3780
3813
|
kind: "jpeg",
|
|
3781
3814
|
data: crop.jpeg
|
|
3782
|
-
},
|
|
3815
|
+
}, deviceId),
|
|
3783
3816
|
width: crop.width,
|
|
3784
3817
|
height: crop.height,
|
|
3785
3818
|
origin: [
|
|
@@ -4005,10 +4038,10 @@ var PipelineExecutor = class {
|
|
|
4005
4038
|
}
|
|
4006
4039
|
} catch {}
|
|
4007
4040
|
}
|
|
4008
|
-
const childOutput = await this.executeStep(child, {
|
|
4041
|
+
const childOutput = await this.executeStep(child, withInferenceDeviceId({
|
|
4009
4042
|
kind: "jpeg",
|
|
4010
4043
|
data: cropJpegBuf
|
|
4011
|
-
}, cropW, cropH, "crop-roi", parentDetection.bbox, parentDetection.macroClass, traceBuilder, stepTimings, poolAgg);
|
|
4044
|
+
}, deviceId), cropW, cropH, "crop-roi", parentDetection.bbox, parentDetection.macroClass, traceBuilder, stepTimings, poolAgg);
|
|
4012
4045
|
const childMs = Date.now() - childStart;
|
|
4013
4046
|
if (childOutput === null) continue;
|
|
4014
4047
|
const detailsBefore = ctx.details.length;
|
|
@@ -4651,8 +4684,6 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
4651
4684
|
*/
|
|
4652
4685
|
deviceProxies = /* @__PURE__ */ new Map();
|
|
4653
4686
|
proxyUnsubs = /* @__PURE__ */ new Map();
|
|
4654
|
-
/** Initialization lock — ensures only one init runs at a time; concurrent callers await the same promise */
|
|
4655
|
-
initPromise = null;
|
|
4656
4687
|
/**
|
|
4657
4688
|
* Last logged "step configured" signature — used to dedupe the
|
|
4658
4689
|
* per-step debug trail so it only fires on actual config CHANGE
|
|
@@ -6693,20 +6724,66 @@ var DetectionPipelineProvider = class DetectionPipelineProvider {
|
|
|
6693
6724
|
* If global steps exist, initializes with them. Otherwise, creates an empty pool.
|
|
6694
6725
|
*/
|
|
6695
6726
|
async ensureEngineFactory() {
|
|
6696
|
-
if (this.initPromise) await this.initPromise;
|
|
6697
6727
|
if (this.engineFactory) return;
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
|
|
6702
|
-
|
|
6703
|
-
|
|
6704
|
-
|
|
6705
|
-
|
|
6706
|
-
|
|
6707
|
-
|
|
6728
|
+
const inflight = this.engineFactoryInflight;
|
|
6729
|
+
if (inflight) {
|
|
6730
|
+
await inflight;
|
|
6731
|
+
return;
|
|
6732
|
+
}
|
|
6733
|
+
const creation = (async () => {
|
|
6734
|
+
await this.assertEngineReady();
|
|
6735
|
+
await this.ensureBackendDeps(this.currentEngine);
|
|
6736
|
+
const factory = new EngineFactory({
|
|
6737
|
+
engine: this.currentEngine,
|
|
6738
|
+
modelsDir: this.modelsDir,
|
|
6739
|
+
logger: this.log.child("engine"),
|
|
6740
|
+
pythonPath: this.executorOptions.pythonPath ?? "",
|
|
6741
|
+
provisioning: this.executorOptions.provisioning
|
|
6742
|
+
});
|
|
6743
|
+
try {
|
|
6744
|
+
await factory.initialize([]);
|
|
6745
|
+
} catch (err) {
|
|
6746
|
+
await factory.dispose().catch(() => void 0);
|
|
6747
|
+
this.log.error("Node-default pool failed to initialize", { meta: {
|
|
6748
|
+
deviceKey: deviceKeyOf(this.currentEngine),
|
|
6749
|
+
backend: this.currentEngine.backend,
|
|
6750
|
+
device: this.currentEngine.device ?? null,
|
|
6751
|
+
error: errMsg(err)
|
|
6752
|
+
} });
|
|
6753
|
+
throw err;
|
|
6754
|
+
}
|
|
6755
|
+
this.engineFactory = factory;
|
|
6756
|
+
return factory;
|
|
6757
|
+
})();
|
|
6758
|
+
this.engineFactoryInflight = creation;
|
|
6759
|
+
try {
|
|
6760
|
+
await creation;
|
|
6761
|
+
} finally {
|
|
6762
|
+
this.engineFactoryInflight = null;
|
|
6763
|
+
}
|
|
6708
6764
|
}
|
|
6709
6765
|
/**
|
|
6766
|
+
* In-flight node-default pool creation. Single-flights
|
|
6767
|
+
* {@link ensureEngineFactory} exactly as `deviceFactoryInflight` does for the
|
|
6768
|
+
* per-device pools.
|
|
6769
|
+
*
|
|
6770
|
+
* Its absence was the chronic `PoolWorker[w0]: not initialized` storm
|
|
6771
|
+
* (1263 lines / 24 h, 2026-08-07): `this.engineFactory` was assigned BEFORE
|
|
6772
|
+
* `initialize()` was awaited, so every caller arriving during the 1-3.5 s
|
|
6773
|
+
* Python spawn took the early-exit and dispatched into a worker whose ready
|
|
6774
|
+
* handshake had not landed. The frames were logged as ERRORs and lost.
|
|
6775
|
+
*
|
|
6776
|
+
* The same bug was found and fixed twice before in this file — once for the
|
|
6777
|
+
* benchmark override cache (whose comment describes it verbatim) and once for
|
|
6778
|
+
* `resolveDeviceFactory` — which is why no `not initialized` line ever
|
|
6779
|
+
* carried a NON-default deviceKey. This is the third and last copy.
|
|
6780
|
+
*
|
|
6781
|
+
* It replaces a `private initPromise` field that was read here and assigned
|
|
6782
|
+
* NOWHERE: a dead lock that read, for as long as it existed, as if this path
|
|
6783
|
+
* were already guarded.
|
|
6784
|
+
*/
|
|
6785
|
+
engineFactoryInflight = null;
|
|
6786
|
+
/**
|
|
6710
6787
|
* Get (or lazily build) the inference-pool factory for an explicit device
|
|
6711
6788
|
* (`<backend>:<device>`, e.g. `openvino:npu`, `edgetpu:usb`) — Phase 2
|
|
6712
6789
|
* multi-device. Each device runs its OWN pool concurrently. Never mutates
|
|
@@ -7716,13 +7793,12 @@ var DetectionPipelineAddon = class extends BaseAddon {
|
|
|
7716
7793
|
}
|
|
7717
7794
|
}
|
|
7718
7795
|
/**
|
|
7719
|
-
* Bare node id
|
|
7720
|
-
*
|
|
7721
|
-
*
|
|
7722
|
-
*
|
|
7723
|
-
*
|
|
7724
|
-
*
|
|
7725
|
-
* provider never read — silently losing the per-node selection.
|
|
7796
|
+
* Bare node id for this instance. MUST match the provider's
|
|
7797
|
+
* `localProbeNodeId()` (kernel.localNodeId, default 'hub') so the per-node
|
|
7798
|
+
* settings projection here and the provider's own node targeting agree. The
|
|
7799
|
+
* old `?? this.ctx.id` fallback resolved to the ADDON id
|
|
7800
|
+
* ('detection-pipeline') when kernel.localNodeId was absent, so UI saves
|
|
7801
|
+
* landed on a key the provider never read.
|
|
7726
7802
|
*/
|
|
7727
7803
|
localNodeId() {
|
|
7728
7804
|
return normalizeEngineNodeId(this.ctxIfReady?.kernel?.localNodeId ?? "hub");
|