app.py 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. from fastapi import FastAPI, UploadFile, File, WebSocket, WebSocketDisconnect
  2. from faster_whisper import WhisperModel
  3. import tempfile
  4. import os
  5. import numpy as np
  6. import time
  7. app = FastAPI()
  8. # =========================
  9. # Whisper model (shared)
  10. # =========================
  11. model = WhisperModel(
  12. "small",
  13. device="cuda",
  14. compute_type="float32" # GTX 1050 Ti compatible
  15. )
  16. # =========================
  17. # REST API (Swagger / tests)
  18. # =========================
  19. @app.post("/transcribe")
  20. async def transcribe(file: UploadFile = File(...)):
  21. with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as tmp:
  22. tmp.write(await file.read())
  23. tmp_path = tmp.name
  24. segments, info = model.transcribe(
  25. tmp_path,
  26. language="fr",
  27. vad_filter=True
  28. )
  29. os.remove(tmp_path)
  30. text = " ".join(seg.text for seg in segments)
  31. return {
  32. "text": text,
  33. "language": info.language
  34. }
  35. # =========================
  36. # WebSocket STT (streaming)
  37. # =========================
  38. SAMPLE_RATE = 16000
  39. MIN_AUDIO_SEC = 0.5
  40. MAX_AUDIO_SEC = 10.0
  41. @app.websocket("/ws/transcribe")
  42. async def ws_transcribe(ws: WebSocket):
  43. await ws.accept()
  44. audio_buffer = []
  45. start_time = time.time()
  46. try:
  47. while True:
  48. data = await ws.receive_bytes()
  49. # PCM int16 → float32
  50. pcm = np.frombuffer(data, dtype=np.int16).astype(np.float32) / 32768.0
  51. audio_buffer.append(pcm)
  52. audio_len = sum(len(chunk) for chunk in audio_buffer) / SAMPLE_RATE
  53. # Sécurité : reset si trop long
  54. if audio_len > MAX_AUDIO_SEC:
  55. audio_buffer.clear()
  56. start_time = time.time()
  57. continue
  58. # Transcription dès qu'on a assez d'audio
  59. if audio_len >= MIN_AUDIO_SEC:
  60. audio = np.concatenate(audio_buffer)
  61. audio_buffer.clear()
  62. segments, _ = model.transcribe(
  63. audio,
  64. language="fr",
  65. vad_filter=True
  66. )
  67. text = " ".join(seg.text for seg in segments).strip()
  68. if text:
  69. await ws.send_json({
  70. "type": "final",
  71. "text": text
  72. })
  73. except WebSocketDisconnect:
  74. pass
  75. except Exception as e:
  76. await ws.send_json({"error": str(e)})
  77. await ws.close()