Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions backend/api/routes/voice.py
Original file line number Diff line number Diff line change
Expand Up @@ -396,20 +396,31 @@ async def device_voice_ws(
):
mac = validate_mac_param(mac)
x_device_token = websocket.headers.get("x-device-token") or websocket.query_params.get("token")

# Accept immediately so the client (ESP32) gets HTTP 101 without waiting for DB queries.
# Auth and session setup happen right after; if they fail we close with an error code.
await websocket.accept()
logger.info("[VOICE_WS] accepted mac=%s has_token=%s", mac, bool(x_device_token))

try:
await require_device_token(mac, x_device_token, websocket.headers.get("accept-language"))
except HTTPException as exc:
logger.warning("[VOICE_WS] auth failed mac=%s status=%d detail=%s", mac, exc.status_code, exc.detail)
await websocket.close(code=1008, reason=str(exc.detail)[:120])
return

settings = await _resolve_device_voice_runtime_settings(mac)
session = create_voice_ws_session(
settings=settings,
access_user_id=None,
access_mac=mac,
)
await websocket.accept()
logger.info("[VOICE_WS] accepted mac=%s session_id=%s", mac, session.session_id)
try:
settings = await _resolve_device_voice_runtime_settings(mac)
session = create_voice_ws_session(
settings=settings,
access_user_id=None,
access_mac=mac,
)
logger.info("[VOICE_WS] session ready mac=%s session_id=%s provider=%s", mac, getattr(session, "session_id", "?"), getattr(settings, "llm_provider", "?"))
except Exception:
logger.exception("[VOICE_WS] session setup failed mac=%s", mac)
await websocket.close(code=1011, reason="internal error")
return

async def _sender() -> None:
async for event in iter_voice_ws_events(session):
Expand All @@ -430,6 +441,7 @@ async def _sender() -> None:
ws_message.get("type"),
)
if ws_message.get("type") == "websocket.disconnect":
logger.info("[VOICE_WS] client disconnected mac=%s code=%s", mac, ws_message.get("code"))
break

if "bytes" in ws_message and ws_message["bytes"]:
Expand Down
Binary file modified docs/en/voice-mode.md
Binary file not shown.
Binary file modified docs/voice-mode.md
Binary file not shown.
3 changes: 1 addition & 2 deletions firmware/src/network.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1431,9 +1431,8 @@ bool voiceWsOpen(int sampleRate, int screenW, int screenH, bool includeImage) {
}

String mac = WiFi.macAddress();
String path = basePath + "/api/device/" + mac + "/voice/ws";
String path = basePath + "/api/device/" + mac + "/voice/ws?token=" + cfgDeviceToken;
String extraHeaders = String("X-Device-Token: ") + cfgDeviceToken;

String startMsg = String("{\"type\":\"session.start\",\"sample_rate\":") + sampleRate
+ ",\"w\":" + screenW
+ ",\"h\":" + screenH
Expand Down
Loading