@blueharford/scrypted-spatial-awareness 0.6.15 → 0.6.16

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
@@ -36492,7 +36492,7 @@ class TopologyDiscoveryEngine {
36492
36492
  ],
36493
36493
  },
36494
36494
  ],
36495
- max_tokens: 1500,
36495
+ max_tokens: 4000, // Increased for detailed scene analysis
36496
36496
  temperature: 0.3,
36497
36497
  });
36498
36498
  const content = result?.choices?.[0]?.message?.content;
@@ -36503,7 +36503,8 @@ class TopologyDiscoveryEngine {
36503
36503
  if (jsonStr.startsWith('```')) {
36504
36504
  jsonStr = jsonStr.replace(/```json?\n?/g, '').replace(/```$/g, '').trim();
36505
36505
  }
36506
- const parsed = JSON.parse(jsonStr);
36506
+ // Try to recover truncated JSON
36507
+ const parsed = this.parseJsonWithRecovery(jsonStr, cameraName);
36507
36508
  // Map parsed data to our types
36508
36509
  if (Array.isArray(parsed.landmarks)) {
36509
36510
  analysis.landmarks = parsed.landmarks.map((l) => ({
@@ -36643,6 +36644,93 @@ class TopologyDiscoveryEngine {
36643
36644
  return 'distant';
36644
36645
  return 'medium'; // Default to medium if not specified
36645
36646
  }
36647
+ /** Try to parse JSON with recovery for truncated responses */
36648
+ parseJsonWithRecovery(jsonStr, context) {
36649
+ // First, try direct parse
36650
+ try {
36651
+ return JSON.parse(jsonStr);
36652
+ }
36653
+ catch (e) {
36654
+ // Log the raw response for debugging (first 500 chars)
36655
+ this.console.log(`[Discovery] Raw LLM response for ${context} (first 500 chars): ${jsonStr.substring(0, 500)}...`);
36656
+ }
36657
+ // Try to recover truncated JSON by finding complete sections
36658
+ try {
36659
+ // Find where valid JSON might end (look for last complete object/array)
36660
+ let recoveredJson = jsonStr;
36661
+ // Try to close unclosed strings
36662
+ const lastQuote = recoveredJson.lastIndexOf('"');
36663
+ const lastColon = recoveredJson.lastIndexOf(':');
36664
+ if (lastQuote > lastColon) {
36665
+ // We might be in the middle of a string value
36666
+ const beforeQuote = recoveredJson.substring(0, lastQuote);
36667
+ const afterLastCompleteEntry = beforeQuote.lastIndexOf('},');
36668
+ if (afterLastCompleteEntry > 0) {
36669
+ recoveredJson = beforeQuote.substring(0, afterLastCompleteEntry + 1);
36670
+ }
36671
+ }
36672
+ // Close any unclosed arrays/objects
36673
+ let openBraces = (recoveredJson.match(/{/g) || []).length;
36674
+ let closeBraces = (recoveredJson.match(/}/g) || []).length;
36675
+ let openBrackets = (recoveredJson.match(/\[/g) || []).length;
36676
+ let closeBrackets = (recoveredJson.match(/\]/g) || []).length;
36677
+ // Add missing closing brackets/braces
36678
+ while (closeBrackets < openBrackets) {
36679
+ recoveredJson += ']';
36680
+ closeBrackets++;
36681
+ }
36682
+ while (closeBraces < openBraces) {
36683
+ recoveredJson += '}';
36684
+ closeBraces++;
36685
+ }
36686
+ const recovered = JSON.parse(recoveredJson);
36687
+ this.console.log(`[Discovery] Recovered truncated JSON for ${context}`);
36688
+ return recovered;
36689
+ }
36690
+ catch (recoveryError) {
36691
+ // Last resort: try to extract just landmarks array
36692
+ try {
36693
+ const landmarksMatch = jsonStr.match(/"landmarks"\s*:\s*\[([\s\S]*?)(?:\]|$)/);
36694
+ const zonesMatch = jsonStr.match(/"zones"\s*:\s*\[([\s\S]*?)(?:\]|$)/);
36695
+ const result = { landmarks: [], zones: [], edges: {}, orientation: 'unknown' };
36696
+ if (landmarksMatch) {
36697
+ // Try to parse individual landmark objects
36698
+ const landmarksStr = landmarksMatch[1];
36699
+ const landmarkObjects = landmarksStr.match(/\{[^{}]*\}/g) || [];
36700
+ result.landmarks = landmarkObjects.map((obj) => {
36701
+ try {
36702
+ return JSON.parse(obj);
36703
+ }
36704
+ catch {
36705
+ return null;
36706
+ }
36707
+ }).filter(Boolean);
36708
+ this.console.log(`[Discovery] Extracted ${result.landmarks.length} landmarks from partial response for ${context}`);
36709
+ }
36710
+ if (zonesMatch) {
36711
+ const zonesStr = zonesMatch[1];
36712
+ const zoneObjects = zonesStr.match(/\{[^{}]*\}/g) || [];
36713
+ result.zones = zoneObjects.map((obj) => {
36714
+ try {
36715
+ return JSON.parse(obj);
36716
+ }
36717
+ catch {
36718
+ return null;
36719
+ }
36720
+ }).filter(Boolean);
36721
+ this.console.log(`[Discovery] Extracted ${result.zones.length} zones from partial response for ${context}`);
36722
+ }
36723
+ if (result.landmarks.length > 0 || result.zones.length > 0) {
36724
+ return result;
36725
+ }
36726
+ }
36727
+ catch (extractError) {
36728
+ // Give up
36729
+ }
36730
+ this.console.warn(`[Discovery] Could not recover JSON for ${context}`);
36731
+ throw new Error(`Failed to parse LLM response: truncated or malformed JSON`);
36732
+ }
36733
+ }
36646
36734
  /** Resolve a camera reference (name or deviceId) to its deviceId */
36647
36735
  resolveCameraRef(ref) {
36648
36736
  if (!this.topology?.cameras || !ref)