Update app.py
Browse files
app.py
CHANGED
@@ -1,6 +1,8 @@
|
|
1 |
|
2 |
from langfuse import Langfuse
|
3 |
from langfuse.decorators import observe, langfuse_context
|
|
|
|
|
4 |
|
5 |
from config.config import settings
|
6 |
from services.llama_generator import LlamaGenerator
|
@@ -68,15 +70,17 @@ async def detect_wakeword(audio_chunk: bytes) -> bool:
|
|
68 |
# You might want to use libraries like Porcupine or build your own wake word detector
|
69 |
return True
|
70 |
|
|
|
71 |
@app.websocket("/ws")
|
72 |
async def websocket_endpoint(websocket: WebSocket):
|
|
|
|
|
|
|
|
|
73 |
await websocket.accept()
|
74 |
try:
|
75 |
-
# Use a queue to manage audio chunks
|
76 |
-
audio_queue = asyncio.Queue()
|
77 |
-
|
78 |
# Create a task to process the audio stream
|
79 |
-
stream_task = asyncio.create_task(process_audio_stream(audio_queue))
|
80 |
|
81 |
# Main receive loop
|
82 |
while True:
|
@@ -104,20 +108,26 @@ async def websocket_endpoint(websocket: WebSocket):
|
|
104 |
print(f"WebSocket endpoint error: {e}")
|
105 |
|
106 |
finally:
|
107 |
-
# Cancel the stream processing task
|
108 |
-
stream_task
|
|
|
|
|
|
|
|
|
|
|
|
|
109 |
try:
|
110 |
await websocket.close(code=1000)
|
111 |
except Exception as close_error:
|
112 |
print(f"Error closing WebSocket: {close_error}")
|
113 |
|
114 |
-
async def process_audio_stream(audio_queue: asyncio.Queue) -> AsyncGenerator[str, None]:
|
115 |
buffer = []
|
116 |
is_speaking = False
|
117 |
silence_frames = 0
|
118 |
|
119 |
-
|
120 |
-
|
121 |
# Get audio data from queue with timeout
|
122 |
try:
|
123 |
audio_data = await asyncio.wait_for(audio_queue.get(), timeout=5.0)
|
@@ -172,30 +182,30 @@ async def process_audio_stream(audio_queue: asyncio.Queue) -> AsyncGenerator[str
|
|
172 |
bot_response_de = from_en_translation(response, desired_language)
|
173 |
|
174 |
# Stream the response
|
175 |
-
|
176 |
"user_text": user_speech_text,
|
177 |
"response_de": bot_response_de,
|
178 |
"response_en": response
|
179 |
})
|
|
|
180 |
|
181 |
# Generate and stream audio response
|
182 |
bot_voice = tts(bot_response_de, desired_language)
|
183 |
bot_voice_bytes = tts_to_bytesio(bot_voice)
|
184 |
-
|
185 |
"audio": bot_voice_bytes.decode('latin1')
|
186 |
})
|
|
|
187 |
|
188 |
except Exception as processing_error:
|
189 |
print(f"Error processing speech utterance: {processing_error}")
|
|
|
|
|
|
|
|
|
|
|
|
|
190 |
|
191 |
-
except asyncio.CancelledError:
|
192 |
-
# Handle task cancellation
|
193 |
-
break
|
194 |
-
except Exception as e:
|
195 |
-
print(f"Unexpected error in audio stream processing: {e}")
|
196 |
-
# Prevent tight error loop
|
197 |
-
await asyncio.sleep(1)
|
198 |
-
|
199 |
@app.get("/", response_class=HTMLResponse)
|
200 |
async def get_index():
|
201 |
with open("static/index.html") as f:
|
|
|
1 |
|
2 |
from langfuse import Langfuse
|
3 |
from langfuse.decorators import observe, langfuse_context
|
4 |
+
from fastapi import WebSocketDisconnect
|
5 |
+
import asyncio
|
6 |
|
7 |
from config.config import settings
|
8 |
from services.llama_generator import LlamaGenerator
|
|
|
70 |
# You might want to use libraries like Porcupine or build your own wake word detector
|
71 |
return True
|
72 |
|
73 |
+
|
74 |
@app.websocket("/ws")
|
75 |
async def websocket_endpoint(websocket: WebSocket):
|
76 |
+
# Create the queue outside the try block
|
77 |
+
audio_queue = asyncio.Queue()
|
78 |
+
stream_task = None
|
79 |
+
|
80 |
await websocket.accept()
|
81 |
try:
|
|
|
|
|
|
|
82 |
# Create a task to process the audio stream
|
83 |
+
stream_task = asyncio.create_task(process_audio_stream(audio_queue, websocket))
|
84 |
|
85 |
# Main receive loop
|
86 |
while True:
|
|
|
108 |
print(f"WebSocket endpoint error: {e}")
|
109 |
|
110 |
finally:
|
111 |
+
# Cancel the stream processing task if it exists
|
112 |
+
if stream_task:
|
113 |
+
stream_task.cancel()
|
114 |
+
try:
|
115 |
+
await stream_task # Wait for the task to be fully cancelled
|
116 |
+
except asyncio.CancelledError:
|
117 |
+
pass
|
118 |
+
|
119 |
try:
|
120 |
await websocket.close(code=1000)
|
121 |
except Exception as close_error:
|
122 |
print(f"Error closing WebSocket: {close_error}")
|
123 |
|
124 |
+
async def process_audio_stream(audio_queue: asyncio.Queue, websocket: WebSocket) -> AsyncGenerator[str, None]:
|
125 |
buffer = []
|
126 |
is_speaking = False
|
127 |
silence_frames = 0
|
128 |
|
129 |
+
try:
|
130 |
+
while True:
|
131 |
# Get audio data from queue with timeout
|
132 |
try:
|
133 |
audio_data = await asyncio.wait_for(audio_queue.get(), timeout=5.0)
|
|
|
182 |
bot_response_de = from_en_translation(response, desired_language)
|
183 |
|
184 |
# Stream the response
|
185 |
+
response_data = json.dumps({
|
186 |
"user_text": user_speech_text,
|
187 |
"response_de": bot_response_de,
|
188 |
"response_en": response
|
189 |
})
|
190 |
+
await websocket.send_text(response_data)
|
191 |
|
192 |
# Generate and stream audio response
|
193 |
bot_voice = tts(bot_response_de, desired_language)
|
194 |
bot_voice_bytes = tts_to_bytesio(bot_voice)
|
195 |
+
audio_data = json.dumps({
|
196 |
"audio": bot_voice_bytes.decode('latin1')
|
197 |
})
|
198 |
+
await websocket.send_text(audio_data)
|
199 |
|
200 |
except Exception as processing_error:
|
201 |
print(f"Error processing speech utterance: {processing_error}")
|
202 |
+
|
203 |
+
except asyncio.CancelledError:
|
204 |
+
# Handle task cancellation
|
205 |
+
print("Audio stream processing task cancelled")
|
206 |
+
except Exception as e:
|
207 |
+
print(f"Unexpected error in audio stream processing: {e}")
|
208 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
209 |
@app.get("/", response_class=HTMLResponse)
|
210 |
async def get_index():
|
211 |
with open("static/index.html") as f:
|