File size: 4,228 Bytes
451b460
 
 
dc559ef
451b460
1ad5db5
451b460
1ad5db5
451b460
 
 
1ad5db5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dc559ef
 
1ad5db5
 
 
 
 
 
451b460
 
1ad5db5
 
 
 
 
 
451b460
 
 
1ad5db5
451b460
1ad5db5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
451b460
 
 
dc559ef
e7cf803
 
 
 
 
103f09f
 
 
 
 
 
 
e7cf803
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
451b460
 
 
1ad5db5
 
103f09f
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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 """
    <!DOCTYPE html>
    <html>
    <head>
        <title>Whisper Transcription API</title>
        <style>
            body { font-family: monospace; background: #0d0d0d; color: #e0e0e0; padding: 40px; }
            h1 { color: #7fff7f; }
            a { color: #7fbfff; }
            code { background: #1a1a1a; padding: 2px 6px; border-radius: 4px; }
        </style>
    </head>
    <body>
        <h1>πŸŽ™οΈ Whisper Transcription API</h1>
        <p>Status: <strong style="color:#7fff7f">Running</strong></p>
        <p>Endpoints:</p>
        <ul>
            <li><code>POST /transcribe</code> β€” Upload audio file</li>
            <li><code>POST /transcribe-url</code> β€” Transcribe from URL</li>
            <li><code>GET /health</code> β€” Health check</li>
            <li><a href="/docs">πŸ“– Swagger Docs</a></li>
        </ul>
    </body>
    </html>
    """

@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)