| import os |
| import uuid |
| import torch |
| import yt_dlp |
| import whisperx |
| from fastapi import FastAPI, BackgroundTasks, Request |
| from fastapi.responses import HTMLResponse, JSONResponse |
| from fastapi.staticfiles import StaticFiles |
| from huggingface_hub import HfApi |
|
|
| |
| torch.set_num_threads(1) |
|
|
| app = FastAPI() |
| app.mount("/static", StaticFiles(directory="static"), name="static") |
|
|
| |
| jobs = {} |
|
|
| HF_TOKEN = os.getenv("HF_TOKEN") |
| DATASET_REPO = "your-username/whisper-transcripts" |
|
|
| def process_audio(job_id: str, url: str): |
| jobs[job_id] = {"status": "downloading", "url": url} |
| audio_path = f"/tmp/{job_id}.mp3" |
| |
| try: |
| |
| ydl_opts = {'format': 'bestaudio/best', 'outtmpl': audio_path, 'quiet': True} |
| with yt_dlp.YoutubeDL(ydl_opts) as ydl: |
| ydl.download([url]) |
| |
| jobs[job_id]["status"] = "transcribing" |
| |
| |
| device = "cpu" |
| audio = whisperx.load_audio(audio_path) |
| |
| model = whisperx.load_model("base", device, compute_type="int8", threads=1) |
| result = model.transcribe(audio) |
| |
| |
| model_a, metadata = whisperx.load_align_model(language_code=result["language"], device=device) |
| result = whisperx.align(result["segments"], model_a, metadata, audio, device, return_char_alignments=False) |
| |
| diarize_model = whisperx.DiarizationPipeline(use_auth_token=HF_TOKEN, device=device) |
| diarize_segments = diarize_model(audio) |
| result = whisperx.assign_word_speakers(diarize_segments, result) |
| |
| |
| output_txt = f"/tmp/{job_id}.txt" |
| with open(output_txt, "w", encoding="utf-8") as f: |
| for segment in result["segments"]: |
| speaker = segment.get("speaker", "UNKNOWN") |
| start = round(segment["start"], 2) |
| end = round(segment["end"], 2) |
| text = segment["text"] |
| f.write(f"[{start} - {end}] {speaker}: {text}\n") |
| |
| jobs[job_id]["status"] = "pushing to dataset" |
| |
| |
| api = HfApi() |
| api.upload_file( |
| path_or_fileobj=output_txt, |
| path_in_repo=f"{job_id}.txt", |
| repo_id=DATASET_REPO, |
| repo_type="dataset", |
| token=HF_TOKEN |
| ) |
| |
| dataset_url = f"https://huggingface.co/datasets/{DATASET_REPO}/blob/main/{job_id}.txt" |
| jobs[job_id] = {"status": "completed", "download_url": dataset_url} |
| |
| except Exception as e: |
| jobs[job_id] = {"status": "error", "error": str(e)} |
| finally: |
| if os.path.exists(audio_path): |
| os.remove(audio_path) |
|
|
| @app.get("/") |
| def read_index(): |
| with open("static/index.html") as f: |
| return HTMLResponse(f.read()) |
|
|
| @app.post("/start") |
| async def start_job(request: Request, background_tasks: BackgroundTasks): |
| data = await request.json() |
| url = data.get("url") |
| job_id = str(uuid.uuid4()) |
| |
| |
| background_tasks.add_task(process_audio, job_id, url) |
| return JSONResponse({"job_id": job_id}) |
|
|
| @app.get("/status/{job_id}") |
| def get_status(job_id: str): |
| return JSONResponse(jobs.get(job_id, {"status": "not_found"})) |