Persist live session receive loop by wrapping session.receive iterator in a while True loop to support multi-turn dialogues
Browse files- backend/main.py +32 -25
backend/main.py
CHANGED
|
@@ -323,36 +323,43 @@ async def websocket_live_endpoint(websocket: WebSocket):
|
|
| 323 |
ws_log("Client WebSocket disconnected (WebSocketDisconnect).")
|
| 324 |
except Exception as e:
|
| 325 |
ws_log(f"[WebSocket Proxy Client -> Gemini] Error: {e}")
|
|
|
|
|
|
|
| 326 |
|
| 327 |
async def send_to_client():
|
| 328 |
try:
|
| 329 |
-
|
| 330 |
-
|
| 331 |
-
|
| 332 |
-
|
| 333 |
-
|
| 334 |
-
|
| 335 |
-
|
| 336 |
-
|
| 337 |
-
|
| 338 |
-
|
| 339 |
-
|
| 340 |
-
|
| 341 |
-
|
| 342 |
-
|
| 343 |
-
|
| 344 |
-
|
| 345 |
-
|
| 346 |
-
|
| 347 |
-
|
| 348 |
-
|
| 349 |
-
|
| 350 |
-
|
| 351 |
-
|
| 352 |
-
|
| 353 |
-
|
|
|
|
|
|
|
|
|
|
| 354 |
except Exception as e:
|
| 355 |
ws_log(f"[WebSocket Proxy Gemini -> Client] Error: {e}")
|
|
|
|
|
|
|
| 356 |
|
| 357 |
# Run both tasks concurrently and terminate when the first one finishes
|
| 358 |
done, pending = await asyncio.wait(
|
|
|
|
| 323 |
ws_log("Client WebSocket disconnected (WebSocketDisconnect).")
|
| 324 |
except Exception as e:
|
| 325 |
ws_log(f"[WebSocket Proxy Client -> Gemini] Error: {e}")
|
| 326 |
+
finally:
|
| 327 |
+
ws_log("receive_from_client loop exited.")
|
| 328 |
|
| 329 |
async def send_to_client():
|
| 330 |
try:
|
| 331 |
+
while True:
|
| 332 |
+
async for response in session.receive():
|
| 333 |
+
server_content = response.server_content
|
| 334 |
+
if server_content is not None:
|
| 335 |
+
model_turn = server_content.model_turn
|
| 336 |
+
if model_turn is not None:
|
| 337 |
+
for part in model_turn.parts:
|
| 338 |
+
if part.inline_data is not None:
|
| 339 |
+
# Stream PCM audio output back to client as Base64
|
| 340 |
+
audio_b64 = base64.b64encode(part.inline_data.data).decode('utf-8')
|
| 341 |
+
await websocket.send_json({
|
| 342 |
+
"type": "audio",
|
| 343 |
+
"data": audio_b64
|
| 344 |
+
})
|
| 345 |
+
elif part.text is not None:
|
| 346 |
+
# Stream text transcription back to client
|
| 347 |
+
ws_log(f"Streaming text chunk from Gemini: {part.text}")
|
| 348 |
+
await websocket.send_json({
|
| 349 |
+
"type": "text",
|
| 350 |
+
"data": part.text
|
| 351 |
+
})
|
| 352 |
+
|
| 353 |
+
# Handle turn completion (model finished speaking)
|
| 354 |
+
if server_content.turn_complete:
|
| 355 |
+
ws_log("Gemini sent turn_complete.")
|
| 356 |
+
await websocket.send_json({"type": "turn_complete"})
|
| 357 |
+
# Avoid tight loop if iterator finishes instantly
|
| 358 |
+
await asyncio.sleep(0.1)
|
| 359 |
except Exception as e:
|
| 360 |
ws_log(f"[WebSocket Proxy Gemini -> Client] Error: {e}")
|
| 361 |
+
finally:
|
| 362 |
+
ws_log("send_to_client loop exited.")
|
| 363 |
|
| 364 |
# Run both tasks concurrently and terminate when the first one finishes
|
| 365 |
done, pending = await asyncio.wait(
|