From b680097dfbfb202763172def602eb2d9cc9a82f3 Mon Sep 17 00:00:00 2001 From: Elem Oghenekaro <71514976+e3o8o@users.noreply.github.com> Date: Mon, 20 Jul 2026 22:39:46 +0300 Subject: [PATCH] Fix: keep the uploaded file extension when transcribing (#903) /transcribe wrote every upload to a temp file named .wav regardless of its real format. librosa picks its decoder from the extension, so any non-wav upload failed with "could not open/decode file" even though the format is one the app handles elsewhere. profiles.py already solves this for voice samples by keeping the uploaded extension when it is one of the audio types it accepts, and falling back to .wav otherwise. Same approach here, same set. The fallback means an unknown or missing extension behaves exactly as it does today. --- backend/routes/transcription.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/backend/routes/transcription.py b/backend/routes/transcription.py index dc949132..7ba19d74 100644 --- a/backend/routes/transcription.py +++ b/backend/routes/transcription.py @@ -15,6 +15,10 @@ router = APIRouter() UPLOAD_CHUNK_SIZE = 1024 * 1024 # 1MB +# Same set profiles.py accepts for voice samples. librosa picks its decoder from the +# file extension, so the temp file has to keep the uploaded one. +ALLOWED_AUDIO_EXTS = {".wav", ".mp3", ".m4a", ".ogg", ".flac", ".aac", ".webm", ".opus"} + @router.post("/transcribe", response_model=models.TranscriptionResponse) async def transcribe_audio( @@ -23,7 +27,10 @@ async def transcribe_audio( model: str | None = Form(None), ): """Transcribe audio file to text.""" - with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp: + uploaded_ext = Path(file.filename or "").suffix.lower() + file_suffix = uploaded_ext if uploaded_ext in ALLOWED_AUDIO_EXTS else ".wav" + + with tempfile.NamedTemporaryFile(suffix=file_suffix, delete=False) as tmp: while chunk := await file.read(UPLOAD_CHUNK_SIZE): tmp.write(chunk) tmp_path = tmp.name