Repository navigation
Expand file tree
/
Copy pathmain.py
More file actions
90 lines (71 loc) · 2.42 KB
/
Copy pathmain.py
File metadata and controls
90 lines (71 loc) · 2.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import asyncio
import os
import tempfile
from concurrent.futures import ThreadPoolExecutor
from contextlib import asynccontextmanager
from dotenv import load_dotenv
from fastapi import FastAPI, File, HTTPException, Query, UploadFile
from fastapi.middleware.cors import CORSMiddleware
from models import TranscribeResponse
from transcribe import get_model, run_transcription
load_dotenv()
ALLOWED_ORIGINS = os.getenv("ALLOWED_ORIGINS", "http://localhost:5174").split(",")
MODEL_SIZE = os.getenv("MODEL_SIZE", "small")
ALLOWED_EXTENSIONS = {".mp3", ".wav", ".m4a", ".aac", ".ogg", ".flac", ".webm"}
MAX_FILE_SIZE_MB = 50
executor = ThreadPoolExecutor(max_workers=1)
@asynccontextmanager
async def lifespan(app: FastAPI):
get_model(MODEL_SIZE)
yield
app = FastAPI(
title="Melodyne Transcription API",
description="Whisper-powered audio transcription with word-level timestamps",
version="0.1.0",
lifespan=lifespan,
)
app.add_middleware(
CORSMiddleware,
allow_origins=ALLOWED_ORIGINS,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/health")
def health():
return {"status": "ok", "model": MODEL_SIZE}
@app.post("/transcribe", response_model=TranscribeResponse)
async def transcribe(
audio: UploadFile = File(...),
model: str = Query(
default=None, description="Override model size for this request"
),
):
filename = audio.filename or ""
ext = os.path.splitext(filename)[-1].lower()
if ext not in ALLOWED_EXTENSIONS:
raise HTTPException(
status_code=400,
detail=f"Unsupported file type '{ext}'. Allowed: {', '.join(ALLOWED_EXTENSIONS)}",
)
content = await audio.read()
size_mb = len(content) / (1024 * 1024)
if size_mb > MAX_FILE_SIZE_MB:
raise HTTPException(
status_code=413,
detail=f"File too large ({size_mb:.1f}MB). Max allowed: {MAX_FILE_SIZE_MB}MB.",
)
with tempfile.NamedTemporaryFile(delete=False, suffix=ext) as tmp:
tmp.write(content)
tmp_path = tmp.name
try:
model_size = model or MODEL_SIZE
loop = asyncio.get_event_loop()
result = await loop.run_in_executor(
executor, run_transcription, tmp_path, model_size
)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Transcription failed: {str(e)}")
finally:
os.unlink(tmp_path)
return result