@camstack/addon-pipeline 1.2.28 → 1.2.29
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/detection-pipeline/index.js +71 -12
- package/dist/detection-pipeline/index.mjs +71 -12
- package/dist/pipeline-runner/index.js +23 -3
- package/dist/pipeline-runner/index.mjs +23 -3
- package/dist/{step-definitions-C8A78dBi.mjs → step-definitions-1GIwU6R8.mjs} +12 -1
- package/dist/{step-definitions-Bo1hJQQw.js → step-definitions-Drb9cWbB.js} +12 -1
- package/package.json +1 -1
|
@@ -4,7 +4,7 @@ Object.defineProperties(exports, {
|
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../chunk-emK7D4bc.js");
|
|
6
6
|
const require_dist = require("../dist-DUHlZcWd.js");
|
|
7
|
-
const require_step_definitions = require("../step-definitions-
|
|
7
|
+
const require_step_definitions = require("../step-definitions-Drb9cWbB.js");
|
|
8
8
|
const require_node_topology_platform = require("../node-topology-platform-CFZ7F4xW.js");
|
|
9
9
|
const require_model_download_service_Cp9f4dk6 = require("../model-download-service-Cp9f4dk6-fsdDExML.js");
|
|
10
10
|
let node_child_process = require("node:child_process");
|
|
@@ -2704,19 +2704,25 @@ async function nativeChildCrop(provider, bbox, imageWidth, imageHeight, maxWidth
|
|
|
2704
2704
|
* DROPS detections outright, so it sits between that and a hard cut).
|
|
2705
2705
|
*/
|
|
2706
2706
|
var FULL_FRAME_MAX_CONFIDENCE = .7;
|
|
2707
|
+
/** A cut only makes sense in (0, 1); anything else is treated as OFF rather
|
|
2708
|
+
* than dropping every detection on a typo. */
|
|
2709
|
+
function isUsableHardAreaCut(ratio) {
|
|
2710
|
+
return Number.isFinite(ratio) && ratio > 0 && ratio < 1;
|
|
2711
|
+
}
|
|
2707
2712
|
/**
|
|
2708
2713
|
* True when `bbox` is a near-full-frame LOW-confidence phantom that should be
|
|
2709
2714
|
* DROPPED from the frame's detections (overlay / tracker / events / motion-wake).
|
|
2710
2715
|
*
|
|
2711
2716
|
* Rule (drop ⇔ returns true):
|
|
2712
|
-
*
|
|
2713
|
-
*
|
|
2714
|
-
*
|
|
2715
|
-
*
|
|
2717
|
+
* areaRatio ≥ `hardAreaRatio` ← score-independent, OFF by default
|
|
2718
|
+
* OR ( (areaRatio ≥ {@link FULL_FRAME_AREA_RATIO}
|
|
2719
|
+
* OR width ≥ {@link FULL_FRAME_DIMENSION_RATIO} × frameWidth
|
|
2720
|
+
* OR height ≥ {@link FULL_FRAME_DIMENSION_RATIO} × frameHeight)
|
|
2721
|
+
* AND score < `maxConfidence` )
|
|
2716
2722
|
*
|
|
2717
|
-
*
|
|
2718
|
-
* subject and
|
|
2719
|
-
* to reject on → not a phantom.
|
|
2723
|
+
* Below the hard cut a high-confidence detection (`score ≥ maxConfidence`) is
|
|
2724
|
+
* trusted as a real subject and survives. Degenerate frame dimensions (≤0)
|
|
2725
|
+
* carry no info to reject on → not a phantom.
|
|
2720
2726
|
*
|
|
2721
2727
|
* @param bbox absolute-pixel `[x1, y1, x2, y2]` box in source-frame coords.
|
|
2722
2728
|
* @param frameWidth source frame width in px.
|
|
@@ -2725,10 +2731,26 @@ var FULL_FRAME_MAX_CONFIDENCE = .7;
|
|
|
2725
2731
|
* @param maxConfidence confidence bar below which a full-frame box is a phantom
|
|
2726
2732
|
* (defaults to {@link FULL_FRAME_MAX_CONFIDENCE}; overridable by the caller so
|
|
2727
2733
|
* the bar can be threaded from detection settings without new cap methods).
|
|
2734
|
+
* @param hardAreaRatio area fraction at/above which the box is dropped NO
|
|
2735
|
+
* MATTER the score. Defaults to {@link HARD_AREA_CUT_DISABLED} (off) — it is
|
|
2736
|
+
* armed per camera, because a doorbell close-up legitimately fills the frame
|
|
2737
|
+
* while an overhead courtyard box never does. Threaded from step settings as
|
|
2738
|
+
* `fullFrameGuardHardAreaRatio`.
|
|
2728
2739
|
*/
|
|
2729
|
-
|
|
2740
|
+
/**
|
|
2741
|
+
* True when a box trips the guard's GEOMETRY test (near-full-frame, or
|
|
2742
|
+
* edge-to-edge in one axis) but SURVIVES because its score cleared the
|
|
2743
|
+
* confidence bar.
|
|
2744
|
+
*
|
|
2745
|
+
* These are the ones worth counting: on 2026-07-30 device 615 produced six
|
|
2746
|
+
* such boxes in a day, at 0.710-0.787, and they were only found by an offline
|
|
2747
|
+
* sweep of stored events — nothing in production reported them. Arming the
|
|
2748
|
+
* hard-area cut on a camera should be a decision made from this count, not
|
|
2749
|
+
* from one incident.
|
|
2750
|
+
*/
|
|
2751
|
+
function isFullFrameSurvivor(bbox, frameWidth, frameHeight, score, maxConfidence = FULL_FRAME_MAX_CONFIDENCE) {
|
|
2730
2752
|
if (frameWidth <= 0 || frameHeight <= 0) return false;
|
|
2731
|
-
if (score
|
|
2753
|
+
if (score < maxConfidence) return false;
|
|
2732
2754
|
const [x1, y1, x2, y2] = bbox;
|
|
2733
2755
|
const w = x2 - x1;
|
|
2734
2756
|
const h = y2 - y1;
|
|
@@ -2737,6 +2759,19 @@ function isFullFramePhantomDetection(bbox, frameWidth, frameHeight, score, maxCo
|
|
|
2737
2759
|
if (h >= frameHeight * .98) return true;
|
|
2738
2760
|
return false;
|
|
2739
2761
|
}
|
|
2762
|
+
function isFullFramePhantomDetection(bbox, frameWidth, frameHeight, score, maxConfidence = FULL_FRAME_MAX_CONFIDENCE, hardAreaRatio = 1) {
|
|
2763
|
+
if (frameWidth <= 0 || frameHeight <= 0) return false;
|
|
2764
|
+
const [x1, y1, x2, y2] = bbox;
|
|
2765
|
+
const w = x2 - x1;
|
|
2766
|
+
const h = y2 - y1;
|
|
2767
|
+
const areaRatio = w * h / (frameWidth * frameHeight);
|
|
2768
|
+
if (isUsableHardAreaCut(hardAreaRatio) && areaRatio >= hardAreaRatio) return true;
|
|
2769
|
+
if (score >= maxConfidence) return false;
|
|
2770
|
+
if (areaRatio >= .9) return true;
|
|
2771
|
+
if (w >= frameWidth * .98) return true;
|
|
2772
|
+
if (h >= frameHeight * .98) return true;
|
|
2773
|
+
return false;
|
|
2774
|
+
}
|
|
2740
2775
|
//#endregion
|
|
2741
2776
|
//#region src/detection-pipeline/pipeline/plate-deskew.ts
|
|
2742
2777
|
/**
|
|
@@ -3584,10 +3619,34 @@ var PipelineExecutor = class {
|
|
|
3584
3619
|
continue;
|
|
3585
3620
|
}
|
|
3586
3621
|
const fullFrameBar = rootStep.settings?.["fullFrameGuardMaxConfidence"];
|
|
3587
|
-
|
|
3588
|
-
|
|
3622
|
+
const fullFrameHardArea = rootStep.settings?.["fullFrameGuardHardAreaRatio"];
|
|
3623
|
+
if (isFullFramePhantomDetection(mutable.bbox, imageWidth, imageHeight, mutable.score, typeof fullFrameBar === "number" ? fullFrameBar : void 0, typeof fullFrameHardArea === "number" ? fullFrameHardArea : void 0)) {
|
|
3624
|
+
this.opts.logger?.info("full-frame phantom guard: detection dropped", {
|
|
3625
|
+
tags: { deviceId },
|
|
3626
|
+
meta: {
|
|
3627
|
+
macroClass: mutable.macroClass,
|
|
3628
|
+
score: mutable.score,
|
|
3629
|
+
bbox: mutable.bbox,
|
|
3630
|
+
frameWidth: imageWidth,
|
|
3631
|
+
frameHeight: imageHeight,
|
|
3632
|
+
areaRatio: imageWidth > 0 && imageHeight > 0 ? Math.round((mutable.bbox[2] - mutable.bbox[0]) * (mutable.bbox[3] - mutable.bbox[1]) / (imageWidth * imageHeight) * 1e3) / 1e3 : void 0,
|
|
3633
|
+
bar: typeof fullFrameBar === "number" ? fullFrameBar : void 0,
|
|
3634
|
+
hardAreaRatio: typeof fullFrameHardArea === "number" ? fullFrameHardArea : void 0
|
|
3635
|
+
}
|
|
3636
|
+
});
|
|
3589
3637
|
continue;
|
|
3590
3638
|
}
|
|
3639
|
+
if (isFullFrameSurvivor(mutable.bbox, imageWidth, imageHeight, mutable.score, typeof fullFrameBar === "number" ? fullFrameBar : void 0)) this.opts.logger?.warn("full-frame box SURVIVED the guard on score", {
|
|
3640
|
+
tags: { deviceId },
|
|
3641
|
+
meta: {
|
|
3642
|
+
macroClass: mutable.macroClass,
|
|
3643
|
+
score: mutable.score,
|
|
3644
|
+
bbox: mutable.bbox,
|
|
3645
|
+
areaRatio: imageWidth > 0 && imageHeight > 0 ? Math.round((mutable.bbox[2] - mutable.bbox[0]) * (mutable.bbox[3] - mutable.bbox[1]) / (imageWidth * imageHeight) * 1e3) / 1e3 : void 0,
|
|
3646
|
+
bar: typeof fullFrameBar === "number" ? fullFrameBar : void 0,
|
|
3647
|
+
hint: "arm fullFrameGuardHardAreaRatio on this camera if these are phantoms"
|
|
3648
|
+
}
|
|
3649
|
+
});
|
|
3591
3650
|
try {
|
|
3592
3651
|
await this.executeChildren(rootStep.children, mutable, fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg, runOpts?.plane, deviceId, nativeCropProvider);
|
|
3593
3652
|
} catch (err) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as __require } from "../chunk-DnnnRqeS.mjs";
|
|
2
2
|
import { B as errMsg, E as evaluateZoneRules, F as runtimeDevices$1, G as createEvent, K as hydrateSchema, R as supportedRuntimes$1, T as enumerateInferenceDevices, V as BaseAddon, X as nodePin, Z as parseJsonUnknown, ct as object, dt as union, et as sleep, ft as EventCategory, h as YAMNET_TO_MACRO, j as pipelineExecutorCapability, nt as array, s as DEVICE_BACKEND_TO_FORMAT, t as APPLE_SA_TO_MACRO, ut as string, w as detectionPipelineCapability, x as defaultDeviceFor$1 } from "../dist-CsKaXmP8.mjs";
|
|
3
|
-
import { a as getStepDefinition, i as getStep, n as ALL_STEPS, o as resolveModelForFormat, r as getDefaultModelForFormat, t as ALL_PIPELINE_STEPS } from "../step-definitions-
|
|
3
|
+
import { a as getStepDefinition, i as getStep, n as ALL_STEPS, o as resolveModelForFormat, r as getDefaultModelForFormat, t as ALL_PIPELINE_STEPS } from "../step-definitions-1GIwU6R8.mjs";
|
|
4
4
|
import { t as pickNodePlatformArch } from "../node-topology-platform-BkR_k6WT.mjs";
|
|
5
5
|
import { a as ensureModel, o as isModelDownloaded, r as deleteModelFromDisk } from "../model-download-service-Cp9f4dk6-CwUb5v3Y.mjs";
|
|
6
6
|
import { spawn } from "node:child_process";
|
|
@@ -2696,19 +2696,25 @@ async function nativeChildCrop(provider, bbox, imageWidth, imageHeight, maxWidth
|
|
|
2696
2696
|
* DROPS detections outright, so it sits between that and a hard cut).
|
|
2697
2697
|
*/
|
|
2698
2698
|
var FULL_FRAME_MAX_CONFIDENCE = .7;
|
|
2699
|
+
/** A cut only makes sense in (0, 1); anything else is treated as OFF rather
|
|
2700
|
+
* than dropping every detection on a typo. */
|
|
2701
|
+
function isUsableHardAreaCut(ratio) {
|
|
2702
|
+
return Number.isFinite(ratio) && ratio > 0 && ratio < 1;
|
|
2703
|
+
}
|
|
2699
2704
|
/**
|
|
2700
2705
|
* True when `bbox` is a near-full-frame LOW-confidence phantom that should be
|
|
2701
2706
|
* DROPPED from the frame's detections (overlay / tracker / events / motion-wake).
|
|
2702
2707
|
*
|
|
2703
2708
|
* Rule (drop ⇔ returns true):
|
|
2704
|
-
*
|
|
2705
|
-
*
|
|
2706
|
-
*
|
|
2707
|
-
*
|
|
2709
|
+
* areaRatio ≥ `hardAreaRatio` ← score-independent, OFF by default
|
|
2710
|
+
* OR ( (areaRatio ≥ {@link FULL_FRAME_AREA_RATIO}
|
|
2711
|
+
* OR width ≥ {@link FULL_FRAME_DIMENSION_RATIO} × frameWidth
|
|
2712
|
+
* OR height ≥ {@link FULL_FRAME_DIMENSION_RATIO} × frameHeight)
|
|
2713
|
+
* AND score < `maxConfidence` )
|
|
2708
2714
|
*
|
|
2709
|
-
*
|
|
2710
|
-
* subject and
|
|
2711
|
-
* to reject on → not a phantom.
|
|
2715
|
+
* Below the hard cut a high-confidence detection (`score ≥ maxConfidence`) is
|
|
2716
|
+
* trusted as a real subject and survives. Degenerate frame dimensions (≤0)
|
|
2717
|
+
* carry no info to reject on → not a phantom.
|
|
2712
2718
|
*
|
|
2713
2719
|
* @param bbox absolute-pixel `[x1, y1, x2, y2]` box in source-frame coords.
|
|
2714
2720
|
* @param frameWidth source frame width in px.
|
|
@@ -2717,10 +2723,26 @@ var FULL_FRAME_MAX_CONFIDENCE = .7;
|
|
|
2717
2723
|
* @param maxConfidence confidence bar below which a full-frame box is a phantom
|
|
2718
2724
|
* (defaults to {@link FULL_FRAME_MAX_CONFIDENCE}; overridable by the caller so
|
|
2719
2725
|
* the bar can be threaded from detection settings without new cap methods).
|
|
2726
|
+
* @param hardAreaRatio area fraction at/above which the box is dropped NO
|
|
2727
|
+
* MATTER the score. Defaults to {@link HARD_AREA_CUT_DISABLED} (off) — it is
|
|
2728
|
+
* armed per camera, because a doorbell close-up legitimately fills the frame
|
|
2729
|
+
* while an overhead courtyard box never does. Threaded from step settings as
|
|
2730
|
+
* `fullFrameGuardHardAreaRatio`.
|
|
2720
2731
|
*/
|
|
2721
|
-
|
|
2732
|
+
/**
|
|
2733
|
+
* True when a box trips the guard's GEOMETRY test (near-full-frame, or
|
|
2734
|
+
* edge-to-edge in one axis) but SURVIVES because its score cleared the
|
|
2735
|
+
* confidence bar.
|
|
2736
|
+
*
|
|
2737
|
+
* These are the ones worth counting: on 2026-07-30 device 615 produced six
|
|
2738
|
+
* such boxes in a day, at 0.710-0.787, and they were only found by an offline
|
|
2739
|
+
* sweep of stored events — nothing in production reported them. Arming the
|
|
2740
|
+
* hard-area cut on a camera should be a decision made from this count, not
|
|
2741
|
+
* from one incident.
|
|
2742
|
+
*/
|
|
2743
|
+
function isFullFrameSurvivor(bbox, frameWidth, frameHeight, score, maxConfidence = FULL_FRAME_MAX_CONFIDENCE) {
|
|
2722
2744
|
if (frameWidth <= 0 || frameHeight <= 0) return false;
|
|
2723
|
-
if (score
|
|
2745
|
+
if (score < maxConfidence) return false;
|
|
2724
2746
|
const [x1, y1, x2, y2] = bbox;
|
|
2725
2747
|
const w = x2 - x1;
|
|
2726
2748
|
const h = y2 - y1;
|
|
@@ -2729,6 +2751,19 @@ function isFullFramePhantomDetection(bbox, frameWidth, frameHeight, score, maxCo
|
|
|
2729
2751
|
if (h >= frameHeight * .98) return true;
|
|
2730
2752
|
return false;
|
|
2731
2753
|
}
|
|
2754
|
+
function isFullFramePhantomDetection(bbox, frameWidth, frameHeight, score, maxConfidence = FULL_FRAME_MAX_CONFIDENCE, hardAreaRatio = 1) {
|
|
2755
|
+
if (frameWidth <= 0 || frameHeight <= 0) return false;
|
|
2756
|
+
const [x1, y1, x2, y2] = bbox;
|
|
2757
|
+
const w = x2 - x1;
|
|
2758
|
+
const h = y2 - y1;
|
|
2759
|
+
const areaRatio = w * h / (frameWidth * frameHeight);
|
|
2760
|
+
if (isUsableHardAreaCut(hardAreaRatio) && areaRatio >= hardAreaRatio) return true;
|
|
2761
|
+
if (score >= maxConfidence) return false;
|
|
2762
|
+
if (areaRatio >= .9) return true;
|
|
2763
|
+
if (w >= frameWidth * .98) return true;
|
|
2764
|
+
if (h >= frameHeight * .98) return true;
|
|
2765
|
+
return false;
|
|
2766
|
+
}
|
|
2732
2767
|
//#endregion
|
|
2733
2768
|
//#region src/detection-pipeline/pipeline/plate-deskew.ts
|
|
2734
2769
|
/**
|
|
@@ -3576,10 +3611,34 @@ var PipelineExecutor = class {
|
|
|
3576
3611
|
continue;
|
|
3577
3612
|
}
|
|
3578
3613
|
const fullFrameBar = rootStep.settings?.["fullFrameGuardMaxConfidence"];
|
|
3579
|
-
|
|
3580
|
-
|
|
3614
|
+
const fullFrameHardArea = rootStep.settings?.["fullFrameGuardHardAreaRatio"];
|
|
3615
|
+
if (isFullFramePhantomDetection(mutable.bbox, imageWidth, imageHeight, mutable.score, typeof fullFrameBar === "number" ? fullFrameBar : void 0, typeof fullFrameHardArea === "number" ? fullFrameHardArea : void 0)) {
|
|
3616
|
+
this.opts.logger?.info("full-frame phantom guard: detection dropped", {
|
|
3617
|
+
tags: { deviceId },
|
|
3618
|
+
meta: {
|
|
3619
|
+
macroClass: mutable.macroClass,
|
|
3620
|
+
score: mutable.score,
|
|
3621
|
+
bbox: mutable.bbox,
|
|
3622
|
+
frameWidth: imageWidth,
|
|
3623
|
+
frameHeight: imageHeight,
|
|
3624
|
+
areaRatio: imageWidth > 0 && imageHeight > 0 ? Math.round((mutable.bbox[2] - mutable.bbox[0]) * (mutable.bbox[3] - mutable.bbox[1]) / (imageWidth * imageHeight) * 1e3) / 1e3 : void 0,
|
|
3625
|
+
bar: typeof fullFrameBar === "number" ? fullFrameBar : void 0,
|
|
3626
|
+
hardAreaRatio: typeof fullFrameHardArea === "number" ? fullFrameHardArea : void 0
|
|
3627
|
+
}
|
|
3628
|
+
});
|
|
3581
3629
|
continue;
|
|
3582
3630
|
}
|
|
3631
|
+
if (isFullFrameSurvivor(mutable.bbox, imageWidth, imageHeight, mutable.score, typeof fullFrameBar === "number" ? fullFrameBar : void 0)) this.opts.logger?.warn("full-frame box SURVIVED the guard on score", {
|
|
3632
|
+
tags: { deviceId },
|
|
3633
|
+
meta: {
|
|
3634
|
+
macroClass: mutable.macroClass,
|
|
3635
|
+
score: mutable.score,
|
|
3636
|
+
bbox: mutable.bbox,
|
|
3637
|
+
areaRatio: imageWidth > 0 && imageHeight > 0 ? Math.round((mutable.bbox[2] - mutable.bbox[0]) * (mutable.bbox[3] - mutable.bbox[1]) / (imageWidth * imageHeight) * 1e3) / 1e3 : void 0,
|
|
3638
|
+
bar: typeof fullFrameBar === "number" ? fullFrameBar : void 0,
|
|
3639
|
+
hint: "arm fullFrameGuardHardAreaRatio on this camera if these are phantoms"
|
|
3640
|
+
}
|
|
3641
|
+
});
|
|
3583
3642
|
try {
|
|
3584
3643
|
await this.executeChildren(rootStep.children, mutable, fullFrameJpegProvider, imageWidth, imageHeight, traceBuilder, stepTimings, ctx, poolAgg, runOpts?.plane, deviceId, nativeCropProvider);
|
|
3585
3644
|
} catch (err) {
|
|
@@ -7,7 +7,7 @@ const require_dist = require("../dist-DUHlZcWd.js");
|
|
|
7
7
|
const require_remote_restream = require("../remote-restream-CO36Sr30.js");
|
|
8
8
|
const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
|
|
9
9
|
const require_worker_protocol = require("../worker-protocol-DextwlTX.js");
|
|
10
|
-
const require_step_definitions = require("../step-definitions-
|
|
10
|
+
const require_step_definitions = require("../step-definitions-Drb9cWbB.js");
|
|
11
11
|
let node_child_process = require("node:child_process");
|
|
12
12
|
let node_url = require("node:url");
|
|
13
13
|
let sharp = require("sharp");
|
|
@@ -658,6 +658,9 @@ function toFrameInput$1(frame) {
|
|
|
658
658
|
* without spinning up Moleculer or the addon framework.
|
|
659
659
|
*/
|
|
660
660
|
var PipelineRunner = class {
|
|
661
|
+
/** Abandoned inference calls that have not yet settled. A BURST reads as
|
|
662
|
+
* one rising number instead of N unrelated lines. */
|
|
663
|
+
inflightTimeouts = 0;
|
|
661
664
|
config;
|
|
662
665
|
cameras = /* @__PURE__ */ new Map();
|
|
663
666
|
semaphore;
|
|
@@ -1144,16 +1147,33 @@ var PipelineRunner = class {
|
|
|
1144
1147
|
timer.unref?.();
|
|
1145
1148
|
});
|
|
1146
1149
|
try {
|
|
1147
|
-
const
|
|
1150
|
+
const inflight = this.config.processFrame(deviceId, frameInput, executorHandle);
|
|
1151
|
+
const outcome = await Promise.race([inflight, expiry]);
|
|
1148
1152
|
if (outcome === TIMED_OUT) {
|
|
1149
1153
|
release();
|
|
1154
|
+
this.inflightTimeouts += 1;
|
|
1150
1155
|
this.logger?.warn("inference timed out — permit released, result discarded", {
|
|
1151
1156
|
tags: { deviceId },
|
|
1152
1157
|
meta: {
|
|
1153
1158
|
timeoutMs,
|
|
1154
|
-
availablePermits: this.semaphore.available
|
|
1159
|
+
availablePermits: this.semaphore.available,
|
|
1160
|
+
outstandingTimeouts: this.inflightTimeouts
|
|
1155
1161
|
}
|
|
1156
1162
|
});
|
|
1163
|
+
const deadlineAt = Date.now();
|
|
1164
|
+
const noteSettled = (fate) => {
|
|
1165
|
+
this.inflightTimeouts = Math.max(0, this.inflightTimeouts - 1);
|
|
1166
|
+
this.logger?.info("inference: abandoned call settled after the deadline", {
|
|
1167
|
+
tags: { deviceId },
|
|
1168
|
+
meta: {
|
|
1169
|
+
lateByMs: Date.now() - deadlineAt,
|
|
1170
|
+
totalMs: timeoutMs + (Date.now() - deadlineAt),
|
|
1171
|
+
fate,
|
|
1172
|
+
outstandingTimeouts: this.inflightTimeouts
|
|
1173
|
+
}
|
|
1174
|
+
});
|
|
1175
|
+
};
|
|
1176
|
+
inflight.then(() => noteSettled("resolved"), () => noteSettled("rejected"));
|
|
1157
1177
|
}
|
|
1158
1178
|
return outcome;
|
|
1159
1179
|
} finally {
|
|
@@ -2,7 +2,7 @@ import { B as errMsg, G as createEvent, M as pipelineRunnerCapability, S as defi
|
|
|
2
2
|
import { n as profileForStreamId, t as isRemoteRestream } from "../remote-restream-BeHi78PZ.mjs";
|
|
3
3
|
import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
|
|
4
4
|
import { t as isWorkerReply } from "../worker-protocol-D7RzZIla.mjs";
|
|
5
|
-
import { a as getStepDefinition } from "../step-definitions-
|
|
5
|
+
import { a as getStepDefinition } from "../step-definitions-1GIwU6R8.mjs";
|
|
6
6
|
import { fork } from "node:child_process";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
import sharp from "sharp";
|
|
@@ -652,6 +652,9 @@ function toFrameInput$1(frame) {
|
|
|
652
652
|
* without spinning up Moleculer or the addon framework.
|
|
653
653
|
*/
|
|
654
654
|
var PipelineRunner = class {
|
|
655
|
+
/** Abandoned inference calls that have not yet settled. A BURST reads as
|
|
656
|
+
* one rising number instead of N unrelated lines. */
|
|
657
|
+
inflightTimeouts = 0;
|
|
655
658
|
config;
|
|
656
659
|
cameras = /* @__PURE__ */ new Map();
|
|
657
660
|
semaphore;
|
|
@@ -1138,16 +1141,33 @@ var PipelineRunner = class {
|
|
|
1138
1141
|
timer.unref?.();
|
|
1139
1142
|
});
|
|
1140
1143
|
try {
|
|
1141
|
-
const
|
|
1144
|
+
const inflight = this.config.processFrame(deviceId, frameInput, executorHandle);
|
|
1145
|
+
const outcome = await Promise.race([inflight, expiry]);
|
|
1142
1146
|
if (outcome === TIMED_OUT) {
|
|
1143
1147
|
release();
|
|
1148
|
+
this.inflightTimeouts += 1;
|
|
1144
1149
|
this.logger?.warn("inference timed out — permit released, result discarded", {
|
|
1145
1150
|
tags: { deviceId },
|
|
1146
1151
|
meta: {
|
|
1147
1152
|
timeoutMs,
|
|
1148
|
-
availablePermits: this.semaphore.available
|
|
1153
|
+
availablePermits: this.semaphore.available,
|
|
1154
|
+
outstandingTimeouts: this.inflightTimeouts
|
|
1149
1155
|
}
|
|
1150
1156
|
});
|
|
1157
|
+
const deadlineAt = Date.now();
|
|
1158
|
+
const noteSettled = (fate) => {
|
|
1159
|
+
this.inflightTimeouts = Math.max(0, this.inflightTimeouts - 1);
|
|
1160
|
+
this.logger?.info("inference: abandoned call settled after the deadline", {
|
|
1161
|
+
tags: { deviceId },
|
|
1162
|
+
meta: {
|
|
1163
|
+
lateByMs: Date.now() - deadlineAt,
|
|
1164
|
+
totalMs: timeoutMs + (Date.now() - deadlineAt),
|
|
1165
|
+
fate,
|
|
1166
|
+
outstandingTimeouts: this.inflightTimeouts
|
|
1167
|
+
}
|
|
1168
|
+
});
|
|
1169
|
+
};
|
|
1170
|
+
inflight.then(() => noteSettled("resolved"), () => noteSettled("rejected"));
|
|
1151
1171
|
}
|
|
1152
1172
|
return outcome;
|
|
1153
1173
|
} finally {
|
|
@@ -1296,7 +1296,18 @@ var ObjectDetectionStep = class {
|
|
|
1296
1296
|
min: 0,
|
|
1297
1297
|
max: 1,
|
|
1298
1298
|
step: .05,
|
|
1299
|
-
default: .
|
|
1299
|
+
default: .65,
|
|
1300
|
+
showValue: true
|
|
1301
|
+
},
|
|
1302
|
+
{
|
|
1303
|
+
type: "slider",
|
|
1304
|
+
key: "fullFrameGuardHardAreaRatio",
|
|
1305
|
+
label: "Drop full-frame boxes above",
|
|
1306
|
+
description: "Fraction of the frame at or above which a detection is dropped WHATEVER its score. 1 = off. Use on cameras where a subject can never fill the frame; leave off for doorbells and close-up lenses.",
|
|
1307
|
+
min: .5,
|
|
1308
|
+
max: 1,
|
|
1309
|
+
step: .01,
|
|
1310
|
+
default: 1,
|
|
1300
1311
|
showValue: true
|
|
1301
1312
|
},
|
|
1302
1313
|
{
|
|
@@ -1296,7 +1296,18 @@ var ObjectDetectionStep = class {
|
|
|
1296
1296
|
min: 0,
|
|
1297
1297
|
max: 1,
|
|
1298
1298
|
step: .05,
|
|
1299
|
-
default: .
|
|
1299
|
+
default: .65,
|
|
1300
|
+
showValue: true
|
|
1301
|
+
},
|
|
1302
|
+
{
|
|
1303
|
+
type: "slider",
|
|
1304
|
+
key: "fullFrameGuardHardAreaRatio",
|
|
1305
|
+
label: "Drop full-frame boxes above",
|
|
1306
|
+
description: "Fraction of the frame at or above which a detection is dropped WHATEVER its score. 1 = off. Use on cameras where a subject can never fill the frame; leave off for doorbells and close-up lenses.",
|
|
1307
|
+
min: .5,
|
|
1308
|
+
max: 1,
|
|
1309
|
+
step: .01,
|
|
1310
|
+
default: 1,
|
|
1300
1311
|
showValue: true
|
|
1301
1312
|
},
|
|
1302
1313
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-pipeline",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.29",
|
|
4
4
|
"description": "CamStack Pipeline bundle — runner, detection, motion, audio + stream broker. Multi-entry npm package shipping pipeline addons under a single bundle.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|