@camstack/addon-post-analysis 1.2.290 → 1.2.291
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/{clip-model-registry--sFeijO7.js → clip-model-registry-CTY5co6P.js} +35 -4
- package/dist/{clip-model-registry-CoYBCvtr.mjs → clip-model-registry-Cudz--Ql.mjs} +35 -4
- package/dist/embedding-encoder/index.js +1 -1
- package/dist/embedding-encoder/index.mjs +1 -1
- package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-r3ZZOSzj.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-CBHxwCSj.mjs} +1 -1
- package/dist/pipeline-analytics/{hostInit-PoeIZAFx.mjs → hostInit-DSKT2dE4.mjs} +1 -1
- package/dist/pipeline-analytics/index.js +226 -39
- package/dist/pipeline-analytics/index.mjs +226 -39
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/package.json +1 -1
|
@@ -23215,7 +23215,15 @@ var RebuildObjectEmbeddingsInput = object({
|
|
|
23215
23215
|
* force is logged at start and finish so a deliberately slow pass reads
|
|
23216
23216
|
* differently from a stalled one.
|
|
23217
23217
|
*/
|
|
23218
|
-
pacingMs: number().int().nonnegative().optional()
|
|
23218
|
+
pacingMs: number().int().nonnegative().optional(),
|
|
23219
|
+
/**
|
|
23220
|
+
* Re-embed ONLY the tracks whose vector is ALREADY in the pinned model's
|
|
23221
|
+
* space (D664) — the in-space skip inverted. It exists to redo vectors
|
|
23222
|
+
* written from the wrong box, which a normal pass would skip as done
|
|
23223
|
+
* forever. Requires `maxTracks`: a forced pass without a bound is refused
|
|
23224
|
+
* (`force-requires-max-tracks`).
|
|
23225
|
+
*/
|
|
23226
|
+
force: boolean().optional()
|
|
23219
23227
|
});
|
|
23220
23228
|
/**
|
|
23221
23229
|
* Result of emptying the CLIP index.
|
|
@@ -23251,6 +23259,7 @@ var WipeObjectEmbeddingsResultSchema = object({
|
|
|
23251
23259
|
* - `reads-disagree` — the two reads named different choices.
|
|
23252
23260
|
* - `not-a-clip-model` — the CONFIRMED id has no CLIP metadata, so there is no
|
|
23253
23261
|
* index to fill and no dimension to check against (D649).
|
|
23262
|
+
* - `force-requires-max-tracks` — `force: true` with no `maxTracks` (D664).
|
|
23254
23263
|
*/
|
|
23255
23264
|
var RebuildObjectEmbeddingsRefusalSchema = _enum([
|
|
23256
23265
|
"stores-unavailable",
|
|
@@ -23258,7 +23267,8 @@ var RebuildObjectEmbeddingsRefusalSchema = _enum([
|
|
|
23258
23267
|
"method-unavailable",
|
|
23259
23268
|
"read-failed",
|
|
23260
23269
|
"reads-disagree",
|
|
23261
|
-
"not-a-clip-model"
|
|
23270
|
+
"not-a-clip-model",
|
|
23271
|
+
"force-requires-max-tracks"
|
|
23262
23272
|
]);
|
|
23263
23273
|
/**
|
|
23264
23274
|
* Acknowledgement that a rebuild STARTED.
|
|
@@ -23283,11 +23293,32 @@ var RebuildStatusSchema = object({
|
|
|
23283
23293
|
running: boolean(),
|
|
23284
23294
|
scanned: number(),
|
|
23285
23295
|
rebuilt: number(),
|
|
23286
|
-
/** Tracks whose key frame is gone — nothing to re-embed from.
|
|
23296
|
+
/** Tracks whose key frame is gone — nothing to re-embed from. Pixels ONLY:
|
|
23297
|
+
* `missingEvent` is its own field since D664, never summed in. */
|
|
23287
23298
|
missingKeyFrame: number(),
|
|
23288
|
-
/** Tracks with no
|
|
23299
|
+
/** Tracks with no object event at all (D664). */
|
|
23300
|
+
missingEvent: number(),
|
|
23301
|
+
/** Tracks with no box measured on the pixels to cut — see `boxSource.refused`. */
|
|
23289
23302
|
missingBbox: number(),
|
|
23290
23303
|
/**
|
|
23304
|
+
* Which rule placed each judged track's box (D664): the key frame row's own
|
|
23305
|
+
* `subjectBox`, `track.positions` at exactly its instant (older key frames),
|
|
23306
|
+
* the event box (a key frame recovered from the recording, at the event's
|
|
23307
|
+
* instant), or `refused` by name — the reasons are in the tagged log lines.
|
|
23308
|
+
*/
|
|
23309
|
+
boxSource: object({
|
|
23310
|
+
subjectBox: number(),
|
|
23311
|
+
positions: number(),
|
|
23312
|
+
event: number(),
|
|
23313
|
+
refused: number()
|
|
23314
|
+
}),
|
|
23315
|
+
/** Tracks skipped because their vector is already in the pinned space. */
|
|
23316
|
+
alreadyInSpace: number(),
|
|
23317
|
+
/** Whether the current / last pass was a `force` pass; `null` before any (D664). */
|
|
23318
|
+
force: boolean().nullable(),
|
|
23319
|
+
/** In-space tracks a `force` pass selected for re-embedding. */
|
|
23320
|
+
forcedInSpace: number(),
|
|
23321
|
+
/**
|
|
23291
23322
|
* Tracks an executing node REFUSED rather than broke on — an unreadable key
|
|
23292
23323
|
* frame, a step that threw. Separate from `failed` because the remedy is
|
|
23293
23324
|
* different, and because a whole camera silently contributing zero vectors
|
|
@@ -23184,7 +23184,15 @@ var RebuildObjectEmbeddingsInput = object({
|
|
|
23184
23184
|
* force is logged at start and finish so a deliberately slow pass reads
|
|
23185
23185
|
* differently from a stalled one.
|
|
23186
23186
|
*/
|
|
23187
|
-
pacingMs: number().int().nonnegative().optional()
|
|
23187
|
+
pacingMs: number().int().nonnegative().optional(),
|
|
23188
|
+
/**
|
|
23189
|
+
* Re-embed ONLY the tracks whose vector is ALREADY in the pinned model's
|
|
23190
|
+
* space (D664) — the in-space skip inverted. It exists to redo vectors
|
|
23191
|
+
* written from the wrong box, which a normal pass would skip as done
|
|
23192
|
+
* forever. Requires `maxTracks`: a forced pass without a bound is refused
|
|
23193
|
+
* (`force-requires-max-tracks`).
|
|
23194
|
+
*/
|
|
23195
|
+
force: boolean().optional()
|
|
23188
23196
|
});
|
|
23189
23197
|
/**
|
|
23190
23198
|
* Result of emptying the CLIP index.
|
|
@@ -23220,6 +23228,7 @@ var WipeObjectEmbeddingsResultSchema = object({
|
|
|
23220
23228
|
* - `reads-disagree` — the two reads named different choices.
|
|
23221
23229
|
* - `not-a-clip-model` — the CONFIRMED id has no CLIP metadata, so there is no
|
|
23222
23230
|
* index to fill and no dimension to check against (D649).
|
|
23231
|
+
* - `force-requires-max-tracks` — `force: true` with no `maxTracks` (D664).
|
|
23223
23232
|
*/
|
|
23224
23233
|
var RebuildObjectEmbeddingsRefusalSchema = _enum([
|
|
23225
23234
|
"stores-unavailable",
|
|
@@ -23227,7 +23236,8 @@ var RebuildObjectEmbeddingsRefusalSchema = _enum([
|
|
|
23227
23236
|
"method-unavailable",
|
|
23228
23237
|
"read-failed",
|
|
23229
23238
|
"reads-disagree",
|
|
23230
|
-
"not-a-clip-model"
|
|
23239
|
+
"not-a-clip-model",
|
|
23240
|
+
"force-requires-max-tracks"
|
|
23231
23241
|
]);
|
|
23232
23242
|
/**
|
|
23233
23243
|
* Acknowledgement that a rebuild STARTED.
|
|
@@ -23252,11 +23262,32 @@ var RebuildStatusSchema = object({
|
|
|
23252
23262
|
running: boolean(),
|
|
23253
23263
|
scanned: number(),
|
|
23254
23264
|
rebuilt: number(),
|
|
23255
|
-
/** Tracks whose key frame is gone — nothing to re-embed from.
|
|
23265
|
+
/** Tracks whose key frame is gone — nothing to re-embed from. Pixels ONLY:
|
|
23266
|
+
* `missingEvent` is its own field since D664, never summed in. */
|
|
23256
23267
|
missingKeyFrame: number(),
|
|
23257
|
-
/** Tracks with no
|
|
23268
|
+
/** Tracks with no object event at all (D664). */
|
|
23269
|
+
missingEvent: number(),
|
|
23270
|
+
/** Tracks with no box measured on the pixels to cut — see `boxSource.refused`. */
|
|
23258
23271
|
missingBbox: number(),
|
|
23259
23272
|
/**
|
|
23273
|
+
* Which rule placed each judged track's box (D664): the key frame row's own
|
|
23274
|
+
* `subjectBox`, `track.positions` at exactly its instant (older key frames),
|
|
23275
|
+
* the event box (a key frame recovered from the recording, at the event's
|
|
23276
|
+
* instant), or `refused` by name — the reasons are in the tagged log lines.
|
|
23277
|
+
*/
|
|
23278
|
+
boxSource: object({
|
|
23279
|
+
subjectBox: number(),
|
|
23280
|
+
positions: number(),
|
|
23281
|
+
event: number(),
|
|
23282
|
+
refused: number()
|
|
23283
|
+
}),
|
|
23284
|
+
/** Tracks skipped because their vector is already in the pinned space. */
|
|
23285
|
+
alreadyInSpace: number(),
|
|
23286
|
+
/** Whether the current / last pass was a `force` pass; `null` before any (D664). */
|
|
23287
|
+
force: boolean().nullable(),
|
|
23288
|
+
/** In-space tracks a `force` pass selected for re-embedding. */
|
|
23289
|
+
forcedInSpace: number(),
|
|
23290
|
+
/**
|
|
23260
23291
|
* Tracks an executing node REFUSED rather than broke on — an unreadable key
|
|
23261
23292
|
* frame, a step that threw. Separate from `failed` because the remedy is
|
|
23262
23293
|
* different, and because a whole camera silently contributing zero vectors
|
|
@@ -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-CTY5co6P.js");
|
|
6
6
|
let node_fs = require("node:fs");
|
|
7
7
|
node_fs = require_clip_model_registry.__toESM(node_fs);
|
|
8
8
|
let node_path = require("node:path");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Bn as normalizeNodeId, Ht as embeddingRequirementsUnavailableError, Rt as embeddingEncoderCapability, Vt as embeddingRequirementsFailedError, a as CLIP_EMBEDDING_STEP_ID, c as resolveClusterModelPin, ft as PoolMemoryWatchdog, i as CLIP_TEXT_MODELS, jn as BaseAddon, mn as resolvePoolMemoryPolicy, n as DEFAULT_CLIP_MODEL, r as CLIP_IMAGE_MODELS, sn as parseProcStatus, t as BUILTIN_CLIP_MODELS, zt as embeddingModelFailedError } from "../clip-model-registry-
|
|
1
|
+
import { Bn as normalizeNodeId, Ht as embeddingRequirementsUnavailableError, Rt as embeddingEncoderCapability, Vt as embeddingRequirementsFailedError, a as CLIP_EMBEDDING_STEP_ID, c as resolveClusterModelPin, ft as PoolMemoryWatchdog, i as CLIP_TEXT_MODELS, jn as BaseAddon, mn as resolvePoolMemoryPolicy, n as DEFAULT_CLIP_MODEL, r as CLIP_IMAGE_MODELS, sn as parseProcStatus, t as BUILTIN_CLIP_MODELS, zt as embeddingModelFailedError } from "../clip-model-registry-Cudz--Ql.mjs";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import * as fs from "node:fs";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
@@ -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-CTY5co6P.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");
|
|
@@ -39677,7 +39677,12 @@ var RebuildInputSchema = require_clip_model_registry.object({
|
|
|
39677
39677
|
* Milliseconds between tracks; omit for the default, `0` to run flat out.
|
|
39678
39678
|
* A rebuild shares hub-main's only thread with every live request.
|
|
39679
39679
|
*/
|
|
39680
|
-
pacingMs: require_clip_model_registry.number().int().nonnegative().optional()
|
|
39680
|
+
pacingMs: require_clip_model_registry.number().int().nonnegative().optional(),
|
|
39681
|
+
/**
|
|
39682
|
+
* Re-embed ONLY tracks already in the pinned space — to redo vectors cut
|
|
39683
|
+
* from the wrong box (D664). Requires `maxTracks`.
|
|
39684
|
+
*/
|
|
39685
|
+
force: require_clip_model_registry.boolean().optional()
|
|
39681
39686
|
});
|
|
39682
39687
|
var RebuildStartedSchema = require_clip_model_registry.object({
|
|
39683
39688
|
started: require_clip_model_registry.boolean(),
|
|
@@ -39697,7 +39702,20 @@ var RebuildStatusSchema = require_clip_model_registry.object({
|
|
|
39697
39702
|
scanned: require_clip_model_registry.number(),
|
|
39698
39703
|
rebuilt: require_clip_model_registry.number(),
|
|
39699
39704
|
missingKeyFrame: require_clip_model_registry.number(),
|
|
39705
|
+
/** No object event at all — its own number since D664. */
|
|
39706
|
+
missingEvent: require_clip_model_registry.number(),
|
|
39700
39707
|
missingBbox: require_clip_model_registry.number(),
|
|
39708
|
+
/** Which rule placed each judged track's box (D664). */
|
|
39709
|
+
boxSource: require_clip_model_registry.object({
|
|
39710
|
+
subjectBox: require_clip_model_registry.number(),
|
|
39711
|
+
positions: require_clip_model_registry.number(),
|
|
39712
|
+
event: require_clip_model_registry.number(),
|
|
39713
|
+
refused: require_clip_model_registry.number()
|
|
39714
|
+
}),
|
|
39715
|
+
alreadyInSpace: require_clip_model_registry.number(),
|
|
39716
|
+
/** Whether the current / last pass was a `force` pass (D664). */
|
|
39717
|
+
force: require_clip_model_registry.boolean().nullable(),
|
|
39718
|
+
forcedInSpace: require_clip_model_registry.number(),
|
|
39701
39719
|
/** Refused by the executing node (unreadable key frame / bad box), not broken. */
|
|
39702
39720
|
notRunnable: require_clip_model_registry.number(),
|
|
39703
39721
|
/** The pass STOPPED: no node in the cluster could serve the pinned model. */
|
|
@@ -40972,7 +40990,7 @@ function toPixelBox(b) {
|
|
|
40972
40990
|
h: b.height
|
|
40973
40991
|
};
|
|
40974
40992
|
}
|
|
40975
|
-
function refused(reason, detail) {
|
|
40993
|
+
function refused$1(reason, detail) {
|
|
40976
40994
|
return {
|
|
40977
40995
|
kind: "refused",
|
|
40978
40996
|
reason,
|
|
@@ -41000,8 +41018,8 @@ function comparableFaces(input) {
|
|
|
41000
41018
|
/** Refuse before choosing when nothing in the photo can become the sample. */
|
|
41001
41019
|
function precondition(input) {
|
|
41002
41020
|
const enrollable = input.faces.filter((f) => f.enrollable && f.embedding !== void 0);
|
|
41003
|
-
if (enrollable.length === 0) return refused("no-enrollable-face", `${input.faces.length} face(s) found, none enrollable (${input.faces.map((f) => f.refusedReason ?? "unknown").join(", ")})`);
|
|
41004
|
-
if (!enrollable.some((f) => isEnrollableIn(f, input.modelId))) return refused("model-mismatch", `faces were embedded by ${[...new Set(enrollable.map((f) => f.modelId))].join(", ")}, the old sample by ${input.modelId} — re-embed the gallery first`);
|
|
41021
|
+
if (enrollable.length === 0) return refused$1("no-enrollable-face", `${input.faces.length} face(s) found, none enrollable (${input.faces.map((f) => f.refusedReason ?? "unknown").join(", ")})`);
|
|
41022
|
+
if (!enrollable.some((f) => isEnrollableIn(f, input.modelId))) return refused$1("model-mismatch", `faces were embedded by ${[...new Set(enrollable.map((f) => f.modelId))].join(", ")}, the old sample by ${input.modelId} — re-embed the gallery first`);
|
|
41005
41023
|
return null;
|
|
41006
41024
|
}
|
|
41007
41025
|
function chooseByIou(input, oldBox, scored) {
|
|
@@ -41010,13 +41028,13 @@ function chooseByIou(input, oldBox, scored) {
|
|
|
41010
41028
|
face,
|
|
41011
41029
|
iou: iou$3(box, toPixelBox(face.bbox))
|
|
41012
41030
|
})).filter((c) => c.iou >= PHOTO_REENROL_MIN_IOU);
|
|
41013
|
-
if (overlapping.length === 0) return refused("no-iou-match", `no face overlaps the old box at IoU ≥ ${PHOTO_REENROL_MIN_IOU}`);
|
|
41014
|
-
if (overlapping.length > 1) return refused("ambiguous", `${overlapping.length} faces overlap the old box (IoU ${overlapping.map((c) => c.iou.toFixed(2)).join(", ")})`);
|
|
41031
|
+
if (overlapping.length === 0) return refused$1("no-iou-match", `no face overlaps the old box at IoU ≥ ${PHOTO_REENROL_MIN_IOU}`);
|
|
41032
|
+
if (overlapping.length > 1) return refused$1("ambiguous", `${overlapping.length} faces overlap the old box (IoU ${overlapping.map((c) => c.iou.toFixed(2)).join(", ")})`);
|
|
41015
41033
|
const [only] = overlapping;
|
|
41016
|
-
if (only === void 0) return refused("no-iou-match", "no overlapping face");
|
|
41017
|
-
if (!isEnrollableIn(only.face, input.modelId)) return refused("no-enrollable-face", `the face on the old box is not enrollable (${only.face.refusedReason ?? `model ${only.face.modelId ?? "none"}`})`);
|
|
41034
|
+
if (only === void 0) return refused$1("no-iou-match", "no overlapping face");
|
|
41035
|
+
if (!isEnrollableIn(only.face, input.modelId)) return refused$1("no-enrollable-face", `the face on the old box is not enrollable (${only.face.refusedReason ?? `model ${only.face.modelId ?? "none"}`})`);
|
|
41018
41036
|
const cosine = scored.find((s) => s.face === only.face)?.cosine;
|
|
41019
|
-
if (cosine === void 0 || cosine < .5) return refused("below-floor", `the overlapping face scores cosine ${cosine?.toFixed(3) ?? "n/a"} < ${PHOTO_REENROL_COSINE_FLOOR}`);
|
|
41037
|
+
if (cosine === void 0 || cosine < .5) return refused$1("below-floor", `the overlapping face scores cosine ${cosine?.toFixed(3) ?? "n/a"} < ${PHOTO_REENROL_COSINE_FLOOR}`);
|
|
41020
41038
|
return {
|
|
41021
41039
|
kind: "chosen",
|
|
41022
41040
|
face: only.face,
|
|
@@ -41027,10 +41045,10 @@ function chooseByIou(input, oldBox, scored) {
|
|
|
41027
41045
|
}
|
|
41028
41046
|
function chooseByCosine(input, scored) {
|
|
41029
41047
|
const [best, runnerUp] = [...scored].toSorted((a, b) => b.cosine - a.cosine);
|
|
41030
|
-
if (best === void 0) return refused("model-mismatch", "no face has a comparable vector");
|
|
41031
|
-
if (best.cosine < .5) return refused("below-floor", `best cosine ${best.cosine.toFixed(3)} < ${PHOTO_REENROL_COSINE_FLOOR}`);
|
|
41032
|
-
if (runnerUp !== void 0 && runnerUp.cosine >= .5 && best.cosine - runnerUp.cosine < .1) return refused("ambiguous", `two faces clear the floor within ${PHOTO_REENROL_AMBIGUITY_MARGIN}: ${best.cosine.toFixed(3)} vs ${runnerUp.cosine.toFixed(3)}`);
|
|
41033
|
-
if (!isEnrollableIn(best.face, input.modelId)) return refused("ambiguous", `the closest face (cosine ${best.cosine.toFixed(3)}) is not enrollable (${best.face.refusedReason ?? "unknown"}) — the enrollable ones may be someone else`);
|
|
41048
|
+
if (best === void 0) return refused$1("model-mismatch", "no face has a comparable vector");
|
|
41049
|
+
if (best.cosine < .5) return refused$1("below-floor", `best cosine ${best.cosine.toFixed(3)} < ${PHOTO_REENROL_COSINE_FLOOR}`);
|
|
41050
|
+
if (runnerUp !== void 0 && runnerUp.cosine >= .5 && best.cosine - runnerUp.cosine < .1) return refused$1("ambiguous", `two faces clear the floor within ${PHOTO_REENROL_AMBIGUITY_MARGIN}: ${best.cosine.toFixed(3)} vs ${runnerUp.cosine.toFixed(3)}`);
|
|
41051
|
+
if (!isEnrollableIn(best.face, input.modelId)) return refused$1("ambiguous", `the closest face (cosine ${best.cosine.toFixed(3)}) is not enrollable (${best.face.refusedReason ?? "unknown"}) — the enrollable ones may be someone else`);
|
|
41034
41052
|
return {
|
|
41035
41053
|
kind: "chosen",
|
|
41036
41054
|
face: best.face,
|
|
@@ -53746,11 +53764,10 @@ var EventStore = class {
|
|
|
53746
53764
|
let entryId;
|
|
53747
53765
|
for (const row of rows) {
|
|
53748
53766
|
const bbox = row.data["bbox"];
|
|
53749
|
-
if (bbox
|
|
53750
|
-
|
|
53751
|
-
|
|
53752
|
-
|
|
53753
|
-
}
|
|
53767
|
+
if (bbox === null || typeof bbox !== "object") continue;
|
|
53768
|
+
const bw = "w" in bbox && typeof bbox.w === "number" ? bbox.w : 0;
|
|
53769
|
+
const bh = "h" in bbox && typeof bbox.h === "number" ? bbox.h : 0;
|
|
53770
|
+
if (bw <= 0 || bh <= 0) continue;
|
|
53754
53771
|
const conf = typeof row.data["confidence"] === "number" ? row.data["confidence"] : 0;
|
|
53755
53772
|
if (conf > bestConf) {
|
|
53756
53773
|
bestConf = conf;
|
|
@@ -62453,6 +62470,26 @@ var EmbeddingDispatcher = class {
|
|
|
62453
62470
|
return this.pendingCrops.size;
|
|
62454
62471
|
}
|
|
62455
62472
|
};
|
|
62473
|
+
//#endregion
|
|
62474
|
+
//#region src/pipeline-analytics/embedding-rebuild.ts
|
|
62475
|
+
/**
|
|
62476
|
+
* Track sources a rebuild never lists (D664). An audio track and a synthetic
|
|
62477
|
+
* sensor track have no object event and no subject to embed — on the live hub
|
|
62478
|
+
* 6,726 + 180 of 42,254 tracks — and walking them only inflated the skip
|
|
62479
|
+
* counters an operator reads to judge media coverage.
|
|
62480
|
+
*/
|
|
62481
|
+
var REBUILD_EXCLUDED_SOURCES = ["audio", "sensor"];
|
|
62482
|
+
/**
|
|
62483
|
+
* One page of the rebuild listing as a `queryRecentIds` query. Pure, so the
|
|
62484
|
+
* exclusion is assertable: dropping it would look identical in every result
|
|
62485
|
+
* except the skip counters.
|
|
62486
|
+
*/
|
|
62487
|
+
function rebuildTrackPageQuery(window) {
|
|
62488
|
+
return {
|
|
62489
|
+
...window,
|
|
62490
|
+
excludeSources: REBUILD_EXCLUDED_SOURCES
|
|
62491
|
+
};
|
|
62492
|
+
}
|
|
62456
62493
|
/**
|
|
62457
62494
|
* Re-embed every listed track from its key frame.
|
|
62458
62495
|
*
|
|
@@ -62468,6 +62505,14 @@ async function rebuildObjectEmbeddings(deps, options = {}) {
|
|
|
62468
62505
|
let recoveredKeyFrame = 0;
|
|
62469
62506
|
let missingEvent = 0;
|
|
62470
62507
|
let missingBbox = 0;
|
|
62508
|
+
let boxSubject = 0;
|
|
62509
|
+
let boxPositions = 0;
|
|
62510
|
+
let boxEvent = 0;
|
|
62511
|
+
let boxRefused = 0;
|
|
62512
|
+
let forcedInSpace = 0;
|
|
62513
|
+
let skippedOutOfSpace = 0;
|
|
62514
|
+
const refusalsByDevice = /* @__PURE__ */ new Map();
|
|
62515
|
+
const force = options.force === true;
|
|
62471
62516
|
let alreadyInSpace = 0;
|
|
62472
62517
|
let notRunnable = 0;
|
|
62473
62518
|
let noCapableNode = 0;
|
|
@@ -62478,6 +62523,12 @@ async function rebuildObjectEmbeddings(deps, options = {}) {
|
|
|
62478
62523
|
let budgetExhausted = false;
|
|
62479
62524
|
/** Set when the cluster ran out of nodes — the pass stops, `complete` is false. */
|
|
62480
62525
|
let abandoned = null;
|
|
62526
|
+
const boxSourceCounts = () => ({
|
|
62527
|
+
subjectBox: boxSubject,
|
|
62528
|
+
positions: boxPositions,
|
|
62529
|
+
event: boxEvent,
|
|
62530
|
+
refused: boxRefused
|
|
62531
|
+
});
|
|
62481
62532
|
while (scanned < maxTracks && abandoned === null) {
|
|
62482
62533
|
const page = await deps.listTrackIdPage(cursor);
|
|
62483
62534
|
if (page.trackIds.length === 0) {
|
|
@@ -62485,9 +62536,14 @@ async function rebuildObjectEmbeddings(deps, options = {}) {
|
|
|
62485
62536
|
break;
|
|
62486
62537
|
}
|
|
62487
62538
|
let pageIds = page.trackIds;
|
|
62539
|
+
let forcedPage = false;
|
|
62488
62540
|
if (deps.filterOutOfSpace) {
|
|
62489
62541
|
const split = await deps.filterOutOfSpace(page.trackIds);
|
|
62490
|
-
if (split !== null) {
|
|
62542
|
+
if (split !== null && force) {
|
|
62543
|
+
skippedOutOfSpace += split.outOfSpace.length;
|
|
62544
|
+
pageIds = split.inSpace;
|
|
62545
|
+
forcedPage = true;
|
|
62546
|
+
} else if (split !== null) {
|
|
62491
62547
|
alreadyInSpace += split.alreadyInSpace;
|
|
62492
62548
|
pageIds = split.outOfSpace;
|
|
62493
62549
|
}
|
|
@@ -62503,6 +62559,7 @@ async function rebuildObjectEmbeddings(deps, options = {}) {
|
|
|
62503
62559
|
const room = maxTracks - scanned;
|
|
62504
62560
|
const batch = pageIds.slice(0, Number.isFinite(room) ? room : void 0);
|
|
62505
62561
|
if (batch.length < pageIds.length) budgetExhausted = true;
|
|
62562
|
+
if (forcedPage) forcedInSpace += batch.length;
|
|
62506
62563
|
for (const trackId of batch) {
|
|
62507
62564
|
if (!deps.canDispatch()) {
|
|
62508
62565
|
abandoned = "no node left in the rotation can serve the pinned model — stopped before loading any further media";
|
|
@@ -62521,6 +62578,25 @@ async function rebuildObjectEmbeddings(deps, options = {}) {
|
|
|
62521
62578
|
missingEvent += 1;
|
|
62522
62579
|
return;
|
|
62523
62580
|
}
|
|
62581
|
+
if (source.bbox === null || source.bbox.w <= 0 || source.bbox.h <= 0) {
|
|
62582
|
+
missingBbox += 1;
|
|
62583
|
+
boxRefused += 1;
|
|
62584
|
+
const reason = source.boxSource.kind === "refused" ? source.boxSource.reason : "degenerate-box";
|
|
62585
|
+
const n = (refusalsByDevice.get(source.deviceId) ?? 0) + 1;
|
|
62586
|
+
refusalsByDevice.set(source.deviceId, n);
|
|
62587
|
+
if (n === 1 || n % 100 === 0) deps.logger.warn("embedding rebuild: no box measured on the key frame — track refused (D303)", {
|
|
62588
|
+
tags: { deviceId: source.deviceId },
|
|
62589
|
+
meta: {
|
|
62590
|
+
trackId,
|
|
62591
|
+
reason,
|
|
62592
|
+
refusedOnThisCamera: n
|
|
62593
|
+
}
|
|
62594
|
+
});
|
|
62595
|
+
return;
|
|
62596
|
+
}
|
|
62597
|
+
if (source.boxSource.kind === "subjectBox") boxSubject += 1;
|
|
62598
|
+
else if (source.boxSource.kind === "positions") boxPositions += 1;
|
|
62599
|
+
else boxEvent += 1;
|
|
62524
62600
|
let keyFrame = source.keyFrame;
|
|
62525
62601
|
let recovered = false;
|
|
62526
62602
|
if (keyFrame === null && deps.recoverKeyFrame) {
|
|
@@ -62532,10 +62608,6 @@ async function rebuildObjectEmbeddings(deps, options = {}) {
|
|
|
62532
62608
|
return;
|
|
62533
62609
|
}
|
|
62534
62610
|
if (recovered) recoveredKeyFrame += 1;
|
|
62535
|
-
if (source.bbox === null || source.bbox.w <= 0 || source.bbox.h <= 0) {
|
|
62536
|
-
missingBbox += 1;
|
|
62537
|
-
return;
|
|
62538
|
-
}
|
|
62539
62611
|
const outcome = await deps.embed(recovered ? {
|
|
62540
62612
|
...source,
|
|
62541
62613
|
keyFrame
|
|
@@ -62603,6 +62675,9 @@ async function rebuildObjectEmbeddings(deps, options = {}) {
|
|
|
62603
62675
|
recoveredKeyFrame,
|
|
62604
62676
|
missingEvent,
|
|
62605
62677
|
missingBbox,
|
|
62678
|
+
boxSource: boxSourceCounts(),
|
|
62679
|
+
forcedInSpace,
|
|
62680
|
+
skippedOutOfSpace,
|
|
62606
62681
|
alreadyInSpace,
|
|
62607
62682
|
notRunnable,
|
|
62608
62683
|
noCapableNode,
|
|
@@ -62626,6 +62701,10 @@ async function rebuildObjectEmbeddings(deps, options = {}) {
|
|
|
62626
62701
|
recoveredKeyFrame,
|
|
62627
62702
|
missingEvent,
|
|
62628
62703
|
missingBbox,
|
|
62704
|
+
boxSource: boxSourceCounts(),
|
|
62705
|
+
force,
|
|
62706
|
+
forcedInSpace,
|
|
62707
|
+
skippedOutOfSpace,
|
|
62629
62708
|
alreadyInSpace,
|
|
62630
62709
|
notRunnable,
|
|
62631
62710
|
noCapableNode,
|
|
@@ -62640,6 +62719,9 @@ async function rebuildObjectEmbeddings(deps, options = {}) {
|
|
|
62640
62719
|
recoveredKeyFrame,
|
|
62641
62720
|
missingEvent,
|
|
62642
62721
|
missingBbox,
|
|
62722
|
+
boxSource: boxSourceCounts(),
|
|
62723
|
+
forcedInSpace,
|
|
62724
|
+
skippedOutOfSpace,
|
|
62643
62725
|
alreadyInSpace,
|
|
62644
62726
|
notRunnable,
|
|
62645
62727
|
noCapableNode,
|
|
@@ -73038,6 +73120,58 @@ function hasKeyFrame(source) {
|
|
|
73038
73120
|
}
|
|
73039
73121
|
//#endregion
|
|
73040
73122
|
//#region src/pipeline-analytics/rebuild-source-loader.ts
|
|
73123
|
+
function refused(reason) {
|
|
73124
|
+
return {
|
|
73125
|
+
bbox: null,
|
|
73126
|
+
boxSource: {
|
|
73127
|
+
kind: "refused",
|
|
73128
|
+
reason
|
|
73129
|
+
}
|
|
73130
|
+
};
|
|
73131
|
+
}
|
|
73132
|
+
function normaliseMeasured(box) {
|
|
73133
|
+
if (box.frameWidth <= 0 || box.frameHeight <= 0 || box.w <= 0 || box.h <= 0) return null;
|
|
73134
|
+
return {
|
|
73135
|
+
x: box.x / box.frameWidth,
|
|
73136
|
+
y: box.y / box.frameHeight,
|
|
73137
|
+
w: box.w / box.frameWidth,
|
|
73138
|
+
h: box.h / box.frameHeight
|
|
73139
|
+
};
|
|
73140
|
+
}
|
|
73141
|
+
/**
|
|
73142
|
+
* The box measured on THIS key frame: its own `subjectBox`, else the track
|
|
73143
|
+
* position at exactly its instant, else a named refusal. Never another
|
|
73144
|
+
* frame's box (D303).
|
|
73145
|
+
*/
|
|
73146
|
+
async function keyFrameBox(deps, trackId, keyFrame) {
|
|
73147
|
+
const own = (await deps.media.listSubjectBoxesByOwner("track", trackId)).find((row) => row.mediaId === keyFrame.mediaId);
|
|
73148
|
+
if (own !== void 0) {
|
|
73149
|
+
const bbox = normaliseMeasured(own.subjectBox);
|
|
73150
|
+
if (bbox !== null) return {
|
|
73151
|
+
bbox,
|
|
73152
|
+
boxSource: { kind: "subjectBox" }
|
|
73153
|
+
};
|
|
73154
|
+
}
|
|
73155
|
+
const track = await deps.tracks.getPersistedByTrackId(trackId);
|
|
73156
|
+
if (track === null) return refused("track-row-missing");
|
|
73157
|
+
const { frameWidth, frameHeight } = track;
|
|
73158
|
+
if (frameWidth === void 0 || frameHeight === void 0) return refused("track-frame-size-unknown");
|
|
73159
|
+
const at = track.positions.find((p) => p.timestamp === keyFrame.timestamp);
|
|
73160
|
+
if (at === void 0) return refused("no-position-at-key-frame");
|
|
73161
|
+
const bbox = normaliseMeasured({
|
|
73162
|
+
...at.bbox,
|
|
73163
|
+
frameWidth,
|
|
73164
|
+
frameHeight
|
|
73165
|
+
});
|
|
73166
|
+
if (bbox === null) return refused("no-position-at-key-frame");
|
|
73167
|
+
return {
|
|
73168
|
+
bbox,
|
|
73169
|
+
boxSource: { kind: "positions" }
|
|
73170
|
+
};
|
|
73171
|
+
}
|
|
73172
|
+
function hasBox(event) {
|
|
73173
|
+
return event.bbox !== void 0 && event.bbox.w > 0 && event.bbox.h > 0;
|
|
73174
|
+
}
|
|
73041
73175
|
/**
|
|
73042
73176
|
* Assemble one track's rebuild inputs, reading at most ONE blob.
|
|
73043
73177
|
*
|
|
@@ -73045,7 +73179,8 @@ function hasKeyFrame(source) {
|
|
|
73045
73179
|
* to describe, and the caller counts it. A track WITH an event but WITHOUT a
|
|
73046
73180
|
* key frame still returns a source (with `keyFrame: null`) so the caller's
|
|
73047
73181
|
* `missingKeyFrame` counter stays the one place that decision is made; no blob
|
|
73048
|
-
* is read in that case either.
|
|
73182
|
+
* is read in that case either. A key frame with no box measured on it returns
|
|
73183
|
+
* `bbox: null` and a named refusal, also without reading the blob.
|
|
73049
73184
|
*/
|
|
73050
73185
|
async function loadRebuildSource(deps, trackId) {
|
|
73051
73186
|
const media = await deps.media.listInfoByOwner("track", trackId);
|
|
@@ -73053,26 +73188,44 @@ async function loadRebuildSource(deps, trackId) {
|
|
|
73053
73188
|
const cropInfo = media.find((m) => m.kind === "thumbnail");
|
|
73054
73189
|
const peak = await deps.events.peakForTrack(trackId);
|
|
73055
73190
|
const events = await deps.events.queryObjectByTrackIds([trackId]);
|
|
73056
|
-
const best = events.find((e) => String(e.id) === peak.bestEventId) ?? events[0];
|
|
73191
|
+
const best = events.find((e) => String(e.id) === peak.bestEventId) ?? events.find(hasBox) ?? events[0];
|
|
73057
73192
|
if (best === void 0) return null;
|
|
73058
73193
|
const common = {
|
|
73059
73194
|
trackId,
|
|
73060
73195
|
deviceId: best.deviceId,
|
|
73061
|
-
timestamp: best.timestamp,
|
|
73062
73196
|
className: best.className,
|
|
73063
73197
|
confidence: best.confidence ?? 0,
|
|
73064
|
-
bbox: normaliseEventBbox(best),
|
|
73065
73198
|
...cropInfo !== void 0 ? { mediaId: cropInfo.mediaId } : {}
|
|
73066
73199
|
};
|
|
73067
|
-
if (keyFrameInfo === void 0)
|
|
73200
|
+
if (keyFrameInfo === void 0) {
|
|
73201
|
+
const bbox = normaliseEventBbox(best);
|
|
73202
|
+
return {
|
|
73203
|
+
...common,
|
|
73204
|
+
timestamp: best.timestamp,
|
|
73205
|
+
bbox,
|
|
73206
|
+
boxSource: bbox !== null ? { kind: "event" } : {
|
|
73207
|
+
kind: "refused",
|
|
73208
|
+
reason: "event-without-box"
|
|
73209
|
+
},
|
|
73210
|
+
keyFrame: null
|
|
73211
|
+
};
|
|
73212
|
+
}
|
|
73213
|
+
const box = await keyFrameBox(deps, trackId, keyFrameInfo);
|
|
73214
|
+
const keyed = {
|
|
73068
73215
|
...common,
|
|
73216
|
+
timestamp: keyFrameInfo.timestamp,
|
|
73217
|
+
bbox: box.bbox,
|
|
73218
|
+
boxSource: box.boxSource,
|
|
73219
|
+
keyFrameMediaId: keyFrameInfo.mediaId
|
|
73220
|
+
};
|
|
73221
|
+
if (box.bbox === null) return {
|
|
73222
|
+
...keyed,
|
|
73069
73223
|
keyFrame: null
|
|
73070
73224
|
};
|
|
73071
73225
|
const keyFrameFile = await deps.media.getById(keyFrameInfo.mediaId);
|
|
73072
73226
|
return {
|
|
73073
|
-
...
|
|
73074
|
-
keyFrame: keyFrameFile ? Buffer.from(keyFrameFile.base64, "base64") : null
|
|
73075
|
-
keyFrameMediaId: keyFrameInfo.mediaId
|
|
73227
|
+
...keyed,
|
|
73228
|
+
keyFrame: keyFrameFile ? Buffer.from(keyFrameFile.base64, "base64") : null
|
|
73076
73229
|
};
|
|
73077
73230
|
}
|
|
73078
73231
|
//#endregion
|
|
@@ -83621,7 +83774,7 @@ function buildGlobalSettingsSchema(cap) {
|
|
|
83621
83774
|
addonId: "pipeline-analytics",
|
|
83622
83775
|
action: "embedding.rebuildStatus",
|
|
83623
83776
|
buttonLabel: "Check progress",
|
|
83624
|
-
successMessage: "{modelId} → {index}: indexed {indexed} · scanned {scanned} · rebuilt {rebuilt} · no key frame {missingKeyFrame} · not runnable {notRunnable} · failed {failed}"
|
|
83777
|
+
successMessage: "{modelId} → {index}: indexed {indexed} · scanned {scanned} · rebuilt {rebuilt} · no key frame {missingKeyFrame} · no box {missingBbox} · no event {missingEvent} · not runnable {notRunnable} · failed {failed}"
|
|
83625
83778
|
},
|
|
83626
83779
|
{
|
|
83627
83780
|
type: "addon-action-button",
|
|
@@ -97208,6 +97361,15 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
97208
97361
|
refusal: "stores-unavailable"
|
|
97209
97362
|
};
|
|
97210
97363
|
}
|
|
97364
|
+
const force = input.force === true;
|
|
97365
|
+
if (force && input.maxTracks === void 0) {
|
|
97366
|
+
this.ctx.logger.warn("rebuildObjectEmbeddings: refusing a force pass with no maxTracks", { meta: { refusal: "force-requires-max-tracks" } });
|
|
97367
|
+
return {
|
|
97368
|
+
started: false,
|
|
97369
|
+
alreadyRunning: false,
|
|
97370
|
+
refusal: "force-requires-max-tracks"
|
|
97371
|
+
};
|
|
97372
|
+
}
|
|
97211
97373
|
const confirmation = await this.getClusterPinConfirmer(api, "clip-rebuild").confirm();
|
|
97212
97374
|
if (confirmation.kind === "refused") {
|
|
97213
97375
|
this.ctx.logger.warn("rebuildObjectEmbeddings: the cluster CLIP model is not confirmed — refusing to start a pass that cannot pin one", { meta: { refusal: confirmation.reason } });
|
|
@@ -97251,16 +97413,17 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
97251
97413
|
logger: this.ctx.logger
|
|
97252
97414
|
}));
|
|
97253
97415
|
const deps = {
|
|
97254
|
-
listTrackIdPage: async (cursor) => trackStore.queryRecentIds({
|
|
97416
|
+
listTrackIdPage: async (cursor) => trackStore.queryRecentIds(rebuildTrackPageQuery({
|
|
97255
97417
|
deviceIds,
|
|
97256
97418
|
...input.since !== void 0 ? { since: input.since } : {},
|
|
97257
97419
|
...input.until !== void 0 ? { until: input.until } : {},
|
|
97258
97420
|
...cursor !== null ? { cursor } : {},
|
|
97259
97421
|
limit: REBUILD_PAGE_SIZE
|
|
97260
|
-
}),
|
|
97422
|
+
})),
|
|
97261
97423
|
loadSource: (trackId) => loadRebuildSource({
|
|
97262
97424
|
media: mediaStore,
|
|
97263
|
-
events: eventStore
|
|
97425
|
+
events: eventStore,
|
|
97426
|
+
tracks: trackStore
|
|
97264
97427
|
}, trackId),
|
|
97265
97428
|
recoverKeyFrame: async (source) => {
|
|
97266
97429
|
const recovered = await recordedStills.recover(source.deviceId, source.timestamp, RECOVERED_KEY_FRAME_MAX_WIDTH);
|
|
@@ -97286,7 +97449,8 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
97286
97449
|
if (split === null) return null;
|
|
97287
97450
|
return {
|
|
97288
97451
|
outOfSpace: split.outOfSpaceIds,
|
|
97289
|
-
alreadyInSpace: split.inSpace
|
|
97452
|
+
alreadyInSpace: split.inSpace,
|
|
97453
|
+
inSpace: split.inSpaceIds
|
|
97290
97454
|
};
|
|
97291
97455
|
},
|
|
97292
97456
|
logger: {
|
|
@@ -97298,6 +97462,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
97298
97462
|
running: true,
|
|
97299
97463
|
modelId,
|
|
97300
97464
|
index,
|
|
97465
|
+
force,
|
|
97301
97466
|
startedAtMs: Date.now(),
|
|
97302
97467
|
progress: {
|
|
97303
97468
|
scanned: 0,
|
|
@@ -97306,6 +97471,14 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
97306
97471
|
recoveredKeyFrame: 0,
|
|
97307
97472
|
missingEvent: 0,
|
|
97308
97473
|
missingBbox: 0,
|
|
97474
|
+
boxSource: {
|
|
97475
|
+
subjectBox: 0,
|
|
97476
|
+
positions: 0,
|
|
97477
|
+
event: 0,
|
|
97478
|
+
refused: 0
|
|
97479
|
+
},
|
|
97480
|
+
forcedInSpace: 0,
|
|
97481
|
+
skippedOutOfSpace: 0,
|
|
97309
97482
|
alreadyInSpace: 0,
|
|
97310
97483
|
notRunnable: 0,
|
|
97311
97484
|
noCapableNode: 0,
|
|
@@ -97313,6 +97486,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
97313
97486
|
}
|
|
97314
97487
|
};
|
|
97315
97488
|
rebuildObjectEmbeddings(deps, {
|
|
97489
|
+
force,
|
|
97316
97490
|
...input.maxTracks !== void 0 ? { maxTracks: input.maxTracks } : {},
|
|
97317
97491
|
...input.pacingMs !== void 0 ? { pacingMs: input.pacingMs } : {},
|
|
97318
97492
|
onProgress: (progress) => {
|
|
@@ -97324,6 +97498,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
97324
97498
|
running: false,
|
|
97325
97499
|
modelId,
|
|
97326
97500
|
index,
|
|
97501
|
+
force,
|
|
97327
97502
|
startedAtMs: this.rebuildState.startedAtMs ?? Date.now(),
|
|
97328
97503
|
finishedAtMs: Date.now(),
|
|
97329
97504
|
progress: outcome,
|
|
@@ -97339,6 +97514,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
97339
97514
|
running: false,
|
|
97340
97515
|
modelId,
|
|
97341
97516
|
index,
|
|
97517
|
+
force,
|
|
97342
97518
|
startedAtMs: this.rebuildState.startedAtMs ?? Date.now(),
|
|
97343
97519
|
finishedAtMs: Date.now(),
|
|
97344
97520
|
error: String(err)
|
|
@@ -97353,7 +97529,8 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
97353
97529
|
modelId,
|
|
97354
97530
|
index,
|
|
97355
97531
|
deviceId: input.deviceId ?? "all",
|
|
97356
|
-
maxTracks: input.maxTracks ?? "unbounded"
|
|
97532
|
+
maxTracks: input.maxTracks ?? "unbounded",
|
|
97533
|
+
force
|
|
97357
97534
|
} });
|
|
97358
97535
|
return {
|
|
97359
97536
|
started: true,
|
|
@@ -98355,8 +98532,18 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
98355
98532
|
running: state.running,
|
|
98356
98533
|
scanned: p?.scanned ?? 0,
|
|
98357
98534
|
rebuilt: p?.rebuilt ?? 0,
|
|
98358
|
-
missingKeyFrame:
|
|
98535
|
+
missingKeyFrame: p?.missingKeyFrame ?? 0,
|
|
98536
|
+
missingEvent: p?.missingEvent ?? 0,
|
|
98359
98537
|
missingBbox: p?.missingBbox ?? 0,
|
|
98538
|
+
boxSource: p?.boxSource ?? {
|
|
98539
|
+
subjectBox: 0,
|
|
98540
|
+
positions: 0,
|
|
98541
|
+
event: 0,
|
|
98542
|
+
refused: 0
|
|
98543
|
+
},
|
|
98544
|
+
alreadyInSpace: p?.alreadyInSpace ?? 0,
|
|
98545
|
+
force: state.force ?? null,
|
|
98546
|
+
forcedInSpace: p?.forcedInSpace ?? 0,
|
|
98360
98547
|
notRunnable: p?.notRunnable ?? 0,
|
|
98361
98548
|
noCapableNode: p?.noCapableNode ?? 0,
|
|
98362
98549
|
failed: p?.failed ?? 0,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as NcRuleSchema, $n as EventCategory, $t as isSourceCap, A as LabelAttributionSchema, An as canonicalHash, At as audioMetricsCapability, B as NC_DEFAULT_SNOOZE_MINUTES, Bt as embeddingRefusalOf, C as EMBEDDING_REQUIREMENTS_FAILED, Cn as systemEventFilterApplies, Ct as TimelapseRuleInputSchema, D as FIRST_LEVEL_MACRO_CLASSES, Dn as vectorDimFromBase64, Dt as addonWidgetsSourceCapability, E as EVENT_OWNER_TYPES, En as templateVarsFor, Et as TrackSourceSchema, F as MOTION_CLOSE_AFTER_MS, Fn as customAction, Ft as deriveRecordingMode, G as NC_TAXONOMY, Gn as discriminatedUnion, Gt as evictionPolicyOfLocation, Hn as _enum, I as MediaFileKindEnum, In as defineCustomActions, It as describeSystemEventDeliveryProblem, J as NcAlarmSettingsPatchSchema, Jn as object, Jt as isDetectionMacroClass, K as NC_TEMPLATE_VARS, Kn as literal, Kt as faceGalleryCapability, L as NC_ALARM_SYSTEM_EVENT_KINDS, Ln as hydrateSchema, Lt as describeSystemEventFamilyProblem, M as MAX_ARCHIVED_DEBUG_NOTES, Mn as CamProfileSchema, Mt as buildEventKindDescriptor, N as MAX_BIRTH_DECISION_RECORDS, Nn as DeviceType, Nt as consumableLowPercentOf, O as FULL_IMAGE_BBOX, On as zoneAnalyticsCapability, Ot as alarmPanelCapability, Pn as createEvent, Pt as cosineSimilarity$1, Q as NcRulePatchSchema, Qn as unknown, Qt as isScheduleActive, R as NC_CONDITION_CATALOG, Rn as isDeviceScopedCap, S as EMBEDDING_MODEL_FAILED, Sn as systemEventFamilyProblems, St as TIMELAPSE_DENSE_FLOOR_SEC, T as EVENT_KIND_BY_CAP, Tn as templateCarriesSummary, Tt as TimelapseRuleSchema, U as NC_SYSTEM_EVENT_KIND_GROUP_SPECS, Un as array, Ut as encodeVectorBase64, V as NC_SENSOR_TRANSITION_KINDS, Vn as sleep$1, W as NC_TANK_SYSTEM_EVENT_KINDS, Wn as boolean, Wt as evaluateSensorEdge, X as NcConditionsSchema, Xn as record, Xt as isKnownTemplateVar, Y as NcConditionDescriptorSchema, Yn as partialRecord, Yt as isEventOwnerType, Z as NcRuleInputSchema, Zn as string, Zt as isMediaOwnerType, _n as sensorRaisedOf, a as CLIP_EMBEDDING_STEP_ID, an as notificationRulesCapability, at as NcSnoozeSuppressedSchema, bn as subKindsOf, bt as SCENE_DIVERGED, c as resolveClusterModelPin, cn as pipelineAnalyticsCapability, ct as NcTemplatePreviewInputSchema, d as ArchivedDebugNoteSchema, dn as readTimelapseGeneratedAt, dt as OpsLogEntrySchema, en as isSystemDelivery, et as NcRuleTargetSchema, f as BaseDevice, fn as resolveClipSearchMinScore, g as DEFAULT_EVENT_COLOR, gn as sceneMonitorCapability, gt as RetrainStatusSchema, h as CoverStateSchema, hn as ruleBelongsToAlarm$1, ht as RebuildObjectEmbeddingsRefusalSchema, in as mayWriteToLocation, it as NcSnoozeSchema, j as LockStateSchema, jn as BaseAddon, jt as audioModeOf, k as FailureCounters, kn as errMsg$1, kt as assertTimelapseCadences, l as AUDIO_MACRO_LABELS, ln as plateGalleryCapability, lt as NcTemplatePreviewSchema, m as COCO_TO_MACRO, mt as RECORDING_SOURCE_CAMSTACK_ADDON, nn as isVectorIndexDimConflict, nt as NcScheduleSchema, o as FACE_EMBEDDING_STEP_ID, on as occupancyScope, ot as NcSystemEventKindSchema, p as BirthDecisionRecordSchema, pn as resolveLocationMode, pt as RECORDING_EXPORT_MAX_READ_BYTES, q as NcAlarmConfigSchema, qn as number, qt as failureContributionCapability, rn as kebabToCamel, rt as NcSnoozeInputSchema, s as readClusterModelPinStrict, st as NcTaxonomySchema, t as BUILTIN_CLIP_MODELS, tn as isSystemEventSummaryRule, tt as NcRuleUpdateInputSchema, u as AlarmArmModeSchema, un as readDeviceStateFrom, ut as NcTemplateVarDescriptorSchema, vn as servedTemplateVars, vt as SCENE_DEFAULT_ANCHOR_THRESHOLD, w as EMBEDDING_REQUIREMENTS_UNAVAILABLE, wn as systemEventSummaryScheduleOf, wt as TimelapseRulePatchSchema, x as DeclaredDevices, xn as systemEventDeliveryProblems, xt as SceneMonitorSchema, y as DETECTION_MACRO_CLASSES, yn as storageOccupancyCapability, yt as SCENE_DEFAULT_UNCOVERED_POLICY, z as NC_CONSUMABLE_SYSTEM_EVENT_KINDS, zn as nodePin } from "../clip-model-registry-
|
|
1
|
+
import { $ as NcRuleSchema, $n as EventCategory, $t as isSourceCap, A as LabelAttributionSchema, An as canonicalHash, At as audioMetricsCapability, B as NC_DEFAULT_SNOOZE_MINUTES, Bt as embeddingRefusalOf, C as EMBEDDING_REQUIREMENTS_FAILED, Cn as systemEventFilterApplies, Ct as TimelapseRuleInputSchema, D as FIRST_LEVEL_MACRO_CLASSES, Dn as vectorDimFromBase64, Dt as addonWidgetsSourceCapability, E as EVENT_OWNER_TYPES, En as templateVarsFor, Et as TrackSourceSchema, F as MOTION_CLOSE_AFTER_MS, Fn as customAction, Ft as deriveRecordingMode, G as NC_TAXONOMY, Gn as discriminatedUnion, Gt as evictionPolicyOfLocation, Hn as _enum, I as MediaFileKindEnum, In as defineCustomActions, It as describeSystemEventDeliveryProblem, J as NcAlarmSettingsPatchSchema, Jn as object, Jt as isDetectionMacroClass, K as NC_TEMPLATE_VARS, Kn as literal, Kt as faceGalleryCapability, L as NC_ALARM_SYSTEM_EVENT_KINDS, Ln as hydrateSchema, Lt as describeSystemEventFamilyProblem, M as MAX_ARCHIVED_DEBUG_NOTES, Mn as CamProfileSchema, Mt as buildEventKindDescriptor, N as MAX_BIRTH_DECISION_RECORDS, Nn as DeviceType, Nt as consumableLowPercentOf, O as FULL_IMAGE_BBOX, On as zoneAnalyticsCapability, Ot as alarmPanelCapability, Pn as createEvent, Pt as cosineSimilarity$1, Q as NcRulePatchSchema, Qn as unknown, Qt as isScheduleActive, R as NC_CONDITION_CATALOG, Rn as isDeviceScopedCap, S as EMBEDDING_MODEL_FAILED, Sn as systemEventFamilyProblems, St as TIMELAPSE_DENSE_FLOOR_SEC, T as EVENT_KIND_BY_CAP, Tn as templateCarriesSummary, Tt as TimelapseRuleSchema, U as NC_SYSTEM_EVENT_KIND_GROUP_SPECS, Un as array, Ut as encodeVectorBase64, V as NC_SENSOR_TRANSITION_KINDS, Vn as sleep$1, W as NC_TANK_SYSTEM_EVENT_KINDS, Wn as boolean, Wt as evaluateSensorEdge, X as NcConditionsSchema, Xn as record, Xt as isKnownTemplateVar, Y as NcConditionDescriptorSchema, Yn as partialRecord, Yt as isEventOwnerType, Z as NcRuleInputSchema, Zn as string, Zt as isMediaOwnerType, _n as sensorRaisedOf, a as CLIP_EMBEDDING_STEP_ID, an as notificationRulesCapability, at as NcSnoozeSuppressedSchema, bn as subKindsOf, bt as SCENE_DIVERGED, c as resolveClusterModelPin, cn as pipelineAnalyticsCapability, ct as NcTemplatePreviewInputSchema, d as ArchivedDebugNoteSchema, dn as readTimelapseGeneratedAt, dt as OpsLogEntrySchema, en as isSystemDelivery, et as NcRuleTargetSchema, f as BaseDevice, fn as resolveClipSearchMinScore, g as DEFAULT_EVENT_COLOR, gn as sceneMonitorCapability, gt as RetrainStatusSchema, h as CoverStateSchema, hn as ruleBelongsToAlarm$1, ht as RebuildObjectEmbeddingsRefusalSchema, in as mayWriteToLocation, it as NcSnoozeSchema, j as LockStateSchema, jn as BaseAddon, jt as audioModeOf, k as FailureCounters, kn as errMsg$1, kt as assertTimelapseCadences, l as AUDIO_MACRO_LABELS, ln as plateGalleryCapability, lt as NcTemplatePreviewSchema, m as COCO_TO_MACRO, mt as RECORDING_SOURCE_CAMSTACK_ADDON, nn as isVectorIndexDimConflict, nt as NcScheduleSchema, o as FACE_EMBEDDING_STEP_ID, on as occupancyScope, ot as NcSystemEventKindSchema, p as BirthDecisionRecordSchema, pn as resolveLocationMode, pt as RECORDING_EXPORT_MAX_READ_BYTES, q as NcAlarmConfigSchema, qn as number, qt as failureContributionCapability, rn as kebabToCamel, rt as NcSnoozeInputSchema, s as readClusterModelPinStrict, st as NcTaxonomySchema, t as BUILTIN_CLIP_MODELS, tn as isSystemEventSummaryRule, tt as NcRuleUpdateInputSchema, u as AlarmArmModeSchema, un as readDeviceStateFrom, ut as NcTemplateVarDescriptorSchema, vn as servedTemplateVars, vt as SCENE_DEFAULT_ANCHOR_THRESHOLD, w as EMBEDDING_REQUIREMENTS_UNAVAILABLE, wn as systemEventSummaryScheduleOf, wt as TimelapseRulePatchSchema, x as DeclaredDevices, xn as systemEventDeliveryProblems, xt as SceneMonitorSchema, y as DETECTION_MACRO_CLASSES, yn as storageOccupancyCapability, yt as SCENE_DEFAULT_UNCOVERED_POLICY, z as NC_CONSUMABLE_SYSTEM_EVENT_KINDS, zn as nodePin } from "../clip-model-registry-Cudz--Ql.mjs";
|
|
2
2
|
import { t as __exportAll } from "../embedding-encoder/index.mjs";
|
|
3
3
|
import * as fs from "node:fs";
|
|
4
4
|
import { promises } from "node:fs";
|
|
@@ -39654,7 +39654,12 @@ var RebuildInputSchema = object({
|
|
|
39654
39654
|
* Milliseconds between tracks; omit for the default, `0` to run flat out.
|
|
39655
39655
|
* A rebuild shares hub-main's only thread with every live request.
|
|
39656
39656
|
*/
|
|
39657
|
-
pacingMs: number().int().nonnegative().optional()
|
|
39657
|
+
pacingMs: number().int().nonnegative().optional(),
|
|
39658
|
+
/**
|
|
39659
|
+
* Re-embed ONLY tracks already in the pinned space — to redo vectors cut
|
|
39660
|
+
* from the wrong box (D664). Requires `maxTracks`.
|
|
39661
|
+
*/
|
|
39662
|
+
force: boolean().optional()
|
|
39658
39663
|
});
|
|
39659
39664
|
var RebuildStartedSchema = object({
|
|
39660
39665
|
started: boolean(),
|
|
@@ -39674,7 +39679,20 @@ var RebuildStatusSchema = object({
|
|
|
39674
39679
|
scanned: number(),
|
|
39675
39680
|
rebuilt: number(),
|
|
39676
39681
|
missingKeyFrame: number(),
|
|
39682
|
+
/** No object event at all — its own number since D664. */
|
|
39683
|
+
missingEvent: number(),
|
|
39677
39684
|
missingBbox: number(),
|
|
39685
|
+
/** Which rule placed each judged track's box (D664). */
|
|
39686
|
+
boxSource: object({
|
|
39687
|
+
subjectBox: number(),
|
|
39688
|
+
positions: number(),
|
|
39689
|
+
event: number(),
|
|
39690
|
+
refused: number()
|
|
39691
|
+
}),
|
|
39692
|
+
alreadyInSpace: number(),
|
|
39693
|
+
/** Whether the current / last pass was a `force` pass (D664). */
|
|
39694
|
+
force: boolean().nullable(),
|
|
39695
|
+
forcedInSpace: number(),
|
|
39678
39696
|
/** Refused by the executing node (unreadable key frame / bad box), not broken. */
|
|
39679
39697
|
notRunnable: number(),
|
|
39680
39698
|
/** The pass STOPPED: no node in the cluster could serve the pinned model. */
|
|
@@ -40949,7 +40967,7 @@ function toPixelBox(b) {
|
|
|
40949
40967
|
h: b.height
|
|
40950
40968
|
};
|
|
40951
40969
|
}
|
|
40952
|
-
function refused(reason, detail) {
|
|
40970
|
+
function refused$1(reason, detail) {
|
|
40953
40971
|
return {
|
|
40954
40972
|
kind: "refused",
|
|
40955
40973
|
reason,
|
|
@@ -40977,8 +40995,8 @@ function comparableFaces(input) {
|
|
|
40977
40995
|
/** Refuse before choosing when nothing in the photo can become the sample. */
|
|
40978
40996
|
function precondition(input) {
|
|
40979
40997
|
const enrollable = input.faces.filter((f) => f.enrollable && f.embedding !== void 0);
|
|
40980
|
-
if (enrollable.length === 0) return refused("no-enrollable-face", `${input.faces.length} face(s) found, none enrollable (${input.faces.map((f) => f.refusedReason ?? "unknown").join(", ")})`);
|
|
40981
|
-
if (!enrollable.some((f) => isEnrollableIn(f, input.modelId))) return refused("model-mismatch", `faces were embedded by ${[...new Set(enrollable.map((f) => f.modelId))].join(", ")}, the old sample by ${input.modelId} — re-embed the gallery first`);
|
|
40998
|
+
if (enrollable.length === 0) return refused$1("no-enrollable-face", `${input.faces.length} face(s) found, none enrollable (${input.faces.map((f) => f.refusedReason ?? "unknown").join(", ")})`);
|
|
40999
|
+
if (!enrollable.some((f) => isEnrollableIn(f, input.modelId))) return refused$1("model-mismatch", `faces were embedded by ${[...new Set(enrollable.map((f) => f.modelId))].join(", ")}, the old sample by ${input.modelId} — re-embed the gallery first`);
|
|
40982
41000
|
return null;
|
|
40983
41001
|
}
|
|
40984
41002
|
function chooseByIou(input, oldBox, scored) {
|
|
@@ -40987,13 +41005,13 @@ function chooseByIou(input, oldBox, scored) {
|
|
|
40987
41005
|
face,
|
|
40988
41006
|
iou: iou$3(box, toPixelBox(face.bbox))
|
|
40989
41007
|
})).filter((c) => c.iou >= PHOTO_REENROL_MIN_IOU);
|
|
40990
|
-
if (overlapping.length === 0) return refused("no-iou-match", `no face overlaps the old box at IoU ≥ ${PHOTO_REENROL_MIN_IOU}`);
|
|
40991
|
-
if (overlapping.length > 1) return refused("ambiguous", `${overlapping.length} faces overlap the old box (IoU ${overlapping.map((c) => c.iou.toFixed(2)).join(", ")})`);
|
|
41008
|
+
if (overlapping.length === 0) return refused$1("no-iou-match", `no face overlaps the old box at IoU ≥ ${PHOTO_REENROL_MIN_IOU}`);
|
|
41009
|
+
if (overlapping.length > 1) return refused$1("ambiguous", `${overlapping.length} faces overlap the old box (IoU ${overlapping.map((c) => c.iou.toFixed(2)).join(", ")})`);
|
|
40992
41010
|
const [only] = overlapping;
|
|
40993
|
-
if (only === void 0) return refused("no-iou-match", "no overlapping face");
|
|
40994
|
-
if (!isEnrollableIn(only.face, input.modelId)) return refused("no-enrollable-face", `the face on the old box is not enrollable (${only.face.refusedReason ?? `model ${only.face.modelId ?? "none"}`})`);
|
|
41011
|
+
if (only === void 0) return refused$1("no-iou-match", "no overlapping face");
|
|
41012
|
+
if (!isEnrollableIn(only.face, input.modelId)) return refused$1("no-enrollable-face", `the face on the old box is not enrollable (${only.face.refusedReason ?? `model ${only.face.modelId ?? "none"}`})`);
|
|
40995
41013
|
const cosine = scored.find((s) => s.face === only.face)?.cosine;
|
|
40996
|
-
if (cosine === void 0 || cosine < .5) return refused("below-floor", `the overlapping face scores cosine ${cosine?.toFixed(3) ?? "n/a"} < ${PHOTO_REENROL_COSINE_FLOOR}`);
|
|
41014
|
+
if (cosine === void 0 || cosine < .5) return refused$1("below-floor", `the overlapping face scores cosine ${cosine?.toFixed(3) ?? "n/a"} < ${PHOTO_REENROL_COSINE_FLOOR}`);
|
|
40997
41015
|
return {
|
|
40998
41016
|
kind: "chosen",
|
|
40999
41017
|
face: only.face,
|
|
@@ -41004,10 +41022,10 @@ function chooseByIou(input, oldBox, scored) {
|
|
|
41004
41022
|
}
|
|
41005
41023
|
function chooseByCosine(input, scored) {
|
|
41006
41024
|
const [best, runnerUp] = [...scored].toSorted((a, b) => b.cosine - a.cosine);
|
|
41007
|
-
if (best === void 0) return refused("model-mismatch", "no face has a comparable vector");
|
|
41008
|
-
if (best.cosine < .5) return refused("below-floor", `best cosine ${best.cosine.toFixed(3)} < ${PHOTO_REENROL_COSINE_FLOOR}`);
|
|
41009
|
-
if (runnerUp !== void 0 && runnerUp.cosine >= .5 && best.cosine - runnerUp.cosine < .1) return refused("ambiguous", `two faces clear the floor within ${PHOTO_REENROL_AMBIGUITY_MARGIN}: ${best.cosine.toFixed(3)} vs ${runnerUp.cosine.toFixed(3)}`);
|
|
41010
|
-
if (!isEnrollableIn(best.face, input.modelId)) return refused("ambiguous", `the closest face (cosine ${best.cosine.toFixed(3)}) is not enrollable (${best.face.refusedReason ?? "unknown"}) — the enrollable ones may be someone else`);
|
|
41025
|
+
if (best === void 0) return refused$1("model-mismatch", "no face has a comparable vector");
|
|
41026
|
+
if (best.cosine < .5) return refused$1("below-floor", `best cosine ${best.cosine.toFixed(3)} < ${PHOTO_REENROL_COSINE_FLOOR}`);
|
|
41027
|
+
if (runnerUp !== void 0 && runnerUp.cosine >= .5 && best.cosine - runnerUp.cosine < .1) return refused$1("ambiguous", `two faces clear the floor within ${PHOTO_REENROL_AMBIGUITY_MARGIN}: ${best.cosine.toFixed(3)} vs ${runnerUp.cosine.toFixed(3)}`);
|
|
41028
|
+
if (!isEnrollableIn(best.face, input.modelId)) return refused$1("ambiguous", `the closest face (cosine ${best.cosine.toFixed(3)}) is not enrollable (${best.face.refusedReason ?? "unknown"}) — the enrollable ones may be someone else`);
|
|
41011
41029
|
return {
|
|
41012
41030
|
kind: "chosen",
|
|
41013
41031
|
face: best.face,
|
|
@@ -53721,11 +53739,10 @@ var EventStore = class {
|
|
|
53721
53739
|
let entryId;
|
|
53722
53740
|
for (const row of rows) {
|
|
53723
53741
|
const bbox = row.data["bbox"];
|
|
53724
|
-
if (bbox
|
|
53725
|
-
|
|
53726
|
-
|
|
53727
|
-
|
|
53728
|
-
}
|
|
53742
|
+
if (bbox === null || typeof bbox !== "object") continue;
|
|
53743
|
+
const bw = "w" in bbox && typeof bbox.w === "number" ? bbox.w : 0;
|
|
53744
|
+
const bh = "h" in bbox && typeof bbox.h === "number" ? bbox.h : 0;
|
|
53745
|
+
if (bw <= 0 || bh <= 0) continue;
|
|
53729
53746
|
const conf = typeof row.data["confidence"] === "number" ? row.data["confidence"] : 0;
|
|
53730
53747
|
if (conf > bestConf) {
|
|
53731
53748
|
bestConf = conf;
|
|
@@ -62377,6 +62394,26 @@ var EmbeddingDispatcher = class {
|
|
|
62377
62394
|
return this.pendingCrops.size;
|
|
62378
62395
|
}
|
|
62379
62396
|
};
|
|
62397
|
+
//#endregion
|
|
62398
|
+
//#region src/pipeline-analytics/embedding-rebuild.ts
|
|
62399
|
+
/**
|
|
62400
|
+
* Track sources a rebuild never lists (D664). An audio track and a synthetic
|
|
62401
|
+
* sensor track have no object event and no subject to embed — on the live hub
|
|
62402
|
+
* 6,726 + 180 of 42,254 tracks — and walking them only inflated the skip
|
|
62403
|
+
* counters an operator reads to judge media coverage.
|
|
62404
|
+
*/
|
|
62405
|
+
var REBUILD_EXCLUDED_SOURCES = ["audio", "sensor"];
|
|
62406
|
+
/**
|
|
62407
|
+
* One page of the rebuild listing as a `queryRecentIds` query. Pure, so the
|
|
62408
|
+
* exclusion is assertable: dropping it would look identical in every result
|
|
62409
|
+
* except the skip counters.
|
|
62410
|
+
*/
|
|
62411
|
+
function rebuildTrackPageQuery(window) {
|
|
62412
|
+
return {
|
|
62413
|
+
...window,
|
|
62414
|
+
excludeSources: REBUILD_EXCLUDED_SOURCES
|
|
62415
|
+
};
|
|
62416
|
+
}
|
|
62380
62417
|
/**
|
|
62381
62418
|
* Re-embed every listed track from its key frame.
|
|
62382
62419
|
*
|
|
@@ -62392,6 +62429,14 @@ async function rebuildObjectEmbeddings(deps, options = {}) {
|
|
|
62392
62429
|
let recoveredKeyFrame = 0;
|
|
62393
62430
|
let missingEvent = 0;
|
|
62394
62431
|
let missingBbox = 0;
|
|
62432
|
+
let boxSubject = 0;
|
|
62433
|
+
let boxPositions = 0;
|
|
62434
|
+
let boxEvent = 0;
|
|
62435
|
+
let boxRefused = 0;
|
|
62436
|
+
let forcedInSpace = 0;
|
|
62437
|
+
let skippedOutOfSpace = 0;
|
|
62438
|
+
const refusalsByDevice = /* @__PURE__ */ new Map();
|
|
62439
|
+
const force = options.force === true;
|
|
62395
62440
|
let alreadyInSpace = 0;
|
|
62396
62441
|
let notRunnable = 0;
|
|
62397
62442
|
let noCapableNode = 0;
|
|
@@ -62402,6 +62447,12 @@ async function rebuildObjectEmbeddings(deps, options = {}) {
|
|
|
62402
62447
|
let budgetExhausted = false;
|
|
62403
62448
|
/** Set when the cluster ran out of nodes — the pass stops, `complete` is false. */
|
|
62404
62449
|
let abandoned = null;
|
|
62450
|
+
const boxSourceCounts = () => ({
|
|
62451
|
+
subjectBox: boxSubject,
|
|
62452
|
+
positions: boxPositions,
|
|
62453
|
+
event: boxEvent,
|
|
62454
|
+
refused: boxRefused
|
|
62455
|
+
});
|
|
62405
62456
|
while (scanned < maxTracks && abandoned === null) {
|
|
62406
62457
|
const page = await deps.listTrackIdPage(cursor);
|
|
62407
62458
|
if (page.trackIds.length === 0) {
|
|
@@ -62409,9 +62460,14 @@ async function rebuildObjectEmbeddings(deps, options = {}) {
|
|
|
62409
62460
|
break;
|
|
62410
62461
|
}
|
|
62411
62462
|
let pageIds = page.trackIds;
|
|
62463
|
+
let forcedPage = false;
|
|
62412
62464
|
if (deps.filterOutOfSpace) {
|
|
62413
62465
|
const split = await deps.filterOutOfSpace(page.trackIds);
|
|
62414
|
-
if (split !== null) {
|
|
62466
|
+
if (split !== null && force) {
|
|
62467
|
+
skippedOutOfSpace += split.outOfSpace.length;
|
|
62468
|
+
pageIds = split.inSpace;
|
|
62469
|
+
forcedPage = true;
|
|
62470
|
+
} else if (split !== null) {
|
|
62415
62471
|
alreadyInSpace += split.alreadyInSpace;
|
|
62416
62472
|
pageIds = split.outOfSpace;
|
|
62417
62473
|
}
|
|
@@ -62427,6 +62483,7 @@ async function rebuildObjectEmbeddings(deps, options = {}) {
|
|
|
62427
62483
|
const room = maxTracks - scanned;
|
|
62428
62484
|
const batch = pageIds.slice(0, Number.isFinite(room) ? room : void 0);
|
|
62429
62485
|
if (batch.length < pageIds.length) budgetExhausted = true;
|
|
62486
|
+
if (forcedPage) forcedInSpace += batch.length;
|
|
62430
62487
|
for (const trackId of batch) {
|
|
62431
62488
|
if (!deps.canDispatch()) {
|
|
62432
62489
|
abandoned = "no node left in the rotation can serve the pinned model — stopped before loading any further media";
|
|
@@ -62445,6 +62502,25 @@ async function rebuildObjectEmbeddings(deps, options = {}) {
|
|
|
62445
62502
|
missingEvent += 1;
|
|
62446
62503
|
return;
|
|
62447
62504
|
}
|
|
62505
|
+
if (source.bbox === null || source.bbox.w <= 0 || source.bbox.h <= 0) {
|
|
62506
|
+
missingBbox += 1;
|
|
62507
|
+
boxRefused += 1;
|
|
62508
|
+
const reason = source.boxSource.kind === "refused" ? source.boxSource.reason : "degenerate-box";
|
|
62509
|
+
const n = (refusalsByDevice.get(source.deviceId) ?? 0) + 1;
|
|
62510
|
+
refusalsByDevice.set(source.deviceId, n);
|
|
62511
|
+
if (n === 1 || n % 100 === 0) deps.logger.warn("embedding rebuild: no box measured on the key frame — track refused (D303)", {
|
|
62512
|
+
tags: { deviceId: source.deviceId },
|
|
62513
|
+
meta: {
|
|
62514
|
+
trackId,
|
|
62515
|
+
reason,
|
|
62516
|
+
refusedOnThisCamera: n
|
|
62517
|
+
}
|
|
62518
|
+
});
|
|
62519
|
+
return;
|
|
62520
|
+
}
|
|
62521
|
+
if (source.boxSource.kind === "subjectBox") boxSubject += 1;
|
|
62522
|
+
else if (source.boxSource.kind === "positions") boxPositions += 1;
|
|
62523
|
+
else boxEvent += 1;
|
|
62448
62524
|
let keyFrame = source.keyFrame;
|
|
62449
62525
|
let recovered = false;
|
|
62450
62526
|
if (keyFrame === null && deps.recoverKeyFrame) {
|
|
@@ -62456,10 +62532,6 @@ async function rebuildObjectEmbeddings(deps, options = {}) {
|
|
|
62456
62532
|
return;
|
|
62457
62533
|
}
|
|
62458
62534
|
if (recovered) recoveredKeyFrame += 1;
|
|
62459
|
-
if (source.bbox === null || source.bbox.w <= 0 || source.bbox.h <= 0) {
|
|
62460
|
-
missingBbox += 1;
|
|
62461
|
-
return;
|
|
62462
|
-
}
|
|
62463
62535
|
const outcome = await deps.embed(recovered ? {
|
|
62464
62536
|
...source,
|
|
62465
62537
|
keyFrame
|
|
@@ -62527,6 +62599,9 @@ async function rebuildObjectEmbeddings(deps, options = {}) {
|
|
|
62527
62599
|
recoveredKeyFrame,
|
|
62528
62600
|
missingEvent,
|
|
62529
62601
|
missingBbox,
|
|
62602
|
+
boxSource: boxSourceCounts(),
|
|
62603
|
+
forcedInSpace,
|
|
62604
|
+
skippedOutOfSpace,
|
|
62530
62605
|
alreadyInSpace,
|
|
62531
62606
|
notRunnable,
|
|
62532
62607
|
noCapableNode,
|
|
@@ -62550,6 +62625,10 @@ async function rebuildObjectEmbeddings(deps, options = {}) {
|
|
|
62550
62625
|
recoveredKeyFrame,
|
|
62551
62626
|
missingEvent,
|
|
62552
62627
|
missingBbox,
|
|
62628
|
+
boxSource: boxSourceCounts(),
|
|
62629
|
+
force,
|
|
62630
|
+
forcedInSpace,
|
|
62631
|
+
skippedOutOfSpace,
|
|
62553
62632
|
alreadyInSpace,
|
|
62554
62633
|
notRunnable,
|
|
62555
62634
|
noCapableNode,
|
|
@@ -62564,6 +62643,9 @@ async function rebuildObjectEmbeddings(deps, options = {}) {
|
|
|
62564
62643
|
recoveredKeyFrame,
|
|
62565
62644
|
missingEvent,
|
|
62566
62645
|
missingBbox,
|
|
62646
|
+
boxSource: boxSourceCounts(),
|
|
62647
|
+
forcedInSpace,
|
|
62648
|
+
skippedOutOfSpace,
|
|
62567
62649
|
alreadyInSpace,
|
|
62568
62650
|
notRunnable,
|
|
62569
62651
|
noCapableNode,
|
|
@@ -72962,6 +73044,58 @@ function hasKeyFrame(source) {
|
|
|
72962
73044
|
}
|
|
72963
73045
|
//#endregion
|
|
72964
73046
|
//#region src/pipeline-analytics/rebuild-source-loader.ts
|
|
73047
|
+
function refused(reason) {
|
|
73048
|
+
return {
|
|
73049
|
+
bbox: null,
|
|
73050
|
+
boxSource: {
|
|
73051
|
+
kind: "refused",
|
|
73052
|
+
reason
|
|
73053
|
+
}
|
|
73054
|
+
};
|
|
73055
|
+
}
|
|
73056
|
+
function normaliseMeasured(box) {
|
|
73057
|
+
if (box.frameWidth <= 0 || box.frameHeight <= 0 || box.w <= 0 || box.h <= 0) return null;
|
|
73058
|
+
return {
|
|
73059
|
+
x: box.x / box.frameWidth,
|
|
73060
|
+
y: box.y / box.frameHeight,
|
|
73061
|
+
w: box.w / box.frameWidth,
|
|
73062
|
+
h: box.h / box.frameHeight
|
|
73063
|
+
};
|
|
73064
|
+
}
|
|
73065
|
+
/**
|
|
73066
|
+
* The box measured on THIS key frame: its own `subjectBox`, else the track
|
|
73067
|
+
* position at exactly its instant, else a named refusal. Never another
|
|
73068
|
+
* frame's box (D303).
|
|
73069
|
+
*/
|
|
73070
|
+
async function keyFrameBox(deps, trackId, keyFrame) {
|
|
73071
|
+
const own = (await deps.media.listSubjectBoxesByOwner("track", trackId)).find((row) => row.mediaId === keyFrame.mediaId);
|
|
73072
|
+
if (own !== void 0) {
|
|
73073
|
+
const bbox = normaliseMeasured(own.subjectBox);
|
|
73074
|
+
if (bbox !== null) return {
|
|
73075
|
+
bbox,
|
|
73076
|
+
boxSource: { kind: "subjectBox" }
|
|
73077
|
+
};
|
|
73078
|
+
}
|
|
73079
|
+
const track = await deps.tracks.getPersistedByTrackId(trackId);
|
|
73080
|
+
if (track === null) return refused("track-row-missing");
|
|
73081
|
+
const { frameWidth, frameHeight } = track;
|
|
73082
|
+
if (frameWidth === void 0 || frameHeight === void 0) return refused("track-frame-size-unknown");
|
|
73083
|
+
const at = track.positions.find((p) => p.timestamp === keyFrame.timestamp);
|
|
73084
|
+
if (at === void 0) return refused("no-position-at-key-frame");
|
|
73085
|
+
const bbox = normaliseMeasured({
|
|
73086
|
+
...at.bbox,
|
|
73087
|
+
frameWidth,
|
|
73088
|
+
frameHeight
|
|
73089
|
+
});
|
|
73090
|
+
if (bbox === null) return refused("no-position-at-key-frame");
|
|
73091
|
+
return {
|
|
73092
|
+
bbox,
|
|
73093
|
+
boxSource: { kind: "positions" }
|
|
73094
|
+
};
|
|
73095
|
+
}
|
|
73096
|
+
function hasBox(event) {
|
|
73097
|
+
return event.bbox !== void 0 && event.bbox.w > 0 && event.bbox.h > 0;
|
|
73098
|
+
}
|
|
72965
73099
|
/**
|
|
72966
73100
|
* Assemble one track's rebuild inputs, reading at most ONE blob.
|
|
72967
73101
|
*
|
|
@@ -72969,7 +73103,8 @@ function hasKeyFrame(source) {
|
|
|
72969
73103
|
* to describe, and the caller counts it. A track WITH an event but WITHOUT a
|
|
72970
73104
|
* key frame still returns a source (with `keyFrame: null`) so the caller's
|
|
72971
73105
|
* `missingKeyFrame` counter stays the one place that decision is made; no blob
|
|
72972
|
-
* is read in that case either.
|
|
73106
|
+
* is read in that case either. A key frame with no box measured on it returns
|
|
73107
|
+
* `bbox: null` and a named refusal, also without reading the blob.
|
|
72973
73108
|
*/
|
|
72974
73109
|
async function loadRebuildSource(deps, trackId) {
|
|
72975
73110
|
const media = await deps.media.listInfoByOwner("track", trackId);
|
|
@@ -72977,26 +73112,44 @@ async function loadRebuildSource(deps, trackId) {
|
|
|
72977
73112
|
const cropInfo = media.find((m) => m.kind === "thumbnail");
|
|
72978
73113
|
const peak = await deps.events.peakForTrack(trackId);
|
|
72979
73114
|
const events = await deps.events.queryObjectByTrackIds([trackId]);
|
|
72980
|
-
const best = events.find((e) => String(e.id) === peak.bestEventId) ?? events[0];
|
|
73115
|
+
const best = events.find((e) => String(e.id) === peak.bestEventId) ?? events.find(hasBox) ?? events[0];
|
|
72981
73116
|
if (best === void 0) return null;
|
|
72982
73117
|
const common = {
|
|
72983
73118
|
trackId,
|
|
72984
73119
|
deviceId: best.deviceId,
|
|
72985
|
-
timestamp: best.timestamp,
|
|
72986
73120
|
className: best.className,
|
|
72987
73121
|
confidence: best.confidence ?? 0,
|
|
72988
|
-
bbox: normaliseEventBbox(best),
|
|
72989
73122
|
...cropInfo !== void 0 ? { mediaId: cropInfo.mediaId } : {}
|
|
72990
73123
|
};
|
|
72991
|
-
if (keyFrameInfo === void 0)
|
|
73124
|
+
if (keyFrameInfo === void 0) {
|
|
73125
|
+
const bbox = normaliseEventBbox(best);
|
|
73126
|
+
return {
|
|
73127
|
+
...common,
|
|
73128
|
+
timestamp: best.timestamp,
|
|
73129
|
+
bbox,
|
|
73130
|
+
boxSource: bbox !== null ? { kind: "event" } : {
|
|
73131
|
+
kind: "refused",
|
|
73132
|
+
reason: "event-without-box"
|
|
73133
|
+
},
|
|
73134
|
+
keyFrame: null
|
|
73135
|
+
};
|
|
73136
|
+
}
|
|
73137
|
+
const box = await keyFrameBox(deps, trackId, keyFrameInfo);
|
|
73138
|
+
const keyed = {
|
|
72992
73139
|
...common,
|
|
73140
|
+
timestamp: keyFrameInfo.timestamp,
|
|
73141
|
+
bbox: box.bbox,
|
|
73142
|
+
boxSource: box.boxSource,
|
|
73143
|
+
keyFrameMediaId: keyFrameInfo.mediaId
|
|
73144
|
+
};
|
|
73145
|
+
if (box.bbox === null) return {
|
|
73146
|
+
...keyed,
|
|
72993
73147
|
keyFrame: null
|
|
72994
73148
|
};
|
|
72995
73149
|
const keyFrameFile = await deps.media.getById(keyFrameInfo.mediaId);
|
|
72996
73150
|
return {
|
|
72997
|
-
...
|
|
72998
|
-
keyFrame: keyFrameFile ? Buffer.from(keyFrameFile.base64, "base64") : null
|
|
72999
|
-
keyFrameMediaId: keyFrameInfo.mediaId
|
|
73151
|
+
...keyed,
|
|
73152
|
+
keyFrame: keyFrameFile ? Buffer.from(keyFrameFile.base64, "base64") : null
|
|
73000
73153
|
};
|
|
73001
73154
|
}
|
|
73002
73155
|
//#endregion
|
|
@@ -83545,7 +83698,7 @@ function buildGlobalSettingsSchema(cap) {
|
|
|
83545
83698
|
addonId: "pipeline-analytics",
|
|
83546
83699
|
action: "embedding.rebuildStatus",
|
|
83547
83700
|
buttonLabel: "Check progress",
|
|
83548
|
-
successMessage: "{modelId} → {index}: indexed {indexed} · scanned {scanned} · rebuilt {rebuilt} · no key frame {missingKeyFrame} · not runnable {notRunnable} · failed {failed}"
|
|
83701
|
+
successMessage: "{modelId} → {index}: indexed {indexed} · scanned {scanned} · rebuilt {rebuilt} · no key frame {missingKeyFrame} · no box {missingBbox} · no event {missingEvent} · not runnable {notRunnable} · failed {failed}"
|
|
83549
83702
|
},
|
|
83550
83703
|
{
|
|
83551
83704
|
type: "addon-action-button",
|
|
@@ -97132,6 +97285,15 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
97132
97285
|
refusal: "stores-unavailable"
|
|
97133
97286
|
};
|
|
97134
97287
|
}
|
|
97288
|
+
const force = input.force === true;
|
|
97289
|
+
if (force && input.maxTracks === void 0) {
|
|
97290
|
+
this.ctx.logger.warn("rebuildObjectEmbeddings: refusing a force pass with no maxTracks", { meta: { refusal: "force-requires-max-tracks" } });
|
|
97291
|
+
return {
|
|
97292
|
+
started: false,
|
|
97293
|
+
alreadyRunning: false,
|
|
97294
|
+
refusal: "force-requires-max-tracks"
|
|
97295
|
+
};
|
|
97296
|
+
}
|
|
97135
97297
|
const confirmation = await this.getClusterPinConfirmer(api, "clip-rebuild").confirm();
|
|
97136
97298
|
if (confirmation.kind === "refused") {
|
|
97137
97299
|
this.ctx.logger.warn("rebuildObjectEmbeddings: the cluster CLIP model is not confirmed — refusing to start a pass that cannot pin one", { meta: { refusal: confirmation.reason } });
|
|
@@ -97175,16 +97337,17 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
97175
97337
|
logger: this.ctx.logger
|
|
97176
97338
|
}));
|
|
97177
97339
|
const deps = {
|
|
97178
|
-
listTrackIdPage: async (cursor) => trackStore.queryRecentIds({
|
|
97340
|
+
listTrackIdPage: async (cursor) => trackStore.queryRecentIds(rebuildTrackPageQuery({
|
|
97179
97341
|
deviceIds,
|
|
97180
97342
|
...input.since !== void 0 ? { since: input.since } : {},
|
|
97181
97343
|
...input.until !== void 0 ? { until: input.until } : {},
|
|
97182
97344
|
...cursor !== null ? { cursor } : {},
|
|
97183
97345
|
limit: REBUILD_PAGE_SIZE
|
|
97184
|
-
}),
|
|
97346
|
+
})),
|
|
97185
97347
|
loadSource: (trackId) => loadRebuildSource({
|
|
97186
97348
|
media: mediaStore,
|
|
97187
|
-
events: eventStore
|
|
97349
|
+
events: eventStore,
|
|
97350
|
+
tracks: trackStore
|
|
97188
97351
|
}, trackId),
|
|
97189
97352
|
recoverKeyFrame: async (source) => {
|
|
97190
97353
|
const recovered = await recordedStills.recover(source.deviceId, source.timestamp, RECOVERED_KEY_FRAME_MAX_WIDTH);
|
|
@@ -97210,7 +97373,8 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
97210
97373
|
if (split === null) return null;
|
|
97211
97374
|
return {
|
|
97212
97375
|
outOfSpace: split.outOfSpaceIds,
|
|
97213
|
-
alreadyInSpace: split.inSpace
|
|
97376
|
+
alreadyInSpace: split.inSpace,
|
|
97377
|
+
inSpace: split.inSpaceIds
|
|
97214
97378
|
};
|
|
97215
97379
|
},
|
|
97216
97380
|
logger: {
|
|
@@ -97222,6 +97386,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
97222
97386
|
running: true,
|
|
97223
97387
|
modelId,
|
|
97224
97388
|
index,
|
|
97389
|
+
force,
|
|
97225
97390
|
startedAtMs: Date.now(),
|
|
97226
97391
|
progress: {
|
|
97227
97392
|
scanned: 0,
|
|
@@ -97230,6 +97395,14 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
97230
97395
|
recoveredKeyFrame: 0,
|
|
97231
97396
|
missingEvent: 0,
|
|
97232
97397
|
missingBbox: 0,
|
|
97398
|
+
boxSource: {
|
|
97399
|
+
subjectBox: 0,
|
|
97400
|
+
positions: 0,
|
|
97401
|
+
event: 0,
|
|
97402
|
+
refused: 0
|
|
97403
|
+
},
|
|
97404
|
+
forcedInSpace: 0,
|
|
97405
|
+
skippedOutOfSpace: 0,
|
|
97233
97406
|
alreadyInSpace: 0,
|
|
97234
97407
|
notRunnable: 0,
|
|
97235
97408
|
noCapableNode: 0,
|
|
@@ -97237,6 +97410,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
97237
97410
|
}
|
|
97238
97411
|
};
|
|
97239
97412
|
rebuildObjectEmbeddings(deps, {
|
|
97413
|
+
force,
|
|
97240
97414
|
...input.maxTracks !== void 0 ? { maxTracks: input.maxTracks } : {},
|
|
97241
97415
|
...input.pacingMs !== void 0 ? { pacingMs: input.pacingMs } : {},
|
|
97242
97416
|
onProgress: (progress) => {
|
|
@@ -97248,6 +97422,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
97248
97422
|
running: false,
|
|
97249
97423
|
modelId,
|
|
97250
97424
|
index,
|
|
97425
|
+
force,
|
|
97251
97426
|
startedAtMs: this.rebuildState.startedAtMs ?? Date.now(),
|
|
97252
97427
|
finishedAtMs: Date.now(),
|
|
97253
97428
|
progress: outcome,
|
|
@@ -97263,6 +97438,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
97263
97438
|
running: false,
|
|
97264
97439
|
modelId,
|
|
97265
97440
|
index,
|
|
97441
|
+
force,
|
|
97266
97442
|
startedAtMs: this.rebuildState.startedAtMs ?? Date.now(),
|
|
97267
97443
|
finishedAtMs: Date.now(),
|
|
97268
97444
|
error: String(err)
|
|
@@ -97277,7 +97453,8 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
97277
97453
|
modelId,
|
|
97278
97454
|
index,
|
|
97279
97455
|
deviceId: input.deviceId ?? "all",
|
|
97280
|
-
maxTracks: input.maxTracks ?? "unbounded"
|
|
97456
|
+
maxTracks: input.maxTracks ?? "unbounded",
|
|
97457
|
+
force
|
|
97281
97458
|
} });
|
|
97282
97459
|
return {
|
|
97283
97460
|
started: true,
|
|
@@ -98279,8 +98456,18 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
98279
98456
|
running: state.running,
|
|
98280
98457
|
scanned: p?.scanned ?? 0,
|
|
98281
98458
|
rebuilt: p?.rebuilt ?? 0,
|
|
98282
|
-
missingKeyFrame:
|
|
98459
|
+
missingKeyFrame: p?.missingKeyFrame ?? 0,
|
|
98460
|
+
missingEvent: p?.missingEvent ?? 0,
|
|
98283
98461
|
missingBbox: p?.missingBbox ?? 0,
|
|
98462
|
+
boxSource: p?.boxSource ?? {
|
|
98463
|
+
subjectBox: 0,
|
|
98464
|
+
positions: 0,
|
|
98465
|
+
event: 0,
|
|
98466
|
+
refused: 0
|
|
98467
|
+
},
|
|
98468
|
+
alreadyInSpace: p?.alreadyInSpace ?? 0,
|
|
98469
|
+
force: state.force ?? null,
|
|
98470
|
+
forcedInSpace: p?.forcedInSpace ?? 0,
|
|
98284
98471
|
notRunnable: p?.notRunnable ?? 0,
|
|
98285
98472
|
noCapableNode: p?.noCapableNode ?? 0,
|
|
98286
98473
|
failed: p?.failed ?? 0,
|
|
@@ -30,7 +30,7 @@ async function d(e) {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
async function f() {
|
|
33
|
-
return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-
|
|
33
|
+
return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-CBHxwCSj.mjs")).catch((e) => {
|
|
34
34
|
throw l = void 0, e;
|
|
35
35
|
}), l;
|
|
36
36
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-post-analysis",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.291",
|
|
4
4
|
"description": "Post-Analysis bundle — enrichment, embedding-encoder, pipeline-analytics. Multi-entry npm package shipping addons that consume pipeline output.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|