voice-isolation-live / docs /step-2-fastapi-backend.md
TonyLikeDev's picture
initial commit
0f623ae
|
Raw
History Blame Contribute Delete
3.19 kB

Step 2 β€” FastAPI Backend

Status: TODO

Goal

Build an API that accepts an audio file upload, runs Demucs on it, and returns the cleaned vocals file.


Install dependencies

source venv/bin/activate
pip install fastapi uvicorn python-multipart

Files to create

backend/
β”œβ”€β”€ main.py            # FastAPI app β€” routes and server config
β”œβ”€β”€ demucs_runner.py   # Demucs logic β€” takes a file path, returns output path
└── uploads/           # Temp folder for uploaded files
    └── .gitkeep

How to build it

1. Create backend/demucs_runner.py

This file has one job: take a file path, run Demucs, return the path to vocals.wav.

import subprocess
import os

def run_demucs(input_path: str) -> str:
    subprocess.run([
        "demucs", "--two-stems=vocals", "-n", "mdx_extra", input_path
    ], check=True)

    filename = os.path.splitext(os.path.basename(input_path))[0]
    output_path = f"separated/mdx_extra/{filename}/vocals.wav"
    return output_path

2. Create backend/main.py

Two endpoints:

  • POST /upload β€” accepts audio file, runs Demucs, returns download URL
  • GET /download/{filename} β€” serves the processed .wav file
from fastapi import FastAPI, UploadFile, File, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse
import shutil, os, uuid
from backend.demucs_runner import run_demucs

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_methods=["*"],
    allow_headers=["*"],
)

UPLOAD_DIR = "backend/uploads"

@app.post("/upload")
async def upload_audio(file: UploadFile = File(...)):
    ext = os.path.splitext(file.filename)[1]
    unique_name = f"{uuid.uuid4()}{ext}"
    save_path = os.path.join(UPLOAD_DIR, unique_name)

    with open(save_path, "wb") as buffer:
        shutil.copyfileobj(file.file, buffer)

    output_path = run_demucs(save_path)
    filename = os.path.basename(output_path)

    return {"download_url": f"/download/{filename}", "status": "done"}

@app.get("/download/{filename}")
def download_audio(filename: str):
    file_path = f"separated/mdx_extra/{filename}/vocals.wav"
    if not os.path.exists(file_path):
        raise HTTPException(status_code=404, detail="File not found")
    return FileResponse(file_path, media_type="audio/wav")

3. Run the server

source venv/bin/activate
uvicorn backend.main:app --reload

Server runs at: http://localhost:8000


Test it manually

curl -X POST http://localhost:8000/upload \
  -F "file=@mp3/Recording 1.mp3"

Expected response:

{"download_url": "/download/vocals.wav", "status": "done"}

Then open http://localhost:8000/download/vocals.wav in the browser to download the file.


Notes

  • uuid4() on the filename prevents collisions if two people upload at the same time
  • CORS is open (*) for now β€” fine for a demo, tighten it before production
  • No file size limit set yet β€” add one later if needed
  • Uploaded files in backend/uploads/ are not cleaned up automatically β€” add a cleanup step later