benhadjermed commited on
Commit
8cb52fb
·
verified ·
1 Parent(s): ac95f56

fix: run partial inference in background to stop blocking WebSocket receive loop

Browse files
Files changed (1) hide show
  1. main.py +13 -6
main.py CHANGED
@@ -38,7 +38,7 @@ CHUNK_LENGTH_S = 30
38
  OVERLAP_S = 1
39
 
40
  # Minimum seconds of audio before running partial inference (reduces hallucinations)
41
- MIN_AUDIO_FOR_INFERENCE_S = 1.5
42
  MIN_SAMPLES_FOR_INFERENCE = int(MIN_AUDIO_FOR_INFERENCE_S * SAMPLE_RATE)
43
 
44
  ALLOWED_EXTS = {".wav", ".m4a", ".mp3", ".flac", ".ogg"}
@@ -141,6 +141,16 @@ async def stream_transcribe(ws: WebSocket):
141
  audio_buffer = bytearray()
142
  last_inference_len = 0 # track buffer size at last inference to avoid redundant runs
143
 
 
 
 
 
 
 
 
 
 
 
144
  try:
145
  while True:
146
  message = await ws.receive()
@@ -157,12 +167,9 @@ async def stream_transcribe(ws: WebSocket):
157
  # Run partial inference ONLY if the CPU is free.
158
  # This prevents thousands of requests from queuing and timing out the final run.
159
  if not _inference_lock.locked():
160
- async with _inference_lock:
161
- text = await asyncio.get_event_loop().run_in_executor(
162
- None, _transcribe_pcm_buffer, bytes(audio_buffer)
163
- )
164
  last_inference_len = len(audio_buffer)
165
- await ws.send_json({"type": "partial", "text": text})
 
166
 
167
  # --- Text frame: control message ------------------------------
168
  elif "text" in message and message["text"] is not None:
 
38
  OVERLAP_S = 1
39
 
40
  # Minimum seconds of audio before running partial inference (reduces hallucinations)
41
+ MIN_AUDIO_FOR_INFERENCE_S = 1.0
42
  MIN_SAMPLES_FOR_INFERENCE = int(MIN_AUDIO_FOR_INFERENCE_S * SAMPLE_RATE)
43
 
44
  ALLOWED_EXTS = {".wav", ".m4a", ".mp3", ".flac", ".ogg"}
 
141
  audio_buffer = bytearray()
142
  last_inference_len = 0 # track buffer size at last inference to avoid redundant runs
143
 
144
+ async def _run_partial(pcm_data: bytes):
145
+ try:
146
+ async with _inference_lock:
147
+ text = await asyncio.get_event_loop().run_in_executor(
148
+ None, _transcribe_pcm_buffer, pcm_data
149
+ )
150
+ await ws.send_json({"type": "partial", "text": text})
151
+ except Exception as e:
152
+ print(f"[ws] partial inference error: {e}", flush=True)
153
+
154
  try:
155
  while True:
156
  message = await ws.receive()
 
167
  # Run partial inference ONLY if the CPU is free.
168
  # This prevents thousands of requests from queuing and timing out the final run.
169
  if not _inference_lock.locked():
 
 
 
 
170
  last_inference_len = len(audio_buffer)
171
+ # We must run this in the background, otherwise we block ws.receive()
172
+ asyncio.create_task(_run_partial(bytes(audio_buffer)))
173
 
174
  # --- Text frame: control message ------------------------------
175
  elif "text" in message and message["text"] is not None: