import whisper
import tempfile
import os
import httpx
from fastapi import FastAPI, UploadFile, File, Form
from fastapi.responses import JSONResponse, HTMLResponse
from fastapi.middleware.cors import CORSMiddleware
import uvicorn
app = FastAPI(title="Whisper Transcription API")
print("Loading Whisper model...")
model = whisper.load_model("base")
print("Model loaded.")
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/", response_class=HTMLResponse)
async def root():
return """
Whisper Transcription API
🎙️ Whisper Transcription API
Status: Running
Endpoints:
POST /transcribe — Upload audio file
POST /transcribe-url — Transcribe from URL
GET /health — Health check
- 📖 Swagger Docs
"""
@app.post("/transcribe")
async def transcribe(
file: UploadFile = File(...),
language: str = Form(default="auto")
):
suffix = os.path.splitext(file.filename)[-1] if file.filename else ".wav"
with tempfile.NamedTemporaryFile(suffix=suffix, delete=False) as tmp:
content = await file.read()
tmp.write(content)
tmp_path = tmp.name
try:
lang = language if language != "auto" else None
result = model.transcribe(tmp_path, language=lang)
return JSONResponse({
"text": result["text"].strip(),
"language": result.get("language", "unknown"),
"segments": [
{
"start": round(s["start"], 2),
"end": round(s["end"], 2),
"text": s["text"].strip()
}
for s in result.get("segments", [])
]
})
except Exception as e:
return JSONResponse({"error": str(e)}, status_code=500)
finally:
os.unlink(tmp_path)
@app.post("/transcribe-url")
async def transcribe_url(
url: str = Form(...),
language: str = Form(default="auto")
):
try:
async with httpx.AsyncClient(timeout=60, follow_redirects=True) as client:
r = await client.get(url, headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Accept": "*/*",
"Accept-Language": "en-US,en;q=0.9",
"Referer": "https://www.google.com/"
})
r.raise_for_status()
except Exception as e:
return JSONResponse({"error": f"Failed to download: {str(e)}"}, status_code=400)
ext = os.path.splitext(url.split("?")[0])[-1] or ".mp3"
with tempfile.NamedTemporaryFile(suffix=ext, delete=False) as tmp:
tmp.write(r.content)
tmp_path = tmp.name
try:
lang = language if language != "auto" else None
result = model.transcribe(tmp_path, language=lang)
return JSONResponse({
"text": result["text"].strip(),
"language": result.get("language", "unknown"),
"segments": [
{
"start": round(s["start"], 2),
"end": round(s["end"], 2),
"text": s["text"].strip()
}
for s in result.get("segments", [])
]
})
except Exception as e:
return JSONResponse({"error": str(e)}, status_code=500)
finally:
os.unlink(tmp_path)
@app.get("/health")
async def health():
return {"status": "ok", "model": "whisper-base"}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=7860)