import os import shutil import tempfile import speech_recognition as sr from fastapi import FastAPI, UploadFile, File, Form from pydub import AudioSegment from pathlib import Path from typing import Optional app = FastAPI(title="VocalizeAPI") # --- LINUX FFMPEG FIX --- # On some HF containers, we need to explicitly tell pydub where ffmpeg is if shutil.which("ffmpeg"): AudioSegment.converter = shutil.which("ffmpeg") def get_audio_info(file_path): """Returns size in MB and duration in seconds.""" size_mb = os.path.getsize(file_path) / (1024 * 1024) audio = AudioSegment.from_file(file_path) duration_sec = len(audio) / 1000.0 return size_mb, duration_sec @app.post("/audio-to-text") async def audio_to_text( file: UploadFile = File(...), lang: Optional[str] = Form(None) ): temp_dir = tempfile.mkdtemp() # Ensure filename exists to avoid suffix errors filename = file.filename if file.filename else "input.ogg" input_ext = Path(filename).suffix.lower() or ".ogg" input_path = os.path.join(temp_dir, f"input{input_ext}") wav_path = os.path.join(temp_dir, "converted.wav") try: # 1. Save uploaded file with open(input_path, "wb") as buffer: shutil.copyfileobj(file.file, buffer) # 2. Convert to WAV (Standardized for Google) audio = AudioSegment.from_file(input_path) audio = audio.set_channels(1).set_frame_rate(16000) audio.export(wav_path, format="wav") target_path = wav_path # 3. Validate size_mb, duration = get_audio_info(target_path) if duration > 60: return {"status": False, "error": "File Rejected: It's longer than 60s.", "result": ""} elif size_mb > 10: return {"status": False, "error": "Error: File is too large (>10MB).", "result": ""} # 4. Transcribe r = sr.Recognizer() with sr.AudioFile(target_path) as source: r.adjust_for_ambient_noise(source, duration=0.5) audio_data = r.record(source) try: # Use provided lang if it exists and isn't just whitespace actual_lang = lang.strip() if (lang and lang.strip()) else None if actual_lang: text = r.recognize_google(audio_data, language=actual_lang) else: text = r.recognize_google(audio_data) return {"status": True, "error": None, "result": text} except sr.UnknownValueError: return {"status": False, "error": "I could not understand the audio (Low quality or silent).", "result": ""} except sr.RequestError: return {"status": False, "error": "API-Key Error: Google limit reached.", "result": ""} except Exception as e: print(f"Server Log Error: {e}") return {"status": False, "error": f"System Error: {str(e)}", "result": ""} finally: # 5. Cleanup shutil.rmtree(temp_dir, ignore_errors=True) if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=7860)