Spaces:
Sleeping
Sleeping
File size: 3,191 Bytes
0f623ae | 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 131 | # 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
```bash
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`.
```python
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
```python
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
```bash
source venv/bin/activate
uvicorn backend.main:app --reload
```
Server runs at: `http://localhost:8000`
---
## Test it manually
```bash
curl -X POST http://localhost:8000/upload \
-F "file=@mp3/Recording 1.mp3"
```
Expected response:
```json
{"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
|