@camstack/addon-post-analysis 1.2.617 → 1.2.619
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/THIRD_PARTY_MODELS.md +3 -1
- package/dist/{clip-model-registry-CYWuH4Rx.js → clip-model-registry-B4VtQ3mk.js} +232 -24
- package/dist/{clip-model-registry-D6yfX_Xq.mjs → clip-model-registry-Clb51mcj.mjs} +203 -19
- 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-DiTZe8LM.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-BGo4IMTT.mjs} +3 -3
- package/dist/pipeline-analytics/{_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CSQBGkvs.mjs → _virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BSMSev-b.mjs} +1 -1
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-CssYIiFD.mjs +26 -0
- package/dist/pipeline-analytics/{hostInit-BXvwC4CQ.mjs → hostInit-p9APfKsm.mjs} +3 -3
- package/dist/pipeline-analytics/index.js +146 -209
- package/dist/pipeline-analytics/index.mjs +146 -208
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/package.json +1 -1
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BB2kgLY1.mjs +0 -26
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_clip_model_registry = require("../clip-model-registry-
|
|
5
|
+
const require_clip_model_registry = require("../clip-model-registry-B4VtQ3mk.js");
|
|
6
6
|
let node_fs = require("node:fs");
|
|
7
7
|
node_fs = require_clip_model_registry.__toESM(node_fs, 1);
|
|
8
8
|
let node_path = require("node:path");
|
|
@@ -9393,7 +9393,7 @@ var IdentityConfigBodySchema = require_clip_model_registry.object({
|
|
|
9393
9393
|
*
|
|
9394
9394
|
* `addedAt` is ALSO in the body: the `identity_added` index names it, and an
|
|
9395
9395
|
* index reads the body, never the header. Optional only because rows written
|
|
9396
|
-
* before the fix
|
|
9396
|
+
* before the fix lacked it (repaired on the operator hubs on 2026-10-22).
|
|
9397
9397
|
*/
|
|
9398
9398
|
var IdentitySampleLedgerBodySchema = require_clip_model_registry.object({
|
|
9399
9399
|
identityId: require_clip_model_registry.string(),
|
|
@@ -9476,7 +9476,7 @@ var FaceRescoreJobStatusSchema = require_clip_model_registry.object({
|
|
|
9476
9476
|
*
|
|
9477
9477
|
* Each kind replaced the legacy `pipeline-analytics:*` collection of the same
|
|
9478
9478
|
* name; the records migration that copied them is closed (D900) and the tables
|
|
9479
|
-
* are gone (
|
|
9479
|
+
* are gone (dropped offline on the operator hubs). The addon declares no
|
|
9480
9480
|
* `execution.group`, so the hub owner stamp is the addon id
|
|
9481
9481
|
* (`pipeline-analytics`).
|
|
9482
9482
|
*/
|
|
@@ -11797,14 +11797,8 @@ var DebugNoteArchiveStore = class {
|
|
|
11797
11797
|
};
|
|
11798
11798
|
//#endregion
|
|
11799
11799
|
//#region src/pipeline-analytics/store/event-ledger-collection.ts
|
|
11800
|
-
/**
|
|
11801
|
-
* One trackless event ledger (motion, audio, or sensor) on settings-store
|
|
11802
|
-
* (agents) or `ctx.records` (hub after phase 5).
|
|
11803
|
-
*/
|
|
11804
11800
|
/** Matches {@link EventStore.LEDGER_PAGE_SIZE} — kept local to avoid a circular import. */
|
|
11805
11801
|
var LEDGER_PAGE_SIZE = 500;
|
|
11806
|
-
/** A backfill patch refused for one of these lost a race with the row's writer, nothing more. */
|
|
11807
|
-
var RACED_CODES = new Set(["rev-conflict", "not-found"]);
|
|
11808
11802
|
var EventLedgerCollection = class EventLedgerCollection {
|
|
11809
11803
|
collection;
|
|
11810
11804
|
store;
|
|
@@ -11813,8 +11807,6 @@ var EventLedgerCollection = class EventLedgerCollection {
|
|
|
11813
11807
|
legacyAtField;
|
|
11814
11808
|
deviceIdMode;
|
|
11815
11809
|
logger;
|
|
11816
|
-
/** Body fields a declared index names that the header also carries (see {@link backfillIndexFields}). */
|
|
11817
|
-
headerIndexFields;
|
|
11818
11810
|
constructor(deps) {
|
|
11819
11811
|
this.collection = deps.collection;
|
|
11820
11812
|
this.store = deps.store;
|
|
@@ -11822,7 +11814,6 @@ var EventLedgerCollection = class EventLedgerCollection {
|
|
|
11822
11814
|
this.legacyAtField = deps.legacyAtField ?? "timestamp";
|
|
11823
11815
|
this.deviceIdMode = deps.deviceIdMode ?? "required";
|
|
11824
11816
|
this.logger = deps.logger;
|
|
11825
|
-
this.headerIndexFields = headerIndexFieldsOf(deps.definition, this.legacyAtField);
|
|
11826
11817
|
if (deps.records !== void 0) {
|
|
11827
11818
|
const handle = deps.records.kind(deps.definition);
|
|
11828
11819
|
this.kind = handle;
|
|
@@ -12069,73 +12060,6 @@ var EventLedgerCollection = class EventLedgerCollection {
|
|
|
12069
12060
|
nextCursor: page.nextCursor
|
|
12070
12061
|
};
|
|
12071
12062
|
}
|
|
12072
|
-
/**
|
|
12073
|
-
* Copy the header values a declared index needs into the body of rows that
|
|
12074
|
-
* lack them — a bounded keyset walk of the kind in `at` order per call.
|
|
12075
|
-
*
|
|
12076
|
-
* An index reads the BODY (`json_extract(data, …)`), never the header. Until
|
|
12077
|
-
* this fix the writer moved the clock (`timestamp`, `addedAt` …) into `at`
|
|
12078
|
-
* only, and the records adoption did the same with `deviceId`, so a `where`
|
|
12079
|
-
* page of such a kind found no ordering value on the last row and threw
|
|
12080
|
-
* "cannot be paged". The value is derivable — the header holds it — so the
|
|
12081
|
-
* repair is a merge patch guarded by `ifRev`: a row rewritten since it was
|
|
12082
|
-
* read is left to its writer (which now writes the field) and counted.
|
|
12083
|
-
*
|
|
12084
|
-
* `dryRun` patches nothing and reports the same counts.
|
|
12085
|
-
*/
|
|
12086
|
-
async backfillIndexFields(input) {
|
|
12087
|
-
if (this.kind === null) throw new Error(`event ledger ${this.collection}: backfillIndexFields needs the records kind`);
|
|
12088
|
-
const missingByField = {};
|
|
12089
|
-
let scanned = 0;
|
|
12090
|
-
let missing = 0;
|
|
12091
|
-
let patched = 0;
|
|
12092
|
-
let raced = 0;
|
|
12093
|
-
let cursor = input.cursor;
|
|
12094
|
-
while (scanned < input.maxRows) {
|
|
12095
|
-
const page = await this.kind.query({
|
|
12096
|
-
order: "at",
|
|
12097
|
-
limit: Math.min(LEDGER_PAGE_SIZE, input.maxRows - scanned),
|
|
12098
|
-
...cursor === null ? {} : { cursor }
|
|
12099
|
-
});
|
|
12100
|
-
for (const row of page.records) {
|
|
12101
|
-
scanned += 1;
|
|
12102
|
-
const patch = this.headerPatchFor(row);
|
|
12103
|
-
const fields = Object.keys(patch);
|
|
12104
|
-
if (fields.length === 0) continue;
|
|
12105
|
-
missing += 1;
|
|
12106
|
-
for (const f of fields) missingByField[f] = (missingByField[f] ?? 0) + 1;
|
|
12107
|
-
if (input.dryRun) continue;
|
|
12108
|
-
try {
|
|
12109
|
-
await this.kind.patch(row.id, patch, { ifRev: row.rev });
|
|
12110
|
-
patched += 1;
|
|
12111
|
-
} catch (err) {
|
|
12112
|
-
if (!(err instanceof require_clip_model_registry.RecordsError) || !RACED_CODES.has(err.code)) throw err;
|
|
12113
|
-
raced += 1;
|
|
12114
|
-
}
|
|
12115
|
-
}
|
|
12116
|
-
cursor = page.nextCursor;
|
|
12117
|
-
if (cursor === null) break;
|
|
12118
|
-
}
|
|
12119
|
-
return {
|
|
12120
|
-
kind: this.kind.name,
|
|
12121
|
-
fields: this.headerIndexFields.map((f) => f.field),
|
|
12122
|
-
scanned,
|
|
12123
|
-
missing,
|
|
12124
|
-
missingByField,
|
|
12125
|
-
patched,
|
|
12126
|
-
raced,
|
|
12127
|
-
nextCursor: cursor
|
|
12128
|
-
};
|
|
12129
|
-
}
|
|
12130
|
-
headerPatchFor(row) {
|
|
12131
|
-
const patch = {};
|
|
12132
|
-
for (const { field, from } of this.headerIndexFields) {
|
|
12133
|
-
if (row.data[field] !== void 0 && row.data[field] !== null) continue;
|
|
12134
|
-
const value = from === "at" ? row.at : row.deviceId;
|
|
12135
|
-
if (typeof value === "number") patch[field] = value;
|
|
12136
|
-
}
|
|
12137
|
-
return patch;
|
|
12138
|
-
}
|
|
12139
12063
|
async getManyByIds(ids) {
|
|
12140
12064
|
if (ids.length === 0) return [];
|
|
12141
12065
|
if (this.kind === null) return (await this.store.query.query({
|
|
@@ -12375,20 +12299,6 @@ function eventBodyFromLegacyRecord(record) {
|
|
|
12375
12299
|
}
|
|
12376
12300
|
return out;
|
|
12377
12301
|
}
|
|
12378
|
-
/** The body fields of `definition`'s indexes that mirror a header column. */
|
|
12379
|
-
function headerIndexFieldsOf(definition, legacyAtField) {
|
|
12380
|
-
const named = new Set(definition.declaration.indexes.flatMap((i) => i.fields));
|
|
12381
|
-
const out = [];
|
|
12382
|
-
if (named.has(legacyAtField)) out.push({
|
|
12383
|
-
field: legacyAtField,
|
|
12384
|
-
from: "at"
|
|
12385
|
-
});
|
|
12386
|
-
if (named.has("deviceId")) out.push({
|
|
12387
|
-
field: "deviceId",
|
|
12388
|
-
from: "deviceId"
|
|
12389
|
-
});
|
|
12390
|
-
return out;
|
|
12391
|
-
}
|
|
12392
12302
|
function recordsRowToLegacy(row, legacyAtField) {
|
|
12393
12303
|
const deviceId = row.deviceId ?? row.data["deviceId"];
|
|
12394
12304
|
const clock = row.at ?? readLegacyClock(row.data, legacyAtField);
|
|
@@ -20136,7 +20046,7 @@ function isWriterBoundedOwnerKind(value) {
|
|
|
20136
20046
|
* `'group'` is the co-moving group entity, removed on 2026-09-01 together with
|
|
20137
20047
|
* `pipeline-analytics:track-groups` / `:track-group-members`
|
|
20138
20048
|
* ([D183](../../../../../docs/decisions/adr-0183-code-that-is-deleted-takes-its-tables-with-it.md)).
|
|
20139
|
-
* The tables are dropped
|
|
20049
|
+
* The tables are gone (dropped on every hub), so a group-owned
|
|
20140
20050
|
* media row can never be claimed again: `resolveMediaOwner` maps it to
|
|
20141
20051
|
* `{ kind: 'retired-owner' }` and the orphan audit reclaims it under the same
|
|
20142
20052
|
* grace window and ceilings as any other orphan.
|
|
@@ -41843,6 +41753,53 @@ function selectTriggerZoneCandidates(input) {
|
|
|
41843
41753
|
}
|
|
41844
41754
|
//#endregion
|
|
41845
41755
|
//#region src/notification-center/notification-image.ts
|
|
41756
|
+
/**
|
|
41757
|
+
* notificationImage — ONE stage renders every notification picture (D897).
|
|
41758
|
+
*
|
|
41759
|
+
* ## The defect this replaces
|
|
41760
|
+
*
|
|
41761
|
+
* A rule's picture used to be a STORED kind picked by a ladder: `best` walked
|
|
41762
|
+
* subject crops and ended in the boxed `firstFrame`, so one rule shipped a
|
|
41763
|
+
* crop on one event and a boxed scene on the next depending on what had
|
|
41764
|
+
* landed; boxes were burnt only at WRITE time and only around the track's own
|
|
41765
|
+
* box; `zoneCrop` was a third mechanism, and the sensor, sound, linked-camera
|
|
41766
|
+
* and mosaic paths each had their own rules for what "the picture" was.
|
|
41767
|
+
*
|
|
41768
|
+
* ## The stage
|
|
41769
|
+
*
|
|
41770
|
+
* The dispatcher resolves a CLEAN source frame of the trigger moment
|
|
41771
|
+
* (`cleanSourcePreference`: keyFrame → sceneFrame → lastSceneFrame, after the
|
|
41772
|
+
* MOMENT and PLACE filters), and this stage renders it by the rule's mode:
|
|
41773
|
+
*
|
|
41774
|
+
* - `scene-boxes` — the whole scene; the subject outlined THICK in the accent
|
|
41775
|
+
* colour, every OTHER track visible at that instant outlined THIN, each
|
|
41776
|
+
* captioned with class and confidence ("dog 87%") on a dark plate that
|
|
41777
|
+
* reads on any background. Boxes are the tracks' normalised trail boxes AT
|
|
41778
|
+
* the source frame's timestamp — never the track envelope — scaled to the
|
|
41779
|
+
* JPEG.
|
|
41780
|
+
* - `crop` — the subject cut out of the clean frame around its box at that
|
|
41781
|
+
* instant.
|
|
41782
|
+
* - `clean` — the scene, nothing drawn.
|
|
41783
|
+
* - `showTriggerZone` adds the zone that fired the rule to a scene mode.
|
|
41784
|
+
* - `showSubjectPath` (D903) adds the subject's path — a line in the
|
|
41785
|
+
* subject's colour through its trail centres up to the frame shown — to
|
|
41786
|
+
* every mode; on a `crop` it is mapped into the crop and clipped. The
|
|
41787
|
+
* geometry is `buildSubjectPath` / `projectSubjectPath` from
|
|
41788
|
+
* `@camstack/types`, the same the debug views draw.
|
|
41789
|
+
*
|
|
41790
|
+
* A mode that cannot be honoured ships `clean` and says why, once per record
|
|
41791
|
+
* (D400: "a branch that fails to produce media names the reason"): no subject
|
|
41792
|
+
* box at that instant, no track visible at that instant, a source that is
|
|
41793
|
+
* already annotated (a track that holds no clean frame), a composite.
|
|
41794
|
+
*
|
|
41795
|
+
* ## Once per record
|
|
41796
|
+
*
|
|
41797
|
+
* N targets and every outbox retry resolve the same row; the render is
|
|
41798
|
+
* memoised per record + subject + mode + zone flag + camera for
|
|
41799
|
+
* {@link NC_IMAGE_MEMO_TTL_MS}, so a 4K decode happens once, not once per
|
|
41800
|
+
* phone. It runs in the process that hosts the Notification Center (the
|
|
41801
|
+
* pipeline-analytics runner), which already carries `sharp`.
|
|
41802
|
+
*/
|
|
41846
41803
|
/** How long a rendered picture is reused for the same record (N targets, retries). */
|
|
41847
41804
|
var NC_IMAGE_MEMO_TTL_MS = 15 * 6e4;
|
|
41848
41805
|
/** At most this many rendered pictures are held. */
|
|
@@ -41910,6 +41867,10 @@ function notificationOverlaySvg(input) {
|
|
|
41910
41867
|
const points = zone.map((p) => `${String(clampPx(p.x * width, width))},${String(clampPx(p.y * height, height))}`).join(" ");
|
|
41911
41868
|
parts.push(`<polygon data-role="zone" points="${points}" fill="${NC_IMAGE_ZONE_COLOR}" fill-opacity="0.18" stroke="${NC_IMAGE_ZONE_COLOR}" stroke-width="${String(strokes.other)}" stroke-dasharray="${String(strokes.subject * 2)},${String(strokes.subject)}"/>`);
|
|
41912
41869
|
}
|
|
41870
|
+
for (const run of input.paths ?? []) {
|
|
41871
|
+
if (run.length < 2) continue;
|
|
41872
|
+
parts.push(`<polyline data-role="subject-path" points="${require_clip_model_registry.subjectPathSvgPoints(run, width, height)}" fill="none" stroke="${NC_IMAGE_SUBJECT_COLOR}" stroke-width="${String(strokes.subject)}" stroke-linejoin="round" stroke-linecap="round" stroke-opacity="0.9"/>`);
|
|
41873
|
+
}
|
|
41913
41874
|
const ordered = [...input.boxes.filter((b) => b.role === "other"), ...input.boxes.filter((b) => b.role === "subject")];
|
|
41914
41875
|
for (const box of ordered) {
|
|
41915
41876
|
const subject = box.role === "subject";
|
|
@@ -41980,6 +41941,10 @@ function payloadZoneOverlayIds(payload) {
|
|
|
41980
41941
|
if (payload.mediaImage === void 0) return payload.mediaZoneIds ?? [];
|
|
41981
41942
|
return [];
|
|
41982
41943
|
}
|
|
41944
|
+
/** True when a row's picture draws the subject's path (D903). */
|
|
41945
|
+
function payloadShowsSubjectPath(payload) {
|
|
41946
|
+
return payload.mediaShowSubjectPath === true;
|
|
41947
|
+
}
|
|
41983
41948
|
/**
|
|
41984
41949
|
* Which camera the primary still SHOWS, or `composite` when it is a composed
|
|
41985
41950
|
* mosaic of several. A sensor row of a linked set names its cameras primary
|
|
@@ -42013,16 +41978,47 @@ async function renderNotificationImage(req) {
|
|
|
42013
41978
|
if (srcW === 0 || srcH === 0) throw new Error("source frame has no dimensions");
|
|
42014
41979
|
if (req.mode === "crop" && req.subject !== null) {
|
|
42015
41980
|
const rect = subjectCropRect(req.subject, srcW, srcH);
|
|
42016
|
-
if (rect !== null)
|
|
42017
|
-
|
|
41981
|
+
if (rect !== null) {
|
|
41982
|
+
const view = {
|
|
41983
|
+
x: rect.left / srcW,
|
|
41984
|
+
y: rect.top / srcH,
|
|
41985
|
+
w: rect.width / srcW,
|
|
41986
|
+
h: rect.height / srcH
|
|
41987
|
+
};
|
|
41988
|
+
const paths = require_clip_model_registry.projectSubjectPath(req.path ?? [], view);
|
|
41989
|
+
const cut = sharp$18(Buffer.from(req.bytes)).extract(rect).resize({
|
|
42018
41990
|
width: NC_IMAGE_CROP_MAX_EDGE,
|
|
42019
41991
|
height: NC_IMAGE_CROP_MAX_EDGE,
|
|
42020
41992
|
fit: "inside",
|
|
42021
41993
|
withoutEnlargement: true
|
|
42022
|
-
})
|
|
42023
|
-
|
|
42024
|
-
|
|
42025
|
-
|
|
41994
|
+
});
|
|
41995
|
+
if (paths.length === 0) return {
|
|
41996
|
+
bytes: toArrayBufferBytes(await cut.jpeg({ quality: JPEG_QUALITY }).toBuffer()),
|
|
41997
|
+
name: "crop.jpg",
|
|
41998
|
+
rendered: "crop"
|
|
41999
|
+
};
|
|
42000
|
+
const { data, info } = await cut.raw().toBuffer({ resolveWithObject: true });
|
|
42001
|
+
const svg = notificationOverlaySvg({
|
|
42002
|
+
width: info.width,
|
|
42003
|
+
height: info.height,
|
|
42004
|
+
boxes: [],
|
|
42005
|
+
zones: [],
|
|
42006
|
+
paths
|
|
42007
|
+
});
|
|
42008
|
+
return {
|
|
42009
|
+
bytes: toArrayBufferBytes(await sharp$18(data, { raw: {
|
|
42010
|
+
width: info.width,
|
|
42011
|
+
height: info.height,
|
|
42012
|
+
channels: info.channels
|
|
42013
|
+
} }).composite([{
|
|
42014
|
+
input: Buffer.from(svg),
|
|
42015
|
+
top: 0,
|
|
42016
|
+
left: 0
|
|
42017
|
+
}]).jpeg({ quality: JPEG_QUALITY }).toBuffer()),
|
|
42018
|
+
name: "crop.jpg",
|
|
42019
|
+
rendered: "crop"
|
|
42020
|
+
};
|
|
42021
|
+
}
|
|
42026
42022
|
}
|
|
42027
42023
|
const scale = Math.min(1, NC_IMAGE_SCENE_MAX_WIDTH / srcW);
|
|
42028
42024
|
const outW = Math.max(1, Math.round(srcW * scale));
|
|
@@ -42037,17 +42033,24 @@ async function renderNotificationImage(req) {
|
|
|
42037
42033
|
label: req.subject.label
|
|
42038
42034
|
}] : []] : [];
|
|
42039
42035
|
const zones = req.mode === "crop" ? [] : req.zones;
|
|
42036
|
+
const paths = require_clip_model_registry.projectSubjectPath(req.path ?? [], {
|
|
42037
|
+
x: 0,
|
|
42038
|
+
y: 0,
|
|
42039
|
+
w: 1,
|
|
42040
|
+
h: 1
|
|
42041
|
+
});
|
|
42040
42042
|
let pipeline = sharp$18(Buffer.from(req.bytes)).resize({
|
|
42041
42043
|
width: outW,
|
|
42042
42044
|
height: outH,
|
|
42043
42045
|
fit: "fill"
|
|
42044
42046
|
});
|
|
42045
|
-
if (boxes.length > 0 || zones.length > 0) {
|
|
42047
|
+
if (boxes.length > 0 || zones.length > 0 || paths.length > 0) {
|
|
42046
42048
|
const svg = notificationOverlaySvg({
|
|
42047
42049
|
width: outW,
|
|
42048
42050
|
height: outH,
|
|
42049
42051
|
boxes,
|
|
42050
|
-
zones
|
|
42052
|
+
zones,
|
|
42053
|
+
paths
|
|
42051
42054
|
});
|
|
42052
42055
|
pipeline = pipeline.composite([{
|
|
42053
42056
|
input: Buffer.from(svg),
|
|
@@ -42085,11 +42088,13 @@ var NcNotificationImageStage = class {
|
|
|
42085
42088
|
const mode = payloadImageMode(payload);
|
|
42086
42089
|
if (mode === "none") return null;
|
|
42087
42090
|
const zoneIds = input.withSubject ? payloadZoneOverlayIds(payload) : [];
|
|
42091
|
+
const withPath = input.withSubject && payloadShowsSubjectPath(payload);
|
|
42088
42092
|
const key = [
|
|
42089
42093
|
input.entry.recordId,
|
|
42090
42094
|
payload.subject.trackId ?? "",
|
|
42091
42095
|
mode,
|
|
42092
42096
|
zoneIds.length > 0 ? "z" : "-",
|
|
42097
|
+
withPath ? "p" : "-",
|
|
42093
42098
|
String(input.camera)
|
|
42094
42099
|
].join("|");
|
|
42095
42100
|
const now = this.deps.now();
|
|
@@ -42099,7 +42104,7 @@ var NcNotificationImageStage = class {
|
|
|
42099
42104
|
this.memo.set(key, hit);
|
|
42100
42105
|
return hit.value;
|
|
42101
42106
|
}
|
|
42102
|
-
const value = this.compute(input, mode, zoneIds);
|
|
42107
|
+
const value = this.compute(input, mode, zoneIds, withPath);
|
|
42103
42108
|
this.remember(key, {
|
|
42104
42109
|
at: now,
|
|
42105
42110
|
value
|
|
@@ -42119,13 +42124,15 @@ var NcNotificationImageStage = class {
|
|
|
42119
42124
|
}
|
|
42120
42125
|
this.memo.set(key, entry);
|
|
42121
42126
|
}
|
|
42122
|
-
async compute(input, mode, zoneIds) {
|
|
42127
|
+
async compute(input, mode, zoneIds, withPath) {
|
|
42123
42128
|
const { entry, source, camera } = input;
|
|
42124
42129
|
const payload = entry.payload;
|
|
42125
42130
|
if (source.annotated) return this.asStored(input, mode, "annotated-source");
|
|
42126
42131
|
if (camera === "composite") return mode === "clean" ? this.asStored(input, mode) : this.asStored(input, mode, "composite-source");
|
|
42127
42132
|
const subjectTrackId = input.withSubject ? payload.subject.trackId : void 0;
|
|
42128
|
-
const
|
|
42133
|
+
const trail = hasTrackedSubject(subjectTrackId) ? await this.subjectTrail(camera, subjectTrackId) : [];
|
|
42134
|
+
const subjectBox = trailAt(trail, source.timestamp, NC_IMAGE_BOX_MATCH_MAX_MS)?.bbox ?? null;
|
|
42135
|
+
const path = withPath ? this.subjectPath(input, trail) : [];
|
|
42129
42136
|
const subject = subjectBox !== null ? {
|
|
42130
42137
|
...subjectBox,
|
|
42131
42138
|
label: imageLabelText(payload.subject.label ?? payload.subject.className, payload.subject.confidence)
|
|
@@ -42141,7 +42148,8 @@ var NcNotificationImageStage = class {
|
|
|
42141
42148
|
bytes: source.bytes,
|
|
42142
42149
|
subject,
|
|
42143
42150
|
others,
|
|
42144
|
-
zones
|
|
42151
|
+
zones,
|
|
42152
|
+
...path.length > 0 ? { path } : {}
|
|
42145
42153
|
});
|
|
42146
42154
|
const reason = image.rendered === mode ? void 0 : mode === "crop" ? "no-subject-box" : "no-tracks-at-instant";
|
|
42147
42155
|
if (reason !== void 0) this.reportFallback(input, mode, reason);
|
|
@@ -42193,22 +42201,48 @@ var NcNotificationImageStage = class {
|
|
|
42193
42201
|
}
|
|
42194
42202
|
});
|
|
42195
42203
|
}
|
|
42196
|
-
|
|
42204
|
+
/** The subject's trail, read once per render for its box AND its path. */
|
|
42205
|
+
async subjectTrail(camera, trackId) {
|
|
42197
42206
|
const read = this.deps.getSubjectTrail;
|
|
42198
|
-
if (read === void 0) return
|
|
42207
|
+
if (read === void 0) return [];
|
|
42199
42208
|
try {
|
|
42200
|
-
return
|
|
42209
|
+
return await read(camera, trackId);
|
|
42201
42210
|
} catch (err) {
|
|
42202
|
-
this.deps.logger.debug("subject trail read failed — no subject box on the picture", {
|
|
42211
|
+
this.deps.logger.debug("subject trail read failed — no subject box or path on the picture", {
|
|
42203
42212
|
tags: { deviceId: camera },
|
|
42204
42213
|
meta: {
|
|
42205
42214
|
trackId,
|
|
42206
42215
|
error: String(err)
|
|
42207
42216
|
}
|
|
42208
42217
|
});
|
|
42209
|
-
return
|
|
42218
|
+
return [];
|
|
42210
42219
|
}
|
|
42211
42220
|
}
|
|
42221
|
+
/**
|
|
42222
|
+
* The subject's path up to the frame shown, normalised in that frame, or
|
|
42223
|
+
* empty when the trail has fewer than two drawable points — then the
|
|
42224
|
+
* picture ships without it, and the line below says so (D400: a branch
|
|
42225
|
+
* that produces nothing names why).
|
|
42226
|
+
*/
|
|
42227
|
+
subjectPath(input, trail) {
|
|
42228
|
+
const path = require_clip_model_registry.buildSubjectPath(trail.map((p) => require_clip_model_registry.subjectPathSampleFromBox(p.bbox, p.timestamp)), { untilTimestamp: input.source.timestamp });
|
|
42229
|
+
if (require_clip_model_registry.isDrawableSubjectPath(path)) return path.nodes.map((n) => ({
|
|
42230
|
+
x: n.x,
|
|
42231
|
+
y: n.y
|
|
42232
|
+
}));
|
|
42233
|
+
const camera = input.camera === "composite" ? input.entry.payload.subject.deviceId : input.camera;
|
|
42234
|
+
this.deps.logger.debug("subject path not drawn — fewer than two trail points", {
|
|
42235
|
+
tags: { deviceId: camera },
|
|
42236
|
+
meta: {
|
|
42237
|
+
ruleId: input.entry.ruleId,
|
|
42238
|
+
recordId: input.entry.recordId,
|
|
42239
|
+
trailPoints: trail.length,
|
|
42240
|
+
nodes: path.nodes.length,
|
|
42241
|
+
unlocalized: path.unlocalized
|
|
42242
|
+
}
|
|
42243
|
+
});
|
|
42244
|
+
return [];
|
|
42245
|
+
}
|
|
42212
42246
|
async tracksAt(camera, timestamp) {
|
|
42213
42247
|
const read = this.deps.getTracksAt;
|
|
42214
42248
|
if (read === void 0) return [];
|
|
@@ -56098,6 +56132,7 @@ function mediaPolicyFields(mediaRule, cropZoneIds) {
|
|
|
56098
56132
|
media: image === "none" ? "none" : "best",
|
|
56099
56133
|
mediaImage: image,
|
|
56100
56134
|
...media.showTriggerZone === true && cropZoneIds !== void 0 && cropZoneIds.length > 0 ? { mediaShowTriggerZone: true } : {},
|
|
56135
|
+
...media.showSubjectPath === true && image !== "none" ? { mediaShowSubjectPath: true } : {},
|
|
56101
56136
|
...cropZoneIds !== void 0 ? { triggerZoneIds: [...cropZoneIds] } : {},
|
|
56102
56137
|
...media.profile !== void 0 ? { mediaProfile: media.profile } : {},
|
|
56103
56138
|
...media.gif === true ? { mediaGif: true } : {},
|
|
@@ -79498,97 +79533,6 @@ async function forgetMissingMediaRows(deps, rawInput) {
|
|
|
79498
79533
|
};
|
|
79499
79534
|
}
|
|
79500
79535
|
//#endregion
|
|
79501
|
-
//#region src/pipeline-analytics/store/ledger-index-backfill.ts
|
|
79502
|
-
/**
|
|
79503
|
-
* The operator door for repairing ledger rows whose BODY lacks a field a
|
|
79504
|
-
* declared index names (`records.backfillIndexFields`).
|
|
79505
|
-
*
|
|
79506
|
-
* Until the fix the event-ledger writer moved the clock (`timestamp`,
|
|
79507
|
-
* `addedAt`, `updatedAt` …) into the record header `at` only, and the records
|
|
79508
|
-
* adoption also left `deviceId` header-only. Indexes read the body, so any
|
|
79509
|
-
* `where` page of such a kind (faces `assigned_ts`, plates `vehicle_ts`,
|
|
79510
|
-
* identity samples `identity_added` …) refused to page: "a row has no value for
|
|
79511
|
-
* an ordering field". The writer now keeps the body field; this copies the
|
|
79512
|
-
* header value into rows written before it. It is a repair of derivable data,
|
|
79513
|
-
* not a migration: nothing is read from anywhere but the row itself.
|
|
79514
|
-
*
|
|
79515
|
-
* One kind per call, bounded, resumable: `dryRun` defaults to `true` (counts
|
|
79516
|
-
* only); pass the returned `nextCursor` back until it is `null`.
|
|
79517
|
-
*/
|
|
79518
|
-
/** Hard ceiling on rows one call examines — the call is synchronous. */
|
|
79519
|
-
var LEDGER_BACKFILL_MAX_ROWS = 5e4;
|
|
79520
|
-
var LEDGER_BACKFILL_DEFAULT_ROWS = 2e4;
|
|
79521
|
-
/** Every event ledger, by its records kind name. A kind with nothing to backfill reports `fields: []`. */
|
|
79522
|
-
var LEDGER_WIRES = {
|
|
79523
|
-
faces: wireFaceLedger,
|
|
79524
|
-
plates: wirePlateLedger,
|
|
79525
|
-
identities: wireIdentityLedger,
|
|
79526
|
-
"identity-samples": wireIdentitySampleLedger,
|
|
79527
|
-
vehicles: wireVehicleLedger,
|
|
79528
|
-
"vehicle-samples": wireVehicleSampleLedger,
|
|
79529
|
-
"track-aliases": wireTrackAliasLedger,
|
|
79530
|
-
"track-purity": wireTrackPurityLedger,
|
|
79531
|
-
"track-relations": wireTrackRelationsLedger,
|
|
79532
|
-
"tracking-tapes": wireTrackingTapeLedger,
|
|
79533
|
-
"motion-events": wireMotionEventLedger,
|
|
79534
|
-
"audio-events": wireAudioEventLedger,
|
|
79535
|
-
"sensor-events": wireSensorEventLedger,
|
|
79536
|
-
"birth-decision-ledger": wireBirthDecisionLedger,
|
|
79537
|
-
"debug-note-archive": wireDebugNoteArchiveLedger,
|
|
79538
|
-
"ops-log": wireOpsLogLedger,
|
|
79539
|
-
"retrain-frames": wireRetrainFrameLedger,
|
|
79540
|
-
"retrain-annotations": wireRetrainAnnotationLedger,
|
|
79541
|
-
"retrain-collections": wireRetrainCollectionLedger,
|
|
79542
|
-
"retrain-collection-frames": wireRetrainCollectionFrameLedger
|
|
79543
|
-
};
|
|
79544
|
-
function isLedgerKindName(name) {
|
|
79545
|
-
return Object.hasOwn(LEDGER_WIRES, name);
|
|
79546
|
-
}
|
|
79547
|
-
var [FIRST_LEDGER_KIND, ...OTHER_LEDGER_KINDS] = Object.keys(LEDGER_WIRES).filter(isLedgerKindName);
|
|
79548
|
-
if (FIRST_LEDGER_KIND === void 0) throw new Error("ledger-index-backfill: no ledger kinds");
|
|
79549
|
-
var LedgerBackfillInputSchema = require_clip_model_registry.object({
|
|
79550
|
-
kind: require_clip_model_registry._enum([FIRST_LEDGER_KIND, ...OTHER_LEDGER_KINDS]),
|
|
79551
|
-
dryRun: require_clip_model_registry.boolean().default(true),
|
|
79552
|
-
/** The previous call's `nextCursor`. Omitted / null starts from the top. */
|
|
79553
|
-
cursor: require_clip_model_registry.string().min(1).nullable().optional(),
|
|
79554
|
-
/** Rows examined in this call. Default 20 000, max {@link LEDGER_BACKFILL_MAX_ROWS}. */
|
|
79555
|
-
maxRows: require_clip_model_registry.number().int().min(1).max(LEDGER_BACKFILL_MAX_ROWS).optional()
|
|
79556
|
-
});
|
|
79557
|
-
var LedgerBackfillResultSchema = require_clip_model_registry.object({
|
|
79558
|
-
kind: require_clip_model_registry.string(),
|
|
79559
|
-
dryRun: require_clip_model_registry.boolean(),
|
|
79560
|
-
/** The body fields this kind's indexes need from the header (`[]` = nothing to repair). */
|
|
79561
|
-
fields: require_clip_model_registry.array(require_clip_model_registry.string()),
|
|
79562
|
-
scanned: require_clip_model_registry.number().int(),
|
|
79563
|
-
/** Rows lacking at least one of `fields`. */
|
|
79564
|
-
missing: require_clip_model_registry.number().int(),
|
|
79565
|
-
missingByField: require_clip_model_registry.record(require_clip_model_registry.string(), require_clip_model_registry.number().int()),
|
|
79566
|
-
/** Rows patched (0 on a dry run). */
|
|
79567
|
-
patched: require_clip_model_registry.number().int(),
|
|
79568
|
-
/** Rows rewritten or deleted between the read and the patch: left to their writer. */
|
|
79569
|
-
raced: require_clip_model_registry.number().int(),
|
|
79570
|
-
/** Pass back to continue; `null` = the kind has been walked to the end. */
|
|
79571
|
-
nextCursor: require_clip_model_registry.string().nullable()
|
|
79572
|
-
});
|
|
79573
|
-
var ledgerIndexBackfillActions = require_clip_model_registry.defineCustomActions({ "records.backfillIndexFields": require_clip_model_registry.customAction(LedgerBackfillInputSchema, LedgerBackfillResultSchema, {
|
|
79574
|
-
kind: "mutation",
|
|
79575
|
-
auth: "admin"
|
|
79576
|
-
}) });
|
|
79577
|
-
/** Run one bounded backfill page of `input.kind` through its ledger. */
|
|
79578
|
-
async function backfillLedgerIndexFields(wiring, rawInput) {
|
|
79579
|
-
const input = LedgerBackfillInputSchema.parse(rawInput);
|
|
79580
|
-
const page = await LEDGER_WIRES[input.kind](wiring).backfillIndexFields({
|
|
79581
|
-
dryRun: input.dryRun,
|
|
79582
|
-
cursor: input.cursor ?? null,
|
|
79583
|
-
maxRows: input.maxRows ?? LEDGER_BACKFILL_DEFAULT_ROWS
|
|
79584
|
-
});
|
|
79585
|
-
return {
|
|
79586
|
-
...page,
|
|
79587
|
-
fields: [...page.fields],
|
|
79588
|
-
dryRun: input.dryRun
|
|
79589
|
-
};
|
|
79590
|
-
}
|
|
79591
|
-
//#endregion
|
|
79592
79536
|
//#region src/pipeline-analytics/retention/media-reclaim.ts
|
|
79593
79537
|
var MEDIA_RECLAIM_SCOPES = ["motion-still", "track-filmstrip"];
|
|
79594
79538
|
var DEFAULT_MEDIA_RECLAIM_LIMITS = {
|
|
@@ -115640,7 +115584,6 @@ var customActions = {
|
|
|
115640
115584
|
...mediaReclaimActions,
|
|
115641
115585
|
...locationDiscardActions,
|
|
115642
115586
|
...mediaForgetActions,
|
|
115643
|
-
...ledgerIndexBackfillActions,
|
|
115644
115587
|
...photoEnrollActions,
|
|
115645
115588
|
...faceRescoreActions,
|
|
115646
115589
|
...stillnessCalibrationActions
|
|
@@ -117673,7 +117616,6 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
117673
117616
|
...mediaReclaimActions,
|
|
117674
117617
|
...locationDiscardActions,
|
|
117675
117618
|
...mediaForgetActions,
|
|
117676
|
-
...ledgerIndexBackfillActions,
|
|
117677
117619
|
...photoEnrollActions,
|
|
117678
117620
|
...faceRescoreActions,
|
|
117679
117621
|
...stillnessCalibrationActions
|
|
@@ -127484,11 +127426,6 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
127484
127426
|
const deps = this.mediaForgetDeps;
|
|
127485
127427
|
if (deps === null) throw new Error("storage.forgetMissingMedia: not initialised");
|
|
127486
127428
|
return forgetMissingMediaRows(deps, input);
|
|
127487
|
-
},
|
|
127488
|
-
"records.backfillIndexFields": async (input) => {
|
|
127489
|
-
const settingsStore = this.settingsStore;
|
|
127490
|
-
if (!settingsStore) throw new Error("records.backfillIndexFields: not initialised");
|
|
127491
|
-
return backfillLedgerIndexFields(this.eventLedgerWiring(settingsStore), input);
|
|
127492
127429
|
}
|
|
127493
127430
|
};
|
|
127494
127431
|
}
|