@camstack/addon-post-analysis 1.2.347 → 1.2.349
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-BftmbgcV.mjs → clip-model-registry-CC-BJYiK.mjs} +1786 -148
- package/dist/{clip-model-registry--UsI8Ud4.js → clip-model-registry-DI12tTgY.js} +1786 -148
- 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-DuQPp3dT.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-BYsMflvm.mjs} +3 -3
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-Du_tzgi2.mjs +26 -0
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-CQOJKiwa.mjs +26 -0
- package/dist/pipeline-analytics/{hostInit-BDQ6oQ7b.mjs → hostInit-Cpi67Icm.mjs} +3 -3
- package/dist/pipeline-analytics/index.js +575 -259
- package/dist/pipeline-analytics/index.mjs +575 -259
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/package.json +1 -1
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-4Fu7jNn9.mjs +0 -26
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-D5IzYeGQ.mjs +0 -26
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as NC_ALARM_DEFAULT_PROFILE_ID, $r as subKindsOf, $t as RECORDING_EXPORT_MAX_READ_BYTES, A as DetectionSourceSchema, Ai as boolean, An as applyBlockingEdit, At as NcConditionsSchema, B as FailureCounters, Bi as templateLiteral, Bn as consumableLowPercentOf, Br as resolveModeNotifyPolicy, Bt as NcSharedSequenceSchema, C as CoverStateSchema, Ci as isDeviceScopedCap, Cn as TrackRelationSchema, Cr as isVectorIndexDimConflict, Ct as NC_TEMPLATE_VARS, D as DETECTION_MACRO_CLASSES, Di as ZodObject, Dn as addonWidgetsSourceCapability, Dr as memoizePinnedFfmpeg, Dt as NcAlarmSensorsSchema, E as DEFAULT_TIMELAPSE_PREVIEW_TEXT, Ei as sleep$1, En as activateAlarmProfile, Er as mayWriteToLocation, Et as NcAlarmSensorsInputSchema, F as EVENT_KIND_BY_CAP, Fi as object, Fn as audioMetricsCapability, Fr as readTimelapseGeneratedAt, Ft as NcRulePatchSchema, G as MAX_ARCHIVED_DEBUG_NOTES, Gn as deriveDetailCropRect, Gr as ruleDeviceCompatCapQueries, Gt as NcSystemEventKindSchema, H as ListTrackRelationsInputSchema, Hi as union, Hn as cosineSimilarity$1, Hr as rootSupplyServes, Ht as NcSnoozeSchema, I as EVENT_OWNER_TYPES, Ii as partialRecord, In as audioModeOf, Ir as renameAlarmProfile, It as NcRuleSchema, J as MAX_TRACK_PURITIES, Jn as describeSystemEventDeliveryProblem, Jr as sceneMonitorCapability, Jt as NcTemplatePreviewSchema, K as MAX_BIRTH_DECISION_RECORDS, Kn as derivePostTriggeredAction, Kr as ruleGroupingApplies, Kt as NcTaxonomySchema, L as EXPORT_DENSE_MAX_RANGES, Li as record, Ln as buildEventKindDescriptor, Lr as resolveClipSearchMinScore, Lt as NcRuleTargetSchema, M as EMBEDDING_REQUIREMENTS_FAILED, Mi as literal, Mn as applyNonBlockingEdit, Mr as plateGalleryCapability, Mt as NcRuleActionSchema, N as EMBEDDING_REQUIREMENTS_UNAVAILABLE, Ni as looseObject, Nn as applySecureOnArmEdit, Nr as readDeviceStateFrom, Nt as NcRuleActionsSchema, O as DETECTION_PIPELINE_CAP_NAME, Oi as _enum, On as alarmDeviceSecureOnArm, Or as notificationRulesCapability, Ot as NcAlarmSettingsPatchSchema, P as EVENT_DENSITY_BATCH_MAX, Pi as number, Pn as assertTimelapseCadences, Pr as readMotionTriggeredBy, Pt as NcRuleInputSchema, Q as MotionTriggeredBySchema, Qn as embeddingRefusalOf, Qr as storageOccupancyCapability, R as FIRST_LEVEL_MACRO_CLASSES, Ri as strictObject, Rn as buildViewerLink, Rr as resolveLocationMode, Rt as NcRuleUpdateInputSchema, S as ClearTrackRelationResultSchema, Si as hydrateSchema, Sn as TrackRelationKindSchema, Sr as isSystemEventSummaryRule, St as NC_TAXONOMY, T as DEFAULT_EVENT_COLOR, Tn as TrackSourceSchema, Tr as linkedStepOf, Tt as NcAlarmPostTriggeredActionSchema, U as ListTrackRelationsResultSchema, Ui as unknown, Un as createAlarmProfile, Ur as ruleAutoTriggersAlarm, Ut as NcSnoozeSuppressedSchema, V as LabelAttributionSchema, Vi as tuple, Vn as coreBlockIdFromAddonId, Vt as NcSnoozeInputSchema, W as LockStateSchema, Wi as EventCategory, Wn as deleteAlarmProfile, Wr as ruleBelongsToAlarm$1, Wt as NcStateSummarySectionIdSchema, X as MOTION_CLOSE_AFTER_MS, Xr as sensorRaisedOf, Xt as OPS_LOG_DEFAULT_LIMIT, Y as MAX_TRACK_RELATIONS, Yn as describeSystemEventFamilyProblem, Yr as secureActuationFor, Yt as NcTemplateVarDescriptorSchema, Z as MediaFileKindEnum, Zr as servedTemplateVars, Zt as OpsLogEntrySchema, _ as BIRTH_DECISION_DEFAULT_LIMIT, _i as BaseAddon, _n as TRACK_RELATIONS_DEFAULT_LIMIT, _r as isMediaOwnerType, _t as NC_GROUPING_MIN_SEC, a as CLIP_EMBEDDING_STEP_ID, ai as systemEventSummarySplitOf, an as SCENE_DEFAULT_ANCHOR_THRESHOLD, ar as faceGalleryCapability, at as NC_ALARM_TRIGGERED_MAX_SEC, b as COCO_TO_MACRO, bi as customAction, bn as TimelapseRuleSchema, br as isScheduleActive, bt as NC_SYSTEM_EVENT_KIND_GROUP_SPECS, c as resolveClusterModelPin, ci as vectorDimFromBase64, cn as SCENE_DEFAULT_QUIET_SECONDS, cr as gifFromMp4Args, ct as NC_CLIP_POST_ROLL_DEFAULT_SEC, d as APPEARANCE_BLOCKS, di as DEFAULT_FIRST_SIGHTING_FRESHNESS_MS, dn as SCENE_RESET_RECAPTURES, dr as isAudioClassName, dt as NC_CONDITION_CATALOG, ei as syncActiveAlarmProfileSettings, en as RECORDING_SOURCE_CAMSTACK_ADDON, et as NC_ALARM_DEFAULT_TRIGGERED_DURATION_SEC, f as APPEARANCE_RESOLVES_AMBIGUITY_DEFAULT, fi as canonicalHash, fn as SceneMonitorSchema, fr as isDefaultAlarmProfileId, ft as NC_CONSUMABLE_LOW_PERCENT_DEFAULT, g as ArchivedDebugNoteSchema, gi as errMsg, gn as TIMELAPSE_DENSE_FLOOR_SEC, gr as isKnownTemplateVar, gt as NC_GROUPING_MAX_SEC, h as AlarmArmModeSchema, hi as DeviceType, hn as SetTrackRelationInputSchema, hr as isEventOwnerType, ht as NC_GROUPING_DEFAULT_SEC, ii as systemEventSummaryScheduleOf, in as SCENE_CONFIRM_DEFAULT_TIMEOUT_MS, ir as evictionPolicyOfLocation, it as NC_ALARM_SYSTEM_EVENT_KINDS, j as EMBEDDING_MODEL_FAILED, ji as discriminatedUnion, jn as applyModeDelaysEdits, jr as pipelineAnalyticsCapability, jt as NcLegacyRuleActionSequenceSchema, k as DeclaredDevices, ki as array, kn as alarmPanelCapability, kr as occupancyScope, kt as NcConditionDescriptorSchema, l as ALL_CAPABILITY_DEFINITIONS, li as viewerLinkBaseOf, ln as SCENE_DEFAULT_UNCOVERED_POLICY, lr as isAlarmControllableCap, lt as NC_CLIP_PRE_ROLL_DEFAULT_SEC, m as AUDIO_MACRO_LABELS, mi as isSourceCap, mn as SetTrackPurityResultSchema, mr as isEventKindLabelKey, mt as NC_DEFAULT_SNOOZE_MINUTES, ni as systemEventFamilyProblems, nn as RetrainStatusSchema, nr as ensureAlarmProfiles, nt as NC_ALARM_DELAY_MAX_SEC, o as FACE_EMBEDDING_STEP_ID, oi as templateCarriesSummary, on as SCENE_DEFAULT_CHECK_INTERVAL_SEC, or as failureContributionCapability, ot as NC_AUDIO_CONFIRM_HITS_DEFAULT, p as ARCHIVED_DEBUG_NOTES_DEFAULT_LIMIT, pi as evaluateSensorEdge, pn as SetTrackPurityInputSchema, pr as isDetectionMacroClass, pt as NC_CONSUMABLE_SYSTEM_EVENT_KINDS, q as MAX_BIRTH_LATENCY_PROXY_MS, qn as deriveRecordingMode, qr as ruleKindOf, qt as NcTemplatePreviewInputSchema, ri as systemEventFilterApplies, rn as SCENE_CONFIRM_DEFAULT_MAX_IMAGE_PX, rr as eventKindLabel, rt as NC_ALARM_NOTIFY_FIELDS, s as readClusterModelPinStrict, si as templateVarsFor, sn as SCENE_DEFAULT_OBSERVATION_SPACING_SEC, sr as gifDeriveSpeed, st as NC_AUDIO_CONFIRM_WINDOW_SEC_DEFAULT, t as BUILTIN_CLIP_MODELS, ti as systemEventDeliveryProblems, tn as RebuildObjectEmbeddingsRefusalSchema, tr as encodeVectorBase64, tt as NC_ALARM_DELAY_FIELDS, u as APPEARANCE_BIN_COUNT, ui as zoneAnalyticsCapability, un as SCENE_DIVERGED, ur as isAppLinkBase, ut as NC_CLIP_RETENTION_MAX_SEC, v as BaseDevice, vi as CamProfileSchema, vn as TimelapseRuleInputSchema, vr as isRetiredClearKey, vt as NC_SENSOR_TRANSITION_KINDS, w as DEFAULT_DETAIL_CROP_CONVENTION, wi as nodePin, wn as TrackSideSchema, wr as kebabToCamel, wt as NcAlarmConfigSchema, x as ClearTrackRelationInputSchema, xi as defineCustomActions, xn as TrackPuritySchema, xr as isSystemDelivery, xt as NC_TANK_SYSTEM_EVENT_KINDS, y as BirthDecisionRecordSchema, yi as createEvent, yn as TimelapseRulePatchSchema, yr as isRootSuppliableStepId, yt as NC_SNOOZE_MAX_MINUTES, z as FULL_IMAGE_BBOX, zi as string, zn as cloneAlarmSettings, zr as resolveModeDelays, zt as NcScheduleSchema } from "../clip-model-registry-
|
|
1
|
+
import { $ as NC_ALARM_DEFAULT_PROFILE_ID, $r as subKindsOf, $t as RECORDING_EXPORT_MAX_READ_BYTES, A as DetectionSourceSchema, Ai as boolean, An as applyBlockingEdit, At as NcConditionsSchema, B as FailureCounters, Bi as templateLiteral, Bn as consumableLowPercentOf, Br as resolveModeNotifyPolicy, Bt as NcSharedSequenceSchema, C as CoverStateSchema, Ci as isDeviceScopedCap, Cn as TrackRelationSchema, Cr as isVectorIndexDimConflict, Ct as NC_TEMPLATE_VARS, D as DETECTION_MACRO_CLASSES, Di as ZodObject, Dn as addonWidgetsSourceCapability, Dr as memoizePinnedFfmpeg, Dt as NcAlarmSensorsSchema, E as DEFAULT_TIMELAPSE_PREVIEW_TEXT, Ei as sleep$1, En as activateAlarmProfile, Er as mayWriteToLocation, Et as NcAlarmSensorsInputSchema, F as EVENT_KIND_BY_CAP, Fi as object, Fn as audioMetricsCapability, Fr as readTimelapseGeneratedAt, Ft as NcRulePatchSchema, G as MAX_ARCHIVED_DEBUG_NOTES, Gn as deriveDetailCropRect, Gr as ruleDeviceCompatCapQueries, Gt as NcSystemEventKindSchema, H as ListTrackRelationsInputSchema, Hi as union, Hn as cosineSimilarity$1, Hr as rootSupplyServes, Ht as NcSnoozeSchema, I as EVENT_OWNER_TYPES, Ii as partialRecord, In as audioModeOf, Ir as renameAlarmProfile, It as NcRuleSchema, J as MAX_TRACK_PURITIES, Jn as describeSystemEventDeliveryProblem, Jr as sceneMonitorCapability, Jt as NcTemplatePreviewSchema, K as MAX_BIRTH_DECISION_RECORDS, Kn as derivePostTriggeredAction, Kr as ruleGroupingApplies, Kt as NcTaxonomySchema, L as EXPORT_DENSE_MAX_RANGES, Li as record, Ln as buildEventKindDescriptor, Lr as resolveClipSearchMinScore, Lt as NcRuleTargetSchema, M as EMBEDDING_REQUIREMENTS_FAILED, Mi as literal, Mn as applyNonBlockingEdit, Mr as plateGalleryCapability, Mt as NcRuleActionSchema, N as EMBEDDING_REQUIREMENTS_UNAVAILABLE, Ni as looseObject, Nn as applySecureOnArmEdit, Nr as readDeviceStateFrom, Nt as NcRuleActionsSchema, O as DETECTION_PIPELINE_CAP_NAME, Oi as _enum, On as alarmDeviceSecureOnArm, Or as notificationRulesCapability, Ot as NcAlarmSettingsPatchSchema, P as EVENT_DENSITY_BATCH_MAX, Pi as number, Pn as assertTimelapseCadences, Pr as readMotionTriggeredBy, Pt as NcRuleInputSchema, Q as MotionTriggeredBySchema, Qn as embeddingRefusalOf, Qr as storageOccupancyCapability, R as FIRST_LEVEL_MACRO_CLASSES, Ri as strictObject, Rn as buildViewerLink, Rr as resolveLocationMode, Rt as NcRuleUpdateInputSchema, S as ClearTrackRelationResultSchema, Si as hydrateSchema, Sn as TrackRelationKindSchema, Sr as isSystemEventSummaryRule, St as NC_TAXONOMY, T as DEFAULT_EVENT_COLOR, Tn as TrackSourceSchema, Tr as linkedStepOf, Tt as NcAlarmPostTriggeredActionSchema, U as ListTrackRelationsResultSchema, Ui as unknown, Un as createAlarmProfile, Ur as ruleAutoTriggersAlarm, Ut as NcSnoozeSuppressedSchema, V as LabelAttributionSchema, Vi as tuple, Vn as coreBlockIdFromAddonId, Vt as NcSnoozeInputSchema, W as LockStateSchema, Wi as EventCategory, Wn as deleteAlarmProfile, Wr as ruleBelongsToAlarm$1, Wt as NcStateSummarySectionIdSchema, X as MOTION_CLOSE_AFTER_MS, Xr as sensorRaisedOf, Xt as OPS_LOG_DEFAULT_LIMIT, Y as MAX_TRACK_RELATIONS, Yn as describeSystemEventFamilyProblem, Yr as secureActuationFor, Yt as NcTemplateVarDescriptorSchema, Z as MediaFileKindEnum, Zr as servedTemplateVars, Zt as OpsLogEntrySchema, _ as BIRTH_DECISION_DEFAULT_LIMIT, _i as BaseAddon, _n as TRACK_RELATIONS_DEFAULT_LIMIT, _r as isMediaOwnerType, _t as NC_GROUPING_MIN_SEC, a as CLIP_EMBEDDING_STEP_ID, ai as systemEventSummarySplitOf, an as SCENE_DEFAULT_ANCHOR_THRESHOLD, ar as faceGalleryCapability, at as NC_ALARM_TRIGGERED_MAX_SEC, b as COCO_TO_MACRO, bi as customAction, bn as TimelapseRuleSchema, br as isScheduleActive, bt as NC_SYSTEM_EVENT_KIND_GROUP_SPECS, c as resolveClusterModelPin, ci as vectorDimFromBase64, cn as SCENE_DEFAULT_QUIET_SECONDS, cr as gifFromMp4Args, ct as NC_CLIP_POST_ROLL_DEFAULT_SEC, d as APPEARANCE_BLOCKS, di as DEFAULT_FIRST_SIGHTING_FRESHNESS_MS, dn as SCENE_RESET_RECAPTURES, dr as isAudioClassName, dt as NC_CONDITION_CATALOG, ei as syncActiveAlarmProfileSettings, en as RECORDING_SOURCE_CAMSTACK_ADDON, et as NC_ALARM_DEFAULT_TRIGGERED_DURATION_SEC, f as APPEARANCE_RESOLVES_AMBIGUITY_DEFAULT, fi as canonicalHash, fn as SceneMonitorSchema, fr as isDefaultAlarmProfileId, ft as NC_CONSUMABLE_LOW_PERCENT_DEFAULT, g as ArchivedDebugNoteSchema, gi as errMsg, gn as TIMELAPSE_DENSE_FLOOR_SEC, gr as isKnownTemplateVar, gt as NC_GROUPING_MAX_SEC, h as AlarmArmModeSchema, hi as DeviceType, hn as SetTrackRelationInputSchema, hr as isEventOwnerType, ht as NC_GROUPING_DEFAULT_SEC, ii as systemEventSummaryScheduleOf, in as SCENE_CONFIRM_DEFAULT_TIMEOUT_MS, ir as evictionPolicyOfLocation, it as NC_ALARM_SYSTEM_EVENT_KINDS, j as EMBEDDING_MODEL_FAILED, ji as discriminatedUnion, jn as applyModeDelaysEdits, jr as pipelineAnalyticsCapability, jt as NcLegacyRuleActionSequenceSchema, k as DeclaredDevices, ki as array, kn as alarmPanelCapability, kr as occupancyScope, kt as NcConditionDescriptorSchema, l as ALL_CAPABILITY_DEFINITIONS, li as viewerLinkBaseOf, ln as SCENE_DEFAULT_UNCOVERED_POLICY, lr as isAlarmControllableCap, lt as NC_CLIP_PRE_ROLL_DEFAULT_SEC, m as AUDIO_MACRO_LABELS, mi as isSourceCap, mn as SetTrackPurityResultSchema, mr as isEventKindLabelKey, mt as NC_DEFAULT_SNOOZE_MINUTES, ni as systemEventFamilyProblems, nn as RetrainStatusSchema, nr as ensureAlarmProfiles, nt as NC_ALARM_DELAY_MAX_SEC, o as FACE_EMBEDDING_STEP_ID, oi as templateCarriesSummary, on as SCENE_DEFAULT_CHECK_INTERVAL_SEC, or as failureContributionCapability, ot as NC_AUDIO_CONFIRM_HITS_DEFAULT, p as ARCHIVED_DEBUG_NOTES_DEFAULT_LIMIT, pi as evaluateSensorEdge, pn as SetTrackPurityInputSchema, pr as isDetectionMacroClass, pt as NC_CONSUMABLE_SYSTEM_EVENT_KINDS, q as MAX_BIRTH_LATENCY_PROXY_MS, qn as deriveRecordingMode, qr as ruleKindOf, qt as NcTemplatePreviewInputSchema, ri as systemEventFilterApplies, rn as SCENE_CONFIRM_DEFAULT_MAX_IMAGE_PX, rr as eventKindLabel, rt as NC_ALARM_NOTIFY_FIELDS, s as readClusterModelPinStrict, si as templateVarsFor, sn as SCENE_DEFAULT_OBSERVATION_SPACING_SEC, sr as gifDeriveSpeed, st as NC_AUDIO_CONFIRM_WINDOW_SEC_DEFAULT, t as BUILTIN_CLIP_MODELS, ti as systemEventDeliveryProblems, tn as RebuildObjectEmbeddingsRefusalSchema, tr as encodeVectorBase64, tt as NC_ALARM_DELAY_FIELDS, u as APPEARANCE_BIN_COUNT, ui as zoneAnalyticsCapability, un as SCENE_DIVERGED, ur as isAppLinkBase, ut as NC_CLIP_RETENTION_MAX_SEC, v as BaseDevice, vi as CamProfileSchema, vn as TimelapseRuleInputSchema, vr as isRetiredClearKey, vt as NC_SENSOR_TRANSITION_KINDS, w as DEFAULT_DETAIL_CROP_CONVENTION, wi as nodePin, wn as TrackSideSchema, wr as kebabToCamel, wt as NcAlarmConfigSchema, x as ClearTrackRelationInputSchema, xi as defineCustomActions, xn as TrackPuritySchema, xr as isSystemDelivery, xt as NC_TANK_SYSTEM_EVENT_KINDS, y as BirthDecisionRecordSchema, yi as createEvent, yn as TimelapseRulePatchSchema, yr as isRootSuppliableStepId, yt as NC_SNOOZE_MAX_MINUTES, z as FULL_IMAGE_BBOX, zi as string, zn as cloneAlarmSettings, zr as resolveModeDelays, zt as NcScheduleSchema } from "../clip-model-registry-CC-BJYiK.mjs";
|
|
2
2
|
import { t as __exportAll } from "../embedding-encoder/index.mjs";
|
|
3
3
|
import * as fs$1 from "node:fs";
|
|
4
4
|
import { createWriteStream, promises } from "node:fs";
|
|
@@ -13383,14 +13383,19 @@ function incomingFromSystemEvent(event, lookup) {
|
|
|
13383
13383
|
case "agent.offline": {
|
|
13384
13384
|
const nodeId = stringField(data, "agentId");
|
|
13385
13385
|
if (nodeId === void 0) return null;
|
|
13386
|
-
const
|
|
13386
|
+
const online = event.category.endsWith(".online");
|
|
13387
|
+
const kind = online ? "node-online" : "node-offline";
|
|
13388
|
+
const reason = online ? void 0 : stringField(data, "reason");
|
|
13387
13389
|
return systemSubject({
|
|
13388
13390
|
facts,
|
|
13389
13391
|
kind,
|
|
13390
13392
|
subject: `node:${nodeId}`,
|
|
13391
13393
|
titleKey: `system.${kind}.title`,
|
|
13392
|
-
bodyKey: `system.${kind}.body.agent`,
|
|
13393
|
-
textParams: {
|
|
13394
|
+
bodyKey: reason === "connection-lost" || reason === "shutdown" ? `system.${kind}.body.agent.${reason}` : `system.${kind}.body.agent`,
|
|
13395
|
+
textParams: {
|
|
13396
|
+
nodeId,
|
|
13397
|
+
nodeName: stringField(data, "nodeName") ?? nodeId
|
|
13398
|
+
},
|
|
13394
13399
|
nodeId
|
|
13395
13400
|
});
|
|
13396
13401
|
}
|
|
@@ -15476,10 +15481,13 @@ var en_default = {
|
|
|
15476
15481
|
"system.stream-offline.title": "Stream offline — {{deviceName}}",
|
|
15477
15482
|
"system.stream-offline.body": "Stream for camera {{deviceName}} is offline",
|
|
15478
15483
|
"system.stream-offline.body.profiled": "{{profile}} stream for camera {{deviceName}} is offline",
|
|
15479
|
-
"system.node-online.title": "Node online — {{
|
|
15480
|
-
"system.node-online.body.agent": "Agent {{
|
|
15481
|
-
"system.node-
|
|
15482
|
-
"system.node-offline.
|
|
15484
|
+
"system.node-online.title": "Node online — {{nodeName}}",
|
|
15485
|
+
"system.node-online.body.agent": "Agent {{nodeName}} is online",
|
|
15486
|
+
"system.node-online.body.agent.after": "Agent {{nodeName}} is back online after {{offlineFor}} offline",
|
|
15487
|
+
"system.node-offline.title": "Node offline — {{nodeName}}",
|
|
15488
|
+
"system.node-offline.body.agent": "Agent {{nodeName}} is offline",
|
|
15489
|
+
"system.node-offline.body.agent.connection-lost": "Agent {{nodeName}} lost its connection to the hub",
|
|
15490
|
+
"system.node-offline.body.agent.shutdown": "Agent {{nodeName}} shut down",
|
|
15483
15491
|
"system.node-inference-unavailable.title": "Node cannot infer — {{nodeId}}",
|
|
15484
15492
|
"system.node-inference-unavailable.body": "Node {{nodeId}} can no longer run inference — every enabled device is unavailable ({{devices}}). It will not receive cameras until one returns.",
|
|
15485
15493
|
"system.addon-crash-loop.title": "Addon crash-loop — {{nodeId}}",
|
|
@@ -15838,10 +15846,13 @@ var it_default = {
|
|
|
15838
15846
|
"system.stream-offline.title": "Stream offline — {{deviceName}}",
|
|
15839
15847
|
"system.stream-offline.body": "Lo stream della camera {{deviceName}} è offline",
|
|
15840
15848
|
"system.stream-offline.body.profiled": "Lo stream {{profile}} della camera {{deviceName}} è offline",
|
|
15841
|
-
"system.node-online.title": "Nodo online — {{
|
|
15842
|
-
"system.node-online.body.agent": "L'agent {{
|
|
15843
|
-
"system.node-
|
|
15844
|
-
"system.node-offline.
|
|
15849
|
+
"system.node-online.title": "Nodo online — {{nodeName}}",
|
|
15850
|
+
"system.node-online.body.agent": "L'agent {{nodeName}} è online",
|
|
15851
|
+
"system.node-online.body.agent.after": "L'agent {{nodeName}} è di nuovo online dopo {{offlineFor}} offline",
|
|
15852
|
+
"system.node-offline.title": "Nodo offline — {{nodeName}}",
|
|
15853
|
+
"system.node-offline.body.agent": "L'agent {{nodeName}} è offline",
|
|
15854
|
+
"system.node-offline.body.agent.connection-lost": "L'agent {{nodeName}} ha perso la connessione con l'hub",
|
|
15855
|
+
"system.node-offline.body.agent.shutdown": "L'agent {{nodeName}} si è spento",
|
|
15845
15856
|
"system.node-inference-unavailable.title": "Nodo senza inferenza — {{nodeId}}",
|
|
15846
15857
|
"system.node-inference-unavailable.body": "Il nodo {{nodeId}} non può più eseguire inferenza — tutti i dispositivi abilitati non sono disponibili ({{devices}}). Non riceverà camere finché uno non torna disponibile.",
|
|
15847
15858
|
"system.addon-crash-loop.title": "Crash-loop addon — {{nodeId}}",
|
|
@@ -18470,6 +18481,7 @@ function planRuleTest(input) {
|
|
|
18470
18481
|
deviceId: String(systemScope.deviceId ?? deviceId),
|
|
18471
18482
|
deviceName: `camera ${String(systemScope.deviceId ?? deviceId)}`,
|
|
18472
18483
|
nodeId: systemScope.nodeId ?? "hub",
|
|
18484
|
+
nodeName: systemScope.nodeId ?? "hub",
|
|
18473
18485
|
packageName: systemScope.packageName ?? "@camstack/server",
|
|
18474
18486
|
currentVersion: "1.0.0",
|
|
18475
18487
|
latestVersion: "1.0.1",
|
|
@@ -26949,6 +26961,7 @@ function buildTemplateVars(texts, entry, deviceName, zoneLabels, timeZone) {
|
|
|
26949
26961
|
currentVersion: typeof systemEvent?.data["currentVersion"] === "string" ? systemEvent.data["currentVersion"] : "",
|
|
26950
26962
|
latestVersion: typeof systemEvent?.data["latestVersion"] === "string" ? systemEvent.data["latestVersion"] : "",
|
|
26951
26963
|
...systemEvent?.deviceId !== void 0 ? { deviceName: String(systemEvent.deviceId) } : {},
|
|
26964
|
+
...systemEvent?.nodeId !== void 0 && (systemEvent.kind === "node-online" || systemEvent.kind === "node-offline") ? { nodeName: systemEvent.nodeId } : {},
|
|
26952
26965
|
...systemEvent?.textParams
|
|
26953
26966
|
};
|
|
26954
26967
|
}
|
|
@@ -28899,6 +28912,11 @@ var NcJudgedTracks = class {
|
|
|
28899
28912
|
//#endregion
|
|
28900
28913
|
//#region src/notification-center/liveness-holdoff.ts
|
|
28901
28914
|
var DEVICE_LIVENESS_HOLDOFF_MS = 5 * 6e4;
|
|
28915
|
+
/** Grace before a node offline (or its recovery) is announced — see the docblock. */
|
|
28916
|
+
var NODE_LIVENESS_HOLDOFF_MS = 6e4;
|
|
28917
|
+
function isNodeLivenessKind(kind) {
|
|
28918
|
+
return kind === "node-online" || kind === "node-offline";
|
|
28919
|
+
}
|
|
28902
28920
|
function isDeviceLivenessKind(kind) {
|
|
28903
28921
|
return kind === "device-online" || kind === "device-offline" || kind === "camera-online" || kind === "camera-offline";
|
|
28904
28922
|
}
|
|
@@ -28910,6 +28928,10 @@ var DeviceLivenessHoldoff = class {
|
|
|
28910
28928
|
pending = /* @__PURE__ */ new Map();
|
|
28911
28929
|
lastNotified = /* @__PURE__ */ new Map();
|
|
28912
28930
|
timers = /* @__PURE__ */ new Map();
|
|
28931
|
+
/** First divergence from the last notified state, per subject (cleared on a bounce back). */
|
|
28932
|
+
departedAt = /* @__PURE__ */ new Map();
|
|
28933
|
+
/** When the last notified state began, per subject. */
|
|
28934
|
+
stateSince = /* @__PURE__ */ new Map();
|
|
28913
28935
|
delayMs;
|
|
28914
28936
|
schedule;
|
|
28915
28937
|
cancel;
|
|
@@ -28922,6 +28944,11 @@ var DeviceLivenessHoldoff = class {
|
|
|
28922
28944
|
/** The seeded (or last delivered) state — a bounce back to this is silence. */
|
|
28923
28945
|
remember(subject, state) {
|
|
28924
28946
|
this.lastNotified.set(subject, state);
|
|
28947
|
+
const pending = this.timers.get(subject);
|
|
28948
|
+
if (pending !== void 0) this.cancel(pending);
|
|
28949
|
+
this.timers.delete(subject);
|
|
28950
|
+
this.pending.delete(subject);
|
|
28951
|
+
this.departedAt.delete(subject);
|
|
28925
28952
|
}
|
|
28926
28953
|
/** Directory-seeded rows never pass through {@link remember}; first flip does. */
|
|
28927
28954
|
rememberIfAbsent(subject, state) {
|
|
@@ -28930,6 +28957,7 @@ var DeviceLivenessHoldoff = class {
|
|
|
28930
28957
|
/** A real ledger flip. Starts / resets the trailing timer. */
|
|
28931
28958
|
arm(subject, incoming) {
|
|
28932
28959
|
this.pending.set(subject, incoming);
|
|
28960
|
+
this.trackDeparture(subject, incoming);
|
|
28933
28961
|
const existing = this.timers.get(subject);
|
|
28934
28962
|
if (existing !== void 0) this.cancel(existing);
|
|
28935
28963
|
if (this.delayMs <= 0) {
|
|
@@ -28947,6 +28975,16 @@ var DeviceLivenessHoldoff = class {
|
|
|
28947
28975
|
for (const id of this.timers.values()) this.cancel(id);
|
|
28948
28976
|
this.timers.clear();
|
|
28949
28977
|
this.pending.clear();
|
|
28978
|
+
this.departedAt.clear();
|
|
28979
|
+
}
|
|
28980
|
+
trackDeparture(subject, incoming) {
|
|
28981
|
+
const kind = incoming.subject.systemEvent?.kind;
|
|
28982
|
+
if (kind === void 0) return;
|
|
28983
|
+
if (this.lastNotified.get(subject) === livenessStateOfKind(kind)) {
|
|
28984
|
+
this.departedAt.delete(subject);
|
|
28985
|
+
return;
|
|
28986
|
+
}
|
|
28987
|
+
if (!this.departedAt.has(subject)) this.departedAt.set(subject, incoming.subject.timestamp);
|
|
28950
28988
|
}
|
|
28951
28989
|
fire(subject) {
|
|
28952
28990
|
const incoming = this.pending.get(subject);
|
|
@@ -28957,10 +28995,64 @@ var DeviceLivenessHoldoff = class {
|
|
|
28957
28995
|
const state = livenessStateOfKind(kind);
|
|
28958
28996
|
if (this.lastNotified.get(subject) === state) return;
|
|
28959
28997
|
this.lastNotified.set(subject, state);
|
|
28960
|
-
this.
|
|
28998
|
+
const since = this.departedAt.get(subject) ?? incoming.subject.timestamp;
|
|
28999
|
+
const previousSince = this.stateSince.get(subject);
|
|
29000
|
+
this.departedAt.delete(subject);
|
|
29001
|
+
this.stateSince.set(subject, since);
|
|
29002
|
+
this.flush(incoming, previousSince !== void 0 ? {
|
|
29003
|
+
since,
|
|
29004
|
+
previousSince
|
|
29005
|
+
} : { since });
|
|
28961
29006
|
}
|
|
28962
29007
|
};
|
|
28963
29008
|
//#endregion
|
|
29009
|
+
//#region src/notification-center/node-liveness-text.ts
|
|
29010
|
+
/** "45 s", "12 min", "2 h 5 min", "3 d 4 h" — unit symbols read the same in en and it. */
|
|
29011
|
+
function formatOutageDuration(ms) {
|
|
29012
|
+
const totalSec = Math.max(0, Math.round(ms / 1e3));
|
|
29013
|
+
if (totalSec < 60) return `${totalSec} s`;
|
|
29014
|
+
const totalMin = Math.floor(totalSec / 60);
|
|
29015
|
+
if (totalMin < 60) return `${totalMin} min`;
|
|
29016
|
+
const totalHours = Math.floor(totalMin / 60);
|
|
29017
|
+
const minutes = totalMin % 60;
|
|
29018
|
+
if (totalHours < 24) return minutes > 0 ? `${totalHours} h ${minutes} min` : `${totalHours} h`;
|
|
29019
|
+
const days = Math.floor(totalHours / 24);
|
|
29020
|
+
const hours = totalHours % 24;
|
|
29021
|
+
return hours > 0 ? `${days} d ${hours} h` : `${days} d`;
|
|
29022
|
+
}
|
|
29023
|
+
/**
|
|
29024
|
+
* Freeze the post-hold-off facts onto a node liveness event.
|
|
29025
|
+
*
|
|
29026
|
+
* - `nodeName`: the display name, when the directory knew one.
|
|
29027
|
+
* - `offlineFor` (recovery only, and only when the outage START is known — a
|
|
29028
|
+
* state that was merely seeded after a restart has none): the outage length,
|
|
29029
|
+
* with the `.after` body variant that says it.
|
|
29030
|
+
*/
|
|
29031
|
+
function withNodeLivenessFacts(incoming, facts) {
|
|
29032
|
+
const system = incoming.subject.systemEvent;
|
|
29033
|
+
if (system === void 0) return incoming;
|
|
29034
|
+
const { since, previousSince } = facts.timing;
|
|
29035
|
+
const recovered = system.kind === "node-online" && previousSince !== void 0;
|
|
29036
|
+
const name = facts.nodeName !== void 0 && facts.nodeName.length > 0 ? facts.nodeName : void 0;
|
|
29037
|
+
if (!recovered && name === void 0) return incoming;
|
|
29038
|
+
const textParams = {
|
|
29039
|
+
...system.textParams,
|
|
29040
|
+
...name !== void 0 ? { nodeName: name } : {},
|
|
29041
|
+
...recovered ? { offlineFor: formatOutageDuration(since - previousSince) } : {}
|
|
29042
|
+
};
|
|
29043
|
+
return {
|
|
29044
|
+
...incoming,
|
|
29045
|
+
subject: {
|
|
29046
|
+
...incoming.subject,
|
|
29047
|
+
systemEvent: {
|
|
29048
|
+
...system,
|
|
29049
|
+
...recovered ? { bodyKey: "system.node-online.body.agent.after" } : {},
|
|
29050
|
+
textParams
|
|
29051
|
+
}
|
|
29052
|
+
}
|
|
29053
|
+
};
|
|
29054
|
+
}
|
|
29055
|
+
//#endregion
|
|
28964
29056
|
//#region src/notification-center/linked-camera-media.ts
|
|
28965
29057
|
/** ADR 0632: absent = mosaic, applied HERE and never as a Zod default. */
|
|
28966
29058
|
function linkedCameraMode(media) {
|
|
@@ -38280,6 +38372,8 @@ var ALARM_PANEL_CAP = alarmPanelCapability.name;
|
|
|
38280
38372
|
/** Bound on remembered departure fallbacks (D691 review M3) — the shelf's own
|
|
38281
38373
|
* capture bound. */
|
|
38282
38374
|
var NC_DEPARTURE_FALLBACK_MAX = 64;
|
|
38375
|
+
/** Bound on the post-hold-off `nodes.directory` read that names a node. */
|
|
38376
|
+
var NODE_NAME_READ_TIMEOUT_MS = 3e3;
|
|
38283
38377
|
/** Bound on the sampled "departed track alias resolution failed" memo
|
|
38284
38378
|
* (D683 × D691) — the alias-resolution call sites' own shape. */
|
|
38285
38379
|
var NC_DEPARTED_ALIAS_FAILURE_MEMO_MAX = 256;
|
|
@@ -39076,6 +39170,8 @@ var NotificationCenter = class {
|
|
|
39076
39170
|
addonUpdates;
|
|
39077
39171
|
/** Trailing 5 min hold-off for camera liveness flaps (plugin restart). */
|
|
39078
39172
|
livenessHoldoff;
|
|
39173
|
+
/** Trailing 60 s hold-off for node liveness (reconnect storms). */
|
|
39174
|
+
nodeLivenessHoldoff;
|
|
39079
39175
|
/**
|
|
39080
39176
|
* Serialized evaluation chain. The persist hooks are fire-and-forget for
|
|
39081
39177
|
* the frame path, but two concurrent evaluations of the same device
|
|
@@ -39777,6 +39873,7 @@ var NotificationCenter = class {
|
|
|
39777
39873
|
if (incoming !== null) this.consumeEvent(incoming);
|
|
39778
39874
|
});
|
|
39779
39875
|
this.livenessHoldoff = new DeviceLivenessHoldoff((event) => this.consumeEvent(event), { delayMs: deps.livenessHoldoffMs ?? (process.env.VITEST ? 0 : DEVICE_LIVENESS_HOLDOFF_MS) });
|
|
39876
|
+
this.nodeLivenessHoldoff = new DeviceLivenessHoldoff((event, timing) => this.consumeNodeLiveness(event, timing), { delayMs: deps.nodeLivenessHoldoffMs ?? (process.env.VITEST ? 0 : NODE_LIVENESS_HOLDOFF_MS) });
|
|
39780
39877
|
this.actionRunner = deps.actuate !== void 0 && deps.isCapDeviceScoped !== void 0 ? new NcRuleActionRunner({
|
|
39781
39878
|
logger: this.logger.child("actions"),
|
|
39782
39879
|
actuate: (input) => this.actuateWithAttribution(input),
|
|
@@ -40338,6 +40435,7 @@ var NotificationCenter = class {
|
|
|
40338
40435
|
this.linkedStills?.clear();
|
|
40339
40436
|
this.addonUpdates.dispose();
|
|
40340
40437
|
this.livenessHoldoff.dispose();
|
|
40438
|
+
this.nodeLivenessHoldoff.dispose();
|
|
40341
40439
|
this.evaluationActive = false;
|
|
40342
40440
|
this.hydration = null;
|
|
40343
40441
|
}
|
|
@@ -40410,6 +40508,42 @@ var NotificationCenter = class {
|
|
|
40410
40508
|
this.scheduleEvaluation(event);
|
|
40411
40509
|
}
|
|
40412
40510
|
/**
|
|
40511
|
+
* A node liveness flip that survived its hold-off: freeze the node's display
|
|
40512
|
+
* name and (on a recovery) the outage length onto it, then consume it.
|
|
40513
|
+
*
|
|
40514
|
+
* The name read is bounded and best-effort — a slow or failed directory
|
|
40515
|
+
* costs the friendly name, never the notification (the intake already froze
|
|
40516
|
+
* the id as `nodeName`).
|
|
40517
|
+
*/
|
|
40518
|
+
consumeNodeLiveness(event, timing) {
|
|
40519
|
+
const nodeId = event.subject.systemEvent?.nodeId;
|
|
40520
|
+
this.readNodeDisplayName(nodeId).then((nodeName) => {
|
|
40521
|
+
this.consumeEvent(withNodeLivenessFacts(event, nodeName !== void 0 ? {
|
|
40522
|
+
timing,
|
|
40523
|
+
nodeName
|
|
40524
|
+
} : { timing }));
|
|
40525
|
+
});
|
|
40526
|
+
}
|
|
40527
|
+
async readNodeDisplayName(nodeId) {
|
|
40528
|
+
const read = this.deps.readNodeDirectory;
|
|
40529
|
+
if (nodeId === void 0 || read === void 0) return void 0;
|
|
40530
|
+
let timer;
|
|
40531
|
+
try {
|
|
40532
|
+
const timeout = new Promise((resolve) => {
|
|
40533
|
+
timer = setTimeout(() => resolve(void 0), NODE_NAME_READ_TIMEOUT_MS);
|
|
40534
|
+
});
|
|
40535
|
+
return (await Promise.race([read(), timeout]))?.nodes.find((node) => node.id === nodeId)?.name;
|
|
40536
|
+
} catch (err) {
|
|
40537
|
+
this.logger.debug("node display name unavailable — notifying with the id", { meta: {
|
|
40538
|
+
nodeId,
|
|
40539
|
+
error: String(err)
|
|
40540
|
+
} });
|
|
40541
|
+
return;
|
|
40542
|
+
} finally {
|
|
40543
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
40544
|
+
}
|
|
40545
|
+
}
|
|
40546
|
+
/**
|
|
40413
40547
|
* The same consumption, awaited, with the verdict returned. Identical code
|
|
40414
40548
|
* path — {@link consumeEvent} is this function with the report discarded — so
|
|
40415
40549
|
* a producer that reads the report is testing what the live producers do, not
|
|
@@ -41342,8 +41476,9 @@ var NotificationCenter = class {
|
|
|
41342
41476
|
if (observation !== null) {
|
|
41343
41477
|
const previous = this.liveness.stateOf(observation.subject);
|
|
41344
41478
|
const verdict = this.liveness.observe(observation, this.now());
|
|
41479
|
+
const holdoff = isNodeLivenessKind(observation.kind) ? this.nodeLivenessHoldoff : this.livenessHoldoff;
|
|
41345
41480
|
if (verdict === "seeded") {
|
|
41346
|
-
|
|
41481
|
+
holdoff.remember(observation.subject, observation.state);
|
|
41347
41482
|
this.reportLivenessDrop(incoming, verdict);
|
|
41348
41483
|
return;
|
|
41349
41484
|
}
|
|
@@ -41351,9 +41486,9 @@ var NotificationCenter = class {
|
|
|
41351
41486
|
this.reportLivenessDrop(incoming, verdict);
|
|
41352
41487
|
return;
|
|
41353
41488
|
}
|
|
41354
|
-
if (previous !== void 0)
|
|
41489
|
+
if (previous !== void 0) holdoff.rememberIfAbsent(observation.subject, previous);
|
|
41355
41490
|
if (observation.state === "online" && !this.deviceAlertSettings().notifyRecovery) {
|
|
41356
|
-
|
|
41491
|
+
holdoff.remember(observation.subject, observation.state);
|
|
41357
41492
|
this.logger.debug("device came back — the all-clear is switched off", {
|
|
41358
41493
|
tags: incoming.log().tags,
|
|
41359
41494
|
meta: {
|
|
@@ -41363,8 +41498,8 @@ var NotificationCenter = class {
|
|
|
41363
41498
|
});
|
|
41364
41499
|
return;
|
|
41365
41500
|
}
|
|
41366
|
-
if (isDeviceLivenessKind(observation.kind)) {
|
|
41367
|
-
|
|
41501
|
+
if (isDeviceLivenessKind(observation.kind) || isNodeLivenessKind(observation.kind)) {
|
|
41502
|
+
holdoff.arm(observation.subject, incoming);
|
|
41368
41503
|
return;
|
|
41369
41504
|
}
|
|
41370
41505
|
} else if (system !== void 0 && (system.kind.startsWith("device-") || system.kind.startsWith("stream-"))) {
|
|
@@ -83412,6 +83547,260 @@ function withDatasetVersion(manifest, version) {
|
|
|
83412
83547
|
};
|
|
83413
83548
|
}
|
|
83414
83549
|
//#endregion
|
|
83550
|
+
//#region src/pipeline-analytics/retrain/retrain-dataset-version-store.ts
|
|
83551
|
+
/**
|
|
83552
|
+
* @durable class=ledger owner=pipeline-analytics
|
|
83553
|
+
* write="one row per dataset version the operator creates: a frozen frameIds list,
|
|
83554
|
+
* the sha256 of the annotations those frames carried, the export parameters and
|
|
83555
|
+
* the counts at creation. Never updated after the insert — a different selection
|
|
83556
|
+
* is a new version."
|
|
83557
|
+
* retention="none — rows leave only when the operator deletes the version. The
|
|
83558
|
+
* frames themselves are owned by the retrain corpus; deleting a version deletes no
|
|
83559
|
+
* frame, and deleting a frame does not edit a version (verify reports it missing)."
|
|
83560
|
+
*/
|
|
83561
|
+
var RETRAIN_DATASET_VERSIONS_COLLECTION = "pipeline-analytics:retrain-dataset-versions";
|
|
83562
|
+
var COLUMNS = [
|
|
83563
|
+
{
|
|
83564
|
+
name: "id",
|
|
83565
|
+
type: "TEXT",
|
|
83566
|
+
primaryKey: true,
|
|
83567
|
+
notNull: true
|
|
83568
|
+
},
|
|
83569
|
+
{
|
|
83570
|
+
name: "name",
|
|
83571
|
+
type: "TEXT",
|
|
83572
|
+
notNull: true
|
|
83573
|
+
},
|
|
83574
|
+
{
|
|
83575
|
+
name: "nameKey",
|
|
83576
|
+
type: "TEXT",
|
|
83577
|
+
notNull: true
|
|
83578
|
+
},
|
|
83579
|
+
{
|
|
83580
|
+
name: "createdAt",
|
|
83581
|
+
type: "INTEGER",
|
|
83582
|
+
notNull: true
|
|
83583
|
+
},
|
|
83584
|
+
{
|
|
83585
|
+
name: "selection",
|
|
83586
|
+
type: "JSON",
|
|
83587
|
+
notNull: true
|
|
83588
|
+
},
|
|
83589
|
+
{
|
|
83590
|
+
name: "layout",
|
|
83591
|
+
type: "TEXT",
|
|
83592
|
+
notNull: true
|
|
83593
|
+
},
|
|
83594
|
+
{
|
|
83595
|
+
name: "completeOnly",
|
|
83596
|
+
type: "BOOLEAN",
|
|
83597
|
+
notNull: true
|
|
83598
|
+
},
|
|
83599
|
+
{
|
|
83600
|
+
name: "frameIds",
|
|
83601
|
+
type: "JSON",
|
|
83602
|
+
notNull: true
|
|
83603
|
+
},
|
|
83604
|
+
{
|
|
83605
|
+
name: "annotationHash",
|
|
83606
|
+
type: "TEXT",
|
|
83607
|
+
notNull: true
|
|
83608
|
+
},
|
|
83609
|
+
{
|
|
83610
|
+
name: "manifestSchema",
|
|
83611
|
+
type: "TEXT",
|
|
83612
|
+
notNull: true
|
|
83613
|
+
},
|
|
83614
|
+
{
|
|
83615
|
+
name: "stats",
|
|
83616
|
+
type: "JSON",
|
|
83617
|
+
notNull: true
|
|
83618
|
+
}
|
|
83619
|
+
];
|
|
83620
|
+
var INDEXES = [{
|
|
83621
|
+
name: "idx_retrain_dataset_versions_name_key",
|
|
83622
|
+
columns: ["nameKey"],
|
|
83623
|
+
unique: true
|
|
83624
|
+
}, {
|
|
83625
|
+
name: "idx_retrain_dataset_versions_created",
|
|
83626
|
+
columns: ["createdAt"]
|
|
83627
|
+
}];
|
|
83628
|
+
function summaryOfVersion(version) {
|
|
83629
|
+
const { frameIds, ...rest } = version;
|
|
83630
|
+
return {
|
|
83631
|
+
...rest,
|
|
83632
|
+
frameCount: frameIds.length
|
|
83633
|
+
};
|
|
83634
|
+
}
|
|
83635
|
+
var nameKeyOf = (name) => name.trim().toLowerCase();
|
|
83636
|
+
function numberList(value) {
|
|
83637
|
+
return Array.isArray(value) ? value.filter((v) => typeof v === "number") : void 0;
|
|
83638
|
+
}
|
|
83639
|
+
function stringList(value) {
|
|
83640
|
+
return Array.isArray(value) ? value.filter((v) => typeof v === "string") : void 0;
|
|
83641
|
+
}
|
|
83642
|
+
function parseJson(value) {
|
|
83643
|
+
if (typeof value !== "string") return value;
|
|
83644
|
+
try {
|
|
83645
|
+
return JSON.parse(value);
|
|
83646
|
+
} catch {
|
|
83647
|
+
return;
|
|
83648
|
+
}
|
|
83649
|
+
}
|
|
83650
|
+
function asRecord(value) {
|
|
83651
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? { ...value } : {};
|
|
83652
|
+
}
|
|
83653
|
+
var EMPTY_STATS = {
|
|
83654
|
+
frames: 0,
|
|
83655
|
+
completeFrames: 0,
|
|
83656
|
+
completeness: 0,
|
|
83657
|
+
subjects: 0,
|
|
83658
|
+
modelErrors: 0,
|
|
83659
|
+
hardNegatives: 0,
|
|
83660
|
+
cells: [],
|
|
83661
|
+
cameras: []
|
|
83662
|
+
};
|
|
83663
|
+
/** A stored stats object, trusted only as far as its shape. */
|
|
83664
|
+
function readStats(value) {
|
|
83665
|
+
const raw = asRecord(parseJson(value));
|
|
83666
|
+
const num = (k) => typeof raw[k] === "number" ? raw[k] : 0;
|
|
83667
|
+
const cells = Array.isArray(raw["cells"]) ? raw["cells"] : [];
|
|
83668
|
+
const cameras = Array.isArray(raw["cameras"]) ? raw["cameras"] : [];
|
|
83669
|
+
return {
|
|
83670
|
+
...EMPTY_STATS,
|
|
83671
|
+
frames: num("frames"),
|
|
83672
|
+
completeFrames: num("completeFrames"),
|
|
83673
|
+
completeness: num("completeness"),
|
|
83674
|
+
subjects: num("subjects"),
|
|
83675
|
+
modelErrors: num("modelErrors"),
|
|
83676
|
+
hardNegatives: num("hardNegatives"),
|
|
83677
|
+
cells: cells.map((c) => {
|
|
83678
|
+
const r = asRecord(c);
|
|
83679
|
+
const lighting = r["lighting"] === "day" || r["lighting"] === "night" ? r["lighting"] : "unknown";
|
|
83680
|
+
return {
|
|
83681
|
+
macroClass: String(r["macroClass"] ?? ""),
|
|
83682
|
+
deviceId: Number(r["deviceId"] ?? 0),
|
|
83683
|
+
lighting,
|
|
83684
|
+
subjects: Number(r["subjects"] ?? 0),
|
|
83685
|
+
frames: Number(r["frames"] ?? 0)
|
|
83686
|
+
};
|
|
83687
|
+
}),
|
|
83688
|
+
cameras: cameras.map((c) => {
|
|
83689
|
+
const r = asRecord(c);
|
|
83690
|
+
return {
|
|
83691
|
+
deviceId: Number(r["deviceId"] ?? 0),
|
|
83692
|
+
frames: Number(r["frames"] ?? 0),
|
|
83693
|
+
completeFrames: Number(r["completeFrames"] ?? 0)
|
|
83694
|
+
};
|
|
83695
|
+
})
|
|
83696
|
+
};
|
|
83697
|
+
}
|
|
83698
|
+
var RetrainDatasetVersionStore = class {
|
|
83699
|
+
store;
|
|
83700
|
+
logger;
|
|
83701
|
+
constructor(deps) {
|
|
83702
|
+
this.store = deps.store;
|
|
83703
|
+
this.logger = deps.logger;
|
|
83704
|
+
}
|
|
83705
|
+
static async declare(store) {
|
|
83706
|
+
await store.declareCollection.mutate({
|
|
83707
|
+
collection: RETRAIN_DATASET_VERSIONS_COLLECTION,
|
|
83708
|
+
columns: [...COLUMNS],
|
|
83709
|
+
indexes: [...INDEXES]
|
|
83710
|
+
});
|
|
83711
|
+
}
|
|
83712
|
+
insert = async (version) => {
|
|
83713
|
+
await this.store.set.mutate({
|
|
83714
|
+
collection: RETRAIN_DATASET_VERSIONS_COLLECTION,
|
|
83715
|
+
key: version.id,
|
|
83716
|
+
value: {
|
|
83717
|
+
name: version.name,
|
|
83718
|
+
nameKey: nameKeyOf(version.name),
|
|
83719
|
+
createdAt: version.createdAt,
|
|
83720
|
+
selection: version.selection,
|
|
83721
|
+
layout: version.layout,
|
|
83722
|
+
completeOnly: version.completeOnly,
|
|
83723
|
+
frameIds: version.frameIds,
|
|
83724
|
+
annotationHash: version.annotationHash,
|
|
83725
|
+
manifestSchema: version.manifestSchema,
|
|
83726
|
+
stats: version.stats
|
|
83727
|
+
}
|
|
83728
|
+
});
|
|
83729
|
+
};
|
|
83730
|
+
get = async (id) => {
|
|
83731
|
+
try {
|
|
83732
|
+
const row = await this.store.get.query({
|
|
83733
|
+
collection: RETRAIN_DATASET_VERSIONS_COLLECTION,
|
|
83734
|
+
key: id
|
|
83735
|
+
});
|
|
83736
|
+
return row === null || row === void 0 ? null : this.toVersion(id, asRecord(row));
|
|
83737
|
+
} catch (err) {
|
|
83738
|
+
this.logger.warn("retrain dataset version read failed", { meta: {
|
|
83739
|
+
versionId: id,
|
|
83740
|
+
error: String(err)
|
|
83741
|
+
} });
|
|
83742
|
+
return null;
|
|
83743
|
+
}
|
|
83744
|
+
};
|
|
83745
|
+
list = async () => {
|
|
83746
|
+
return (await this.listRows()).map(summaryOfVersion);
|
|
83747
|
+
};
|
|
83748
|
+
/** Every row WITH its frame list — the migration into `training` reads this. */
|
|
83749
|
+
listRows = async () => {
|
|
83750
|
+
try {
|
|
83751
|
+
return (await this.store.query.query({
|
|
83752
|
+
collection: RETRAIN_DATASET_VERSIONS_COLLECTION,
|
|
83753
|
+
filter: { orderBy: {
|
|
83754
|
+
field: "createdAt",
|
|
83755
|
+
direction: "desc"
|
|
83756
|
+
} }
|
|
83757
|
+
})).map((r) => this.toVersion(r.id, asRecord(r.data)));
|
|
83758
|
+
} catch (err) {
|
|
83759
|
+
this.logger.warn("retrain dataset versions list failed", { meta: { error: String(err) } });
|
|
83760
|
+
return [];
|
|
83761
|
+
}
|
|
83762
|
+
};
|
|
83763
|
+
findIdByName = async (name) => {
|
|
83764
|
+
return (await this.store.query.query({
|
|
83765
|
+
collection: RETRAIN_DATASET_VERSIONS_COLLECTION,
|
|
83766
|
+
filter: {
|
|
83767
|
+
where: { nameKey: nameKeyOf(name) },
|
|
83768
|
+
limit: 1
|
|
83769
|
+
}
|
|
83770
|
+
}))[0]?.id ?? null;
|
|
83771
|
+
};
|
|
83772
|
+
remove = async (id) => {
|
|
83773
|
+
if (await this.get(id) === null) return false;
|
|
83774
|
+
await this.store.delete.mutate({
|
|
83775
|
+
collection: RETRAIN_DATASET_VERSIONS_COLLECTION,
|
|
83776
|
+
key: id
|
|
83777
|
+
});
|
|
83778
|
+
return true;
|
|
83779
|
+
};
|
|
83780
|
+
toVersion(id, data) {
|
|
83781
|
+
const selection = asRecord(parseJson(data["selection"]));
|
|
83782
|
+
const deviceIds = numberList(selection["deviceIds"]);
|
|
83783
|
+
const collectionIds = stringList(selection["collectionIds"]);
|
|
83784
|
+
const frameIdsSel = stringList(selection["frameIds"]);
|
|
83785
|
+
return {
|
|
83786
|
+
id,
|
|
83787
|
+
name: String(data["name"] ?? ""),
|
|
83788
|
+
createdAt: Number(data["createdAt"] ?? 0),
|
|
83789
|
+
selection: {
|
|
83790
|
+
...deviceIds !== void 0 ? { deviceIds } : {},
|
|
83791
|
+
...collectionIds !== void 0 ? { collectionIds } : {},
|
|
83792
|
+
...frameIdsSel !== void 0 ? { frameIds: frameIdsSel } : {}
|
|
83793
|
+
},
|
|
83794
|
+
layout: data["layout"] === "crops" ? "crops" : "frames",
|
|
83795
|
+
completeOnly: data["completeOnly"] === true || data["completeOnly"] === 1,
|
|
83796
|
+
frameIds: stringList(parseJson(data["frameIds"])) ?? [],
|
|
83797
|
+
annotationHash: String(data["annotationHash"] ?? ""),
|
|
83798
|
+
manifestSchema: String(data["manifestSchema"] ?? ""),
|
|
83799
|
+
stats: readStats(data["stats"])
|
|
83800
|
+
};
|
|
83801
|
+
}
|
|
83802
|
+
};
|
|
83803
|
+
//#endregion
|
|
83415
83804
|
//#region src/pipeline-analytics/retrain/retrain-geometry.ts
|
|
83416
83805
|
function clamp01(v) {
|
|
83417
83806
|
return v < 0 ? 0 : v > 1 ? 1 : v;
|
|
@@ -83700,13 +84089,6 @@ function filterOf(selection, completeOnly) {
|
|
|
83700
84089
|
...completeOnly ? { completeOnly: true } : {}
|
|
83701
84090
|
};
|
|
83702
84091
|
}
|
|
83703
|
-
function summaryOf(version) {
|
|
83704
|
-
const { frameIds, ...rest } = version;
|
|
83705
|
-
return {
|
|
83706
|
-
...rest,
|
|
83707
|
-
frameCount: frameIds.length
|
|
83708
|
-
};
|
|
83709
|
-
}
|
|
83710
84092
|
var RetrainDatasetService = class {
|
|
83711
84093
|
deps;
|
|
83712
84094
|
constructor(deps) {
|
|
@@ -83759,11 +84141,11 @@ var RetrainDatasetService = class {
|
|
|
83759
84141
|
} });
|
|
83760
84142
|
return {
|
|
83761
84143
|
kind: "created",
|
|
83762
|
-
version:
|
|
84144
|
+
version: summaryOfVersion(version)
|
|
83763
84145
|
};
|
|
83764
84146
|
}
|
|
83765
84147
|
async list() {
|
|
83766
|
-
return
|
|
84148
|
+
return this.deps.versions.list();
|
|
83767
84149
|
}
|
|
83768
84150
|
async delete(input) {
|
|
83769
84151
|
const deleted = await this.deps.versions.remove(input.id);
|
|
@@ -83821,246 +84203,62 @@ var RetrainDatasetService = class {
|
|
|
83821
84203
|
}
|
|
83822
84204
|
};
|
|
83823
84205
|
//#endregion
|
|
83824
|
-
//#region src/pipeline-analytics/retrain/retrain-dataset-version-
|
|
83825
|
-
|
|
83826
|
-
|
|
83827
|
-
|
|
83828
|
-
|
|
83829
|
-
|
|
83830
|
-
* is a new version."
|
|
83831
|
-
* retention="none — rows leave only when the operator deletes the version. The
|
|
83832
|
-
* frames themselves are owned by the retrain corpus; deleting a version deletes no
|
|
83833
|
-
* frame, and deleting a frame does not edit a version (verify reports it missing)."
|
|
83834
|
-
*/
|
|
83835
|
-
var RETRAIN_DATASET_VERSIONS_COLLECTION = "pipeline-analytics:retrain-dataset-versions";
|
|
83836
|
-
var COLUMNS = [
|
|
83837
|
-
{
|
|
83838
|
-
name: "id",
|
|
83839
|
-
type: "TEXT",
|
|
83840
|
-
primaryKey: true,
|
|
83841
|
-
notNull: true
|
|
83842
|
-
},
|
|
83843
|
-
{
|
|
83844
|
-
name: "name",
|
|
83845
|
-
type: "TEXT",
|
|
83846
|
-
notNull: true
|
|
83847
|
-
},
|
|
83848
|
-
{
|
|
83849
|
-
name: "nameKey",
|
|
83850
|
-
type: "TEXT",
|
|
83851
|
-
notNull: true
|
|
83852
|
-
},
|
|
83853
|
-
{
|
|
83854
|
-
name: "createdAt",
|
|
83855
|
-
type: "INTEGER",
|
|
83856
|
-
notNull: true
|
|
83857
|
-
},
|
|
83858
|
-
{
|
|
83859
|
-
name: "selection",
|
|
83860
|
-
type: "JSON",
|
|
83861
|
-
notNull: true
|
|
83862
|
-
},
|
|
83863
|
-
{
|
|
83864
|
-
name: "layout",
|
|
83865
|
-
type: "TEXT",
|
|
83866
|
-
notNull: true
|
|
83867
|
-
},
|
|
83868
|
-
{
|
|
83869
|
-
name: "completeOnly",
|
|
83870
|
-
type: "BOOLEAN",
|
|
83871
|
-
notNull: true
|
|
83872
|
-
},
|
|
83873
|
-
{
|
|
83874
|
-
name: "frameIds",
|
|
83875
|
-
type: "JSON",
|
|
83876
|
-
notNull: true
|
|
83877
|
-
},
|
|
83878
|
-
{
|
|
83879
|
-
name: "annotationHash",
|
|
83880
|
-
type: "TEXT",
|
|
83881
|
-
notNull: true
|
|
83882
|
-
},
|
|
83883
|
-
{
|
|
83884
|
-
name: "manifestSchema",
|
|
83885
|
-
type: "TEXT",
|
|
83886
|
-
notNull: true
|
|
83887
|
-
},
|
|
83888
|
-
{
|
|
83889
|
-
name: "stats",
|
|
83890
|
-
type: "JSON",
|
|
83891
|
-
notNull: true
|
|
83892
|
-
}
|
|
83893
|
-
];
|
|
83894
|
-
var INDEXES = [{
|
|
83895
|
-
name: "idx_retrain_dataset_versions_name_key",
|
|
83896
|
-
columns: ["nameKey"],
|
|
83897
|
-
unique: true
|
|
83898
|
-
}, {
|
|
83899
|
-
name: "idx_retrain_dataset_versions_created",
|
|
83900
|
-
columns: ["createdAt"]
|
|
83901
|
-
}];
|
|
83902
|
-
var nameKeyOf = (name) => name.trim().toLowerCase();
|
|
83903
|
-
function numberList(value) {
|
|
83904
|
-
return Array.isArray(value) ? value.filter((v) => typeof v === "number") : void 0;
|
|
83905
|
-
}
|
|
83906
|
-
function stringList(value) {
|
|
83907
|
-
return Array.isArray(value) ? value.filter((v) => typeof v === "string") : void 0;
|
|
83908
|
-
}
|
|
83909
|
-
function parseJson(value) {
|
|
83910
|
-
if (typeof value !== "string") return value;
|
|
83911
|
-
try {
|
|
83912
|
-
return JSON.parse(value);
|
|
83913
|
-
} catch {
|
|
83914
|
-
return;
|
|
83915
|
-
}
|
|
83916
|
-
}
|
|
83917
|
-
function asRecord(value) {
|
|
83918
|
-
return value !== null && typeof value === "object" && !Array.isArray(value) ? { ...value } : {};
|
|
83919
|
-
}
|
|
83920
|
-
var EMPTY_STATS = {
|
|
83921
|
-
frames: 0,
|
|
83922
|
-
completeFrames: 0,
|
|
83923
|
-
completeness: 0,
|
|
83924
|
-
subjects: 0,
|
|
83925
|
-
modelErrors: 0,
|
|
83926
|
-
hardNegatives: 0,
|
|
83927
|
-
cells: [],
|
|
83928
|
-
cameras: []
|
|
83929
|
-
};
|
|
83930
|
-
/** A stored stats object, trusted only as far as its shape. */
|
|
83931
|
-
function readStats(value) {
|
|
83932
|
-
const raw = asRecord(parseJson(value));
|
|
83933
|
-
const num = (k) => typeof raw[k] === "number" ? raw[k] : 0;
|
|
83934
|
-
const cells = Array.isArray(raw["cells"]) ? raw["cells"] : [];
|
|
83935
|
-
const cameras = Array.isArray(raw["cameras"]) ? raw["cameras"] : [];
|
|
83936
|
-
return {
|
|
83937
|
-
...EMPTY_STATS,
|
|
83938
|
-
frames: num("frames"),
|
|
83939
|
-
completeFrames: num("completeFrames"),
|
|
83940
|
-
completeness: num("completeness"),
|
|
83941
|
-
subjects: num("subjects"),
|
|
83942
|
-
modelErrors: num("modelErrors"),
|
|
83943
|
-
hardNegatives: num("hardNegatives"),
|
|
83944
|
-
cells: cells.map((c) => {
|
|
83945
|
-
const r = asRecord(c);
|
|
83946
|
-
const lighting = r["lighting"] === "day" || r["lighting"] === "night" ? r["lighting"] : "unknown";
|
|
83947
|
-
return {
|
|
83948
|
-
macroClass: String(r["macroClass"] ?? ""),
|
|
83949
|
-
deviceId: Number(r["deviceId"] ?? 0),
|
|
83950
|
-
lighting,
|
|
83951
|
-
subjects: Number(r["subjects"] ?? 0),
|
|
83952
|
-
frames: Number(r["frames"] ?? 0)
|
|
83953
|
-
};
|
|
83954
|
-
}),
|
|
83955
|
-
cameras: cameras.map((c) => {
|
|
83956
|
-
const r = asRecord(c);
|
|
83957
|
-
return {
|
|
83958
|
-
deviceId: Number(r["deviceId"] ?? 0),
|
|
83959
|
-
frames: Number(r["frames"] ?? 0),
|
|
83960
|
-
completeFrames: Number(r["completeFrames"] ?? 0)
|
|
83961
|
-
};
|
|
83962
|
-
})
|
|
83963
|
-
};
|
|
83964
|
-
}
|
|
83965
|
-
var RetrainDatasetVersionStore = class {
|
|
83966
|
-
store;
|
|
83967
|
-
logger;
|
|
84206
|
+
//#region src/pipeline-analytics/retrain/retrain-dataset-version-routing.ts
|
|
84207
|
+
var RoutingDatasetVersionRepository = class {
|
|
84208
|
+
deps;
|
|
84209
|
+
lastPresence = false;
|
|
84210
|
+
migrated = false;
|
|
84211
|
+
migration = null;
|
|
83968
84212
|
constructor(deps) {
|
|
83969
|
-
this.
|
|
83970
|
-
this.logger = deps.logger;
|
|
83971
|
-
}
|
|
83972
|
-
static async declare(store) {
|
|
83973
|
-
await store.declareCollection.mutate({
|
|
83974
|
-
collection: RETRAIN_DATASET_VERSIONS_COLLECTION,
|
|
83975
|
-
columns: [...COLUMNS],
|
|
83976
|
-
indexes: [...INDEXES]
|
|
83977
|
-
});
|
|
84213
|
+
this.deps = deps;
|
|
83978
84214
|
}
|
|
83979
84215
|
insert = async (version) => {
|
|
83980
|
-
await this.
|
|
83981
|
-
|
|
83982
|
-
|
|
83983
|
-
|
|
83984
|
-
|
|
83985
|
-
nameKey: nameKeyOf(version.name),
|
|
83986
|
-
createdAt: version.createdAt,
|
|
83987
|
-
selection: version.selection,
|
|
83988
|
-
layout: version.layout,
|
|
83989
|
-
completeOnly: version.completeOnly,
|
|
83990
|
-
frameIds: version.frameIds,
|
|
83991
|
-
annotationHash: version.annotationHash,
|
|
83992
|
-
manifestSchema: version.manifestSchema,
|
|
83993
|
-
stats: version.stats
|
|
83994
|
-
}
|
|
83995
|
-
});
|
|
84216
|
+
if (await this.route() === "local") {
|
|
84217
|
+
await this.deps.local.insert(version);
|
|
84218
|
+
return;
|
|
84219
|
+
}
|
|
84220
|
+
await this.deps.training.put(version);
|
|
83996
84221
|
};
|
|
83997
|
-
get = async (id) =>
|
|
84222
|
+
get = async (id) => await this.route() === "local" ? this.deps.local.get(id) : this.deps.training.get(id);
|
|
84223
|
+
list = async () => await this.route() === "local" ? this.deps.local.list() : this.deps.training.list();
|
|
84224
|
+
findIdByName = async (name) => await this.route() === "local" ? this.deps.local.findIdByName(name) : this.deps.training.findIdByName(name);
|
|
84225
|
+
remove = async (id) => await this.route() === "local" ? this.deps.local.remove(id) : this.deps.training.remove(id);
|
|
84226
|
+
async route() {
|
|
84227
|
+
if (!await this.presence()) return "local";
|
|
84228
|
+
if (this.migrated) return "training";
|
|
84229
|
+
return await this.migrateOnce() ? "training" : "local";
|
|
84230
|
+
}
|
|
84231
|
+
async presence() {
|
|
84232
|
+
let answer;
|
|
83998
84233
|
try {
|
|
83999
|
-
|
|
84000
|
-
|
|
84001
|
-
|
|
84002
|
-
});
|
|
84003
|
-
return row === null || row === void 0 ? null : this.toVersion(id, asRecord(row));
|
|
84004
|
-
} catch (err) {
|
|
84005
|
-
this.logger.warn("retrain dataset version read failed", { meta: {
|
|
84006
|
-
versionId: id,
|
|
84007
|
-
error: String(err)
|
|
84008
|
-
} });
|
|
84009
|
-
return null;
|
|
84234
|
+
answer = await this.deps.trainingPresent();
|
|
84235
|
+
} catch {
|
|
84236
|
+
answer = null;
|
|
84010
84237
|
}
|
|
84011
|
-
|
|
84012
|
-
|
|
84238
|
+
if (answer !== null) this.lastPresence = answer;
|
|
84239
|
+
return this.lastPresence;
|
|
84240
|
+
}
|
|
84241
|
+
migrateOnce() {
|
|
84242
|
+
if (this.migration === null) this.migration = this.migrate().finally(() => {
|
|
84243
|
+
this.migration = null;
|
|
84244
|
+
});
|
|
84245
|
+
return this.migration;
|
|
84246
|
+
}
|
|
84247
|
+
async migrate() {
|
|
84248
|
+
const { local, training, logger } = this.deps;
|
|
84013
84249
|
try {
|
|
84014
|
-
|
|
84015
|
-
|
|
84016
|
-
|
|
84017
|
-
|
|
84018
|
-
|
|
84019
|
-
|
|
84020
|
-
|
|
84250
|
+
const rows = await local.listRows();
|
|
84251
|
+
for (const row of rows) {
|
|
84252
|
+
await training.put(row);
|
|
84253
|
+
await local.remove(row.id);
|
|
84254
|
+
}
|
|
84255
|
+
this.migrated = true;
|
|
84256
|
+
if (rows.length > 0) logger.info("retrain dataset versions moved to the training capability", { meta: { versions: rows.length } });
|
|
84257
|
+
return true;
|
|
84021
84258
|
} catch (err) {
|
|
84022
|
-
|
|
84023
|
-
return
|
|
84259
|
+
logger.warn("retrain dataset versions could not move to training yet — kept local", { meta: { error: err instanceof Error ? err.message : String(err) } });
|
|
84260
|
+
return false;
|
|
84024
84261
|
}
|
|
84025
|
-
};
|
|
84026
|
-
findIdByName = async (name) => {
|
|
84027
|
-
return (await this.store.query.query({
|
|
84028
|
-
collection: RETRAIN_DATASET_VERSIONS_COLLECTION,
|
|
84029
|
-
filter: {
|
|
84030
|
-
where: { nameKey: nameKeyOf(name) },
|
|
84031
|
-
limit: 1
|
|
84032
|
-
}
|
|
84033
|
-
}))[0]?.id ?? null;
|
|
84034
|
-
};
|
|
84035
|
-
remove = async (id) => {
|
|
84036
|
-
if (await this.get(id) === null) return false;
|
|
84037
|
-
await this.store.delete.mutate({
|
|
84038
|
-
collection: RETRAIN_DATASET_VERSIONS_COLLECTION,
|
|
84039
|
-
key: id
|
|
84040
|
-
});
|
|
84041
|
-
return true;
|
|
84042
|
-
};
|
|
84043
|
-
toVersion(id, data) {
|
|
84044
|
-
const selection = asRecord(parseJson(data["selection"]));
|
|
84045
|
-
const deviceIds = numberList(selection["deviceIds"]);
|
|
84046
|
-
const collectionIds = stringList(selection["collectionIds"]);
|
|
84047
|
-
const frameIdsSel = stringList(selection["frameIds"]);
|
|
84048
|
-
return {
|
|
84049
|
-
id,
|
|
84050
|
-
name: String(data["name"] ?? ""),
|
|
84051
|
-
createdAt: Number(data["createdAt"] ?? 0),
|
|
84052
|
-
selection: {
|
|
84053
|
-
...deviceIds !== void 0 ? { deviceIds } : {},
|
|
84054
|
-
...collectionIds !== void 0 ? { collectionIds } : {},
|
|
84055
|
-
...frameIdsSel !== void 0 ? { frameIds: frameIdsSel } : {}
|
|
84056
|
-
},
|
|
84057
|
-
layout: data["layout"] === "crops" ? "crops" : "frames",
|
|
84058
|
-
completeOnly: data["completeOnly"] === true || data["completeOnly"] === 1,
|
|
84059
|
-
frameIds: stringList(parseJson(data["frameIds"])) ?? [],
|
|
84060
|
-
annotationHash: String(data["annotationHash"] ?? ""),
|
|
84061
|
-
manifestSchema: String(data["manifestSchema"] ?? ""),
|
|
84062
|
-
stats: readStats(data["stats"])
|
|
84063
|
-
};
|
|
84064
84262
|
}
|
|
84065
84263
|
};
|
|
84066
84264
|
//#endregion
|
|
@@ -84730,6 +84928,61 @@ async function writeRetrainArchiveTo(deps) {
|
|
|
84730
84928
|
return stats;
|
|
84731
84929
|
}
|
|
84732
84930
|
//#endregion
|
|
84931
|
+
//#region src/pipeline-analytics/retrain/retrain-archive-offer.ts
|
|
84932
|
+
/** A reader silent this long is gone; the body is cut. */
|
|
84933
|
+
var RETRAIN_OFFER_STALL_MS = 6e4;
|
|
84934
|
+
function responseArchiveSink(res, stallMs = RETRAIN_OFFER_STALL_MS) {
|
|
84935
|
+
let closed = false;
|
|
84936
|
+
res.once("close", () => {
|
|
84937
|
+
closed = true;
|
|
84938
|
+
});
|
|
84939
|
+
return { write: (chunk) => new Promise((resolve, reject) => {
|
|
84940
|
+
if (closed || res.destroyed) {
|
|
84941
|
+
reject(/* @__PURE__ */ new Error("retrain archive reader went away"));
|
|
84942
|
+
return;
|
|
84943
|
+
}
|
|
84944
|
+
if (res.write(chunk)) {
|
|
84945
|
+
resolve();
|
|
84946
|
+
return;
|
|
84947
|
+
}
|
|
84948
|
+
const onDrain = () => {
|
|
84949
|
+
cleanup();
|
|
84950
|
+
resolve();
|
|
84951
|
+
};
|
|
84952
|
+
const onClose = () => {
|
|
84953
|
+
cleanup();
|
|
84954
|
+
reject(/* @__PURE__ */ new Error("retrain archive reader went away"));
|
|
84955
|
+
};
|
|
84956
|
+
const timer = setTimeout(() => {
|
|
84957
|
+
cleanup();
|
|
84958
|
+
res.destroy(/* @__PURE__ */ new Error("retrain archive reader stalled"));
|
|
84959
|
+
reject(/* @__PURE__ */ new Error(`retrain archive reader stalled for ${stallMs} ms`));
|
|
84960
|
+
}, stallMs);
|
|
84961
|
+
const cleanup = () => {
|
|
84962
|
+
clearTimeout(timer);
|
|
84963
|
+
res.off("drain", onDrain);
|
|
84964
|
+
res.off("close", onClose);
|
|
84965
|
+
};
|
|
84966
|
+
res.once("drain", onDrain);
|
|
84967
|
+
res.once("close", onClose);
|
|
84968
|
+
}) };
|
|
84969
|
+
}
|
|
84970
|
+
/**
|
|
84971
|
+
* Serve one archive: headers, the writer's chunks, the end. A writer that
|
|
84972
|
+
* throws destroys the response (the reader sees a truncated body, never a
|
|
84973
|
+
* clean end) and the error propagates to the caller's log.
|
|
84974
|
+
*/
|
|
84975
|
+
async function serveRetrainArchive(_req, res, writeArchive) {
|
|
84976
|
+
res.writeHead(200, { "content-type": "application/x-tar" });
|
|
84977
|
+
try {
|
|
84978
|
+
await writeArchive(responseArchiveSink(res));
|
|
84979
|
+
await new Promise((resolve) => res.end(resolve));
|
|
84980
|
+
} catch (err) {
|
|
84981
|
+
res.destroy(err instanceof Error ? err : new Error(String(err)));
|
|
84982
|
+
throw err;
|
|
84983
|
+
}
|
|
84984
|
+
}
|
|
84985
|
+
//#endregion
|
|
84733
84986
|
//#region src/pipeline-analytics/retrain/retrain-crop-cut.ts
|
|
84734
84987
|
/**
|
|
84735
84988
|
* The `crops` layout's cutter: one subject crop from a retrain frame copy.
|
|
@@ -111026,8 +111279,26 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
111026
111279
|
logger: logger.child("RetrainDatasets")
|
|
111027
111280
|
});
|
|
111028
111281
|
this.retrainDatasetVersions = retrainDatasetVersions;
|
|
111282
|
+
const routedDatasetVersions = new RoutingDatasetVersionRepository({
|
|
111283
|
+
local: retrainDatasetVersions,
|
|
111284
|
+
training: {
|
|
111285
|
+
put: (row) => api.training.putDatasetVersion.mutate({ ...row }),
|
|
111286
|
+
get: (id) => api.training.getDatasetVersion.query({ id }),
|
|
111287
|
+
list: async () => api.training.listDatasetVersions.query({}),
|
|
111288
|
+
findIdByName: async (name) => (await api.training.findDatasetVersionIdByName.query({ name })).id,
|
|
111289
|
+
remove: async (id) => (await api.training.removeDatasetVersion.mutate({ id })).removed
|
|
111290
|
+
},
|
|
111291
|
+
trainingPresent: async () => {
|
|
111292
|
+
try {
|
|
111293
|
+
return (await api.addons.listCapabilityProviders.query({ capName: "training" })).length > 0;
|
|
111294
|
+
} catch {
|
|
111295
|
+
return null;
|
|
111296
|
+
}
|
|
111297
|
+
},
|
|
111298
|
+
logger: logger.child("RetrainDatasets")
|
|
111299
|
+
});
|
|
111029
111300
|
this.retrainDatasets = new RetrainDatasetService({
|
|
111030
|
-
versions:
|
|
111301
|
+
versions: routedDatasetVersions,
|
|
111031
111302
|
buildPlan: (request) => this.buildRetrainExportPlan(request),
|
|
111032
111303
|
now: () => Date.now(),
|
|
111033
111304
|
newId: () => randomUUID(),
|
|
@@ -112392,6 +112663,51 @@ var PipelineAnalyticsAddon = class PipelineAnalyticsAddon extends BaseAddon {
|
|
|
112392
112663
|
}
|
|
112393
112664
|
}
|
|
112394
112665
|
/**
|
|
112666
|
+
* The same archive behind a one-shot `ctx.peerBytes` ticket (D805): the
|
|
112667
|
+
* caller (a training provider, same host) dials it at once and streams it
|
|
112668
|
+
* into its cloud. The plan is built now, so an empty or unknown selection
|
|
112669
|
+
* fails here rather than as an empty body; the bytes and their sha256 are
|
|
112670
|
+
* the reader's to measure.
|
|
112671
|
+
*/
|
|
112672
|
+
async offerRetrainArchive(input) {
|
|
112673
|
+
const frameStore = this.retrainFrames;
|
|
112674
|
+
if (frameStore === null) throw new Error("retrain export: analytics stores unavailable");
|
|
112675
|
+
const peerBytes = this.ctx.peerBytes;
|
|
112676
|
+
if (peerBytes === void 0) throw new Error("retrain archive offer: no peer-bytes facility");
|
|
112677
|
+
const plan = await this.buildRetrainExportPlan({
|
|
112678
|
+
filter: input.filter,
|
|
112679
|
+
layout: input.layout
|
|
112680
|
+
});
|
|
112681
|
+
if (plan.frames.length === 0) throw new Error("retrain archive offer: the selection holds no frame");
|
|
112682
|
+
const logger = this.ctx.logger;
|
|
112683
|
+
const offered = await peerBytes.offer({
|
|
112684
|
+
label: "retrain-archive",
|
|
112685
|
+
handler: (req, res) => serveRetrainArchive(req, res, async (sink) => {
|
|
112686
|
+
await writeRetrainArchiveTo({
|
|
112687
|
+
plan,
|
|
112688
|
+
readFrame: (frame) => frameStore.readFrame(frame),
|
|
112689
|
+
cutCrop: this.retrainCropCutter(),
|
|
112690
|
+
sink,
|
|
112691
|
+
markExported: (frameIds, batchId) => this.markRetrainExported(frameIds, batchId),
|
|
112692
|
+
logger,
|
|
112693
|
+
now: () => Date.now()
|
|
112694
|
+
});
|
|
112695
|
+
}).catch((err) => {
|
|
112696
|
+
logger.warn("retrain archive offer failed mid-body", { meta: { error: errMsg(err) } });
|
|
112697
|
+
})
|
|
112698
|
+
});
|
|
112699
|
+
if (offered.kind === "refused") throw new Error(`retrain archive offer refused: ${offered.code} — ${offered.detail}`);
|
|
112700
|
+
logger.info("retrain archive offered", { meta: {
|
|
112701
|
+
frames: plan.frames.length,
|
|
112702
|
+
layout: input.layout
|
|
112703
|
+
} });
|
|
112704
|
+
return {
|
|
112705
|
+
ticket: offered.ticket,
|
|
112706
|
+
frames: plan.frames.length,
|
|
112707
|
+
annotations: plan.manifest.annotationCount
|
|
112708
|
+
};
|
|
112709
|
+
}
|
|
112710
|
+
/**
|
|
112395
112711
|
* The store seam the `debug.*` actions and the debug bundle both read through.
|
|
112396
112712
|
*
|
|
112397
112713
|
* Index reads, plus ONE existence probe per media row — never a blob. The
|