@camstack/addon-post-analysis 1.2.364 → 1.2.365
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-B69Mktce.mjs → clip-model-registry-BRXTB6Qa.mjs} +361 -4
- package/dist/{clip-model-registry-D8XeJhT4.js → clip-model-registry-CsJpPkau.js} +390 -3
- 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-CUQTWug8.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-DUGlfHVc.mjs} +2 -2
- package/dist/pipeline-analytics/{_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-B3Ko_8Ah.mjs → _virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-Cul2786X.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-DOcfQnib.mjs → _virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-Duvan2CO.mjs} +1 -1
- package/dist/pipeline-analytics/{hostInit-Be7_ixng.mjs → hostInit-DH-l3-BR.mjs} +2 -2
- package/dist/pipeline-analytics/index.js +519 -41
- package/dist/pipeline-analytics/index.mjs +519 -41
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/package.json +1 -1
|
@@ -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-CsJpPkau.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");
|
|
@@ -48402,6 +48402,7 @@ function startAlarmPanelConvergence(ports) {
|
|
|
48402
48402
|
var NC_ARTIFACT_READ_PREFIX_REF = NC_ARTIFACT_READ_PREFIX;
|
|
48403
48403
|
var TRAINING_EXPORT_PREFIX_REF = "training-export";
|
|
48404
48404
|
var RETRAIN_EXPORT_PREFIX_REF = "retrain-export";
|
|
48405
|
+
var RETRAIN_FRAME_PREFIX_REF = "retrain-frame";
|
|
48405
48406
|
var DEBUG_EXPORT_PREFIX_REF = "debug-export";
|
|
48406
48407
|
var TAPE_EXPORT_PREFIX_REF = "tape-export";
|
|
48407
48408
|
/**
|
|
@@ -48427,6 +48428,13 @@ var PIPELINE_ANALYTICS_PLANE_ACCESS = {
|
|
|
48427
48428
|
/** Every frame behind a marked selection — a corpus, not an item. */
|
|
48428
48429
|
[TRAINING_EXPORT_PREFIX_REF]: "admin",
|
|
48429
48430
|
[RETRAIN_EXPORT_PREFIX_REF]: "admin",
|
|
48431
|
+
/**
|
|
48432
|
+
* One copied retrain frame by its id. `admin`, not `authenticated`: the item
|
|
48433
|
+
* is single, but the cap that served the same bytes (`getRetrainFrameImage`)
|
|
48434
|
+
* is `auth: 'admin'` and the surface is admin curation — widening the bytes
|
|
48435
|
+
* beyond the method they replace would be a policy change nobody asked for.
|
|
48436
|
+
*/
|
|
48437
|
+
[RETRAIN_FRAME_PREFIX_REF]: "admin",
|
|
48430
48438
|
/** Diagnostic bundle: logs, config and frames. */
|
|
48431
48439
|
[DEBUG_EXPORT_PREFIX_REF]: "admin",
|
|
48432
48440
|
/** A promoted tracking tape and its ground truth (D681) — a corpus, not an item. */
|
|
@@ -70955,6 +70963,67 @@ var TrackStore = class {
|
|
|
70955
70963
|
}
|
|
70956
70964
|
};
|
|
70957
70965
|
//#endregion
|
|
70966
|
+
//#region src/pipeline-analytics/retrain/retrain-origin.ts
|
|
70967
|
+
/**
|
|
70968
|
+
* Reading the two JSON columns the review rests on — an annotation's `origin`
|
|
70969
|
+
* and a frame's `dismissed` set — back into typed values.
|
|
70970
|
+
*
|
|
70971
|
+
* Parsed with the cap's own schemas rather than cast: a column written by
|
|
70972
|
+
* something that bypassed the guard reads as "no origin" / "nothing dismissed",
|
|
70973
|
+
* which is the safe direction (a missing snapshot makes a verdict approximate;
|
|
70974
|
+
* it never invents one).
|
|
70975
|
+
*/
|
|
70976
|
+
function parseJsonIfText(value) {
|
|
70977
|
+
if (typeof value !== "string") return value;
|
|
70978
|
+
try {
|
|
70979
|
+
return JSON.parse(value);
|
|
70980
|
+
} catch {
|
|
70981
|
+
return null;
|
|
70982
|
+
}
|
|
70983
|
+
}
|
|
70984
|
+
/** The stored origin snapshot, or `null` (legacy row / unreadable value). */
|
|
70985
|
+
function narrowOrigin(value) {
|
|
70986
|
+
const parsed = require_clip_model_registry.RetrainOriginSchema.safeParse(parseJsonIfText(value));
|
|
70987
|
+
return parsed.success ? parsed.data : null;
|
|
70988
|
+
}
|
|
70989
|
+
/** The stored dismissed set, or an empty list. */
|
|
70990
|
+
function narrowDismissed(value) {
|
|
70991
|
+
const parsed = require_clip_model_registry.RetrainDismissedSchema.array().safeParse(parseJsonIfText(value));
|
|
70992
|
+
return parsed.success ? parsed.data : [];
|
|
70993
|
+
}
|
|
70994
|
+
/**
|
|
70995
|
+
* The stable name of a pipeline box inside its frame. One live track draws one
|
|
70996
|
+
* box on a frame, and the track id survives a re-derivation, which is what lets
|
|
70997
|
+
* a dismissal made today still match tomorrow's list.
|
|
70998
|
+
*/
|
|
70999
|
+
function pipelineOriginRef(trackId) {
|
|
71000
|
+
return `pipeline:${trackId}`;
|
|
71001
|
+
}
|
|
71002
|
+
/** A re-derived pipeline box as the snapshot an annotation or dismissal keeps. */
|
|
71003
|
+
function pipelineBoxOrigin(box) {
|
|
71004
|
+
return {
|
|
71005
|
+
source: "pipeline",
|
|
71006
|
+
ref: pipelineOriginRef(box.trackId),
|
|
71007
|
+
bbox: box.bbox,
|
|
71008
|
+
macroClass: box.macroClass,
|
|
71009
|
+
...box.label !== void 0 ? { label: box.label } : {},
|
|
71010
|
+
...box.score !== void 0 ? { score: box.score } : {},
|
|
71011
|
+
...box.modelId !== void 0 ? { modelId: box.modelId } : {}
|
|
71012
|
+
};
|
|
71013
|
+
}
|
|
71014
|
+
/** The n-th proposal of a detector (`assist`) or vision-LLM (`llm`) run. */
|
|
71015
|
+
function proposalOrigin(source, index, facts) {
|
|
71016
|
+
return {
|
|
71017
|
+
source,
|
|
71018
|
+
ref: `${source}:${String(index)}`,
|
|
71019
|
+
bbox: facts.bbox,
|
|
71020
|
+
macroClass: facts.macroClass,
|
|
71021
|
+
...facts.label !== void 0 ? { label: facts.label } : {},
|
|
71022
|
+
...facts.score !== void 0 ? { score: facts.score } : {},
|
|
71023
|
+
...facts.modelId !== void 0 ? { modelId: facts.modelId } : {}
|
|
71024
|
+
};
|
|
71025
|
+
}
|
|
71026
|
+
//#endregion
|
|
70958
71027
|
//#region src/pipeline-analytics/retrain/retrain-frame-store.ts
|
|
70959
71028
|
/**
|
|
70960
71029
|
* RetrainFrameStore — the COPIES the retrain dataset owns.
|
|
@@ -71124,6 +71193,22 @@ var RETRAIN_FRAME_COLUMNS = [
|
|
|
71124
71193
|
{
|
|
71125
71194
|
name: "epochMs",
|
|
71126
71195
|
type: "INTEGER"
|
|
71196
|
+
}),
|
|
71197
|
+
(
|
|
71198
|
+
/** Bumped by every annotation save; the compare-and-set a save is guarded
|
|
71199
|
+
* by. The column default makes a pre-revision row read `0`. */
|
|
71200
|
+
{
|
|
71201
|
+
name: "revision",
|
|
71202
|
+
type: "INTEGER",
|
|
71203
|
+
notNull: true,
|
|
71204
|
+
defaultValue: 0
|
|
71205
|
+
}),
|
|
71206
|
+
(
|
|
71207
|
+
/** The proposals the operator deleted (`RetrainDismissed[]`), so a deleted
|
|
71208
|
+
* pipeline box is not offered again. NULL = none. */
|
|
71209
|
+
{
|
|
71210
|
+
name: "dismissed",
|
|
71211
|
+
type: "JSON"
|
|
71127
71212
|
})
|
|
71128
71213
|
];
|
|
71129
71214
|
var RETRAIN_FRAME_INDEXES = [
|
|
@@ -71237,7 +71322,9 @@ var RetrainFrameStore = class {
|
|
|
71237
71322
|
...finiteNumber(data["capturedAt"]) !== void 0 ? { capturedAt: finiteNumber(data["capturedAt"]) } : {},
|
|
71238
71323
|
...finiteNumber(data["chromaSpread"]) !== void 0 ? { chromaSpread: finiteNumber(data["chromaSpread"]) } : {},
|
|
71239
71324
|
complete: data["complete"] === true || data["complete"] === 1,
|
|
71240
|
-
...finiteNumber(data["epochMs"]) !== void 0 ? { epochMs: finiteNumber(data["epochMs"]) } : {}
|
|
71325
|
+
...finiteNumber(data["epochMs"]) !== void 0 ? { epochMs: finiteNumber(data["epochMs"]) } : {},
|
|
71326
|
+
revision: finiteNumber(data["revision"]) ?? 0,
|
|
71327
|
+
dismissed: narrowDismissed(data["dismissed"])
|
|
71241
71328
|
};
|
|
71242
71329
|
}
|
|
71243
71330
|
/** The copies with these ids, in the order given; unknown ids are skipped. */
|
|
@@ -80810,7 +80897,7 @@ async function ensureTrackHierarchyMedia(deps, input) {
|
|
|
80810
80897
|
}
|
|
80811
80898
|
//#endregion
|
|
80812
80899
|
//#region src/pipeline-analytics/event-media-handler.ts
|
|
80813
|
-
var CACHE_CONTROL = "public, max-age=31536000, immutable";
|
|
80900
|
+
var CACHE_CONTROL$1 = "public, max-age=31536000, immutable";
|
|
80814
80901
|
/** Default / clamp bounds for the `thumb` variant edge (px). Mirrors
|
|
80815
80902
|
* `shared/frame/square-thumb.ts`; kept here so query parsing stays pure. */
|
|
80816
80903
|
var THUMB_DEFAULT_SIZE = 160;
|
|
@@ -80995,14 +81082,14 @@ function createEventMediaHandler(deps) {
|
|
|
80995
81082
|
if (req.headers["if-none-match"] === etag) {
|
|
80996
81083
|
res.writeHead(304, {
|
|
80997
81084
|
etag,
|
|
80998
|
-
"cache-control": CACHE_CONTROL,
|
|
81085
|
+
"cache-control": CACHE_CONTROL$1,
|
|
80999
81086
|
"server-timing": serverTiming
|
|
81000
81087
|
}).end();
|
|
81001
81088
|
return;
|
|
81002
81089
|
}
|
|
81003
81090
|
res.writeHead(200, {
|
|
81004
81091
|
"content-type": "image/jpeg",
|
|
81005
|
-
"cache-control": CACHE_CONTROL,
|
|
81092
|
+
"cache-control": CACHE_CONTROL$1,
|
|
81006
81093
|
etag,
|
|
81007
81094
|
"content-length": String(media.bytes.byteLength),
|
|
81008
81095
|
"server-timing": serverTiming
|
|
@@ -82932,6 +83019,13 @@ var RETRAIN_ANNOTATION_COLUMNS = [
|
|
|
82932
83019
|
name: "assistScore",
|
|
82933
83020
|
type: "REAL"
|
|
82934
83021
|
},
|
|
83022
|
+
(
|
|
83023
|
+
/** The proposal the box started from (`RetrainOrigin`), snapshotted at
|
|
83024
|
+
* accept time. NULL on a row saved before origins existed. */
|
|
83025
|
+
{
|
|
83026
|
+
name: "origin",
|
|
83027
|
+
type: "JSON"
|
|
83028
|
+
}),
|
|
82935
83029
|
{
|
|
82936
83030
|
name: "exportedInBatch",
|
|
82937
83031
|
type: "TEXT"
|
|
@@ -83015,6 +83109,7 @@ var RetrainAnnotationStore = class {
|
|
|
83015
83109
|
source: narrowSource(data["source"]),
|
|
83016
83110
|
assistModelId: optionalString(data["assistModelId"]),
|
|
83017
83111
|
assistScore: typeof score === "number" ? score : void 0,
|
|
83112
|
+
origin: narrowOrigin(data["origin"]),
|
|
83018
83113
|
exportedInBatch: optionalString(data["exportedInBatch"]),
|
|
83019
83114
|
createdAt: Number(data["createdAt"] ?? 0)
|
|
83020
83115
|
};
|
|
@@ -83032,12 +83127,14 @@ var RetrainAnnotationStore = class {
|
|
|
83032
83127
|
source: a.source,
|
|
83033
83128
|
assistModelId: a.assistModelId ?? null,
|
|
83034
83129
|
assistScore: a.assistScore ?? null,
|
|
83130
|
+
origin: a.origin ?? null,
|
|
83035
83131
|
exportedInBatch: a.exportedInBatch ?? null,
|
|
83036
83132
|
createdAt: a.createdAt
|
|
83037
83133
|
};
|
|
83038
83134
|
}
|
|
83039
83135
|
/**
|
|
83040
|
-
* Replace EVERY annotation on one frame with the supplied set
|
|
83136
|
+
* Replace EVERY annotation on one frame with the supplied set — atomically,
|
|
83137
|
+
* and only if the frame is still at the revision the caller saw.
|
|
83041
83138
|
*
|
|
83042
83139
|
* Whole-frame replacement rather than per-box upsert, deliberately: the unit
|
|
83043
83140
|
* of ground truth is the frame, and "the operator deleted a box" and "the
|
|
@@ -83045,38 +83142,113 @@ var RetrainAnnotationStore = class {
|
|
|
83045
83142
|
* patch API would let a frame keep a box the operator removed on a surface
|
|
83046
83143
|
* that only knew about the boxes it sent.
|
|
83047
83144
|
*
|
|
83145
|
+
* The old rows' deletion, the new rows, the frame's `dismissed` set and its
|
|
83146
|
+
* bumped `revision` are ONE `settingsStore.transact`, guarded by
|
|
83147
|
+
* `commit.fromRevision`: a crash leaves the frame as it was, a concurrent
|
|
83148
|
+
* save leaves one winner and one `conflict` — never a blend, never a frame
|
|
83149
|
+
* blanked between a delete and an insert.
|
|
83150
|
+
*
|
|
83048
83151
|
* Returns the persisted rows so the caller renders ids it can address.
|
|
83049
83152
|
*/
|
|
83050
|
-
async replaceForFrame(mediaKey, drafts) {
|
|
83051
|
-
const existing = await this.listByFrame(mediaKey);
|
|
83153
|
+
async replaceForFrame(mediaKey, drafts, commit) {
|
|
83052
83154
|
const createdAt = this.now();
|
|
83053
83155
|
const rows = drafts.map((d) => ({
|
|
83054
83156
|
...d,
|
|
83157
|
+
origin: d.origin ?? null,
|
|
83055
83158
|
id: this.newId(),
|
|
83056
83159
|
createdAt,
|
|
83057
83160
|
mediaKey
|
|
83058
83161
|
}));
|
|
83059
|
-
|
|
83060
|
-
|
|
83061
|
-
|
|
83062
|
-
|
|
83162
|
+
const nextRevision = commit.fromRevision + 1;
|
|
83163
|
+
const result = await this.store.transact.mutate({
|
|
83164
|
+
guard: {
|
|
83165
|
+
collection: RETRAIN_FRAMES_COLLECTION,
|
|
83166
|
+
key: mediaKey,
|
|
83167
|
+
column: "revision",
|
|
83168
|
+
equals: commit.fromRevision
|
|
83169
|
+
},
|
|
83170
|
+
ops: [
|
|
83171
|
+
{
|
|
83172
|
+
op: "deleteWhere",
|
|
83173
|
+
collection: RETRAIN_ANNOTATIONS_COLLECTION,
|
|
83174
|
+
filter: { where: { mediaKey } }
|
|
83175
|
+
},
|
|
83176
|
+
{
|
|
83177
|
+
op: "insertMany",
|
|
83178
|
+
collection: RETRAIN_ANNOTATIONS_COLLECTION,
|
|
83179
|
+
records: rows.map((row) => ({
|
|
83180
|
+
id: row.id,
|
|
83181
|
+
data: this.toRecord(row)
|
|
83182
|
+
}))
|
|
83183
|
+
},
|
|
83184
|
+
{
|
|
83185
|
+
op: "update",
|
|
83186
|
+
collection: RETRAIN_FRAMES_COLLECTION,
|
|
83187
|
+
id: mediaKey,
|
|
83188
|
+
data: {
|
|
83189
|
+
revision: nextRevision,
|
|
83190
|
+
...commit.dismissed !== void 0 ? { dismissed: [...commit.dismissed] } : {}
|
|
83191
|
+
}
|
|
83192
|
+
}
|
|
83193
|
+
]
|
|
83063
83194
|
});
|
|
83064
|
-
|
|
83065
|
-
|
|
83195
|
+
if (!result.applied) {
|
|
83196
|
+
const current = result.current;
|
|
83197
|
+
return {
|
|
83198
|
+
kind: "conflict",
|
|
83199
|
+
currentRevision: typeof current === "number" ? current : null
|
|
83200
|
+
};
|
|
83201
|
+
}
|
|
83202
|
+
return {
|
|
83203
|
+
kind: "saved",
|
|
83204
|
+
rows,
|
|
83205
|
+
revision: nextRevision
|
|
83206
|
+
};
|
|
83207
|
+
}
|
|
83208
|
+
/**
|
|
83209
|
+
* Set `origin` on rows that have none, in one guarded transaction with a
|
|
83210
|
+
* revision bump. Rows that already carry an origin, or are not on this frame,
|
|
83211
|
+
* are left untouched and not counted. No eligible row ⇒ no write at all.
|
|
83212
|
+
*/
|
|
83213
|
+
async setOrigins(mediaKey, origins, commit) {
|
|
83214
|
+
const eligible = (await this.listByFrame(mediaKey)).filter((row) => !row.origin && origins.has(row.id));
|
|
83215
|
+
if (eligible.length === 0) return {
|
|
83216
|
+
kind: "updated",
|
|
83217
|
+
updated: 0,
|
|
83218
|
+
revision: commit.fromRevision
|
|
83219
|
+
};
|
|
83220
|
+
const nextRevision = commit.fromRevision + 1;
|
|
83221
|
+
const result = await this.store.transact.mutate({
|
|
83222
|
+
guard: {
|
|
83223
|
+
collection: RETRAIN_FRAMES_COLLECTION,
|
|
83224
|
+
key: mediaKey,
|
|
83225
|
+
column: "revision",
|
|
83226
|
+
equals: commit.fromRevision
|
|
83227
|
+
},
|
|
83228
|
+
ops: [...eligible.map((row) => ({
|
|
83229
|
+
op: "update",
|
|
83066
83230
|
collection: RETRAIN_ANNOTATIONS_COLLECTION,
|
|
83067
|
-
|
|
83068
|
-
|
|
83069
|
-
|
|
83070
|
-
|
|
83071
|
-
|
|
83072
|
-
|
|
83073
|
-
|
|
83074
|
-
|
|
83075
|
-
|
|
83076
|
-
|
|
83077
|
-
|
|
83231
|
+
id: row.id,
|
|
83232
|
+
data: { origin: origins.get(row.id) ?? null }
|
|
83233
|
+
})), {
|
|
83234
|
+
op: "update",
|
|
83235
|
+
collection: RETRAIN_FRAMES_COLLECTION,
|
|
83236
|
+
id: mediaKey,
|
|
83237
|
+
data: { revision: nextRevision }
|
|
83238
|
+
}]
|
|
83239
|
+
});
|
|
83240
|
+
if (!result.applied) {
|
|
83241
|
+
const current = result.current;
|
|
83242
|
+
return {
|
|
83243
|
+
kind: "conflict",
|
|
83244
|
+
currentRevision: typeof current === "number" ? current : null
|
|
83245
|
+
};
|
|
83078
83246
|
}
|
|
83079
|
-
return
|
|
83247
|
+
return {
|
|
83248
|
+
kind: "updated",
|
|
83249
|
+
updated: eligible.length,
|
|
83250
|
+
revision: nextRevision
|
|
83251
|
+
};
|
|
83080
83252
|
}
|
|
83081
83253
|
async listByFrame(mediaKey) {
|
|
83082
83254
|
return this.queryWhere({ mediaKey }, `frame ${mediaKey}`);
|
|
@@ -84196,7 +84368,14 @@ var RetrainLlmAssistService = class {
|
|
|
84196
84368
|
profileId: profile.id,
|
|
84197
84369
|
model: answer.model,
|
|
84198
84370
|
leftHouse: leavesHouse,
|
|
84199
|
-
proposals: parsed.objects.map((o) => ({
|
|
84371
|
+
proposals: parsed.objects.map((o, index) => ({
|
|
84372
|
+
origin: proposalOrigin("llm", index, {
|
|
84373
|
+
bbox: o.bbox,
|
|
84374
|
+
macroClass: o.macroClass,
|
|
84375
|
+
...o.label !== void 0 ? { label: o.label } : {},
|
|
84376
|
+
score: o.confidence,
|
|
84377
|
+
modelId: answer.model
|
|
84378
|
+
}),
|
|
84200
84379
|
bbox: o.bbox,
|
|
84201
84380
|
macroClass: o.macroClass,
|
|
84202
84381
|
...o.label !== void 0 ? { label: o.label } : {},
|
|
@@ -84541,6 +84720,87 @@ async function serveRetrainArchive(_req, res, writeArchive) {
|
|
|
84541
84720
|
}
|
|
84542
84721
|
}
|
|
84543
84722
|
//#endregion
|
|
84723
|
+
//#region src/pipeline-analytics/retrain/retrain-frame-handler.ts
|
|
84724
|
+
var RETRAIN_FRAME_PREFIX = "retrain-frame";
|
|
84725
|
+
/** Longest side of a `size=thumb` response. */
|
|
84726
|
+
var RETRAIN_THUMB_MAX_SIDE = 480;
|
|
84727
|
+
var CACHE_CONTROL = "private, max-age=31536000, immutable";
|
|
84728
|
+
/** The path `getRetrainFrameUrl`-style callers compose for a frame. */
|
|
84729
|
+
function retrainFramePath$1(addonId, frameId, size) {
|
|
84730
|
+
return `/addon/${addonId}/${RETRAIN_FRAME_PREFIX}/${encodeURIComponent(frameId)}?size=${size}`;
|
|
84731
|
+
}
|
|
84732
|
+
/** `{ frameId, size }` from the request URL (path after the prefix), or `null`. */
|
|
84733
|
+
function parseRetrainFrameRequest(url) {
|
|
84734
|
+
const queryAt = url.indexOf("?");
|
|
84735
|
+
const rawPath = queryAt === -1 ? url : url.slice(0, queryAt);
|
|
84736
|
+
const query = queryAt === -1 ? "" : url.slice(queryAt + 1);
|
|
84737
|
+
const segment = rawPath.replace(/^\/+/, "");
|
|
84738
|
+
if (segment === "" || segment.includes("/")) return null;
|
|
84739
|
+
let frameId;
|
|
84740
|
+
try {
|
|
84741
|
+
frameId = decodeURIComponent(segment);
|
|
84742
|
+
} catch {
|
|
84743
|
+
return null;
|
|
84744
|
+
}
|
|
84745
|
+
if (frameId === "") return null;
|
|
84746
|
+
const size = new URLSearchParams(query).get("size");
|
|
84747
|
+
if (size !== null && size !== "thumb" && size !== "full") return null;
|
|
84748
|
+
return {
|
|
84749
|
+
frameId,
|
|
84750
|
+
size: size ?? "full"
|
|
84751
|
+
};
|
|
84752
|
+
}
|
|
84753
|
+
function createRetrainFrameHandler(deps) {
|
|
84754
|
+
return async (req, res) => {
|
|
84755
|
+
const method = req.method ?? "GET";
|
|
84756
|
+
if (method !== "GET" && method !== "HEAD") {
|
|
84757
|
+
res.writeHead(405, { allow: "GET, HEAD" });
|
|
84758
|
+
res.end();
|
|
84759
|
+
return;
|
|
84760
|
+
}
|
|
84761
|
+
const request = parseRetrainFrameRequest(req.url ?? "");
|
|
84762
|
+
if (request === null) {
|
|
84763
|
+
res.writeHead(404);
|
|
84764
|
+
res.end();
|
|
84765
|
+
return;
|
|
84766
|
+
}
|
|
84767
|
+
const etag = `"${request.frameId}:${request.size}"`;
|
|
84768
|
+
if (req.headers["if-none-match"] === etag) {
|
|
84769
|
+
res.writeHead(304, {
|
|
84770
|
+
etag,
|
|
84771
|
+
"cache-control": CACHE_CONTROL
|
|
84772
|
+
});
|
|
84773
|
+
res.end();
|
|
84774
|
+
return;
|
|
84775
|
+
}
|
|
84776
|
+
try {
|
|
84777
|
+
const stored = await deps.readFrame(request.frameId);
|
|
84778
|
+
if (stored === null) {
|
|
84779
|
+
res.writeHead(404);
|
|
84780
|
+
res.end();
|
|
84781
|
+
return;
|
|
84782
|
+
}
|
|
84783
|
+
const body = request.size === "thumb" ? await deps.resize(stored, RETRAIN_THUMB_MAX_SIDE) : stored;
|
|
84784
|
+
res.writeHead(200, {
|
|
84785
|
+
"content-type": "image/jpeg",
|
|
84786
|
+
"content-length": String(body.byteLength),
|
|
84787
|
+
"cache-control": CACHE_CONTROL,
|
|
84788
|
+
etag
|
|
84789
|
+
});
|
|
84790
|
+
if (method === "HEAD") res.end();
|
|
84791
|
+
else res.end(body);
|
|
84792
|
+
} catch (err) {
|
|
84793
|
+
deps.logger.warn("retrain frame read failed", { meta: {
|
|
84794
|
+
frameId: request.frameId,
|
|
84795
|
+
size: request.size,
|
|
84796
|
+
error: String(err)
|
|
84797
|
+
} });
|
|
84798
|
+
res.writeHead(500, { "content-type": "text/plain" });
|
|
84799
|
+
res.end("retrain frame read failed");
|
|
84800
|
+
}
|
|
84801
|
+
};
|
|
84802
|
+
}
|
|
84803
|
+
//#endregion
|
|
84544
84804
|
//#region src/pipeline-analytics/retrain/retrain-crop-cut.ts
|
|
84545
84805
|
/**
|
|
84546
84806
|
* The `crops` layout's cutter: one subject crop from a retrain frame copy.
|
|
@@ -84575,6 +84835,15 @@ function retrainCropWindow(input) {
|
|
|
84575
84835
|
height: bottom - top
|
|
84576
84836
|
};
|
|
84577
84837
|
}
|
|
84838
|
+
/** A frame re-encoded to a JPEG whose longest side is at most `maxSide` (grid thumbnails). */
|
|
84839
|
+
async function resizeRetrainJpeg(bytes, maxSide) {
|
|
84840
|
+
return (0, sharp.default)(bytes).resize({
|
|
84841
|
+
width: maxSide,
|
|
84842
|
+
height: maxSide,
|
|
84843
|
+
fit: "inside",
|
|
84844
|
+
withoutEnlargement: true
|
|
84845
|
+
}).jpeg({ quality: 80 }).toBuffer();
|
|
84846
|
+
}
|
|
84578
84847
|
async function cutRetrainCrop(input) {
|
|
84579
84848
|
const window = retrainCropWindow(input);
|
|
84580
84849
|
if (window === null) return null;
|
|
@@ -85677,9 +85946,27 @@ async function restageRetrainTrack(deps, input) {
|
|
|
85677
85946
|
}
|
|
85678
85947
|
//#endregion
|
|
85679
85948
|
//#region src/pipeline-analytics/retrain/retrain-service.ts
|
|
85949
|
+
/**
|
|
85950
|
+
* RetrainService — the bodies behind the eleven `pipelineAnalytics.*Retrain*`
|
|
85951
|
+
* cap methods.
|
|
85952
|
+
*
|
|
85953
|
+
* It exists as a service rather than as eleven more methods on a 7,500-line
|
|
85954
|
+
* addon class for the reason `analytics-query-facade.ts` and `track-flags.ts`
|
|
85955
|
+
* already exist: the interesting parts (the copy ordering, the assist plan, the
|
|
85956
|
+
* lifecycle preconditions) are decidable from injected contracts alone, and a
|
|
85957
|
+
* test that had to boot the addon to reach them would not be written.
|
|
85958
|
+
*
|
|
85959
|
+
* Everything durable lives in two collections and one blob prefix:
|
|
85960
|
+
* `pipeline-analytics:retrain-frames` (the copies),
|
|
85961
|
+
* `pipeline-analytics:retrain-annotations` (the ground truth), and
|
|
85962
|
+
* `retrain/<deviceId>/<trackId>/…` (the pixels). No age sweep and no owner
|
|
85963
|
+
* cascade walks any of them — that is the whole point of copying.
|
|
85964
|
+
*/
|
|
85680
85965
|
/** Default page size for the staging worklist. Staging is bounded at 500 per
|
|
85681
85966
|
* camera (D81), so this is a page, not a ceiling. */
|
|
85682
85967
|
var DEFAULT_STAGING_LIMIT = 100;
|
|
85968
|
+
/** Tries a last-write-wins save gets when it keeps losing the revision race. */
|
|
85969
|
+
var LAST_WRITE_WINS_ATTEMPTS = 3;
|
|
85683
85970
|
/** A macro class that failed validation — the write is refused, never coerced. */
|
|
85684
85971
|
var RetrainAnnotationError = class extends Error {};
|
|
85685
85972
|
/** A store frame on the wire. A recording still carries no track and no
|
|
@@ -85700,7 +85987,31 @@ function toWireFrame(f) {
|
|
|
85700
85987
|
height: f.height,
|
|
85701
85988
|
copiedAt: f.copiedAt,
|
|
85702
85989
|
...f.capturedAt !== void 0 ? { capturedAt: f.capturedAt } : {},
|
|
85703
|
-
complete: f.complete
|
|
85990
|
+
complete: f.complete,
|
|
85991
|
+
revision: f.revision ?? 0,
|
|
85992
|
+
dismissed: f.dismissed ?? []
|
|
85993
|
+
};
|
|
85994
|
+
}
|
|
85995
|
+
/**
|
|
85996
|
+
* What the operator did with the proposals on a frame (`retrain-review.ts`).
|
|
85997
|
+
*
|
|
85998
|
+
* A frame whose rows predate origins is judged against the pipeline boxes
|
|
85999
|
+
* re-derived now, and a proposal nobody kept is reported `removed` — both
|
|
86000
|
+
* flagged approximate. A frame with snapshots is judged on them alone.
|
|
86001
|
+
*/
|
|
86002
|
+
function reviewOfFrame(annotations, pipelineBoxes, dismissed) {
|
|
86003
|
+
const legacy = annotations.some((a) => !a.origin);
|
|
86004
|
+
const review = require_clip_model_registry.classifyRetrainReview(annotations.map((a) => ({
|
|
86005
|
+
id: a.id,
|
|
86006
|
+
bbox: a.bbox,
|
|
86007
|
+
macroClass: a.macroClass,
|
|
86008
|
+
...a.label !== void 0 ? { label: a.label } : {},
|
|
86009
|
+
kind: a.kind,
|
|
86010
|
+
origin: a.origin ?? null
|
|
86011
|
+
})), pipelineBoxes.map(pipelineBoxOrigin), dismissed, { inferRemoved: legacy });
|
|
86012
|
+
return {
|
|
86013
|
+
boxes: review.boxes,
|
|
86014
|
+
summary: require_clip_model_registry.summarizeReview(review)
|
|
85704
86015
|
};
|
|
85705
86016
|
}
|
|
85706
86017
|
function toWireAnnotation(a) {
|
|
@@ -85717,6 +86028,7 @@ function toWireAnnotation(a) {
|
|
|
85717
86028
|
source: a.source,
|
|
85718
86029
|
...a.assistModelId !== void 0 ? { assistModelId: a.assistModelId } : {},
|
|
85719
86030
|
...a.assistScore !== void 0 ? { assistScore: a.assistScore } : {},
|
|
86031
|
+
origin: a.origin ?? null,
|
|
85720
86032
|
...a.exportedInBatch !== void 0 ? { exportedInBatch: a.exportedInBatch } : {},
|
|
85721
86033
|
createdAt: a.createdAt
|
|
85722
86034
|
};
|
|
@@ -85798,16 +86110,24 @@ var RetrainService = class {
|
|
|
85798
86110
|
const evidence = this.deps.pipelineEvidence;
|
|
85799
86111
|
const ownTracks = /* @__PURE__ */ new Map();
|
|
85800
86112
|
const subjectBoxes = /* @__PURE__ */ new Map();
|
|
86113
|
+
const annotationsByFrame = await this.annotationsByFrame(copies);
|
|
85801
86114
|
const out = [];
|
|
85802
86115
|
for (const copy of copies) {
|
|
85803
86116
|
const wire = toWireFrame(copy);
|
|
85804
86117
|
const collectionIds = collections?.get(copy.frameId);
|
|
85805
|
-
const withCollections =
|
|
85806
|
-
...
|
|
85807
|
-
|
|
85808
|
-
|
|
86118
|
+
const withCollections = {
|
|
86119
|
+
...collections !== null ? {
|
|
86120
|
+
...wire,
|
|
86121
|
+
collectionIds: collectionIds ?? []
|
|
86122
|
+
} : wire,
|
|
86123
|
+
...this.frameUrls(copy.frameId)
|
|
86124
|
+
};
|
|
86125
|
+
const reviewOf = (boxes) => reviewOfFrame(annotationsByFrame.get(copy.frameId) ?? [], boxes, copy.dismissed ?? []);
|
|
85809
86126
|
if (evidence === void 0) {
|
|
85810
|
-
out.push(
|
|
86127
|
+
out.push({
|
|
86128
|
+
...withCollections,
|
|
86129
|
+
review: reviewOf([])
|
|
86130
|
+
});
|
|
85811
86131
|
continue;
|
|
85812
86132
|
}
|
|
85813
86133
|
const trackId = copy.origin === "track" ? copy.trackId : "";
|
|
@@ -85828,11 +86148,32 @@ var RetrainService = class {
|
|
|
85828
86148
|
});
|
|
85829
86149
|
out.push({
|
|
85830
86150
|
...withCollections,
|
|
85831
|
-
pipelineBoxes
|
|
86151
|
+
pipelineBoxes,
|
|
86152
|
+
review: reviewOf(pipelineBoxes)
|
|
85832
86153
|
});
|
|
85833
86154
|
}
|
|
85834
86155
|
return out;
|
|
85835
86156
|
}
|
|
86157
|
+
/** The URLs of a frame's pixels, when a data plane is served for them. */
|
|
86158
|
+
frameUrls(frameId) {
|
|
86159
|
+
const frameUrl = this.deps.frameUrl;
|
|
86160
|
+
if (frameUrl === void 0) return {};
|
|
86161
|
+
return {
|
|
86162
|
+
imageUrl: frameUrl(frameId, "full"),
|
|
86163
|
+
thumbnailUrl: frameUrl(frameId, "thumb")
|
|
86164
|
+
};
|
|
86165
|
+
}
|
|
86166
|
+
/** The saved annotations of these frames, grouped by frame. */
|
|
86167
|
+
async annotationsByFrame(copies) {
|
|
86168
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
86169
|
+
if (copies.length === 0) return grouped;
|
|
86170
|
+
for (const a of await this.deps.annotations.listByFrames(copies.map((c) => c.frameId))) {
|
|
86171
|
+
const list = grouped.get(a.mediaKey);
|
|
86172
|
+
if (list === void 0) grouped.set(a.mediaKey, [a]);
|
|
86173
|
+
else list.push(a);
|
|
86174
|
+
}
|
|
86175
|
+
return grouped;
|
|
86176
|
+
}
|
|
85836
86177
|
/**
|
|
85837
86178
|
* The frame a frame-scoped call names, or a refusal. The frame is the
|
|
85838
86179
|
* authority: its camera must be the caller's, and a `trackId`, when the
|
|
@@ -85919,7 +86260,10 @@ var RetrainService = class {
|
|
|
85919
86260
|
sourceKind: kindOf.get(mediaId) ?? "keyFrame",
|
|
85920
86261
|
...capturedAtOf.has(mediaId) ? { capturedAt: capturedAtOf.get(mediaId) } : {}
|
|
85921
86262
|
});
|
|
85922
|
-
if (result.kind === "copied") copied.push(
|
|
86263
|
+
if (result.kind === "copied") copied.push({
|
|
86264
|
+
...toWireFrame(result.frame),
|
|
86265
|
+
...this.frameUrls(result.frame.frameId)
|
|
86266
|
+
});
|
|
85923
86267
|
else refused.push({
|
|
85924
86268
|
sourceMediaId: result.sourceMediaId,
|
|
85925
86269
|
reason: result.reason
|
|
@@ -85946,7 +86290,10 @@ var RetrainService = class {
|
|
|
85946
86290
|
complete: input.complete
|
|
85947
86291
|
}
|
|
85948
86292
|
});
|
|
85949
|
-
return
|
|
86293
|
+
return {
|
|
86294
|
+
...toWireFrame(updated),
|
|
86295
|
+
...this.frameUrls(updated.frameId)
|
|
86296
|
+
};
|
|
85950
86297
|
}
|
|
85951
86298
|
/** Un-select: annotations first, then the copy. Never the other way round —
|
|
85952
86299
|
* an annotation whose frame is gone is unopenable and unfixable. The frame's
|
|
@@ -86087,9 +86434,16 @@ var RetrainService = class {
|
|
|
86087
86434
|
modelId: result.modelId,
|
|
86088
86435
|
stepId: plan.stepId,
|
|
86089
86436
|
minScore: plan.minScore,
|
|
86090
|
-
proposals: mapping.proposals.map((p) => {
|
|
86437
|
+
proposals: mapping.proposals.map((p, index) => {
|
|
86091
86438
|
const draft = proposalToDraft(p, owner);
|
|
86092
86439
|
return {
|
|
86440
|
+
origin: proposalOrigin("assist", index, {
|
|
86441
|
+
bbox: draft.bbox,
|
|
86442
|
+
macroClass: draft.macroClass,
|
|
86443
|
+
...draft.label !== void 0 ? { label: draft.label } : {},
|
|
86444
|
+
...draft.assistScore !== void 0 ? { score: draft.assistScore } : {},
|
|
86445
|
+
...draft.assistModelId !== void 0 ? { modelId: draft.assistModelId } : {}
|
|
86446
|
+
}),
|
|
86093
86447
|
bbox: draft.bbox,
|
|
86094
86448
|
macroClass: draft.macroClass,
|
|
86095
86449
|
...draft.label !== void 0 ? { label: draft.label } : {},
|
|
@@ -86136,9 +86490,12 @@ var RetrainService = class {
|
|
|
86136
86490
|
kind: a.kind,
|
|
86137
86491
|
source: a.source,
|
|
86138
86492
|
...a.assistModelId !== void 0 ? { assistModelId: a.assistModelId } : {},
|
|
86139
|
-
...a.assistScore !== void 0 ? { assistScore: a.assistScore } : {}
|
|
86493
|
+
...a.assistScore !== void 0 ? { assistScore: a.assistScore } : {},
|
|
86494
|
+
origin: a.origin ?? null
|
|
86140
86495
|
}));
|
|
86141
|
-
const
|
|
86496
|
+
const keptRefs = new Set(drafts.flatMap((d) => d.origin ? [d.origin.ref] : []));
|
|
86497
|
+
const dismissed = input.dismissed !== void 0 ? input.dismissed.filter((d) => !keptRefs.has(d.ref)) : void 0;
|
|
86498
|
+
const saved = await this.replaceGuarded(frame, input, drafts, dismissed);
|
|
86142
86499
|
const errors = saved.filter((a) => a.kind === "model_error").length;
|
|
86143
86500
|
this.deps.logger.info("retrain annotations saved", {
|
|
86144
86501
|
tags: { deviceId: input.deviceId },
|
|
@@ -86147,12 +86504,99 @@ var RetrainService = class {
|
|
|
86147
86504
|
trackId: frame.trackId,
|
|
86148
86505
|
frameId: input.frameId,
|
|
86149
86506
|
subjects: saved.length - errors,
|
|
86150
|
-
modelErrors: errors
|
|
86507
|
+
modelErrors: errors,
|
|
86508
|
+
dismissed: dismissed?.length
|
|
86151
86509
|
}
|
|
86152
86510
|
});
|
|
86153
86511
|
return saved.map(toWireAnnotation);
|
|
86154
86512
|
}
|
|
86155
86513
|
/**
|
|
86514
|
+
* The guarded replace. A caller that names the revision it saw gets exactly
|
|
86515
|
+
* one attempt: a different current revision is a conflict, never a retry —
|
|
86516
|
+
* the point is that it must look again. A caller that names none asked for
|
|
86517
|
+
* last-write-wins, so a race lost between our read and the transaction is
|
|
86518
|
+
* retried on the fresh revision, a bounded number of times.
|
|
86519
|
+
*/
|
|
86520
|
+
async replaceGuarded(frame, input, drafts, dismissed) {
|
|
86521
|
+
return await this.underRevision(frame, input, async (revision) => {
|
|
86522
|
+
const result = await this.deps.annotations.replaceForFrame(input.frameId, drafts, {
|
|
86523
|
+
fromRevision: revision,
|
|
86524
|
+
...dismissed !== void 0 ? { dismissed } : {}
|
|
86525
|
+
});
|
|
86526
|
+
return result.kind === "saved" ? {
|
|
86527
|
+
kind: "done",
|
|
86528
|
+
value: result.rows
|
|
86529
|
+
} : {
|
|
86530
|
+
kind: "conflict",
|
|
86531
|
+
currentRevision: result.currentRevision
|
|
86532
|
+
};
|
|
86533
|
+
});
|
|
86534
|
+
}
|
|
86535
|
+
/**
|
|
86536
|
+
* Run one revision-guarded write. `attempt` is handed the revision to guard
|
|
86537
|
+
* on and reports `done` or `conflict` (the frame moved; `null` = it is gone).
|
|
86538
|
+
*/
|
|
86539
|
+
async underRevision(frame, input, attempt) {
|
|
86540
|
+
let revision = frame.revision ?? 0;
|
|
86541
|
+
for (let tries = 0; tries < LAST_WRITE_WINS_ATTEMPTS; tries += 1) {
|
|
86542
|
+
if (input.expectedRevision !== void 0 && input.expectedRevision !== revision) this.refuseStale(input, revision, input.expectedRevision);
|
|
86543
|
+
const result = await attempt(revision);
|
|
86544
|
+
if (result.kind === "done") return result.value;
|
|
86545
|
+
if (result.currentRevision === null) throw new RetrainAnnotationError(`retrain frame ${input.frameId} vanished`);
|
|
86546
|
+
revision = result.currentRevision;
|
|
86547
|
+
if (input.expectedRevision !== void 0) this.refuseStale(input, revision, input.expectedRevision);
|
|
86548
|
+
}
|
|
86549
|
+
throw new RetrainAnnotationError(`retrain frame ${input.frameId} kept changing under the save — try again`);
|
|
86550
|
+
}
|
|
86551
|
+
/**
|
|
86552
|
+
* Give rows saved before origins existed the origin a caller reconstructed
|
|
86553
|
+
* for them — and touch nothing else (ids, creation time and the export stamp
|
|
86554
|
+
* of the row stay). Only rows that have NO origin yet are written; a row that
|
|
86555
|
+
* already has one is skipped, because a snapshot taken at accept time is
|
|
86556
|
+
* evidence and a reconstruction must never overwrite it.
|
|
86557
|
+
*/
|
|
86558
|
+
async backfillOrigins(input) {
|
|
86559
|
+
const frame = await this.requireFrame(input, "backfill-origins");
|
|
86560
|
+
const wanted = new Map(input.origins.map((o) => [o.annotationId, o.origin]));
|
|
86561
|
+
const result = await this.underRevision(frame, input, async (revision) => {
|
|
86562
|
+
const outcome = await this.deps.annotations.setOrigins(input.frameId, wanted, { fromRevision: revision });
|
|
86563
|
+
return outcome.kind === "updated" ? {
|
|
86564
|
+
kind: "done",
|
|
86565
|
+
value: outcome
|
|
86566
|
+
} : {
|
|
86567
|
+
kind: "conflict",
|
|
86568
|
+
currentRevision: outcome.currentRevision
|
|
86569
|
+
};
|
|
86570
|
+
});
|
|
86571
|
+
this.deps.logger.info("retrain origins backfilled", {
|
|
86572
|
+
tags: { deviceId: input.deviceId },
|
|
86573
|
+
meta: {
|
|
86574
|
+
frameId: input.frameId,
|
|
86575
|
+
updated: result.updated,
|
|
86576
|
+
skipped: input.origins.length - result.updated
|
|
86577
|
+
}
|
|
86578
|
+
});
|
|
86579
|
+
return {
|
|
86580
|
+
updated: result.updated,
|
|
86581
|
+
skipped: input.origins.length - result.updated,
|
|
86582
|
+
revision: result.revision
|
|
86583
|
+
};
|
|
86584
|
+
}
|
|
86585
|
+
refuseStale(input, current, expected) {
|
|
86586
|
+
this.deps.logger.warn("retrain annotations save refused — the frame moved on", {
|
|
86587
|
+
tags: { deviceId: input.deviceId },
|
|
86588
|
+
meta: {
|
|
86589
|
+
frameId: input.frameId,
|
|
86590
|
+
currentRevision: current,
|
|
86591
|
+
expectedRevision: expected
|
|
86592
|
+
}
|
|
86593
|
+
});
|
|
86594
|
+
throw new RetrainAnnotationError(require_clip_model_registry.retrainRevisionConflictMessage(input.frameId, {
|
|
86595
|
+
currentRevision: current,
|
|
86596
|
+
expectedRevision: expected
|
|
86597
|
+
}));
|
|
86598
|
+
}
|
|
86599
|
+
/**
|
|
86156
86600
|
* Paginated corpus list for the Frames grid. Index reads only — copies,
|
|
86157
86601
|
* annotation counts/classes, collection membership; no JPEG.
|
|
86158
86602
|
*/
|
|
@@ -111351,6 +111795,8 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
111351
111795
|
trainingExportDataPlane = null;
|
|
111352
111796
|
/** Handle for the retrain-export data-plane listener (dispose on shutdown). */
|
|
111353
111797
|
retrainExportDataPlane = null;
|
|
111798
|
+
/** Handle for the retrain-frame data-plane listener (dispose on shutdown). */
|
|
111799
|
+
retrainFrameDataPlane = null;
|
|
111354
111800
|
/** Handle for the debug-export data-plane listener (dispose on shutdown). */
|
|
111355
111801
|
debugExportDataPlane = null;
|
|
111356
111802
|
/** Handle for the tape-export data-plane listener (dispose on shutdown). */
|
|
@@ -113448,7 +113894,8 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
113448
113894
|
}),
|
|
113449
113895
|
subjectBoxes: (trackId, deviceId) => mediaStore.listSubjectBoxesByOwner("track", trackId, deviceId)
|
|
113450
113896
|
},
|
|
113451
|
-
memberships: retrainCollectionStore
|
|
113897
|
+
memberships: retrainCollectionStore,
|
|
113898
|
+
frameUrl: (frameId, size) => retrainFramePath$1(this.ctx.id, frameId, size)
|
|
113452
113899
|
});
|
|
113453
113900
|
this.retrain = retrain;
|
|
113454
113901
|
const retrainStills = new RecordedStillService(buildRecordedStillPorts({
|
|
@@ -114552,6 +114999,7 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
114552
114999
|
await this.serveNcArtifactPlane();
|
|
114553
115000
|
await this.serveTrainingExportPlane();
|
|
114554
115001
|
await this.serveRetrainExportPlane();
|
|
115002
|
+
await this.serveRetrainFramePlane();
|
|
114555
115003
|
await this.serveDebugExportPlane();
|
|
114556
115004
|
await this.serveTapeExportPlane();
|
|
114557
115005
|
this.ctx.logger.info("event-media data-plane served", { meta: {
|
|
@@ -114703,6 +115151,9 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
114703
115151
|
async saveRetrainAnnotations(input) {
|
|
114704
115152
|
return this.requireRetrain().saveAnnotations(input);
|
|
114705
115153
|
}
|
|
115154
|
+
async backfillRetrainOrigins(input) {
|
|
115155
|
+
return this.requireRetrain().backfillOrigins(input);
|
|
115156
|
+
}
|
|
114706
115157
|
async completeRetrainTrack(input) {
|
|
114707
115158
|
return this.requireRetrain().complete(input);
|
|
114708
115159
|
}
|
|
@@ -115183,6 +115634,31 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
115183
115634
|
}
|
|
115184
115635
|
}
|
|
115185
115636
|
/**
|
|
115637
|
+
* The retrain-frame data plane: one copied frame's JPEG (`?size=thumb|full`).
|
|
115638
|
+
* Admin-only like the cap that used to serve it as base64 (D613).
|
|
115639
|
+
*/
|
|
115640
|
+
async serveRetrainFramePlane() {
|
|
115641
|
+
try {
|
|
115642
|
+
const handler = createRetrainFrameHandler({
|
|
115643
|
+
readFrame: async (frameId) => {
|
|
115644
|
+
const frames = this.retrainFrames;
|
|
115645
|
+
if (frames === null) return null;
|
|
115646
|
+
const frame = await frames.get(frameId);
|
|
115647
|
+
return frame === null ? null : frames.readFrame(frame);
|
|
115648
|
+
},
|
|
115649
|
+
resize: resizeRetrainJpeg,
|
|
115650
|
+
logger: this.ctx.logger
|
|
115651
|
+
});
|
|
115652
|
+
this.retrainFrameDataPlane = await this.ctx.dataPlane?.serve({
|
|
115653
|
+
prefix: RETRAIN_FRAME_PREFIX,
|
|
115654
|
+
access: planeAccess("retrain-frame"),
|
|
115655
|
+
handler
|
|
115656
|
+
}) ?? null;
|
|
115657
|
+
} catch (err) {
|
|
115658
|
+
this.ctx.logger.warn("retrain-frame data-plane failed to serve", { meta: { error: require_clip_model_registry.errMsg(err) } });
|
|
115659
|
+
}
|
|
115660
|
+
}
|
|
115661
|
+
/**
|
|
115186
115662
|
* Plan the annotated export — INDEX READS ONLY, no blob touched.
|
|
115187
115663
|
*
|
|
115188
115664
|
* The zone used for the `zoneCrop` derivation is the bounding box of the
|
|
@@ -115964,6 +116440,8 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends require_clip_m
|
|
|
115964
116440
|
this.trainingExportDataPlane = null;
|
|
115965
116441
|
await this.retrainExportDataPlane?.dispose();
|
|
115966
116442
|
this.retrainExportDataPlane = null;
|
|
116443
|
+
await this.retrainFrameDataPlane?.dispose();
|
|
116444
|
+
this.retrainFrameDataPlane = null;
|
|
115967
116445
|
await this.debugExportDataPlane?.dispose();
|
|
115968
116446
|
this.debugExportDataPlane = null;
|
|
115969
116447
|
await this.tapeExportDataPlane?.dispose();
|