MCPcopy Create free account
hub / github.com/KoljaB/RealtimeVoiceChat / websocket_endpoint

Function websocket_endpoint

code/server.py:874–937  ·  view source on GitHub ↗

Handles the main WebSocket connection for real-time voice chat. Accepts a connection, sets up connection-specific state via `TranscriptionCallbacks`, initializes audio/message queues, and creates asyncio tasks for handling incoming data, audio processing, outgoing text messages, an

(ws: WebSocket)

Source from the content-addressed store, hash-verified

872# --------------------------------------------------------------------
873@app.websocket("/ws")
874async def websocket_endpoint(ws: WebSocket):
875 """
876 Handles the main WebSocket connection for real-time voice chat.
877
878 Accepts a connection, sets up connection-specific state via `TranscriptionCallbacks`,
879 initializes audio/message queues, and creates asyncio tasks for handling
880 incoming data, audio processing, outgoing text messages, and outgoing TTS chunks.
881 Manages the lifecycle of these tasks and cleans up on disconnect.
882
883 Args:
884 ws: The WebSocket connection instance provided by FastAPI.
885 """
886 await ws.accept()
887 logger.info("🖥️✅ Client connected via WebSocket.")
888
889 message_queue = asyncio.Queue()
890 audio_chunks = asyncio.Queue()
891
892 # Set up callback manager - THIS NOW HOLDS THE CONNECTION-SPECIFIC STATE
893 callbacks = TranscriptionCallbacks(app, message_queue)
894
895 # Assign callbacks to the AudioInputProcessor (global component)
896 # These methods within callbacks will now operate on its *instance* state
897 app.state.AudioInputProcessor.realtime_callback = callbacks.on_partial
898 app.state.AudioInputProcessor.transcriber.potential_sentence_end = callbacks.on_potential_sentence
899 app.state.AudioInputProcessor.transcriber.on_tts_allowed_to_synthesize = callbacks.on_tts_allowed_to_synthesize
900 app.state.AudioInputProcessor.transcriber.potential_full_transcription_callback = callbacks.on_potential_final
901 app.state.AudioInputProcessor.transcriber.potential_full_transcription_abort_callback = callbacks.on_potential_abort
902 app.state.AudioInputProcessor.transcriber.full_transcription_callback = callbacks.on_final
903 app.state.AudioInputProcessor.transcriber.before_final_sentence = callbacks.on_before_final
904 app.state.AudioInputProcessor.recording_start_callback = callbacks.on_recording_start
905 app.state.AudioInputProcessor.silence_active_callback = callbacks.on_silence_active
906
907 # Assign callback to the SpeechPipelineManager (global component)
908 app.state.SpeechPipelineManager.on_partial_assistant_text = callbacks.on_partial_assistant_text
909
910 # Create tasks for handling different responsibilities
911 # Pass the 'callbacks' instance to tasks that need connection-specific state
912 tasks = [
913 asyncio.create_task(process_incoming_data(ws, app, audio_chunks, callbacks)), # Pass callbacks
914 asyncio.create_task(app.state.AudioInputProcessor.process_chunk_queue(audio_chunks)),
915 asyncio.create_task(send_text_messages(ws, message_queue)),
916 asyncio.create_task(send_tts_chunks(app, message_queue, callbacks)), # Pass callbacks
917 ]
918
919 try:
920 # Wait for any task to complete (e.g., client disconnect)
921 done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
922 for task in pending:
923 if not task.done():
924 task.cancel()
925 # Await cancelled tasks to let them clean up if needed
926 await asyncio.gather(*pending, return_exceptions=True)
927 except Exception as e:
928 logger.error(f"🖥️💥 {Colors.apply('ERROR').red} in WebSocket session: {repr(e)}")
929 finally:
930 logger.info("🖥️🧹 Cleaning up WebSocket tasks...")
931 for task in tasks:

Callers

nothing calls this directly

Calls 6

process_incoming_dataFunction · 0.85
send_text_messagesFunction · 0.85
send_tts_chunksFunction · 0.85
process_chunk_queueMethod · 0.80
applyMethod · 0.80

Tested by

no test coverage detected