Spaces:
Running
Running
File size: 2,092 Bytes
e561008 889e86b 94dd7b2 e561008 889e86b e561008 94dd7b2 e561008 020705e e561008 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | from fastapi import APIRouter, UploadFile, File, Depends, HTTPException
from utils.rate_limiter import with_rate_limit
from utils.groq_client import call_groq_transcribe
router = APIRouter()
SUPPORTED_AUDIO_TYPES = {
"audio/webm", "audio/mp4", "audio/mpeg", "audio/wav",
"audio/ogg", "audio/flac", "audio/x-m4a",
}
MAX_AUDIO_BYTES = 25 * 1024 * 1024 # 25 MB — Groq Whisper limit
@router.post("/transcribe")
async def transcribe_audio(
audio: UploadFile = File(...),
user: dict = Depends(with_rate_limit("transcription")),
):
"""
Accepts a browser-recorded audio blob, sends it to Groq Whisper,
and returns the transcript text.
Voice input is NEVER stored — the audio bytes are discarded after
transcription returns. Only the resulting text is saved by the caller.
See VUL-019 (no audio persistence).
"""
# Basic content-type guard — not a hard security boundary since the
# browser may send 'application/octet-stream'. Real validation happens
# when Groq rejects unsupported formats.
content_type = audio.content_type or "audio/webm"
if content_type not in SUPPORTED_AUDIO_TYPES and content_type != "application/octet-stream":
raise HTTPException(
status_code=415,
detail=f"Unsupported audio format: {content_type}",
)
audio_bytes = await audio.read()
if len(audio_bytes) > MAX_AUDIO_BYTES:
raise HTTPException(
status_code=413,
detail="Audio file exceeds 25 MB limit.",
)
if len(audio_bytes) == 0:
raise HTTPException(status_code=400, detail="Audio file is empty.")
try:
transcription = call_groq_transcribe(
file=(audio.filename or "recording.webm", audio_bytes, content_type),
response_format="json",
language="en",
fixture="transcript",
)
return {"transcript": transcription.text}
except Exception as e:
raise HTTPException(
status_code=500,
detail=f"Transcription failed: {str(e)}",
)
|