@camstack/addon-post-analysis 1.2.664 → 1.2.665
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/CHANGELOG.md +8 -0
- package/dist/{clip-model-registry-Ch9Sz-Qb.mjs → clip-model-registry-DZTzG2p4.mjs} +292 -132
- package/dist/{clip-model-registry-TeNUAAPP.js → clip-model-registry-nn_STiGt.js} +297 -131
- package/dist/embedding-encoder/index.js +1 -1
- package/dist/embedding-encoder/index.mjs +1 -1
- package/dist/pipeline-analytics/_stub.js +2 -2
- package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-CXG7YPYq.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-Hy74pMMo.mjs} +2 -2
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BXTAZYaJ.mjs +26 -0
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-Br6eWzp_.mjs +26 -0
- package/dist/pipeline-analytics/{hostInit-BZ_D3_sF.mjs → hostInit-BAYLsfoZ.mjs} +2 -2
- package/dist/pipeline-analytics/index.js +316 -38
- package/dist/pipeline-analytics/index.mjs +316 -38
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/package.json +2 -2
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CIt_RDlm.mjs +0 -26
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-4TTlyJ66.mjs +0 -26
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as MAX_TRACK_RELATIONS, $i as
|
|
1
|
+
import { $ as MAX_TRACK_RELATIONS, $i as zoneAnalyticsCapability, $n as buildViewerLink, $r as ncMediaPolicyError, $t as NcTemplatePreviewSchema, A as DETECTION_MACRO_CLASSES, Aa as record, Ai as ruleKindOf, An as TrackPlacementSchema, Ar as isAlarmControllableCap, At as NcAlarmConfigSchema, B as EXPORT_DENSE_MAX_RANGES, Bi as summarizeReview, Bn as alertEpisodeId, Br as isKnownTemplateVar, Bt as NcRuleSchema, C as COCO_TO_MACRO, Ca as boolean, Cn as SetTrackPurityResultSchema, Cr as ensureAlarmProfiles, Ct as NC_GROUPING_MIN_SEC, D as DEFAULT_DETAIL_CROP_CONVENTION, Da as number, Di as ruleBelongsToAlarm$1, Dn as TimelapseRuleInputSchema, Dr as failureContributionCapability, Dt as NC_SYSTEM_EVENT_KIND_GROUP_SPECS, E as CoverStateSchema, Ea as looseObject, Ei as ruleAutoTriggersAlarm, En as TRACK_RELATIONS_DEFAULT_LIMIT, Er as faceGalleryCapability, Et as NC_STATE_SUMMARY_SECTION_IDS, F as EMBEDDING_REQUIREMENTS_FAILED, Fa as union, Fi as startMoverUnderClearance, Fn as TrackSourceSchema, Fr as isDefaultAlarmProfileId, Ft as NcConditionDescriptorSchema, G as LabelAttributionSchema, Gi as systemEventFilterApplies, Gn as applyNonBlockingEdit, Gr as isScheduleActive, Gt as NcSnoozeInputSchema, H as FULL_IMAGE_BBOX, Hi as syncActiveAlarmProfileSettings, Hn as alertEpisodePayload, Hr as isMediaOwnerType, Ht as NcRuleUpdateInputSchema, I as EMBEDDING_REQUIREMENTS_UNAVAILABLE, Ia as unknown, Ii as storageOccupancyCapability, In as activateAlarmProfile, Ir as isDetectionMacroClass, It as NcConditionsSchema, J as LockStateSchema, Ji as templateCarriesSummary, Jn as assertTimelapseCadences, Jr as isVectorIndexDimConflict, Jt as NcStateSummarySectionIdSchema, K as ListTrackRelationsInputSchema, Ki as systemEventSummaryScheduleOf, Kn as applySecureOnArmEdit, Kr as isSystemDelivery, Kt as NcSnoozeSchema, L as EVENT_DENSITY_BATCH_MAX, La as DeviceType, Li as subKindsOf, Ln as addonWidgetsSourceCapability, Lr as isDrawableSubjectPath, Lt as NcRuleActionSchema, M as DeclaredDevices, Ma as string, Mi as secureActuationFor, Mn as TrackRelationKindSchema, Mr as isAlertEpisodeSeverity, Mt as NcAlarmSensorsInputSchema, N as DetectionSourceSchema, Na as templateLiteral, Ni as sensorRaisedOf, Nn as TrackRelationSchema, Nr as isAppLinkBase, Nt as NcAlarmSensorsSchema, O as DEFAULT_EVENT_COLOR, Oa as object, Oi as ruleDeviceCompatCapQueries, On as TimelapseRulePatchSchema, Or as gifDeriveSpeed, Ot as NC_TAXONOMY, P as EMBEDDING_MODEL_FAILED, Pa as tuple, Pi as servedTemplateVars, Pn as TrackSideSchema, Pr as isAudioClassName, Pt as NcAlarmSettingsPatchSchema, Q as MAX_TRACK_PURITIES, Qi as withSystemEventClasses, Qn as buildSubjectPath, Qr as memoizePinnedFfmpeg, Qt as NcTemplatePreviewInputSchema, R as EVENT_KIND_BY_CAP, Ra as errMsg, Ri as subjectPathSampleFromBox, Rn as alarmDeviceSecureOnArm, Rr as isEventKindLabelKey, Rt as NcRuleInputSchema, S as BucketAccumulator, Sa as array, Si as resolveNcMediaImage, Sn as SetTrackPurityInputSchema, Sr as encodeVectorBase64, St as NC_GROUPING_MAX_SEC, T as ClearTrackRelationResultSchema, Ta as literal, Ti as rootSupplyServes, Tn as TIMELAPSE_DENSE_FLOOR_SEC, Tr as evictionPolicyOfLocation, Tt as NC_SNOOZE_MAX_MINUTES, U as FailureCounters, Ui as systemEventDeliveryProblems, Un as applyBlockingEdit, Ur as isRetiredClearKey, Ut as NcScheduleSchema, V as FIRST_LEVEL_MACRO_CLASSES, Vi as sunTimes, Vn as alertEpisodeKind, Vr as isLabelSupplyStepId, Vt as NcRuleTargetSchema, W as LABEL_SUPPLY_MACRO, Wi as systemEventFamilyProblems, Wn as applyModeDelaysEdits, Wr as isRootSuppliableStepId, Wt as NcSharedSequenceSchema, X as MAX_BIRTH_DECISION_RECORDS, Xi as vectorDimFromBase64, Xn as audioModeOf, Xr as linkedStepOf, Xt as NcTaxonomySchema, Y as MAX_ARCHIVED_DEBUG_NOTES, Yi as templateVarsFor, Yn as audioMetricsCapability, Yr as kebabToCamel, Yt as NcSystemEventKindSchema, Z as MAX_BIRTH_LATENCY_PROXY_MS, Zi as viewerLinkBaseOf, Zn as buildEventKindDescriptor, Zr as mayWriteToLocation, Zt as NcTemplateDefaultSchema, _ as AlarmArmModeSchema, _a as nodePin, _i as resolveClipSearchMinScore, _n as SCENE_DEFAULT_QUIET_SECONDS, _t as NC_CONFIRM_DEFAULT_TIMEOUT_MS, a as CLIP_EMBEDDING_STEP_ID, aa as CAP_ADVANCE_FIELDS, ai as paintHex, an as RECORDING_EXPORT_MAX_READ_BYTES, ar as consumableLowPercentOf, at as NC_ALARM_DELAY_FIELDS, b as BaseDevice, ba as ZodObject, bi as resolveModeDelays, bn as SCENE_RESET_RECAPTURES, bt as NC_DEFAULT_SNOOZE_MINUTES, c as readClusterModelPinStrict, ca as RECORD_MAX_DATA_BYTES, cn as RetrainDismissedSchema, cr as createAlarmProfile, ct as NC_ALARM_SYSTEM_EVENT_KINDS, d as APPEARANCE_BIN_COUNT, da as customAction, di as plateGalleryCapability, dn as RetrainVerdictSubjectSchema, dr as derivePostTriggeredAction, dt as NC_AUDIO_CONFIRM_WINDOW_SEC_DEFAULT, ea as DEFAULT_FIRST_SIGHTING_FRESHNESS_MS, ei as normalizeNcAction, en as NcTemplateVarDescriptorSchema, er as bundledCamstack, et as MOTION_CLOSE_AFTER_MS, f as APPEARANCE_BLOCKS, fa as defineAddonMigrations, fi as projectSubjectPath, fn as SCENE_CONFIRM_DEFAULT_MAX_IMAGE_PX, fr as deriveRecordingMode, ft as NC_CLIP_POST_ROLL_DEFAULT_SEC, g as ActionTargetResolver, ga as isDeviceScopedCap, gi as renameAlarmProfile, gn as SCENE_DEFAULT_OBSERVATION_SPACING_SEC, gr as deviceRemovalHookCapability, gt as NC_CONFIRM_DEFAULT_MAX_IMAGE_PX, h as AUDIO_MACRO_LABELS, ha as hydrateSchema, hi as readTimelapseGeneratedAt, hn as SCENE_DEFAULT_CHECK_INTERVAL_SEC, hr as deviceAttentionKind, ht as NC_CONDITION_CATALOG, ia as BaseAddon, ii as occupancyScope, ir as consumableFormOf, it as NC_ALARM_DEFAULT_TRIGGERED_DURATION_SEC, j as DETECTION_PIPELINE_CAP_NAME, ja as strictObject, ji as sceneMonitorCapability, jn as TrackPuritySchema, jr as isAlertEpisodeOpen, jt as NcAlarmPostTriggeredActionSchema, k as DEFAULT_TIMELAPSE_PREVIEW_TEXT, ka as partialRecord, ki as ruleGroupingApplies, kn as TimelapseRuleSchema, kr as gifFromMp4Args, kt as NC_TEMPLATE_VARS, l as resolveClusterModelPin, la as RECORD_QUERY_MAX, li as pickFaceRescoreIntervalMinutes, ln as RetrainOriginSchema, lr as deleteAlarmProfile, lt as NC_ALARM_TRIGGERED_MAX_SEC, m as ARCHIVED_DEBUG_NOTES_DEFAULT_LIMIT, ma as defineRecordKinds, mi as readMotionTriggeredBy, mn as SCENE_DEFAULT_ANCHOR_THRESHOLD, mr as describeSystemEventFamilyProblem, mt as NC_CLIP_RETENTION_MAX_SEC, na as evaluateSensorEdge, ni as normalizeNcMediaPolicy, nn as OpsLogEntrySchema, nr as classifyRetrainReview, nt as MotionTriggeredBySchema, o as CLUSTER_MODEL_OWNER_ADDON_ID, oa as CamProfileSchema, oi as paletteResultSchema, on as RECORDING_SOURCE_CAMSTACK_ADDON, or as coreBlockIdFromAddonId, ot as NC_ALARM_DELAY_MAX_SEC, p as APPEARANCE_RESOLVES_AMBIGUITY_DEFAULT, pa as defineCustomActions, pi as readDeviceStateFrom, pn as SCENE_CONFIRM_DEFAULT_TIMEOUT_MS, pr as describeSystemEventDeliveryProblem, pt as NC_CLIP_PRE_ROLL_DEFAULT_SEC, q as ListTrackRelationsResultSchema, qi as systemEventSummarySplitOf, qn as armRemovalReconcile, qr as isSystemEventSummaryRule, qt as NcSnoozeSuppressedSchema, ra as isSourceCap, ri as notificationRulesCapability, rn as PackageLlmVerdictSchema, rr as cloneAlarmSettings, rt as NC_ALARM_DEFAULT_PROFILE_ID, s as FACE_EMBEDDING_STEP_ID, sa as InvalidRecordError, si as parseAlertEpisodePayload, sn as RebuildObjectEmbeddingsRefusalSchema, sr as cosineSimilarity$1, st as NC_ALARM_NOTIFY_FIELDS, t as BUILTIN_CLIP_MODELS, ta as canonicalHash, ti as normalizeNcCapTarget, tn as OPS_LOG_DEFAULT_LIMIT, tr as calendarEventLocalSpan, tt as MediaFileKindEnum, u as ACTION_TARGET_INVALIDATION_EVENTS, ua as createEvent, ui as pipelineAnalyticsCapability, un as RetrainStatusSchema, ur as deriveDetailCropRect, ut as NC_AUDIO_CONFIRM_HITS_DEFAULT, v as ArchivedDebugNoteSchema, vi as resolveDeliveryParams, vn as SCENE_DEFAULT_UNCOVERED_POLICY, vt as NC_CONSUMABLE_LOW_PERCENT_DEFAULT, w as ClearTrackRelationInputSchema, wa as discriminatedUnion, wi as retrainRevisionConflictMessage, wn as SetTrackRelationInputSchema, wr as eventKindLabel, wt as NC_SENSOR_TRANSITION_KINDS, x as BirthDecisionRecordSchema, xa as _enum, xi as resolveModeNotifyPolicy, xn as SceneMonitorSchema, xt as NC_GROUPING_DEFAULT_SEC, y as BIRTH_DECISION_DEFAULT_LIMIT, ya as sleep$1, yi as resolveLocationMode, yn as SCENE_DIVERGED, yr as embeddingRefusalOf, yt as NC_CONSUMABLE_SYSTEM_EVENT_KINDS, z as EVENT_OWNER_TYPES, za as EventCategory, zi as subjectPathSvgPoints, zn as alarmPanelCapability, zr as isEventOwnerType, zt as NcRulePatchSchema } from "../clip-model-registry-DZTzG2p4.mjs";
|
|
2
2
|
import { t as __exportAll } from "../embedding-encoder/index.mjs";
|
|
3
3
|
import * as fs$1 from "node:fs";
|
|
4
4
|
import { createWriteStream, promises } from "node:fs";
|
|
@@ -12276,6 +12276,16 @@ var NcStateSummaryTestSchema = object({
|
|
|
12276
12276
|
}))
|
|
12277
12277
|
});
|
|
12278
12278
|
//#endregion
|
|
12279
|
+
//#region src/notification-center/template-defaults.ts
|
|
12280
|
+
function servedTemplateDefaults(texts) {
|
|
12281
|
+
return [{
|
|
12282
|
+
id: "appliance-cycle",
|
|
12283
|
+
kind: "sensor",
|
|
12284
|
+
title: texts.raw("appliance.finished.title") ?? "",
|
|
12285
|
+
body: texts.raw("appliance.finished.body") ?? ""
|
|
12286
|
+
}];
|
|
12287
|
+
}
|
|
12288
|
+
//#endregion
|
|
12279
12289
|
//#region src/notification-center/clock-text.ts
|
|
12280
12290
|
/**
|
|
12281
12291
|
* `{{time}}` — hours and minutes in the NOTIFICATION language.
|
|
@@ -13659,7 +13669,10 @@ var ncActions = defineCustomActions({
|
|
|
13659
13669
|
catalog: array(NcConditionDescriptorSchema),
|
|
13660
13670
|
taxonomy: NcTaxonomySchema
|
|
13661
13671
|
})),
|
|
13662
|
-
"nc.getTemplateCatalog": customAction(object({}), object({
|
|
13672
|
+
"nc.getTemplateCatalog": customAction(object({}), object({
|
|
13673
|
+
vars: array(NcTemplateVarDescriptorSchema),
|
|
13674
|
+
defaults: array(NcTemplateDefaultSchema)
|
|
13675
|
+
})),
|
|
13663
13676
|
"nc.previewTemplate": customAction(NcTemplatePreviewInputSchema, NcTemplatePreviewSchema, { kind: "mutation" }),
|
|
13664
13677
|
"nc.createRule": customAction(object({ rule: NcRuleInputSchema }), object({ rule: NcRuleSchema }), {
|
|
13665
13678
|
kind: "mutation",
|
|
@@ -14439,7 +14452,10 @@ function makeNcActionHandlers(deps) {
|
|
|
14439
14452
|
catalog: [...NC_CONDITION_CATALOG],
|
|
14440
14453
|
taxonomy: NC_TAXONOMY
|
|
14441
14454
|
}),
|
|
14442
|
-
"nc.getTemplateCatalog": async () => ({
|
|
14455
|
+
"nc.getTemplateCatalog": async () => ({
|
|
14456
|
+
vars: servedTemplateVars(),
|
|
14457
|
+
defaults: deps.previewTexts === void 0 ? [] : servedTemplateDefaults(deps.previewTexts)
|
|
14458
|
+
}),
|
|
14443
14459
|
"nc.previewTemplate": async (input) => {
|
|
14444
14460
|
const texts = deps.previewTexts;
|
|
14445
14461
|
if (texts === void 0) throw new Error("nc.previewTemplate: text catalog not wired");
|
|
@@ -49856,7 +49872,7 @@ async function encodeRgbCropToJpeg(bytes, width, height) {
|
|
|
49856
49872
|
* what lets the caller stop base64-ing purely to be understood.
|
|
49857
49873
|
*/
|
|
49858
49874
|
async function decodeJpegToRgb(jpeg) {
|
|
49859
|
-
const { data, info } = await sharp(typeof jpeg === "string" ? Buffer.from(jpeg, "base64") : jpeg).raw().toBuffer({ resolveWithObject: true });
|
|
49875
|
+
const { data, info } = await sharp(typeof jpeg === "string" ? Buffer.from(jpeg, "base64") : jpeg).removeAlpha().toColourspace("srgb").raw().toBuffer({ resolveWithObject: true });
|
|
49860
49876
|
return {
|
|
49861
49877
|
bytes: data,
|
|
49862
49878
|
width: info.width,
|
|
@@ -52942,6 +52958,42 @@ function collectPackageZoneIds(rules) {
|
|
|
52942
52958
|
}
|
|
52943
52959
|
return ids;
|
|
52944
52960
|
}
|
|
52961
|
+
/**
|
|
52962
|
+
* How much the package zone box grows on every side when asking whether motion
|
|
52963
|
+
* reached it. Mirrors the D144 dilation of the pipeline's burst trigger
|
|
52964
|
+
* (`PACKAGE_ZONE_DILATION` in addon-pipeline, not importable from here): about
|
|
52965
|
+
* one adult's width beside a doormat, the place a courier stands.
|
|
52966
|
+
*/
|
|
52967
|
+
var PACKAGE_ZONE_MOTION_DILATION = .5;
|
|
52968
|
+
/**
|
|
52969
|
+
* A motion region covering more than this fraction of the frame is a light
|
|
52970
|
+
* change or the weather, not a person: it never counts as a deliverer.
|
|
52971
|
+
*/
|
|
52972
|
+
var PACKAGE_ZONE_MOTION_MAX_REGION_FRAC = .8;
|
|
52973
|
+
/**
|
|
52974
|
+
* Did analyzer motion reach the dilated package zone with a person-sized
|
|
52975
|
+
* region? Unknown geometry answers false: this stamp only ever BACKS the open
|
|
52976
|
+
* of a candidate, so failing closed keeps the light-wedge guard intact.
|
|
52977
|
+
*/
|
|
52978
|
+
function delivererMotionNearPackageZone(input) {
|
|
52979
|
+
const { zoneRect, frameWidth, frameHeight } = input;
|
|
52980
|
+
if (zoneRect === null || frameWidth <= 0 || frameHeight <= 0) return false;
|
|
52981
|
+
const dx = zoneRect.w * PACKAGE_ZONE_MOTION_DILATION;
|
|
52982
|
+
const dy = zoneRect.h * PACKAGE_ZONE_MOTION_DILATION;
|
|
52983
|
+
const left = Math.max(0, zoneRect.x - dx);
|
|
52984
|
+
const top = Math.max(0, zoneRect.y - dy);
|
|
52985
|
+
const right = Math.min(1, zoneRect.x + zoneRect.w + dx);
|
|
52986
|
+
const bottom = Math.min(1, zoneRect.y + zoneRect.h + dy);
|
|
52987
|
+
for (const region of input.regions) {
|
|
52988
|
+
const x = region.bbox.x / frameWidth;
|
|
52989
|
+
const y = region.bbox.y / frameHeight;
|
|
52990
|
+
const w = region.bbox.w / frameWidth;
|
|
52991
|
+
const h = region.bbox.h / frameHeight;
|
|
52992
|
+
if (w * h > PACKAGE_ZONE_MOTION_MAX_REGION_FRAC) continue;
|
|
52993
|
+
if (x < right && left < x + w && y < bottom && top < y + h) return true;
|
|
52994
|
+
}
|
|
52995
|
+
return false;
|
|
52996
|
+
}
|
|
52945
52997
|
//#endregion
|
|
52946
52998
|
//#region src/pipeline-analytics/pipeline/package/package-collector-mirror.ts
|
|
52947
52999
|
/**
|
|
@@ -53887,6 +53939,15 @@ var PACKAGE_STILLNESS_TTL_MS = 5 * 6e4;
|
|
|
53887
53939
|
*/
|
|
53888
53940
|
var PACKAGE_STILLNESS_ASSOC_IOU = .3;
|
|
53889
53941
|
/**
|
|
53942
|
+
* Lowest score of a below-threshold box that may CONTINUE an open candidate
|
|
53943
|
+
* (D665: a box under the floor may continue, never open). Observed on a real
|
|
53944
|
+
* parcel after the day to IR flip: 0.35 to 0.50.
|
|
53945
|
+
*/
|
|
53946
|
+
var PACKAGE_STILLNESS_CONTINUATION_MIN_SCORE = .3;
|
|
53947
|
+
/** Above-floor sightings a candidate needs before a sub-floor box may count:
|
|
53948
|
+
* one confident look plus a doormat-shaped reading is not a parcel. */
|
|
53949
|
+
var PACKAGE_CONTINUATION_MIN_REAL_HITS = 2;
|
|
53950
|
+
/**
|
|
53890
53951
|
* Two absence reads closer than this are ONE look, not two. A settle burst
|
|
53891
53952
|
* runs the package step 5 s apart and a poll 45 s apart, so a real second
|
|
53892
53953
|
* look is always further away; two frames of one moment (a re-dispatch, a
|
|
@@ -53936,6 +53997,7 @@ var PackageStillnessTracker = class {
|
|
|
53936
53997
|
const next = [...this.byDevice.get(input.deviceId) ?? []];
|
|
53937
53998
|
const consumed = /* @__PURE__ */ new Set();
|
|
53938
53999
|
const promoted = [];
|
|
54000
|
+
const continuedLog = [];
|
|
53939
54001
|
for (const s of input.sightings) {
|
|
53940
54002
|
const index = this.bestMatch(next, s, consumed);
|
|
53941
54003
|
if (index < 0) {
|
|
@@ -53948,17 +54010,33 @@ var PackageStillnessTracker = class {
|
|
|
53948
54010
|
if (prev === void 0) continue;
|
|
53949
54011
|
consumed.add(prev.id);
|
|
53950
54012
|
const updated = confirm(prev, input, s);
|
|
53951
|
-
const
|
|
53952
|
-
|
|
53953
|
-
|
|
53954
|
-
|
|
53955
|
-
|
|
53956
|
-
const
|
|
53957
|
-
|
|
53958
|
-
|
|
54013
|
+
const parked = this.promoteWhenReady(updated, input);
|
|
54014
|
+
next[index] = parked ?? updated;
|
|
54015
|
+
if (parked !== null) promoted.push(toEntry(parked));
|
|
54016
|
+
}
|
|
54017
|
+
if (input.looked === true && input.continuationBoxes !== void 0) for (let i = 0; i < next.length; i += 1) {
|
|
54018
|
+
const c = next[i];
|
|
54019
|
+
if (c === void 0 || c.promotedAt !== null || consumed.has(c.id)) continue;
|
|
54020
|
+
if (c.realHits < PACKAGE_CONTINUATION_MIN_REAL_HITS) continue;
|
|
54021
|
+
const box = this.continuationFor(c, input.continuationBoxes);
|
|
54022
|
+
if (box === null) continue;
|
|
54023
|
+
consumed.add(c.id);
|
|
54024
|
+
const continued = {
|
|
54025
|
+
...c,
|
|
54026
|
+
lastSeenAt: input.timestamp,
|
|
54027
|
+
hits: c.hits + 1,
|
|
54028
|
+
absenceReads: [],
|
|
54029
|
+
lastLook: "present",
|
|
54030
|
+
earlyUnbackedReported: false
|
|
53959
54031
|
};
|
|
53960
|
-
|
|
53961
|
-
|
|
54032
|
+
continuedLog.push({
|
|
54033
|
+
id: c.id,
|
|
54034
|
+
hits: continued.hits,
|
|
54035
|
+
score: box.score
|
|
54036
|
+
});
|
|
54037
|
+
const parked = this.promoteWhenReady(continued, input);
|
|
54038
|
+
next[i] = parked ?? continued;
|
|
54039
|
+
if (parked !== null) promoted.push(toEntry(parked));
|
|
53962
54040
|
}
|
|
53963
54041
|
const present = input.rawPackageBoxes !== void 0 ? withRawPresence(next, consumed, input.rawPackageBoxes, input.timestamp, this.config.assocIou) : next;
|
|
53964
54042
|
const looked = input.looked === true && input.rawPackageBoxes !== void 0 ? withLook(present, consumed, input, input.rawPackageBoxes, this.config.assocIou) : present;
|
|
@@ -53994,7 +54072,8 @@ var PackageStillnessTracker = class {
|
|
|
53994
54072
|
...input.lastActivityAt !== void 0 ? { lastActivityAt: input.lastActivityAt } : {}
|
|
53995
54073
|
}),
|
|
53996
54074
|
earlyDepartureIds: [...early],
|
|
53997
|
-
earlyEvidenceUnbacked: unbacked
|
|
54075
|
+
earlyEvidenceUnbacked: unbacked,
|
|
54076
|
+
continued: continuedLog
|
|
53998
54077
|
};
|
|
53999
54078
|
}
|
|
54000
54079
|
/** Why complete early evidence may NOT conclude, or null when it may. */
|
|
@@ -54021,7 +54100,8 @@ var PackageStillnessTracker = class {
|
|
|
54021
54100
|
...input.lastActivityAt !== void 0 ? { lastActivityAt: input.lastActivityAt } : {}
|
|
54022
54101
|
}),
|
|
54023
54102
|
earlyDepartureIds: [],
|
|
54024
|
-
earlyEvidenceUnbacked: []
|
|
54103
|
+
earlyEvidenceUnbacked: [],
|
|
54104
|
+
continued: []
|
|
54025
54105
|
};
|
|
54026
54106
|
}
|
|
54027
54107
|
/** The devices holding a candidate — what a sweep has to visit. */
|
|
@@ -54085,6 +54165,43 @@ var PackageStillnessTracker = class {
|
|
|
54085
54165
|
/** Best same-class candidate over the association floor, ignoring any already
|
|
54086
54166
|
* consumed by an earlier sighting in THIS frame (two boxes never collapse
|
|
54087
54167
|
* into one parcel). */
|
|
54168
|
+
continuationFor(c, boxes) {
|
|
54169
|
+
let best = null;
|
|
54170
|
+
let bestIou = this.config.assocIou;
|
|
54171
|
+
for (const b of boxes) {
|
|
54172
|
+
if (b.score < PACKAGE_STILLNESS_CONTINUATION_MIN_SCORE) continue;
|
|
54173
|
+
const overlap = iou$2(c.bbox, b.bbox);
|
|
54174
|
+
if (overlap >= bestIou) {
|
|
54175
|
+
bestIou = overlap;
|
|
54176
|
+
best = b;
|
|
54177
|
+
}
|
|
54178
|
+
}
|
|
54179
|
+
return best;
|
|
54180
|
+
}
|
|
54181
|
+
promoteWhenReady(candidate, input) {
|
|
54182
|
+
const updated = this.backedLate(candidate, input);
|
|
54183
|
+
const minHits = input.minHits ?? this.config.minHits;
|
|
54184
|
+
return updated.promotedAt === null && updated.activityBackedAtOpen && updated.hits >= minHits && input.timestamp - updated.firstSeenAt >= input.minDwellMs ? {
|
|
54185
|
+
...updated,
|
|
54186
|
+
promotedAt: input.timestamp
|
|
54187
|
+
} : null;
|
|
54188
|
+
}
|
|
54189
|
+
/**
|
|
54190
|
+
* Zone motion learned AFTER the open still backs the candidate when its stamp
|
|
54191
|
+
* lies in the window around the FIRST sighting (the same slack a pick-up
|
|
54192
|
+
* gets): the backing stays anchored at the open, a later passer-by never
|
|
54193
|
+
* validates scenery (D1003).
|
|
54194
|
+
*/
|
|
54195
|
+
backedLate(c, input) {
|
|
54196
|
+
if (c.activityBackedAtOpen || c.promotedAt !== null) return c;
|
|
54197
|
+
const at = input.lastDelivererMotionAt;
|
|
54198
|
+
const windowMs = input.activityWindowMs ?? 0;
|
|
54199
|
+
if (at === void 0 || windowMs <= 0) return c;
|
|
54200
|
+
return at >= c.firstSeenAt - windowMs && at <= c.firstSeenAt + this.config.roundGapMs ? {
|
|
54201
|
+
...c,
|
|
54202
|
+
activityBackedAtOpen: true
|
|
54203
|
+
} : c;
|
|
54204
|
+
}
|
|
54088
54205
|
bestMatch(candidates, s, consumed) {
|
|
54089
54206
|
let bestIndex = -1;
|
|
54090
54207
|
let bestIou = this.config.assocIou;
|
|
@@ -54101,7 +54218,7 @@ var PackageStillnessTracker = class {
|
|
|
54101
54218
|
}
|
|
54102
54219
|
openCandidate(input, s) {
|
|
54103
54220
|
const windowMs = input.activityWindowMs ?? 0;
|
|
54104
|
-
const activityBackedAtOpen = windowMs <= 0 || input.lastActivityAt !== void 0 && input.timestamp - input.lastActivityAt <= windowMs;
|
|
54221
|
+
const activityBackedAtOpen = windowMs <= 0 || input.lastActivityAt !== void 0 && input.timestamp - input.lastActivityAt <= windowMs || input.lastDelivererMotionAt !== void 0 && input.timestamp - input.lastDelivererMotionAt <= windowMs;
|
|
54105
54222
|
return {
|
|
54106
54223
|
id: this.newId(),
|
|
54107
54224
|
deviceId: input.deviceId,
|
|
@@ -54112,6 +54229,7 @@ var PackageStillnessTracker = class {
|
|
|
54112
54229
|
firstSeenAt: input.timestamp,
|
|
54113
54230
|
lastSeenAt: input.timestamp,
|
|
54114
54231
|
hits: 1,
|
|
54232
|
+
realHits: 1,
|
|
54115
54233
|
promotedAt: null,
|
|
54116
54234
|
absenceReads: [],
|
|
54117
54235
|
lastLook: null,
|
|
@@ -54134,6 +54252,7 @@ function confirm(prev, input, s) {
|
|
|
54134
54252
|
frameHeight: input.frameHeight,
|
|
54135
54253
|
lastSeenAt: input.timestamp,
|
|
54136
54254
|
hits: prev.hits + 1,
|
|
54255
|
+
realHits: prev.realHits + 1,
|
|
54137
54256
|
absenceReads: [],
|
|
54138
54257
|
lastLook: "present",
|
|
54139
54258
|
earlyUnbackedReported: false,
|
|
@@ -54670,6 +54789,9 @@ var FrameState = class {
|
|
|
54670
54789
|
* which would let the streetlight wedge vouch for its own delivery.
|
|
54671
54790
|
*/
|
|
54672
54791
|
lastNonPackageActivityAt = /* @__PURE__ */ new Map();
|
|
54792
|
+
/** Last analyzer motion near a package drop-off zone, per device (D1003).
|
|
54793
|
+
* Backs the OPEN of a candidate only; never a pick-up witness. */
|
|
54794
|
+
lastPackageZoneMotionAt = /* @__PURE__ */ new Map();
|
|
54673
54795
|
/**
|
|
54674
54796
|
* WHO was in the drop-off zone, and when (D404). The pick-up is CONCLUDED
|
|
54675
54797
|
* minutes after the fact, so the collector must be remembered while it is
|
|
@@ -58029,6 +58151,7 @@ function nextPackageLookDropEpisodes(previous, drops) {
|
|
|
58029
58151
|
//#region src/pipeline-analytics/pipeline/package/package-look-evidence.ts
|
|
58030
58152
|
function packageLookEvidence(input) {
|
|
58031
58153
|
const raw = [];
|
|
58154
|
+
const continuation = [];
|
|
58032
58155
|
for (const d of input.frame.detections) {
|
|
58033
58156
|
if (d.kind !== "first-level" || !input.packageClasses.has(d.macroClass)) continue;
|
|
58034
58157
|
raw.push({
|
|
@@ -58041,11 +58164,16 @@ function packageLookEvidence(input) {
|
|
|
58041
58164
|
for (const d of input.frame.discarded ?? []) {
|
|
58042
58165
|
if (!input.packageClasses.has(d.macroClass)) continue;
|
|
58043
58166
|
const [x1, y1, x2, y2] = d.bbox;
|
|
58044
|
-
|
|
58167
|
+
const box = {
|
|
58045
58168
|
x: x1,
|
|
58046
58169
|
y: y1,
|
|
58047
58170
|
w: x2 - x1,
|
|
58048
58171
|
h: y2 - y1
|
|
58172
|
+
};
|
|
58173
|
+
raw.push(box);
|
|
58174
|
+
if (d.reason === "below-threshold") continuation.push({
|
|
58175
|
+
bbox: box,
|
|
58176
|
+
score: d.score
|
|
58049
58177
|
});
|
|
58050
58178
|
}
|
|
58051
58179
|
return {
|
|
@@ -58057,6 +58185,7 @@ function packageLookEvidence(input) {
|
|
|
58057
58185
|
h: t.bbox.h
|
|
58058
58186
|
})),
|
|
58059
58187
|
rawPackageBoxes: raw,
|
|
58188
|
+
continuationBoxes: continuation,
|
|
58060
58189
|
earlyPickup: input.earlyPickupEnabled
|
|
58061
58190
|
};
|
|
58062
58191
|
}
|
|
@@ -58244,6 +58373,13 @@ function clamp01(value) {
|
|
|
58244
58373
|
}
|
|
58245
58374
|
//#endregion
|
|
58246
58375
|
//#region src/pipeline-analytics/pipeline/package/package-scene-diff.ts
|
|
58376
|
+
/**
|
|
58377
|
+
* Zone-crop scene difference for a packages rule (D931).
|
|
58378
|
+
*
|
|
58379
|
+
* A uniform brightness shift is removed by subtracting the median luma delta,
|
|
58380
|
+
* so a shadow that lifts the whole crop leaves no blob. What remains is a
|
|
58381
|
+
* connected region. The package model is not consulted here.
|
|
58382
|
+
*/
|
|
58247
58383
|
/** Residual, after the median shift, that counts as a changed pixel. */
|
|
58248
58384
|
var PACKAGE_SCENE_DIFF_LUMA_THRESHOLD = 28;
|
|
58249
58385
|
/** A changed region this large, relative to the zone, is the zone itself. */
|
|
@@ -58258,12 +58394,26 @@ var PACKAGE_SCENE_DIFF_SETTLE_MS = 3e3;
|
|
|
58258
58394
|
var PACKAGE_SCENE_DIFF_LOOK_GAP_MS = 2e3;
|
|
58259
58395
|
/** Confidence stamped on a scene-diff sighting the model did not box. */
|
|
58260
58396
|
var PACKAGE_SCENE_DIFF_CONFIDENCE = .5;
|
|
58397
|
+
/** True when the crop was shot in infrared (no colour). */
|
|
58398
|
+
function isIrCrop(crop) {
|
|
58399
|
+
return crop.chromaSpread < IR_CHROMA_THRESHOLD;
|
|
58400
|
+
}
|
|
58261
58401
|
function diffZoneLuma(input) {
|
|
58262
58402
|
const { before, after } = input;
|
|
58263
58403
|
if (before.width !== after.width || before.height !== after.height || before.luma.length !== after.luma.length) return {
|
|
58264
58404
|
blobs: [],
|
|
58265
58405
|
rejections: [{ reason: "crop-mismatch" }]
|
|
58266
58406
|
};
|
|
58407
|
+
if (isIrCrop(before) !== isIrCrop(after)) return {
|
|
58408
|
+
blobs: [],
|
|
58409
|
+
rejections: [{
|
|
58410
|
+
reason: "lighting-mode-changed",
|
|
58411
|
+
chroma: {
|
|
58412
|
+
before: before.chromaSpread,
|
|
58413
|
+
after: after.chromaSpread
|
|
58414
|
+
}
|
|
58415
|
+
}]
|
|
58416
|
+
};
|
|
58267
58417
|
const median = medianDelta(before.luma, after.luma);
|
|
58268
58418
|
const mask = residualMask(before.luma, after.luma, median);
|
|
58269
58419
|
const zonePx = before.width * before.height;
|
|
@@ -58478,6 +58628,7 @@ function okCrop(rgb, width, height, jpeg) {
|
|
|
58478
58628
|
width,
|
|
58479
58629
|
height,
|
|
58480
58630
|
luma: lumaFromRgb(rgb, width, height),
|
|
58631
|
+
chromaSpread: chromaSpreadFromRgb(rgb, width, height),
|
|
58481
58632
|
jpeg: new Uint8Array(jpeg)
|
|
58482
58633
|
};
|
|
58483
58634
|
}
|
|
@@ -58494,6 +58645,46 @@ function lumaFromRgb(bytes, width, height) {
|
|
|
58494
58645
|
}
|
|
58495
58646
|
return luma;
|
|
58496
58647
|
}
|
|
58648
|
+
/** The grid `IR_CHROMA_THRESHOLD` was calibrated on (`chromaSpread`, scene-crop.ts). */
|
|
58649
|
+
var CHROMA_GRID = 32;
|
|
58650
|
+
/**
|
|
58651
|
+
* Mean of max(r,g,b) - min(r,g,b), 0..255, measured on a 32x32 box-averaged
|
|
58652
|
+
* copy of the crop: the same measure and grid as `chromaSpread` in
|
|
58653
|
+
* `scene-crop.ts` (which needs sharp), so `IR_CHROMA_THRESHOLD` means the same
|
|
58654
|
+
* thing. Averaging first matters: sensor noise and JPEG chroma speckle on an IR
|
|
58655
|
+
* frame cancel out, where per-pixel they read as colour.
|
|
58656
|
+
*/
|
|
58657
|
+
function chromaSpreadFromRgb(bytes, width, height) {
|
|
58658
|
+
if (width <= 0 || height <= 0 || bytes.length < width * height * 3) return 0;
|
|
58659
|
+
const gw = Math.min(CHROMA_GRID, width);
|
|
58660
|
+
const gh = Math.min(CHROMA_GRID, height);
|
|
58661
|
+
const sum = new Float64Array(gw * gh * 3);
|
|
58662
|
+
const count = new Float64Array(gw * gh);
|
|
58663
|
+
for (let y = 0; y < height; y++) {
|
|
58664
|
+
const cy = Math.min(gh - 1, Math.floor(y * gh / height));
|
|
58665
|
+
for (let x = 0; x < width; x++) {
|
|
58666
|
+
const cx = Math.min(gw - 1, Math.floor(x * gw / width));
|
|
58667
|
+
const cell = cy * gw + cx;
|
|
58668
|
+
const o = (y * width + x) * 3;
|
|
58669
|
+
sum[cell * 3] = (sum[cell * 3] ?? 0) + (bytes[o] ?? 0);
|
|
58670
|
+
sum[cell * 3 + 1] = (sum[cell * 3 + 1] ?? 0) + (bytes[o + 1] ?? 0);
|
|
58671
|
+
sum[cell * 3 + 2] = (sum[cell * 3 + 2] ?? 0) + (bytes[o + 2] ?? 0);
|
|
58672
|
+
count[cell] = (count[cell] ?? 0) + 1;
|
|
58673
|
+
}
|
|
58674
|
+
}
|
|
58675
|
+
let total = 0;
|
|
58676
|
+
let cells = 0;
|
|
58677
|
+
for (let cell = 0; cell < gw * gh; cell++) {
|
|
58678
|
+
const n = count[cell] ?? 0;
|
|
58679
|
+
if (n === 0) continue;
|
|
58680
|
+
const r = (sum[cell * 3] ?? 0) / n;
|
|
58681
|
+
const g = (sum[cell * 3 + 1] ?? 0) / n;
|
|
58682
|
+
const b = (sum[cell * 3 + 2] ?? 0) / n;
|
|
58683
|
+
total += Math.max(r, g, b) - Math.min(r, g, b);
|
|
58684
|
+
cells += 1;
|
|
58685
|
+
}
|
|
58686
|
+
return cells === 0 ? 0 : total / cells;
|
|
58687
|
+
}
|
|
58497
58688
|
//#endregion
|
|
58498
58689
|
//#region src/pipeline-analytics/pipeline/package/package-scene-step.ts
|
|
58499
58690
|
/**
|
|
@@ -58593,6 +58784,14 @@ function compareAfterLeave(prev, input) {
|
|
|
58593
58784
|
minAreaFrac: input.minAreaFrac,
|
|
58594
58785
|
occluders: input.occluders
|
|
58595
58786
|
});
|
|
58787
|
+
if (diff.rejections.some((r) => r.reason === "lighting-mode-changed")) return {
|
|
58788
|
+
state: {
|
|
58789
|
+
...rememberClear(prev, input).state,
|
|
58790
|
+
lastDiffAt: input.timestamp
|
|
58791
|
+
},
|
|
58792
|
+
sightings: [],
|
|
58793
|
+
rejections: diff.rejections
|
|
58794
|
+
};
|
|
58596
58795
|
const blocked = diff.rejections.some((r) => r.reason === "overlaps-person" || r.reason === "overlaps-vehicle");
|
|
58597
58796
|
if (diff.blobs.length === 0) {
|
|
58598
58797
|
if (blocked) return {
|
|
@@ -58636,6 +58835,20 @@ function confirmPending(prev, input) {
|
|
|
58636
58835
|
sightings: [],
|
|
58637
58836
|
rejections: []
|
|
58638
58837
|
};
|
|
58838
|
+
if (isIrCrop(prev.after) !== isIrCrop(input.crop)) return {
|
|
58839
|
+
state: {
|
|
58840
|
+
...rememberClear(prev, input).state,
|
|
58841
|
+
lastDiffAt: input.timestamp
|
|
58842
|
+
},
|
|
58843
|
+
sightings: [],
|
|
58844
|
+
rejections: [{
|
|
58845
|
+
reason: "lighting-mode-changed",
|
|
58846
|
+
chroma: {
|
|
58847
|
+
before: prev.after.chromaSpread,
|
|
58848
|
+
after: input.crop.chromaSpread
|
|
58849
|
+
}
|
|
58850
|
+
}]
|
|
58851
|
+
};
|
|
58639
58852
|
const sightings = [];
|
|
58640
58853
|
const rejections = [];
|
|
58641
58854
|
const still = [];
|
|
@@ -58682,7 +58895,7 @@ function judgeBlob(prev, input, blob) {
|
|
|
58682
58895
|
bbox: blob.bbox
|
|
58683
58896
|
} };
|
|
58684
58897
|
const stable = meanAbsInBox(after, crop, blob.bbox) <= PACKAGE_SCENE_DIFF_STABLE_MEAN;
|
|
58685
|
-
const present = meanAbsInBox(before, crop, blob.bbox) >= PACKAGE_SCENE_DIFF_LUMA_THRESHOLD;
|
|
58898
|
+
const present = isIrCrop(before) !== isIrCrop(crop) || meanAbsInBox(before, crop, blob.bbox) >= PACKAGE_SCENE_DIFF_LUMA_THRESHOLD;
|
|
58686
58899
|
if (!stable || !present) return { rejection: {
|
|
58687
58900
|
reason: "unstable",
|
|
58688
58901
|
bbox: blob.bbox,
|
|
@@ -58850,7 +59063,8 @@ var PackageSceneCoordinator = class {
|
|
|
58850
59063
|
const crop = {
|
|
58851
59064
|
width: fetched.width,
|
|
58852
59065
|
height: fetched.height,
|
|
58853
|
-
luma: fetched.luma
|
|
59066
|
+
luma: fetched.luma,
|
|
59067
|
+
chromaSpread: fetched.chromaSpread
|
|
58854
59068
|
};
|
|
58855
59069
|
const stepped = stepPackageScene({
|
|
58856
59070
|
deviceId,
|
|
@@ -58916,6 +59130,10 @@ var PackageSceneCoordinator = class {
|
|
|
58916
59130
|
tags: { deviceId },
|
|
58917
59131
|
meta: {
|
|
58918
59132
|
reason: rejection.reason,
|
|
59133
|
+
...rejection.chroma !== void 0 ? {
|
|
59134
|
+
chromaBefore: Number(rejection.chroma.before.toFixed(2)),
|
|
59135
|
+
chromaAfter: Number(rejection.chroma.after.toFixed(2))
|
|
59136
|
+
} : {},
|
|
58919
59137
|
...rejection.areaFrac !== void 0 ? { areaFrac: Number(rejection.areaFrac.toFixed(5)) } : {}
|
|
58920
59138
|
}
|
|
58921
59139
|
});
|
|
@@ -59024,14 +59242,8 @@ function planPackageSceneFrame(deviceId, input) {
|
|
|
59024
59242
|
frameWidth: input.frameWidth,
|
|
59025
59243
|
frameHeight: input.frameHeight
|
|
59026
59244
|
});
|
|
59027
|
-
const sceneRect = sceneZones.size === 0 ? null : packageZoneCropRect({
|
|
59028
|
-
zones: input.zones,
|
|
59029
|
-
packageZoneIds: sceneZones,
|
|
59030
|
-
frameWidth: input.frameWidth,
|
|
59031
|
-
frameHeight: input.frameHeight
|
|
59032
|
-
});
|
|
59033
59245
|
return {
|
|
59034
|
-
sightings:
|
|
59246
|
+
sightings: input.sightings,
|
|
59035
59247
|
note: {
|
|
59036
59248
|
deviceId,
|
|
59037
59249
|
timestamp: input.timestamp,
|
|
@@ -59074,15 +59286,6 @@ function occludersOf(tracked) {
|
|
|
59074
59286
|
}
|
|
59075
59287
|
return out;
|
|
59076
59288
|
}
|
|
59077
|
-
function withoutSceneCenters(input, rect) {
|
|
59078
|
-
if (input.frameWidth <= 0 || input.frameHeight <= 0) return input.sightings;
|
|
59079
|
-
return input.sightings.filter((sighting) => !centerInside(sighting.bbox, rect, input));
|
|
59080
|
-
}
|
|
59081
|
-
function centerInside(bbox, rect, input) {
|
|
59082
|
-
const cx = (bbox.x + bbox.w / 2) / input.frameWidth;
|
|
59083
|
-
const cy = (bbox.y + bbox.h / 2) / input.frameHeight;
|
|
59084
|
-
return cx >= rect.x && cx < rect.x + rect.w && cy >= rect.y && cy < rect.y + rect.h;
|
|
59085
|
-
}
|
|
59086
59289
|
//#endregion
|
|
59087
59290
|
//#region src/pipeline-analytics/pipeline/package/package-llm-confirm.ts
|
|
59088
59291
|
/**
|
|
@@ -71062,6 +71265,7 @@ Object.freeze({
|
|
|
71062
71265
|
"addon-pages-source": ["listPages"],
|
|
71063
71266
|
"addon-routes": ["getRoutes"],
|
|
71064
71267
|
"addon-widgets-source": ["listWidgets"],
|
|
71268
|
+
"board-key-source": ["listSources"],
|
|
71065
71269
|
"broker": ["list", "listProviders"],
|
|
71066
71270
|
"calendar-source": ["listCalendars", "listEvents"],
|
|
71067
71271
|
"custom-model-registry": ["listModels"],
|
|
@@ -72590,7 +72794,7 @@ function buildGlobalSettingsSchema(cap) {
|
|
|
72590
72794
|
type: "slider",
|
|
72591
72795
|
key: "packageDropActivityWindowSec",
|
|
72592
72796
|
label: "Deliverer window",
|
|
72593
|
-
description: "A delivery only counts if a person or vehicle was in the configured package drop-off zone within this many seconds before the package appeared — and a pick-up only with somebody in that zone when it vanished. Motion elsewhere on the camera does not count. 0 disables the requirement.",
|
|
72797
|
+
description: "A delivery only counts if a person or vehicle was in the configured package drop-off zone within this many seconds before the package appeared — and a pick-up only with somebody in that zone when it vanished. Person-sized motion beside the drop-off zone also counts when nobody was tracked. Motion elsewhere on the camera does not count. 0 disables the requirement.",
|
|
72594
72798
|
min: 0,
|
|
72595
72799
|
max: 1800,
|
|
72596
72800
|
step: 30,
|
|
@@ -87110,6 +87314,13 @@ var NC_STILL_WAIT_MAX_AGE_MS = 3e4;
|
|
|
87110
87314
|
function canStillGainMedia(entry) {
|
|
87111
87315
|
return entry.recordKind === "object-event";
|
|
87112
87316
|
}
|
|
87317
|
+
/** The variables that carry a finished cycle's run summary. */
|
|
87318
|
+
var CYCLE_SUMMARY_VARS = [
|
|
87319
|
+
"duration",
|
|
87320
|
+
"energy",
|
|
87321
|
+
"afterDuration",
|
|
87322
|
+
"usedEnergy"
|
|
87323
|
+
];
|
|
87113
87324
|
var NcDispatcher = class {
|
|
87114
87325
|
deps;
|
|
87115
87326
|
targetCache = null;
|
|
@@ -88013,6 +88224,7 @@ var NcDispatcher = class {
|
|
|
88013
88224
|
}
|
|
88014
88225
|
/** Rules already warned about a deprecated variable in this process — once each. */
|
|
88015
88226
|
deprecatedVarWarned = /* @__PURE__ */ new Set();
|
|
88227
|
+
cycleSummaryWarned = /* @__PURE__ */ new Set();
|
|
88016
88228
|
/**
|
|
88017
88229
|
* A rule template written by an older client may still say `{{camera}}`. It
|
|
88018
88230
|
* renders (the alias), and the rule is named once so the operator can edit it.
|
|
@@ -88032,6 +88244,27 @@ var NcDispatcher = class {
|
|
|
88032
88244
|
});
|
|
88033
88245
|
}
|
|
88034
88246
|
/**
|
|
88247
|
+
* A FINISHED-cycle row whose own template places none of the four cycle
|
|
88248
|
+
* variables delivers no run summary (D391: accepted, produced less). Said
|
|
88249
|
+
* once per rule; the operator's text is never touched.
|
|
88250
|
+
*/
|
|
88251
|
+
warnCycleSummaryDropped(entry) {
|
|
88252
|
+
const deviceId = entry.payload.subject.applianceCycle?.deviceId;
|
|
88253
|
+
const template = entry.payload.template;
|
|
88254
|
+
if (deviceId === void 0 || template === void 0) return;
|
|
88255
|
+
if (this.cycleSummaryWarned.has(entry.ruleId)) return;
|
|
88256
|
+
const used = new Set([...templatePlaceholders(template.title ?? ""), ...templatePlaceholders(template.body ?? "")]);
|
|
88257
|
+
if (CYCLE_SUMMARY_VARS.some((name) => used.has(name))) return;
|
|
88258
|
+
this.cycleSummaryWarned.add(entry.ruleId);
|
|
88259
|
+
this.deps.logger.warn("appliance cycle finished but the rule template places no run summary — the message carries no duration or energy", {
|
|
88260
|
+
tags: {
|
|
88261
|
+
deviceId,
|
|
88262
|
+
ruleId: entry.ruleId
|
|
88263
|
+
},
|
|
88264
|
+
meta: { placeholders: [...CYCLE_SUMMARY_VARS] }
|
|
88265
|
+
});
|
|
88266
|
+
}
|
|
88267
|
+
/**
|
|
88035
88268
|
* The facts of a finished appliance cycle; unknown on every other row and on
|
|
88036
88269
|
* any failure (a part that cannot be read is omitted, never a blocked send).
|
|
88037
88270
|
*/
|
|
@@ -88076,6 +88309,7 @@ var NcDispatcher = class {
|
|
|
88076
88309
|
const cycleFacts = await this.applianceCycleFacts(entry);
|
|
88077
88310
|
const vars = buildTemplateVars(this.texts, entry, deviceName, zoneLabels, void 0, cycleFacts);
|
|
88078
88311
|
this.warnDeprecatedVars(entry);
|
|
88312
|
+
this.warnCycleSummaryDropped(entry);
|
|
88079
88313
|
const systemCount = systemEvent?.textCount !== void 0 ? { count: systemEvent.textCount } : {};
|
|
88080
88314
|
const title = renderRowTitle(this.texts, entry, vars);
|
|
88081
88315
|
const authoredBody = entry.payload.template?.body;
|
|
@@ -102058,7 +102292,10 @@ function buildProvider(host) {
|
|
|
102058
102292
|
catalog: [...NC_CONDITION_CATALOG],
|
|
102059
102293
|
taxonomy: NC_TAXONOMY
|
|
102060
102294
|
}),
|
|
102061
|
-
getTemplateCatalog: async () => ({
|
|
102295
|
+
getTemplateCatalog: async () => ({
|
|
102296
|
+
vars: servedTemplateVars(),
|
|
102297
|
+
defaults: servedTemplateDefaults(host.texts)
|
|
102298
|
+
}),
|
|
102062
102299
|
previewTemplate: async (input) => previewTemplate(host.texts, input),
|
|
102063
102300
|
getHistory: async ({ filter }) => {
|
|
102064
102301
|
const entries = await host.outbox.queryHistory({
|
|
@@ -124995,6 +125232,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
124995
125232
|
this.packageDropDetector?.forgetDevice(data.deviceId);
|
|
124996
125233
|
this.packageScene?.forget(data.deviceId);
|
|
124997
125234
|
this.frameState.lastNonPackageActivityAt.delete(data.deviceId);
|
|
125235
|
+
this.frameState.lastPackageZoneMotionAt.delete(data.deviceId);
|
|
124998
125236
|
this.frameState.packageCollectors.forgetDevice(data.deviceId);
|
|
124999
125237
|
this.frameState.packageOversizeLogAt.delete(data.deviceId);
|
|
125000
125238
|
this.frameState.packageLookFrames.delete(data.deviceId);
|
|
@@ -125019,6 +125257,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
125019
125257
|
this.packageDropDetector?.forgetDevice(deviceId);
|
|
125020
125258
|
this.packageScene?.forget(deviceId);
|
|
125021
125259
|
this.frameState.lastNonPackageActivityAt.delete(deviceId);
|
|
125260
|
+
this.frameState.lastPackageZoneMotionAt.delete(deviceId);
|
|
125022
125261
|
this.frameState.packageCollectors.forgetDevice(deviceId);
|
|
125023
125262
|
this.frameState.packageOversizeLogAt.delete(deviceId);
|
|
125024
125263
|
this.frameState.packageLookFrames.delete(deviceId);
|
|
@@ -127591,6 +127830,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
127591
127830
|
detected,
|
|
127592
127831
|
atMs: timestamp
|
|
127593
127832
|
});
|
|
127833
|
+
if (detected) await this.stampPackageZoneMotion(deviceId, payload, timestamp);
|
|
127594
127834
|
if (detected) this.eventStore?.noteMotionSample(deviceId, payload.regionCount, timestamp);
|
|
127595
127835
|
await this.motionEpisodes?.observe(deviceId, "analyzer", detected, timestamp, {
|
|
127596
127836
|
regionCount: payload.regionCount,
|
|
@@ -127609,6 +127849,28 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
127609
127849
|
});
|
|
127610
127850
|
}
|
|
127611
127851
|
/**
|
|
127852
|
+
* Stamp analyzer motion that reached a package drop-off zone (D1003): the
|
|
127853
|
+
* courier who never became an L1 track still backs the OPEN of a candidate.
|
|
127854
|
+
* Onboard motion carries no regions or dimensions and never stamps.
|
|
127855
|
+
*/
|
|
127856
|
+
async stampPackageZoneMotion(deviceId, payload, timestamp) {
|
|
127857
|
+
const proxy = await this.ensureProxy(deviceId);
|
|
127858
|
+
const packageZoneIds = collectPackageZoneIds(proxy?.state.zoneRules.value?.package ?? []);
|
|
127859
|
+
if (packageZoneIds.size === 0) return;
|
|
127860
|
+
const zoneRect = packageZoneCropRect({
|
|
127861
|
+
zones: proxy?.state.zones.value?.zones ?? [],
|
|
127862
|
+
packageZoneIds,
|
|
127863
|
+
frameWidth: payload.frameWidth,
|
|
127864
|
+
frameHeight: payload.frameHeight
|
|
127865
|
+
});
|
|
127866
|
+
if (delivererMotionNearPackageZone({
|
|
127867
|
+
regions: payload.regions,
|
|
127868
|
+
frameWidth: payload.frameWidth,
|
|
127869
|
+
frameHeight: payload.frameHeight,
|
|
127870
|
+
zoneRect
|
|
127871
|
+
})) this.frameState.lastPackageZoneMotionAt.set(deviceId, timestamp);
|
|
127872
|
+
}
|
|
127873
|
+
/**
|
|
127612
127874
|
* Persist firmware-driven (onboard / device-activity) motion events into
|
|
127613
127875
|
* the SAME episode tracker as {@link handleMotionAnalysis}, keyed per
|
|
127614
127876
|
* `(deviceId, source)` so the two paths can never share — or fight over —
|
|
@@ -127941,6 +128203,10 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
127941
128203
|
encodeJpeg: request.encodeJpeg
|
|
127942
128204
|
}, request.pin);
|
|
127943
128205
|
}
|
|
128206
|
+
zoneMotionStamp(deviceId) {
|
|
128207
|
+
const at = this.frameState.lastPackageZoneMotionAt.get(deviceId);
|
|
128208
|
+
return at === void 0 ? {} : { lastDelivererMotionAt: at };
|
|
128209
|
+
}
|
|
127944
128210
|
deliverPackageSceneSightings(delivery) {
|
|
127945
128211
|
const settings = this.packageDropSettingsFromCache(delivery.deviceId);
|
|
127946
128212
|
const lastActivityAt = this.frameState.lastNonPackageActivityAt.get(delivery.deviceId);
|
|
@@ -127954,6 +128220,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
127954
128220
|
minDwellMs: settings.packageDropDwellSec * 1e3,
|
|
127955
128221
|
activityWindowMs: settings.packageDropActivityWindowSec * 1e3,
|
|
127956
128222
|
...lastActivityAt !== void 0 ? { lastActivityAt } : {},
|
|
128223
|
+
...this.zoneMotionStamp(delivery.deviceId),
|
|
127957
128224
|
looked: false
|
|
127958
128225
|
});
|
|
127959
128226
|
this.bridgePackageStillness({
|
|
@@ -128139,6 +128406,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
128139
128406
|
minDwellMs: input.settings.packageDropDwellSec * 1e3,
|
|
128140
128407
|
activityWindowMs: input.settings.packageDropActivityWindowSec * 1e3,
|
|
128141
128408
|
...lastActivityAt !== void 0 ? { lastActivityAt } : {},
|
|
128409
|
+
...this.zoneMotionStamp(input.deviceId),
|
|
128142
128410
|
...lookEvidence
|
|
128143
128411
|
});
|
|
128144
128412
|
this.bridgePackageStillness({
|
|
@@ -128334,6 +128602,15 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
128334
128602
|
});
|
|
128335
128603
|
}).catch(() => void 0);
|
|
128336
128604
|
}
|
|
128605
|
+
for (const c of outcome.continued) this.ctx.logger.info("package candidate continued by a sub-floor box", {
|
|
128606
|
+
tags,
|
|
128607
|
+
meta: {
|
|
128608
|
+
entryId: c.id,
|
|
128609
|
+
hits: c.hits,
|
|
128610
|
+
score: c.score,
|
|
128611
|
+
via: input.via
|
|
128612
|
+
}
|
|
128613
|
+
});
|
|
128337
128614
|
for (const u of outcome.earlyEvidenceUnbacked) this.ctx.logger.info("early pick-up evidence complete — nobody around, left to the TTL", {
|
|
128338
128615
|
tags,
|
|
128339
128616
|
meta: {
|
|
@@ -128361,6 +128638,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
128361
128638
|
observedDwellMs,
|
|
128362
128639
|
requiredDwellMs,
|
|
128363
128640
|
activityBackedAtOpen: ex.activityBackedAtOpen,
|
|
128641
|
+
lastZoneMotionAt: this.frameState.lastPackageZoneMotionAt.get(input.deviceId) ?? null,
|
|
128364
128642
|
reasons
|
|
128365
128643
|
}
|
|
128366
128644
|
});
|