@blueharford/scrypted-spatial-awareness 0.6.5 → 0.6.7

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/plugin.zip CHANGED
Binary file
@@ -40054,7 +40054,7 @@ class SpatialAwarenessPlugin extends sdk_1.ScryptedDeviceBase {
40054
40054
  });
40055
40055
  }
40056
40056
  }
40057
- handleTrainingEndRequest(response) {
40057
+ async handleTrainingEndRequest(response) {
40058
40058
  if (!this.trackingEngine) {
40059
40059
  response.send(JSON.stringify({ error: 'Tracking engine not running' }), {
40060
40060
  code: 500,
@@ -40064,6 +40064,39 @@ class SpatialAwarenessPlugin extends sdk_1.ScryptedDeviceBase {
40064
40064
  }
40065
40065
  const session = this.trackingEngine.endTrainingSession();
40066
40066
  if (session) {
40067
+ // Get unique visited cameras
40068
+ const visitedCameraIds = [...new Set(session.visits.map(v => v.cameraId))];
40069
+ // Auto-run discovery on visited cameras to detect landmarks and zones
40070
+ if (this.discoveryEngine && visitedCameraIds.length > 0) {
40071
+ this.console.log(`[Training] Running discovery analysis on ${visitedCameraIds.length} visited cameras...`);
40072
+ let landmarksFound = 0;
40073
+ let zonesFound = 0;
40074
+ for (const cameraId of visitedCameraIds) {
40075
+ try {
40076
+ const analysis = await this.discoveryEngine.analyzeScene(cameraId);
40077
+ if (analysis.isValid) {
40078
+ landmarksFound += analysis.landmarks.length;
40079
+ zonesFound += analysis.zones.length;
40080
+ this.console.log(`[Training] ${cameraId}: Found ${analysis.landmarks.length} landmarks, ${analysis.zones.length} zones`);
40081
+ }
40082
+ }
40083
+ catch (e) {
40084
+ this.console.warn(`[Training] Failed to analyze ${cameraId}:`, e);
40085
+ }
40086
+ }
40087
+ // Get all pending suggestions and auto-accept them
40088
+ const suggestions = this.discoveryEngine.getPendingSuggestions();
40089
+ for (const suggestion of suggestions) {
40090
+ this.applyDiscoverySuggestion(suggestion);
40091
+ this.discoveryEngine.acceptSuggestion(suggestion.id);
40092
+ }
40093
+ // Persist topology after applying suggestions
40094
+ if (suggestions.length > 0 && this.trackingEngine) {
40095
+ const updatedTopology = this.trackingEngine.getTopology();
40096
+ await this.storageSettings.putSetting('topology', JSON.stringify(updatedTopology));
40097
+ this.console.log(`[Training] Auto-applied ${suggestions.length} discoveries (${landmarksFound} landmarks, ${zonesFound} zones)`);
40098
+ }
40099
+ }
40067
40100
  response.send(JSON.stringify(session), {
40068
40101
  headers: { 'Content-Type': 'application/json' },
40069
40102
  });
@@ -40311,34 +40344,53 @@ class SpatialAwarenessPlugin extends sdk_1.ScryptedDeviceBase {
40311
40344
  // Convert direction to radians (0 = up/north, 90 = right/east)
40312
40345
  const dirRad = (direction - 90) * Math.PI / 180;
40313
40346
  const halfFov = (fovAngle / 2) * Math.PI / 180;
40314
- // Use bounding box if available to position landmark accurately within FOV
40347
+ // Use landmark TYPE to determine distance - some things are inherently far away
40348
+ // regardless of where they appear in the camera frame
40349
+ const landmarkType = suggestion.landmark.type;
40350
+ const farTypes = ['neighbor', 'boundary', 'street']; // Always place at edge of FOV
40351
+ const isFarType = farTypes.includes(landmarkType || '');
40352
+ // Use bounding box if available for horizontal positioning
40315
40353
  // boundingBox format: [x, y, width, height] normalized 0-1
40316
40354
  const bbox = suggestion.landmark.boundingBox;
40317
40355
  let angleOffset;
40318
40356
  let distanceMultiplier;
40319
40357
  if (bbox && bbox.length >= 2) {
40320
- // Use bounding box center to determine position in FOV
40358
+ // Use bounding box X for horizontal position in FOV
40321
40359
  const bboxCenterX = bbox[0] + (bbox[2] || 0) / 2; // 0 = left edge, 1 = right edge
40322
- const bboxCenterY = bbox[1] + (bbox[3] || 0) / 2; // 0 = top (far), 1 = bottom (close)
40323
40360
  // Map X position to angle within FOV
40324
- // bboxCenterX 0 → left side of FOV (-halfFov)
40325
- // bboxCenterX 0.5 → center of FOV (0)
40326
- // bboxCenterX 1 → right side of FOV (+halfFov)
40327
40361
  angleOffset = (bboxCenterX - 0.5) * 2 * halfFov;
40328
- // Map Y position to distance from camera
40329
- // bboxCenterY 0 (top of frame) → far from camera (90% of range)
40330
- // bboxCenterY 1 (bottom of frame) close to camera (30% of range)
40331
- distanceMultiplier = 0.9 - (bboxCenterY * 0.6);
40332
- this.console.log(`[Discovery] Using bounding box [${bbox.join(',')}] center (${bboxCenterX.toFixed(2)}, ${bboxCenterY.toFixed(2)})`);
40362
+ // For distance: use TYPE first, then bbox Y as hint
40363
+ if (isFarType) {
40364
+ // Neighbors, boundaries, streets are BEYOND the camera's normal range
40365
+ // Place at 150-200% of range to indicate they're distant background features
40366
+ distanceMultiplier = 1.5 + Math.random() * 0.5; // 150-200% of range
40367
+ this.console.log(`[Discovery] Far-type landmark "${landmarkType}" placed BEYOND FOV (${(distanceMultiplier * 100).toFixed(0)}% of range)`);
40368
+ }
40369
+ else {
40370
+ // For other types, use bbox Y as a hint (but cap minimum distance)
40371
+ const bboxCenterY = bbox[1] + (bbox[3] || 0) / 2;
40372
+ // Map Y to distance: 0 (top) = far, 1 (bottom) = closer (but not too close)
40373
+ distanceMultiplier = Math.max(0.4, 0.9 - (bboxCenterY * 0.5));
40374
+ }
40375
+ this.console.log(`[Discovery] Using bounding box [${bbox.join(',')}] for horizontal position`);
40333
40376
  }
40334
40377
  else {
40335
- // Fallback: spread landmarks across FOV if no bounding box
40378
+ // No bounding box - use type and spread pattern
40336
40379
  const cameraDeviceId = camera.deviceId;
40337
40380
  const existingFromCamera = (topology.landmarks || []).filter(l => l.visibleFromCameras?.includes(cameraDeviceId) ||
40338
40381
  l.visibleFromCameras?.includes(camera.name)).length;
40382
+ // Spread horizontally across FOV
40339
40383
  angleOffset = (existingFromCamera % 3 - 1) * halfFov * 0.6;
40340
- distanceMultiplier = 0.5 + (existingFromCamera % 2) * 0.3;
40341
- this.console.log(`[Discovery] No bounding box, using fallback spread (existing: ${existingFromCamera})`);
40384
+ // Distance based on type
40385
+ if (isFarType) {
40386
+ // Neighbors, boundaries, streets are BEYOND the camera's normal range
40387
+ distanceMultiplier = 1.5 + Math.random() * 0.5; // 150-200% of range
40388
+ this.console.log(`[Discovery] Far-type landmark "${landmarkType}" (no bbox) placed BEYOND FOV`);
40389
+ }
40390
+ else {
40391
+ distanceMultiplier = 0.5 + (existingFromCamera % 2) * 0.3;
40392
+ this.console.log(`[Discovery] No bounding box, using fallback spread (existing: ${existingFromCamera})`);
40393
+ }
40342
40394
  }
40343
40395
  const finalAngle = dirRad + angleOffset;
40344
40396
  const distance = range * distanceMultiplier;