from fastapi import FastAPI, UploadFile, File, Depends, HTTPException, status from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials from fastapi.responses import HTMLResponse from faster_whisper import WhisperModel import tempfile import os app = FastAPI() security = HTTPBearer() API_KEY = os.environ.get("API_KEY") # 1. Authentication Dependency def verify_api_key(credentials: HTTPAuthorizationCredentials = Depends(security)): if credentials.credentials != API_KEY: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid API Key" ) return credentials.credentials # 2. Load Model globally (Runs on CPU with int8 quantization for speed) print("Loading model...") model = WhisperModel("base", device="cpu", compute_type="int8") print("Model loaded!") # 3. Transcription Endpoint @app.post("/v1/transcribe") async def transcribe( file: UploadFile = File(...), token: str = Depends(verify_api_key) ): # Save uploaded file to a temporary location with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as tmp: tmp.write(await file.read()) tmp_path = tmp.name try: # Transcribe with word_timestamps=True to get word-level timing segments, info = model.transcribe(tmp_path, beam_size=5, word_timestamps=True) # Convert the segments generator into a list of dictionaries segments_data = [] full_text = [] for segment in segments: full_text.append(segment.text) seg_dict = { "text": segment.text, "start": segment.start, "end": segment.end, "words": [] } # If word timestamps are available, include them if segment.words: for word in segment.words: seg_dict["words"].append({ "word": word.word, "start": word.start, "end": word.end }) segments_data.append(seg_dict) return { "text": " ".join(full_text).strip(), "language": info.language, "segments": segments_data } finally: # Clean up the temp file os.remove(tmp_path) # 4. Health Check Endpoint (For Automated Ping) @app.get("/health") def health_check(): return {"status": "awake"} # 5. Simple UI for Testing HTML_TEMPLATE = """
Test your Whisper model directly in the browser.