@blueharford/scrypted-spatial-awareness 0.6.8 → 0.6.9
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 +40 -5
- package/out/main.nodejs.js.map +1 -1
- package/out/plugin.zip +0 -0
- package/package.json +1 -1
- package/src/core/spatial-reasoning.ts +29 -2
- package/src/core/tracking-engine.ts +12 -3
package/dist/plugin.zip
CHANGED
|
Binary file
|
package/out/main.nodejs.js
CHANGED
|
@@ -35531,9 +35531,12 @@ class SpatialReasoningEngine {
|
|
|
35531
35531
|
}
|
|
35532
35532
|
const basicDescription = `${objectType} arrived at ${location}${source}`;
|
|
35533
35533
|
// Try LLM for enhanced description with visual details
|
|
35534
|
+
this.console.log(`[Entry] enableLlm=${this.config.enableLlm}, hasMediaObject=${!!mediaObject}`);
|
|
35534
35535
|
if (this.config.enableLlm && mediaObject) {
|
|
35536
|
+
this.console.log(`[Entry] Attempting LLM description for entry event`);
|
|
35535
35537
|
const llmDescription = await this.getLlmEntryExitDescription(tracked, camera, landmarks, 'entry', mediaObject);
|
|
35536
35538
|
if (llmDescription) {
|
|
35539
|
+
this.console.log(`[Entry] LLM returned: ${llmDescription.substring(0, 50)}...`);
|
|
35537
35540
|
return {
|
|
35538
35541
|
description: llmDescription,
|
|
35539
35542
|
involvedLandmarks: landmarks,
|
|
@@ -35541,6 +35544,10 @@ class SpatialReasoningEngine {
|
|
|
35541
35544
|
usedLlm: true,
|
|
35542
35545
|
};
|
|
35543
35546
|
}
|
|
35547
|
+
this.console.warn(`[Entry] LLM returned null, falling back to basic`);
|
|
35548
|
+
}
|
|
35549
|
+
else {
|
|
35550
|
+
this.console.log(`[Entry] Skipping LLM (enableLlm=${this.config.enableLlm}, mediaObject=${!!mediaObject})`);
|
|
35544
35551
|
}
|
|
35545
35552
|
return {
|
|
35546
35553
|
description: basicDescription,
|
|
@@ -35617,9 +35624,12 @@ class SpatialReasoningEngine {
|
|
|
35617
35624
|
}
|
|
35618
35625
|
const basicDescription = `${objectType} left ${location}${destination}${timeContext}${journeyContext}`;
|
|
35619
35626
|
// Try LLM for enhanced description with visual details
|
|
35627
|
+
this.console.log(`[Exit] enableLlm=${this.config.enableLlm}, hasMediaObject=${!!mediaObject}`);
|
|
35620
35628
|
if (this.config.enableLlm && mediaObject) {
|
|
35629
|
+
this.console.log(`[Exit] Attempting LLM description for exit event`);
|
|
35621
35630
|
const llmDescription = await this.getLlmEntryExitDescription(tracked, camera, landmarks, 'exit', mediaObject, journeyContext);
|
|
35622
35631
|
if (llmDescription) {
|
|
35632
|
+
this.console.log(`[Exit] LLM returned: ${llmDescription.substring(0, 50)}...`);
|
|
35623
35633
|
return {
|
|
35624
35634
|
description: llmDescription,
|
|
35625
35635
|
involvedLandmarks: landmarks,
|
|
@@ -35627,6 +35637,10 @@ class SpatialReasoningEngine {
|
|
|
35627
35637
|
usedLlm: true,
|
|
35628
35638
|
};
|
|
35629
35639
|
}
|
|
35640
|
+
this.console.warn(`[Exit] LLM returned null, falling back to basic`);
|
|
35641
|
+
}
|
|
35642
|
+
else {
|
|
35643
|
+
this.console.log(`[Exit] Skipping LLM (enableLlm=${this.config.enableLlm}, mediaObject=${!!mediaObject})`);
|
|
35630
35644
|
}
|
|
35631
35645
|
return {
|
|
35632
35646
|
description: basicDescription,
|
|
@@ -35828,12 +35842,21 @@ class SpatialReasoningEngine {
|
|
|
35828
35842
|
}
|
|
35829
35843
|
/** Get LLM-enhanced description for entry/exit events */
|
|
35830
35844
|
async getLlmEntryExitDescription(tracked, camera, landmarks, eventType, mediaObject, journeyContext) {
|
|
35845
|
+
this.console.log(`[LLM] getLlmEntryExitDescription called for ${eventType} event`);
|
|
35831
35846
|
const llm = await this.findLlmDevice();
|
|
35832
|
-
if (!llm
|
|
35847
|
+
if (!llm) {
|
|
35848
|
+
this.console.warn(`[LLM] No LLM device found for ${eventType} description`);
|
|
35849
|
+
return null;
|
|
35850
|
+
}
|
|
35851
|
+
if (!llm.getChatCompletion) {
|
|
35852
|
+
this.console.warn(`[LLM] LLM device has no getChatCompletion method`);
|
|
35833
35853
|
return null;
|
|
35854
|
+
}
|
|
35855
|
+
this.console.log(`[LLM] Using LLM device: ${this.llmProvider}`);
|
|
35834
35856
|
try {
|
|
35835
35857
|
// Convert image to base64 for vision LLM
|
|
35836
35858
|
const imageData = await mediaObjectToBase64(mediaObject);
|
|
35859
|
+
this.console.log(`[LLM] Image converted: ${imageData ? 'success' : 'failed'}, type: ${imageData?.mediaType}`);
|
|
35837
35860
|
const landmarkNames = landmarks.map(l => l.name).join(', ') || 'none identified';
|
|
35838
35861
|
const dwellTime = Math.round((tracked.lastSeen - tracked.firstSeen) / 1000);
|
|
35839
35862
|
// Build context-aware prompt
|
|
@@ -35894,6 +35917,7 @@ Generate ONLY the description, nothing else:`;
|
|
|
35894
35917
|
messageContent = prompt;
|
|
35895
35918
|
}
|
|
35896
35919
|
// Call LLM using ChatCompletion interface
|
|
35920
|
+
this.console.log(`[LLM] Calling getChatCompletion for ${eventType}...`);
|
|
35897
35921
|
const result = await llm.getChatCompletion({
|
|
35898
35922
|
messages: [
|
|
35899
35923
|
{
|
|
@@ -35906,12 +35930,14 @@ Generate ONLY the description, nothing else:`;
|
|
|
35906
35930
|
});
|
|
35907
35931
|
const content = result?.choices?.[0]?.message?.content;
|
|
35908
35932
|
if (content && typeof content === 'string') {
|
|
35933
|
+
this.console.log(`[LLM] Got ${eventType} description: ${content.trim().substring(0, 50)}...`);
|
|
35909
35934
|
return content.trim();
|
|
35910
35935
|
}
|
|
35936
|
+
this.console.warn(`[LLM] No content in response for ${eventType}`);
|
|
35911
35937
|
return null;
|
|
35912
35938
|
}
|
|
35913
35939
|
catch (e) {
|
|
35914
|
-
this.console.warn(`LLM ${eventType} description generation failed:`, e);
|
|
35940
|
+
this.console.warn(`[LLM] ${eventType} description generation failed:`, e);
|
|
35915
35941
|
return null;
|
|
35916
35942
|
}
|
|
35917
35943
|
}
|
|
@@ -37222,19 +37248,24 @@ class TrackingEngine {
|
|
|
37222
37248
|
return;
|
|
37223
37249
|
// Get snapshot for LLM description (if LLM is enabled)
|
|
37224
37250
|
let mediaObject;
|
|
37251
|
+
this.console.log(`[Entry Alert] useLlmDescriptions=${this.config.useLlmDescriptions}`);
|
|
37225
37252
|
if (this.config.useLlmDescriptions) {
|
|
37226
37253
|
try {
|
|
37227
37254
|
const camera = systemManager.getDeviceById(sighting.cameraId);
|
|
37255
|
+
this.console.log(`[Entry Alert] Camera ${sighting.cameraId} has Camera interface: ${camera?.interfaces?.includes(sdk_1.ScryptedInterface.Camera)}`);
|
|
37228
37256
|
if (camera?.interfaces?.includes(sdk_1.ScryptedInterface.Camera)) {
|
|
37229
37257
|
mediaObject = await camera.takePicture();
|
|
37258
|
+
this.console.log(`[Entry Alert] Got snapshot: ${!!mediaObject}`);
|
|
37230
37259
|
}
|
|
37231
37260
|
}
|
|
37232
37261
|
catch (e) {
|
|
37233
|
-
this.console.warn('Failed to get snapshot
|
|
37262
|
+
this.console.warn('[Entry Alert] Failed to get snapshot:', e);
|
|
37234
37263
|
}
|
|
37235
37264
|
}
|
|
37236
37265
|
// Generate spatial description (now async with LLM support)
|
|
37266
|
+
this.console.log(`[Entry Alert] Calling generateEntryDescription with mediaObject=${!!mediaObject}`);
|
|
37237
37267
|
const spatialResult = await this.spatialReasoning.generateEntryDescription(tracked, sighting.cameraId, mediaObject);
|
|
37268
|
+
this.console.log(`[Entry Alert] Got description: "${spatialResult.description.substring(0, 60)}...", usedLlm=${spatialResult.usedLlm}`);
|
|
37238
37269
|
if (isEntryPoint) {
|
|
37239
37270
|
// Entry point - generate property entry alert
|
|
37240
37271
|
await this.alertManager.checkAndAlert('property_entry', tracked, {
|
|
@@ -37311,20 +37342,24 @@ class TrackingEngine {
|
|
|
37311
37342
|
this.state.markExited(tracked.globalId, sighting.cameraId, sighting.cameraName);
|
|
37312
37343
|
// Get snapshot for LLM description (if LLM is enabled)
|
|
37313
37344
|
let mediaObject;
|
|
37345
|
+
this.console.log(`[Exit Alert] useLlmDescriptions=${this.config.useLlmDescriptions}`);
|
|
37314
37346
|
if (this.config.useLlmDescriptions) {
|
|
37315
37347
|
try {
|
|
37316
37348
|
const camera = systemManager.getDeviceById(sighting.cameraId);
|
|
37349
|
+
this.console.log(`[Exit Alert] Camera ${sighting.cameraId} has Camera interface: ${camera?.interfaces?.includes(sdk_1.ScryptedInterface.Camera)}`);
|
|
37317
37350
|
if (camera?.interfaces?.includes(sdk_1.ScryptedInterface.Camera)) {
|
|
37318
37351
|
mediaObject = await camera.takePicture();
|
|
37352
|
+
this.console.log(`[Exit Alert] Got snapshot: ${!!mediaObject}`);
|
|
37319
37353
|
}
|
|
37320
37354
|
}
|
|
37321
37355
|
catch (e) {
|
|
37322
|
-
this.console.warn('Failed to get snapshot
|
|
37356
|
+
this.console.warn('[Exit Alert] Failed to get snapshot:', e);
|
|
37323
37357
|
}
|
|
37324
37358
|
}
|
|
37325
37359
|
// Generate rich exit description using topology context (now async with LLM support)
|
|
37360
|
+
this.console.log(`[Exit Alert] Calling generateExitDescription with mediaObject=${!!mediaObject}`);
|
|
37326
37361
|
const spatialResult = await this.spatialReasoning.generateExitDescription(current, sighting.cameraId, mediaObject);
|
|
37327
|
-
this.console.log(`Object ${tracked.globalId.slice(0, 8)} exited: ${spatialResult.description}`);
|
|
37362
|
+
this.console.log(`[Exit Alert] Object ${tracked.globalId.slice(0, 8)} exited: "${spatialResult.description.substring(0, 60)}...", usedLlm=${spatialResult.usedLlm}`);
|
|
37328
37363
|
await this.alertManager.checkAndAlert('property_exit', current, {
|
|
37329
37364
|
cameraId: sighting.cameraId,
|
|
37330
37365
|
cameraName: sighting.cameraName,
|