Spaces:
Running
Running
deploy(S4): Blender headless pipeline + WebAR client + backend fixes
Browse files- backend/main.py +4 -1
- backend/memory/episodic_memory.py +1 -2
- backend/services/token_manager.py +3 -1
- backend/services/usb_monitor.py +1 -1
- backend/voice/space_injection.py +1 -1
- backend/ws/agent_ws.py +25 -6
- dist/app-release.apk +1 -1
backend/main.py
CHANGED
|
@@ -547,7 +547,10 @@ async def websocket_hub(websocket: WebSocket):
|
|
| 547 |
try:
|
| 548 |
await websocket.close()
|
| 549 |
except Exception as e:
|
| 550 |
-
import logging
|
|
|
|
|
|
|
|
|
|
| 551 |
break
|
| 552 |
|
| 553 |
heartbeat_task = asyncio.create_task(heartbeat())
|
|
|
|
| 547 |
try:
|
| 548 |
await websocket.close()
|
| 549 |
except Exception as e:
|
| 550 |
+
# NO `import logging` here: it would make `logging` local to
|
| 551 |
+
# heartbeat() and turn the warning three lines above into an
|
| 552 |
+
# UnboundLocalError β silently killing the WS heartbeat.
|
| 553 |
+
logging.getLogger(__name__).error(f"Swallowed exception: {e}")
|
| 554 |
break
|
| 555 |
|
| 556 |
heartbeat_task = asyncio.create_task(heartbeat())
|
backend/memory/episodic_memory.py
CHANGED
|
@@ -62,8 +62,7 @@ class EpisodicMemory:
|
|
| 62 |
logging.error("chromadb is not installed. Episodic memory will not work.")
|
| 63 |
self.client = None
|
| 64 |
return
|
| 65 |
-
|
| 66 |
-
import logging
|
| 67 |
logging.getLogger("chromadb").setLevel(logging.ERROR)
|
| 68 |
self.client = chromadb.PersistentClient(
|
| 69 |
path=persist_dir,
|
|
|
|
| 62 |
logging.error("chromadb is not installed. Episodic memory will not work.")
|
| 63 |
self.client = None
|
| 64 |
return
|
| 65 |
+
|
|
|
|
| 66 |
logging.getLogger("chromadb").setLevel(logging.ERROR)
|
| 67 |
self.client = chromadb.PersistentClient(
|
| 68 |
path=persist_dir,
|
backend/services/token_manager.py
CHANGED
|
@@ -610,7 +610,9 @@ async def _resume_checkpoint(checkpoint: dict):
|
|
| 610 |
)
|
| 611 |
conn.commit()
|
| 612 |
except Exception as e:
|
| 613 |
-
import logging
|
|
|
|
|
|
|
| 614 |
except Exception as e:
|
| 615 |
logging.error(f"TokenManager: Resume error for [{task_id}]: {e}")
|
| 616 |
|
|
|
|
| 610 |
)
|
| 611 |
conn.commit()
|
| 612 |
except Exception as e:
|
| 613 |
+
# No local `import logging` β it would shadow the module import for
|
| 614 |
+
# the whole of _resume_checkpoint() and break the logging calls above.
|
| 615 |
+
logging.getLogger(__name__).error(f"Swallowed exception: {e}")
|
| 616 |
except Exception as e:
|
| 617 |
logging.error(f"TokenManager: Resume error for [{task_id}]: {e}")
|
| 618 |
|
backend/services/usb_monitor.py
CHANGED
|
@@ -218,7 +218,7 @@ async def start_usb_monitor():
|
|
| 218 |
return mapping
|
| 219 |
wmi_drive_map = await loop.run_in_executor(None, fetch_wmi_letters)
|
| 220 |
except Exception as e:
|
| 221 |
-
|
| 222 |
|
| 223 |
for dev in usb_devices:
|
| 224 |
vid, pid = dev["vid"], dev["pid"]
|
|
|
|
| 218 |
return mapping
|
| 219 |
wmi_drive_map = await loop.run_in_executor(None, fetch_wmi_letters)
|
| 220 |
except Exception as e:
|
| 221 |
+
logging.getLogger(__name__).error(f"Swallowed exception: {e}")
|
| 222 |
|
| 223 |
for dev in usb_devices:
|
| 224 |
vid, pid = dev["vid"], dev["pid"]
|
backend/voice/space_injection.py
CHANGED
|
@@ -81,7 +81,7 @@ async def speak_space_acknowledgement(new_space: SpaceKey, persona: str) -> None
|
|
| 81 |
try:
|
| 82 |
await conn.send_bytes(audio_bytes)
|
| 83 |
except Exception as e:
|
| 84 |
-
|
| 85 |
# Signal end
|
| 86 |
await ws_manager.broadcast({
|
| 87 |
"event": "voice:space_ack_end",
|
|
|
|
| 81 |
try:
|
| 82 |
await conn.send_bytes(audio_bytes)
|
| 83 |
except Exception as e:
|
| 84 |
+
logging.getLogger(__name__).error(f"Swallowed exception: {e}")
|
| 85 |
# Signal end
|
| 86 |
await ws_manager.broadcast({
|
| 87 |
"event": "voice:space_ack_end",
|
backend/ws/agent_ws.py
CHANGED
|
@@ -1,8 +1,31 @@
|
|
| 1 |
import asyncio
|
|
|
|
| 2 |
import logging
|
|
|
|
| 3 |
from fastapi import WebSocket
|
| 4 |
import uuid
|
| 5 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
from backend.agent.react_agent import ReActAgent
|
| 7 |
from backend.tools.tool_registry import TOOL_REGISTRY
|
| 8 |
get_assistant_name = lambda: __import__('modules.assistant_identity', fromlist=['get_assistant_name']).get_assistant_name()
|
|
@@ -179,7 +202,6 @@ class ConnectionManager:
|
|
| 179 |
|
| 180 |
if data.get("event") == "auth:handshake":
|
| 181 |
pin = data.get("payload", {}).get("pin", "")
|
| 182 |
-
import os
|
| 183 |
expected_pin = os.environ.get("JARVIS_PIN", "0000")
|
| 184 |
if pin == expected_pin:
|
| 185 |
if websocket:
|
|
@@ -233,7 +255,6 @@ class ConnectionManager:
|
|
| 233 |
detected_lang = data.get("language", "en")
|
| 234 |
# Load config to check for forced override
|
| 235 |
try:
|
| 236 |
-
import os, json
|
| 237 |
config_path = os.path.join(os.getcwd(), "config.json")
|
| 238 |
if os.path.exists(config_path):
|
| 239 |
with open(config_path, "r", encoding="utf-8") as f:
|
|
@@ -242,7 +263,7 @@ class ConnectionManager:
|
|
| 242 |
if forced_lang:
|
| 243 |
detected_lang = forced_lang
|
| 244 |
except Exception as e:
|
| 245 |
-
|
| 246 |
|
| 247 |
agent_name = context.get("ai", get_assistant_name()).upper()
|
| 248 |
|
|
@@ -421,8 +442,7 @@ class ConnectionManager:
|
|
| 421 |
|
| 422 |
asyncio.create_task(_propose_and_notify_or_execute())
|
| 423 |
|
| 424 |
-
|
| 425 |
-
save_message("assistant", ack, str(_uuid.uuid4()), agent_name.lower())
|
| 426 |
return
|
| 427 |
# ββ End Β§2.3+2.4 Interception ββββββββββββββββββββββββββββββββββ
|
| 428 |
|
|
@@ -474,7 +494,6 @@ class ConnectionManager:
|
|
| 474 |
else:
|
| 475 |
await self.broadcast(msg_done)
|
| 476 |
|
| 477 |
-
import uuid
|
| 478 |
save_message("assistant", full_response.strip(), str(uuid.uuid4()), agent_name.lower())
|
| 479 |
|
| 480 |
# Auto-store memory in background without blocking response stream
|
|
|
|
| 1 |
import asyncio
|
| 2 |
+
import json
|
| 3 |
import logging
|
| 4 |
+
import os
|
| 5 |
from fastapi import WebSocket
|
| 6 |
import uuid
|
| 7 |
|
| 8 |
+
# EVERY import used by handle_client_event lives HERE, at module scope, and must
|
| 9 |
+
# stay here.
|
| 10 |
+
#
|
| 11 |
+
# handle_client_event used to re-import logging, os, json and uuid inside its own
|
| 12 |
+
# body. Python decides scope at compile time: one `import logging` anywhere in a
|
| 13 |
+
# function makes `logging` a local name for the WHOLE function, so every use
|
| 14 |
+
# *before* that line raises UnboundLocalError. The re-imports sat near the bottom,
|
| 15 |
+
# in the chat branch, so the branches above them were all dead on arrival:
|
| 16 |
+
#
|
| 17 |
+
# line 102 logging -> client:identify (PC relay registration)
|
| 18 |
+
# line 132 logging -> voice:wake_word (persona switch)
|
| 19 |
+
# line 154 logging -> xr:gesture
|
| 20 |
+
# line 194 logging -> switch_persona
|
| 21 |
+
# line 231 uuid -> type=="chat" (the ReAct agent loop)
|
| 22 |
+
#
|
| 23 |
+
# Each one killed the socket: the exception escaped the `while True` in
|
| 24 |
+
# main.py::websocket_hub, which only catches WebSocketDisconnect, so the
|
| 25 |
+
# connection was torn down and the client reconnected into the same crash. That
|
| 26 |
+
# is precisely why the PC relay looked connected in netstat while never
|
| 27 |
+
# registering β it was a reconnect loop, not a session.
|
| 28 |
+
|
| 29 |
from backend.agent.react_agent import ReActAgent
|
| 30 |
from backend.tools.tool_registry import TOOL_REGISTRY
|
| 31 |
get_assistant_name = lambda: __import__('modules.assistant_identity', fromlist=['get_assistant_name']).get_assistant_name()
|
|
|
|
| 202 |
|
| 203 |
if data.get("event") == "auth:handshake":
|
| 204 |
pin = data.get("payload", {}).get("pin", "")
|
|
|
|
| 205 |
expected_pin = os.environ.get("JARVIS_PIN", "0000")
|
| 206 |
if pin == expected_pin:
|
| 207 |
if websocket:
|
|
|
|
| 255 |
detected_lang = data.get("language", "en")
|
| 256 |
# Load config to check for forced override
|
| 257 |
try:
|
|
|
|
| 258 |
config_path = os.path.join(os.getcwd(), "config.json")
|
| 259 |
if os.path.exists(config_path):
|
| 260 |
with open(config_path, "r", encoding="utf-8") as f:
|
|
|
|
| 263 |
if forced_lang:
|
| 264 |
detected_lang = forced_lang
|
| 265 |
except Exception as e:
|
| 266 |
+
logging.getLogger(__name__).error(f"Swallowed exception: {e}")
|
| 267 |
|
| 268 |
agent_name = context.get("ai", get_assistant_name()).upper()
|
| 269 |
|
|
|
|
| 442 |
|
| 443 |
asyncio.create_task(_propose_and_notify_or_execute())
|
| 444 |
|
| 445 |
+
save_message("assistant", ack, str(uuid.uuid4()), agent_name.lower())
|
|
|
|
| 446 |
return
|
| 447 |
# ββ End Β§2.3+2.4 Interception ββββββββββββββββββββββββββββββββββ
|
| 448 |
|
|
|
|
| 494 |
else:
|
| 495 |
await self.broadcast(msg_done)
|
| 496 |
|
|
|
|
| 497 |
save_message("assistant", full_response.strip(), str(uuid.uuid4()), agent_name.lower())
|
| 498 |
|
| 499 |
# Auto-store memory in background without blocking response stream
|
dist/app-release.apk
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
size 116538395
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:3ad8ae06d51f018c394e07acd4492bd6d3ec89137891812596d50286595ecd3b
|
| 3 |
size 116538395
|