@blueharford/scrypted-spatial-awareness 0.6.24 → 0.6.25
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 +46 -20
- 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 +42 -19
- package/src/main.ts +2 -2
package/out/plugin.zip
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -324,6 +324,16 @@ export class TrackingEngine {
|
|
|
324
324
|
this.lastLlmCallTime = Date.now();
|
|
325
325
|
}
|
|
326
326
|
|
|
327
|
+
/** Check and record LLM call - returns false if rate limited */
|
|
328
|
+
private tryLlmCall(): boolean {
|
|
329
|
+
if (!this.isLlmCallAllowed()) {
|
|
330
|
+
this.console.log('[LLM] Rate limited, skipping LLM call');
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
333
|
+
this.recordLlmCall();
|
|
334
|
+
return true;
|
|
335
|
+
}
|
|
336
|
+
|
|
327
337
|
/** Get spatial reasoning result for movement (uses RAG + LLM) with debouncing and fallback */
|
|
328
338
|
private async getSpatialDescription(
|
|
329
339
|
tracked: TrackedObject,
|
|
@@ -337,8 +347,8 @@ export class TrackingEngine {
|
|
|
337
347
|
|
|
338
348
|
try {
|
|
339
349
|
// Check rate limiting - if not allowed, return null to use basic description
|
|
340
|
-
if (!this.
|
|
341
|
-
this.console.log('LLM rate-limited, using basic notification');
|
|
350
|
+
if (!this.tryLlmCall()) {
|
|
351
|
+
this.console.log('[Movement] LLM rate-limited, using basic notification');
|
|
342
352
|
return null;
|
|
343
353
|
}
|
|
344
354
|
|
|
@@ -351,9 +361,6 @@ export class TrackingEngine {
|
|
|
351
361
|
}
|
|
352
362
|
}
|
|
353
363
|
|
|
354
|
-
// Record that we're making an LLM call
|
|
355
|
-
this.recordLlmCall();
|
|
356
|
-
|
|
357
364
|
// Use spatial reasoning engine for rich context-aware description
|
|
358
365
|
// Apply timeout if fallback is enabled
|
|
359
366
|
let result: SpatialReasoningResult;
|
|
@@ -567,16 +574,23 @@ export class TrackingEngine {
|
|
|
567
574
|
spatialResult = await pendingDescription;
|
|
568
575
|
this.console.log(`[Entry Alert] Prefetch result: "${spatialResult.description.substring(0, 60)}...", usedLlm=${spatialResult.usedLlm}`);
|
|
569
576
|
} catch (e) {
|
|
570
|
-
this.console.warn(`[Entry Alert] Prefetch failed,
|
|
577
|
+
this.console.warn(`[Entry Alert] Prefetch failed, using basic description: ${e}`);
|
|
578
|
+
// Don't make another LLM call - use basic description (no mediaObject = no LLM)
|
|
571
579
|
spatialResult = await this.spatialReasoning.generateEntryDescription(tracked, sighting.cameraId);
|
|
572
580
|
}
|
|
573
581
|
this.pendingDescriptions.delete(globalId);
|
|
574
582
|
} else {
|
|
575
|
-
//
|
|
576
|
-
this.
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
583
|
+
// No prefetch available - only call LLM if rate limit allows
|
|
584
|
+
if (this.tryLlmCall()) {
|
|
585
|
+
this.console.log(`[Entry Alert] No prefetch, generating with LLM`);
|
|
586
|
+
const mediaObject = this.snapshotCache.get(globalId);
|
|
587
|
+
spatialResult = await this.spatialReasoning.generateEntryDescription(tracked, sighting.cameraId, mediaObject);
|
|
588
|
+
this.console.log(`[Entry Alert] Got description: "${spatialResult.description.substring(0, 60)}...", usedLlm=${spatialResult.usedLlm}`);
|
|
589
|
+
} else {
|
|
590
|
+
// Rate limited - use basic description (no LLM)
|
|
591
|
+
this.console.log(`[Entry Alert] Rate limited, using basic description`);
|
|
592
|
+
spatialResult = await this.spatialReasoning.generateEntryDescription(tracked, sighting.cameraId);
|
|
593
|
+
}
|
|
580
594
|
}
|
|
581
595
|
|
|
582
596
|
// Always use movement alert type for smart notifications with LLM descriptions
|
|
@@ -611,9 +625,9 @@ export class TrackingEngine {
|
|
|
611
625
|
this.snapshotCache.set(globalId, mediaObject);
|
|
612
626
|
this.console.log(`[Snapshot] Cached snapshot for ${globalId.slice(0, 8)} from ${cameraId}`);
|
|
613
627
|
|
|
614
|
-
// Start LLM analysis immediately in parallel (don't await)
|
|
628
|
+
// Start LLM analysis immediately in parallel (don't await) - but respect rate limits
|
|
615
629
|
const tracked = this.state.getObject(globalId);
|
|
616
|
-
if (tracked && this.config.useLlmDescriptions) {
|
|
630
|
+
if (tracked && this.config.useLlmDescriptions && this.tryLlmCall()) {
|
|
617
631
|
this.console.log(`[LLM Prefetch] Starting ${eventType} analysis for ${globalId.slice(0, 8)}`);
|
|
618
632
|
const descriptionPromise = eventType === 'exit'
|
|
619
633
|
? this.spatialReasoning.generateExitDescription(tracked, cameraId, mediaObject)
|
|
@@ -627,6 +641,8 @@ export class TrackingEngine {
|
|
|
627
641
|
}).catch(e => {
|
|
628
642
|
this.console.warn(`[LLM Prefetch] Failed for ${globalId.slice(0, 8)}: ${e}`);
|
|
629
643
|
});
|
|
644
|
+
} else if (tracked && this.config.useLlmDescriptions) {
|
|
645
|
+
this.console.log(`[LLM Prefetch] Skipped for ${globalId.slice(0, 8)} - rate limited`);
|
|
630
646
|
}
|
|
631
647
|
}
|
|
632
648
|
}
|
|
@@ -706,16 +722,23 @@ export class TrackingEngine {
|
|
|
706
722
|
spatialResult = await pendingDescription;
|
|
707
723
|
this.console.log(`[Exit Alert] Prefetch result: "${spatialResult.description.substring(0, 60)}...", usedLlm=${spatialResult.usedLlm}`);
|
|
708
724
|
} catch (e) {
|
|
709
|
-
this.console.warn(`[Exit Alert] Prefetch failed,
|
|
725
|
+
this.console.warn(`[Exit Alert] Prefetch failed, using basic description: ${e}`);
|
|
726
|
+
// Don't make another LLM call - use basic description
|
|
710
727
|
spatialResult = await this.spatialReasoning.generateExitDescription(current, sighting.cameraId);
|
|
711
728
|
}
|
|
712
729
|
this.pendingDescriptions.delete(tracked.globalId);
|
|
713
730
|
} else {
|
|
714
|
-
//
|
|
715
|
-
this.
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
731
|
+
// No prefetch available - only call LLM if rate limit allows
|
|
732
|
+
if (this.tryLlmCall()) {
|
|
733
|
+
this.console.log(`[Exit Alert] No prefetch, generating with LLM`);
|
|
734
|
+
const mediaObject = this.snapshotCache.get(tracked.globalId);
|
|
735
|
+
spatialResult = await this.spatialReasoning.generateExitDescription(current, sighting.cameraId, mediaObject);
|
|
736
|
+
this.console.log(`[Exit Alert] Got description: "${spatialResult.description.substring(0, 60)}...", usedLlm=${spatialResult.usedLlm}`);
|
|
737
|
+
} else {
|
|
738
|
+
// Rate limited - use basic description (no LLM)
|
|
739
|
+
this.console.log(`[Exit Alert] Rate limited, using basic description`);
|
|
740
|
+
spatialResult = await this.spatialReasoning.generateExitDescription(current, sighting.cameraId);
|
|
741
|
+
}
|
|
719
742
|
}
|
|
720
743
|
|
|
721
744
|
// Use movement alert for exit too - smart notifications with LLM descriptions
|
package/src/main.ts
CHANGED
|
@@ -130,8 +130,8 @@ export class SpatialAwarenessPlugin extends ScryptedDeviceBase
|
|
|
130
130
|
llmDebounceInterval: {
|
|
131
131
|
title: 'LLM Rate Limit (seconds)',
|
|
132
132
|
type: 'number',
|
|
133
|
-
defaultValue:
|
|
134
|
-
description: 'Minimum time between LLM calls to prevent API
|
|
133
|
+
defaultValue: 30,
|
|
134
|
+
description: 'Minimum time between LLM calls to prevent API rate limiting. Increase if you get rate limit errors. (0 = no limit)',
|
|
135
135
|
group: 'AI & Spatial Reasoning',
|
|
136
136
|
},
|
|
137
137
|
llmFallbackEnabled: {
|