@blueharford/scrypted-spatial-awareness 0.6.14 → 0.6.15
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 +154 -38
- package/out/main.nodejs.js.map +1 -1
- package/out/plugin.zip +0 -0
- package/package.json +1 -1
- package/src/core/topology-discovery.ts +142 -38
- package/src/models/discovery.ts +17 -0
package/dist/plugin.zip
CHANGED
|
Binary file
|
package/out/main.nodejs.js
CHANGED
|
@@ -36173,59 +36173,140 @@ const topology_1 = __webpack_require__(/*! ../models/topology */ "./src/models/t
|
|
|
36173
36173
|
const spatial_reasoning_1 = __webpack_require__(/*! ./spatial-reasoning */ "./src/core/spatial-reasoning.ts");
|
|
36174
36174
|
const { systemManager } = sdk_1.default;
|
|
36175
36175
|
/** Scene analysis prompt for single camera */
|
|
36176
|
-
const SCENE_ANALYSIS_PROMPT = `
|
|
36176
|
+
const SCENE_ANALYSIS_PROMPT = `You are analyzing a security camera image. Describe EVERYTHING you can see in detail.
|
|
36177
|
+
|
|
36178
|
+
## INSTRUCTIONS
|
|
36179
|
+
Look at this image carefully and identify ALL visible objects, structures, and areas. Be thorough - even small or partially visible items are important for security awareness.
|
|
36180
|
+
|
|
36181
|
+
## 1. LANDMARKS - List EVERY distinct object or feature you can see:
|
|
36182
|
+
|
|
36183
|
+
**Structures** (buildings, parts of buildings):
|
|
36184
|
+
- Houses, garages, sheds, porches, decks, patios, carports, gazebos
|
|
36185
|
+
- Walls, pillars, columns, railings, stairs, steps
|
|
36186
|
+
|
|
36187
|
+
**Vegetation** (plants, trees, landscaping):
|
|
36188
|
+
- Trees (describe type if identifiable: oak, palm, pine, etc.)
|
|
36189
|
+
- Bushes, shrubs, hedges
|
|
36190
|
+
- Flower beds, gardens, planters, potted plants
|
|
36191
|
+
- Grass/lawn areas, mulch beds
|
|
36192
|
+
|
|
36193
|
+
**Boundaries & Barriers**:
|
|
36194
|
+
- Fences (wood, chain-link, aluminum, vinyl, iron, privacy)
|
|
36195
|
+
- Walls (brick, stone, concrete, retaining)
|
|
36196
|
+
- Gates, gate posts
|
|
36197
|
+
- Hedges used as boundaries
|
|
36198
|
+
|
|
36199
|
+
**Access Points & Pathways**:
|
|
36200
|
+
- Doors (front, side, garage, screen)
|
|
36201
|
+
- Driveways (concrete, asphalt, gravel, pavers)
|
|
36202
|
+
- Walkways, sidewalks, paths, stepping stones
|
|
36203
|
+
- Stairs, ramps, porches
|
|
36204
|
+
|
|
36205
|
+
**Utility & Fixtures**:
|
|
36206
|
+
- Mailboxes, package boxes
|
|
36207
|
+
- Light fixtures, lamp posts, solar lights
|
|
36208
|
+
- A/C units, utility boxes, meters
|
|
36209
|
+
- Trash cans, recycling bins
|
|
36210
|
+
- Hoses, spigots, sprinklers
|
|
36211
|
+
|
|
36212
|
+
**Outdoor Items**:
|
|
36213
|
+
- Vehicles (cars, trucks, motorcycles, boats, trailers)
|
|
36214
|
+
- Furniture (chairs, tables, benches, swings)
|
|
36215
|
+
- Grills, fire pits, outdoor kitchens
|
|
36216
|
+
- Play equipment, trampolines, pools
|
|
36217
|
+
- Decorations, flags, signs
|
|
36218
|
+
|
|
36219
|
+
**Off-Property Elements** (important for security context):
|
|
36220
|
+
- Street, road, sidewalk
|
|
36221
|
+
- Neighbor's property/fence/house
|
|
36222
|
+
- Public areas visible
|
|
36223
|
+
|
|
36224
|
+
For EACH landmark, estimate its DISTANCE from the camera:
|
|
36225
|
+
- "close" = 0-10 feet (within arm's reach of camera)
|
|
36226
|
+
- "near" = 10-30 feet
|
|
36227
|
+
- "medium" = 30-60 feet
|
|
36228
|
+
- "far" = 60-100 feet
|
|
36229
|
+
- "distant" = 100+ feet (edge of property or beyond)
|
|
36230
|
+
|
|
36231
|
+
## 2. ZONES - Identify distinct AREAS visible:
|
|
36232
|
+
- Front yard, backyard, side yard
|
|
36233
|
+
- Driveway, parking area
|
|
36234
|
+
- Patio, deck, porch
|
|
36235
|
+
- Garden area, lawn
|
|
36236
|
+
- Street/road
|
|
36237
|
+
- Neighbor's yard
|
|
36238
|
+
|
|
36239
|
+
For each zone, estimate what percentage of the image it covers (0.0 to 1.0).
|
|
36240
|
+
|
|
36241
|
+
## 3. EDGES - What's at each edge of the frame:
|
|
36242
|
+
This helps understand what's just out of view.
|
|
36243
|
+
|
|
36244
|
+
## 4. CAMERA CONTEXT:
|
|
36245
|
+
- Estimated mounting height (ground level, 8ft, 12ft, roofline, etc.)
|
|
36246
|
+
- Approximate field of view (narrow, medium, wide)
|
|
36247
|
+
- Facing direction if determinable (north, south, street-facing, etc.)
|
|
36177
36248
|
|
|
36178
|
-
|
|
36179
|
-
- Structures (house, garage, shed, porch, deck)
|
|
36180
|
-
- Features (mailbox, tree, pool, garden, fountain)
|
|
36181
|
-
- Access points (door, gate, driveway entrance, walkway)
|
|
36182
|
-
- Boundaries (fence, wall, hedge)
|
|
36183
|
-
|
|
36184
|
-
2. ZONES - Identify area types visible:
|
|
36185
|
-
- What type of area is this? (front yard, backyard, driveway, street, patio, walkway)
|
|
36186
|
-
- Estimate what percentage of the frame each zone covers (0.0 to 1.0)
|
|
36187
|
-
|
|
36188
|
-
3. EDGES - What's visible at the frame edges:
|
|
36189
|
-
- Top edge: (sky, roof, trees, etc.)
|
|
36190
|
-
- Left edge: (fence, neighbor, street, etc.)
|
|
36191
|
-
- Right edge: (fence, garage, etc.)
|
|
36192
|
-
- Bottom edge: (ground, driveway, grass, etc.)
|
|
36193
|
-
|
|
36194
|
-
4. ORIENTATION - Estimate camera facing direction based on shadows, sun position, or landmarks
|
|
36195
|
-
|
|
36196
|
-
Respond with ONLY valid JSON in this exact format:
|
|
36249
|
+
Respond with ONLY valid JSON:
|
|
36197
36250
|
{
|
|
36198
36251
|
"landmarks": [
|
|
36199
|
-
{"name": "
|
|
36252
|
+
{"name": "Mailbox", "type": "feature", "distance": "medium", "confidence": 0.95, "description": "Black metal mailbox on wooden post, approximately 40 feet from camera"},
|
|
36253
|
+
{"name": "Aluminum Fence", "type": "boundary", "distance": "near", "confidence": 0.9, "description": "Silver aluminum fence running along left side of property, about 15-20 feet away"},
|
|
36254
|
+
{"name": "Large Oak Tree", "type": "feature", "distance": "far", "confidence": 0.85, "description": "Mature oak tree near property line, roughly 80 feet from camera"}
|
|
36200
36255
|
],
|
|
36201
36256
|
"zones": [
|
|
36202
|
-
{"name": "Front Yard", "type": "yard", "coverage": 0.
|
|
36257
|
+
{"name": "Front Yard", "type": "yard", "coverage": 0.5, "description": "Grass lawn with some bare patches"},
|
|
36258
|
+
{"name": "Driveway", "type": "driveway", "coverage": 0.25, "description": "Concrete driveway leading to garage"}
|
|
36203
36259
|
],
|
|
36204
|
-
"edges": {
|
|
36205
|
-
|
|
36206
|
-
|
|
36260
|
+
"edges": {
|
|
36261
|
+
"top": "sky, tree canopy",
|
|
36262
|
+
"left": "aluminum fence, neighbor's yard beyond",
|
|
36263
|
+
"right": "side of house, garage door",
|
|
36264
|
+
"bottom": "concrete walkway, grass edge"
|
|
36265
|
+
},
|
|
36266
|
+
"cameraContext": {
|
|
36267
|
+
"mountHeight": "8 feet",
|
|
36268
|
+
"fieldOfView": "wide",
|
|
36269
|
+
"facingDirection": "street-facing"
|
|
36270
|
+
}
|
|
36271
|
+
}
|
|
36272
|
+
|
|
36273
|
+
BE THOROUGH. List every distinct item you can identify. A typical outdoor scene should have 5-15+ landmarks.`;
|
|
36207
36274
|
/** Multi-camera correlation prompt */
|
|
36208
|
-
const CORRELATION_PROMPT = `I have scene analyses from multiple security cameras at the same property. Help me
|
|
36275
|
+
const CORRELATION_PROMPT = `I have detailed scene analyses from multiple security cameras at the same property. Help me understand which landmarks appear in multiple camera views.
|
|
36209
36276
|
|
|
36210
36277
|
CAMERA SCENES:
|
|
36211
36278
|
{scenes}
|
|
36212
36279
|
|
|
36213
|
-
|
|
36214
|
-
|
|
36215
|
-
|
|
36216
|
-
|
|
36280
|
+
## PRIORITY ORDER (most important first):
|
|
36281
|
+
|
|
36282
|
+
### 1. SHARED LANDMARKS (HIGHEST PRIORITY)
|
|
36283
|
+
Identify features that are visible from MULTIPLE cameras. This is crucial for understanding the property layout.
|
|
36284
|
+
- Look for the SAME fence, tree, mailbox, driveway, structure, etc. appearing in different camera views
|
|
36285
|
+
- Even partial visibility counts (e.g., a tree visible in full from one camera and just the edge from another)
|
|
36286
|
+
- Include landmarks that are at the boundary between camera views
|
|
36287
|
+
|
|
36288
|
+
### 2. PROPERTY LAYOUT
|
|
36289
|
+
Based on what each camera sees and their overlapping features, describe:
|
|
36290
|
+
- Which areas each camera covers
|
|
36291
|
+
- How the cameras relate spatially (e.g., "Camera A looks toward Camera B's direction")
|
|
36292
|
+
- Overall property shape and features
|
|
36293
|
+
|
|
36294
|
+
### 3. CONNECTIONS (Lower Priority)
|
|
36295
|
+
Only if clearly determinable, suggest walking paths between camera views.
|
|
36217
36296
|
|
|
36218
36297
|
IMPORTANT: For camera references, use the EXACT device ID shown in parentheses (e.g., "device_123"), NOT the camera name.
|
|
36219
36298
|
|
|
36220
36299
|
Respond with ONLY valid JSON:
|
|
36221
36300
|
{
|
|
36222
36301
|
"sharedLandmarks": [
|
|
36223
|
-
{"name": "
|
|
36302
|
+
{"name": "Aluminum Fence", "type": "boundary", "seenByCameras": ["device_123", "device_456"], "confidence": 0.85, "description": "Silver aluminum fence visible on right edge of Camera A and left edge of Camera B"},
|
|
36303
|
+
{"name": "Large Oak Tree", "type": "feature", "seenByCameras": ["device_123", "device_789"], "confidence": 0.9, "description": "Mature oak tree in front yard, visible from both front and side cameras"},
|
|
36304
|
+
{"name": "Concrete Driveway", "type": "access", "seenByCameras": ["device_123", "device_456", "device_789"], "confidence": 0.95, "description": "Driveway visible from multiple angles"}
|
|
36224
36305
|
],
|
|
36225
36306
|
"connections": [
|
|
36226
|
-
{"from": "device_123", "to": "device_456", "transitSeconds":
|
|
36307
|
+
{"from": "device_123", "to": "device_456", "transitSeconds": 8, "via": "along driveway", "confidence": 0.6, "bidirectional": true}
|
|
36227
36308
|
],
|
|
36228
|
-
"layoutDescription": "
|
|
36309
|
+
"layoutDescription": "Ranch-style house. Front camera covers front yard and street. Garage camera covers driveway entrance. Side camera covers side yard with aluminum fence separating from neighbor. Backyard camera shows deck and pool area."
|
|
36229
36310
|
}`;
|
|
36230
36311
|
class TopologyDiscoveryEngine {
|
|
36231
36312
|
config;
|
|
@@ -36429,6 +36510,7 @@ class TopologyDiscoveryEngine {
|
|
|
36429
36510
|
name: l.name || 'Unknown',
|
|
36430
36511
|
type: this.mapLandmarkType(l.type),
|
|
36431
36512
|
confidence: typeof l.confidence === 'number' ? l.confidence : 0.7,
|
|
36513
|
+
distance: this.mapDistance(l.distance),
|
|
36432
36514
|
description: l.description || '',
|
|
36433
36515
|
boundingBox: l.boundingBox,
|
|
36434
36516
|
}));
|
|
@@ -36546,6 +36628,21 @@ class TopologyDiscoveryEngine {
|
|
|
36546
36628
|
return 'west';
|
|
36547
36629
|
return 'unknown';
|
|
36548
36630
|
}
|
|
36631
|
+
/** Map LLM distance to our type */
|
|
36632
|
+
mapDistance(distance) {
|
|
36633
|
+
const dist = distance?.toLowerCase();
|
|
36634
|
+
if (dist?.includes('close'))
|
|
36635
|
+
return 'close';
|
|
36636
|
+
if (dist?.includes('near'))
|
|
36637
|
+
return 'near';
|
|
36638
|
+
if (dist?.includes('medium'))
|
|
36639
|
+
return 'medium';
|
|
36640
|
+
if (dist?.includes('far') && !dist?.includes('distant'))
|
|
36641
|
+
return 'far';
|
|
36642
|
+
if (dist?.includes('distant'))
|
|
36643
|
+
return 'distant';
|
|
36644
|
+
return 'medium'; // Default to medium if not specified
|
|
36645
|
+
}
|
|
36549
36646
|
/** Resolve a camera reference (name or deviceId) to its deviceId */
|
|
36550
36647
|
resolveCameraRef(ref) {
|
|
36551
36648
|
if (!this.topology?.cameras || !ref)
|
|
@@ -36721,9 +36818,12 @@ class TopologyDiscoveryEngine {
|
|
|
36721
36818
|
generateSuggestionsFromAnalysis(analysis) {
|
|
36722
36819
|
if (!analysis.isValid)
|
|
36723
36820
|
return;
|
|
36821
|
+
this.console.log(`[Discovery] Generating suggestions from ${analysis.landmarks.length} landmarks, ${analysis.zones.length} zones`);
|
|
36724
36822
|
// Generate landmark suggestions
|
|
36725
36823
|
for (const landmark of analysis.landmarks) {
|
|
36726
36824
|
if (landmark.confidence >= this.config.minLandmarkConfidence) {
|
|
36825
|
+
// Calculate distance in feet from distance estimate
|
|
36826
|
+
const distanceFeet = landmark.distance ? (0, discovery_1.distanceToFeet)(landmark.distance) : 50;
|
|
36727
36827
|
const suggestion = {
|
|
36728
36828
|
id: `landmark_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
36729
36829
|
type: 'landmark',
|
|
@@ -36736,26 +36836,30 @@ class TopologyDiscoveryEngine {
|
|
|
36736
36836
|
type: landmark.type,
|
|
36737
36837
|
description: landmark.description,
|
|
36738
36838
|
visibleFromCameras: [analysis.cameraId],
|
|
36739
|
-
// Include
|
|
36839
|
+
// Include extra metadata for positioning
|
|
36740
36840
|
boundingBox: landmark.boundingBox,
|
|
36741
|
-
|
|
36841
|
+
distance: landmark.distance,
|
|
36842
|
+
distanceFeet: distanceFeet,
|
|
36843
|
+
}, // Extra metadata not in base Landmark interface
|
|
36742
36844
|
};
|
|
36743
36845
|
this.suggestions.set(suggestion.id, suggestion);
|
|
36846
|
+
this.console.log(`[Discovery] Landmark suggestion: ${landmark.name} (${landmark.type}, ${landmark.distance || 'medium'}, ~${distanceFeet}ft)`);
|
|
36744
36847
|
}
|
|
36745
36848
|
}
|
|
36746
|
-
// Generate zone suggestions
|
|
36849
|
+
// Generate zone suggestions (even for smaller coverage - 10% is enough)
|
|
36747
36850
|
for (const zone of analysis.zones) {
|
|
36748
|
-
if (zone.coverage >= 0.
|
|
36851
|
+
if (zone.coverage >= 0.1) {
|
|
36749
36852
|
const suggestion = {
|
|
36750
36853
|
id: `zone_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
36751
36854
|
type: 'zone',
|
|
36752
36855
|
timestamp: Date.now(),
|
|
36753
36856
|
sourceCameras: [analysis.cameraId],
|
|
36754
|
-
confidence: 0.
|
|
36857
|
+
confidence: Math.min(0.9, 0.5 + zone.coverage), // Higher coverage = higher confidence
|
|
36755
36858
|
status: 'pending',
|
|
36756
36859
|
zone: zone,
|
|
36757
36860
|
};
|
|
36758
36861
|
this.suggestions.set(suggestion.id, suggestion);
|
|
36862
|
+
this.console.log(`[Discovery] Zone suggestion: ${zone.name} (${zone.type}, ${Math.round(zone.coverage * 100)}% coverage)`);
|
|
36759
36863
|
}
|
|
36760
36864
|
}
|
|
36761
36865
|
}
|
|
@@ -41157,6 +41261,7 @@ function createAlert(type, trackedObjectId, details, severity = 'info', ruleId)
|
|
|
41157
41261
|
*/
|
|
41158
41262
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
41159
41263
|
exports.DEFAULT_DISCOVERY_STATUS = exports.RATE_LIMIT_WARNING_THRESHOLD = exports.DEFAULT_DISCOVERY_CONFIG = void 0;
|
|
41264
|
+
exports.distanceToFeet = distanceToFeet;
|
|
41160
41265
|
/** Default discovery configuration */
|
|
41161
41266
|
exports.DEFAULT_DISCOVERY_CONFIG = {
|
|
41162
41267
|
discoveryIntervalHours: 0, // Disabled by default
|
|
@@ -41166,6 +41271,17 @@ exports.DEFAULT_DISCOVERY_CONFIG = {
|
|
|
41166
41271
|
};
|
|
41167
41272
|
/** Rate limit warning thresholds (in hours) */
|
|
41168
41273
|
exports.RATE_LIMIT_WARNING_THRESHOLD = 1; // Warn if interval is less than 1 hour
|
|
41274
|
+
/** Convert distance estimate to approximate feet */
|
|
41275
|
+
function distanceToFeet(distance) {
|
|
41276
|
+
switch (distance) {
|
|
41277
|
+
case 'close': return 5; // 0-10 feet
|
|
41278
|
+
case 'near': return 20; // 10-30 feet
|
|
41279
|
+
case 'medium': return 45; // 30-60 feet
|
|
41280
|
+
case 'far': return 80; // 60-100 feet
|
|
41281
|
+
case 'distant': return 150; // 100+ feet
|
|
41282
|
+
default: return 50;
|
|
41283
|
+
}
|
|
41284
|
+
}
|
|
41169
41285
|
/** Default discovery status */
|
|
41170
41286
|
exports.DEFAULT_DISCOVERY_STATUS = {
|
|
41171
41287
|
isRunning: false,
|