| from fastapi import WebSocket, WebSocketDisconnect |
| from typing import AsyncGenerator |
| import asyncio |
| from app.utils.logger import logger |
| from app.services.bedrock_streaming import bedrock |
| from app.services.dynamodb import db |
| from app.services.redis_cache import cache |
|
|
| class WebSocketHandler: |
| def __init__(self): |
| self.active_connections = {} |
| |
| async def handle_audio_stream(self, websocket: WebSocket, session_id: str): |
| """Handle bidirectional audio streaming""" |
| |
| await websocket.accept() |
| logger.info("WebSocket connected", session_id=session_id) |
| |
| |
| cache.set(f"session_active:{session_id}", True, 600) |
| |
| try: |
| |
| async def audio_input_stream() -> AsyncGenerator[bytes, None]: |
| while True: |
| try: |
| |
| data = await websocket.receive() |
| |
| if 'bytes' in data: |
| yield data['bytes'] |
| elif 'text' in data: |
| |
| import json |
| control = json.loads(data['text']) |
| if control.get('type') == 'end': |
| break |
| except WebSocketDisconnect: |
| break |
| except Exception as e: |
| logger.error("Audio receive error", session_id=session_id, error=str(e)) |
| break |
| |
| |
| await bedrock.stream_conversation( |
| session_id=session_id, |
| audio_input_stream=audio_input_stream(), |
| websocket=websocket |
| ) |
| |
| except WebSocketDisconnect: |
| logger.info("Client disconnected", session_id=session_id) |
| except Exception as e: |
| logger.error("WebSocket error", session_id=session_id, error=str(e)) |
| await websocket.send_json({ |
| "type": "error", |
| "message": str(e) |
| }) |
| finally: |
| |
| db.update_session_state(session_id, "ended") |
| cache.delete(f"session_active:{session_id}") |
| logger.info("Session ended", session_id=session_id) |
|
|
| ws_handler = WebSocketHandler() |
|
|