Update app.py
Browse files
app.py
CHANGED
|
@@ -3,6 +3,8 @@ import asyncio
|
|
| 3 |
import tempfile
|
| 4 |
import torch
|
| 5 |
import torchaudio
|
|
|
|
|
|
|
| 6 |
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
|
| 7 |
from fastapi.middleware.cors import CORSMiddleware
|
| 8 |
from faster_whisper import WhisperModel
|
|
@@ -199,7 +201,7 @@ def run_transcription(audio_path):
|
|
| 199 |
|
| 200 |
def run_diarization(audio_path):
|
| 201 |
"""فقط تشخیص گوینده - بلاککننده، توی یه thread جدا اجرا میشه"""
|
| 202 |
-
return diarize_pipeline(audio_path)
|
| 203 |
|
| 204 |
|
| 205 |
def run_alignment_pass(segments_raw, align_waveform, diarization):
|
|
@@ -234,11 +236,16 @@ def run_alignment_pass(segments_raw, align_waveform, diarization):
|
|
| 234 |
return segments
|
| 235 |
|
| 236 |
|
| 237 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 238 |
"""
|
| 239 |
یه تابع سنگین و بلاککننده رو توی یه thread جدا اجرا میکنه، و تا وقتی تموم بشه،
|
| 240 |
هر چند ثانیه یه پیام "هنوز کار میکنم" روی همون status میفرسته - این هم جلوی
|
| 241 |
قطعشدن اتصال بهخاطر سکوت طولانی رو میگیره، هم UI رو زنده نگه میداره.
|
|
|
|
| 242 |
"""
|
| 243 |
task = asyncio.create_task(asyncio.to_thread(blocking_fn, *args))
|
| 244 |
elapsed = 0
|
|
@@ -248,6 +255,11 @@ async def run_with_heartbeat(websocket, blocking_fn, *args, status, detail):
|
|
| 248 |
await asyncio.wait_for(asyncio.shield(task), timeout=HEARTBEAT_SEC)
|
| 249 |
except asyncio.TimeoutError:
|
| 250 |
elapsed += HEARTBEAT_SEC
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 251 |
await websocket.send_json({
|
| 252 |
"status": status,
|
| 253 |
"detail": f"{detail} ({elapsed} ثانیه)",
|
|
@@ -359,6 +371,12 @@ async def transcribe(websocket: WebSocket):
|
|
| 359 |
|
| 360 |
except WebSocketDisconnect:
|
| 361 |
print("WebSocket disconnected by client")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 362 |
except Exception as e:
|
| 363 |
print(f"ERROR: {type(e).__name__}: {e}")
|
| 364 |
import traceback
|
|
|
|
| 3 |
import tempfile
|
| 4 |
import torch
|
| 5 |
import torchaudio
|
| 6 |
+
|
| 7 |
+
torch.set_num_threads(2) # جلوی رقابت بیفایدهی رشتهها روی CPU محدود رو میگیره
|
| 8 |
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
|
| 9 |
from fastapi.middleware.cors import CORSMiddleware
|
| 10 |
from faster_whisper import WhisperModel
|
|
|
|
| 201 |
|
| 202 |
def run_diarization(audio_path):
|
| 203 |
"""فقط تشخیص گوینده - بلاککننده، توی یه thread جدا اجرا میشه"""
|
| 204 |
+
return diarize_pipeline(audio_path, max_speakers=8)
|
| 205 |
|
| 206 |
|
| 207 |
def run_alignment_pass(segments_raw, align_waveform, diarization):
|
|
|
|
| 236 |
return segments
|
| 237 |
|
| 238 |
|
| 239 |
+
class ProcessingTimeout(Exception):
|
| 240 |
+
pass
|
| 241 |
+
|
| 242 |
+
|
| 243 |
+
async def run_with_heartbeat(websocket, blocking_fn, *args, status, detail, max_seconds=240):
|
| 244 |
"""
|
| 245 |
یه تابع سنگین و بلاککننده رو توی یه thread جدا اجرا میکنه، و تا وقتی تموم بشه،
|
| 246 |
هر چند ثانیه یه پیام "هنوز کار میکنم" روی همون status میفرسته - این هم جلوی
|
| 247 |
قطعشدن اتصال بهخاطر سکوت طولانی رو میگیره، هم UI رو زنده نگه میداره.
|
| 248 |
+
اگه از max_seconds بیشتر طول بکشه، بهجای قفل ابدی، خطای مشخص میده.
|
| 249 |
"""
|
| 250 |
task = asyncio.create_task(asyncio.to_thread(blocking_fn, *args))
|
| 251 |
elapsed = 0
|
|
|
|
| 255 |
await asyncio.wait_for(asyncio.shield(task), timeout=HEARTBEAT_SEC)
|
| 256 |
except asyncio.TimeoutError:
|
| 257 |
elapsed += HEARTBEAT_SEC
|
| 258 |
+
if elapsed >= max_seconds:
|
| 259 |
+
task.cancel()
|
| 260 |
+
raise ProcessingTimeout(
|
| 261 |
+
f"مرحلهی «{detail}» بیشتر از {max_seconds} ثانیه طول کشید و متوقف شد."
|
| 262 |
+
)
|
| 263 |
await websocket.send_json({
|
| 264 |
"status": status,
|
| 265 |
"detail": f"{detail} ({elapsed} ثانیه)",
|
|
|
|
| 371 |
|
| 372 |
except WebSocketDisconnect:
|
| 373 |
print("WebSocket disconnected by client")
|
| 374 |
+
except ProcessingTimeout as e:
|
| 375 |
+
print(f"TIMEOUT: {e}")
|
| 376 |
+
try:
|
| 377 |
+
await websocket.send_json({"status": "error", "message": str(e)})
|
| 378 |
+
except Exception:
|
| 379 |
+
pass
|
| 380 |
except Exception as e:
|
| 381 |
print(f"ERROR: {type(e).__name__}: {e}")
|
| 382 |
import traceback
|