Spaces:
Running
Running
Download routes/transcribe.py from Success-dev/venthrive-api: direct link, hf CLI and curl.
- Browser
- Download file 2.09 kB
-
https://huggingface.co/spaces/Success-dev/venthrive-api/resolve/main/routes/transcribe.py
- Command line
-
hf download hf://spaces/Success-dev/venthrive-api/routes/transcribe.py
-
curl -L -o transcribe.py https://huggingface.co/spaces/Success-dev/venthrive-api/resolve/main/routes/transcribe.py
2.09 kB
| 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 | |
| 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)}", | |
| ) | |