@blueharford/scrypted-spatial-awareness 0.6.12 → 0.6.13
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/main.nodejs.js +1 -1
- package/dist/main.nodejs.js.map +1 -1
- package/dist/plugin.zip +0 -0
- package/out/main.nodejs.js +48 -32
- package/out/main.nodejs.js.map +1 -1
- package/out/plugin.zip +0 -0
- package/package.json +1 -1
- package/src/core/tracking-engine.ts +54 -30
package/out/plugin.zip
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -138,6 +138,10 @@ export class TrackingEngine {
|
|
|
138
138
|
/** Callback for training status updates */
|
|
139
139
|
private onTrainingStatusUpdate?: (status: TrainingStatusUpdate) => void;
|
|
140
140
|
|
|
141
|
+
// ==================== Snapshot Cache ====================
|
|
142
|
+
/** Cached snapshots for tracked objects (for faster notifications) */
|
|
143
|
+
private snapshotCache: Map<GlobalTrackingId, MediaObject> = new Map();
|
|
144
|
+
|
|
141
145
|
constructor(
|
|
142
146
|
topology: CameraTopology,
|
|
143
147
|
state: TrackingState,
|
|
@@ -437,6 +441,13 @@ export class TrackingEngine {
|
|
|
437
441
|
if (lastSighting && lastSighting.cameraId !== sighting.cameraId) {
|
|
438
442
|
const transitDuration = sighting.timestamp - lastSighting.timestamp;
|
|
439
443
|
|
|
444
|
+
// Update cached snapshot from new camera (object is now visible here)
|
|
445
|
+
if (this.config.useLlmDescriptions) {
|
|
446
|
+
this.captureAndCacheSnapshot(tracked.globalId, sighting.cameraId).catch(e => {
|
|
447
|
+
this.console.warn(`[Transition Snapshot] Failed to update snapshot: ${e}`);
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
|
|
440
451
|
// Add journey segment
|
|
441
452
|
this.state.addJourney(tracked.globalId, {
|
|
442
453
|
fromCameraId: lastSighting.cameraId,
|
|
@@ -528,6 +539,14 @@ export class TrackingEngine {
|
|
|
528
539
|
sighting: ObjectSighting,
|
|
529
540
|
isEntryPoint: boolean
|
|
530
541
|
): void {
|
|
542
|
+
// Capture snapshot IMMEDIATELY when object is first detected (don't wait for loitering threshold)
|
|
543
|
+
// This ensures we have a good image while the person/object is still in frame
|
|
544
|
+
if (this.config.useLlmDescriptions) {
|
|
545
|
+
this.captureAndCacheSnapshot(globalId, sighting.cameraId).catch(e => {
|
|
546
|
+
this.console.warn(`[Snapshot] Failed to cache initial snapshot: ${e}`);
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
|
|
531
550
|
// Check after loitering threshold if object is still being tracked
|
|
532
551
|
setTimeout(async () => {
|
|
533
552
|
const tracked = this.state.getObject(globalId);
|
|
@@ -536,21 +555,9 @@ export class TrackingEngine {
|
|
|
536
555
|
// Check if we've already alerted for this object
|
|
537
556
|
if (this.isInAlertCooldown(globalId)) return;
|
|
538
557
|
|
|
539
|
-
//
|
|
540
|
-
let mediaObject
|
|
541
|
-
this.console.log(`[Entry Alert]
|
|
542
|
-
if (this.config.useLlmDescriptions) {
|
|
543
|
-
try {
|
|
544
|
-
const camera = systemManager.getDeviceById<Camera>(sighting.cameraId);
|
|
545
|
-
this.console.log(`[Entry Alert] Camera ${sighting.cameraId} has Camera interface: ${camera?.interfaces?.includes(ScryptedInterface.Camera)}`);
|
|
546
|
-
if (camera?.interfaces?.includes(ScryptedInterface.Camera)) {
|
|
547
|
-
mediaObject = await camera.takePicture();
|
|
548
|
-
this.console.log(`[Entry Alert] Got snapshot: ${!!mediaObject}`);
|
|
549
|
-
}
|
|
550
|
-
} catch (e) {
|
|
551
|
-
this.console.warn('[Entry Alert] Failed to get snapshot:', e);
|
|
552
|
-
}
|
|
553
|
-
}
|
|
558
|
+
// Use cached snapshot (captured when object was first detected)
|
|
559
|
+
let mediaObject = this.snapshotCache.get(globalId);
|
|
560
|
+
this.console.log(`[Entry Alert] Using cached snapshot: ${!!mediaObject}`);
|
|
554
561
|
|
|
555
562
|
// Generate spatial description (now async with LLM support)
|
|
556
563
|
this.console.log(`[Entry Alert] Calling generateEntryDescription with mediaObject=${!!mediaObject}`);
|
|
@@ -592,6 +599,22 @@ export class TrackingEngine {
|
|
|
592
599
|
}, this.config.loiteringThreshold);
|
|
593
600
|
}
|
|
594
601
|
|
|
602
|
+
/** Capture and cache a snapshot for a tracked object */
|
|
603
|
+
private async captureAndCacheSnapshot(globalId: GlobalTrackingId, cameraId: string): Promise<void> {
|
|
604
|
+
try {
|
|
605
|
+
const camera = systemManager.getDeviceById<Camera>(cameraId);
|
|
606
|
+
if (camera?.interfaces?.includes(ScryptedInterface.Camera)) {
|
|
607
|
+
const mediaObject = await camera.takePicture();
|
|
608
|
+
if (mediaObject) {
|
|
609
|
+
this.snapshotCache.set(globalId, mediaObject);
|
|
610
|
+
this.console.log(`[Snapshot] Cached snapshot for ${globalId.slice(0, 8)} from ${cameraId}`);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
} catch (e) {
|
|
614
|
+
this.console.warn(`[Snapshot] Failed to capture snapshot: ${e}`);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
595
618
|
/** Attempt to correlate a sighting with existing tracked objects */
|
|
596
619
|
private async correlateDetection(
|
|
597
620
|
sighting: ObjectSighting
|
|
@@ -639,27 +662,22 @@ export class TrackingEngine {
|
|
|
639
662
|
// Mark as pending and set timer
|
|
640
663
|
this.state.markPending(tracked.globalId);
|
|
641
664
|
|
|
665
|
+
// Capture a fresh snapshot now while object is still visible (before they leave)
|
|
666
|
+
if (this.config.useLlmDescriptions) {
|
|
667
|
+
this.captureAndCacheSnapshot(tracked.globalId, sighting.cameraId).catch(e => {
|
|
668
|
+
this.console.warn(`[Exit Snapshot] Failed to update snapshot: ${e}`);
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
|
|
642
672
|
// Wait for correlation window before marking as exited
|
|
643
673
|
const timer = setTimeout(async () => {
|
|
644
674
|
const current = this.state.getObject(tracked.globalId);
|
|
645
675
|
if (current && current.state === 'pending') {
|
|
646
676
|
this.state.markExited(tracked.globalId, sighting.cameraId, sighting.cameraName);
|
|
647
677
|
|
|
648
|
-
//
|
|
649
|
-
let mediaObject
|
|
650
|
-
this.console.log(`[Exit Alert]
|
|
651
|
-
if (this.config.useLlmDescriptions) {
|
|
652
|
-
try {
|
|
653
|
-
const camera = systemManager.getDeviceById<Camera>(sighting.cameraId);
|
|
654
|
-
this.console.log(`[Exit Alert] Camera ${sighting.cameraId} has Camera interface: ${camera?.interfaces?.includes(ScryptedInterface.Camera)}`);
|
|
655
|
-
if (camera?.interfaces?.includes(ScryptedInterface.Camera)) {
|
|
656
|
-
mediaObject = await camera.takePicture();
|
|
657
|
-
this.console.log(`[Exit Alert] Got snapshot: ${!!mediaObject}`);
|
|
658
|
-
}
|
|
659
|
-
} catch (e) {
|
|
660
|
-
this.console.warn('[Exit Alert] Failed to get snapshot:', e);
|
|
661
|
-
}
|
|
662
|
-
}
|
|
678
|
+
// Use cached snapshot (captured when exit was first detected, while object was still visible)
|
|
679
|
+
let mediaObject = this.snapshotCache.get(tracked.globalId);
|
|
680
|
+
this.console.log(`[Exit Alert] Using cached snapshot: ${!!mediaObject}`);
|
|
663
681
|
|
|
664
682
|
// Generate rich exit description using topology context (now async with LLM support)
|
|
665
683
|
this.console.log(`[Exit Alert] Calling generateExitDescription with mediaObject=${!!mediaObject}`);
|
|
@@ -681,6 +699,9 @@ export class TrackingEngine {
|
|
|
681
699
|
involvedLandmarks: spatialResult.involvedLandmarks?.map(l => l.name),
|
|
682
700
|
usedLlm: spatialResult.usedLlm,
|
|
683
701
|
});
|
|
702
|
+
|
|
703
|
+
// Clean up cached snapshot after exit alert
|
|
704
|
+
this.snapshotCache.delete(tracked.globalId);
|
|
684
705
|
}
|
|
685
706
|
this.pendingTimers.delete(tracked.globalId);
|
|
686
707
|
}, this.config.correlationWindow);
|
|
@@ -703,6 +724,9 @@ export class TrackingEngine {
|
|
|
703
724
|
`(not seen for ${Math.round(timeSinceSeen / 1000)}s)`
|
|
704
725
|
);
|
|
705
726
|
|
|
727
|
+
// Clean up cached snapshot
|
|
728
|
+
this.snapshotCache.delete(tracked.globalId);
|
|
729
|
+
|
|
706
730
|
this.alertManager.checkAndAlert('lost_tracking', tracked, {
|
|
707
731
|
objectClass: tracked.className,
|
|
708
732
|
objectLabel: tracked.label,
|