kaio-backend / app.py
Generalclassic1700's picture
Create app.py
b6690af verified
Raw
History Blame Contribute Delete
2.14 kB
import os
import tempfile
import base64
import gradio as gr
import demucs.separate
import librosa
def separate_audio(file):
"""
Accepts an audio file, runs Demucs, returns instrumental and vocals as base64.
"""
if file is None:
raise gr.Error("No audio file provided")
with tempfile.TemporaryDirectory() as tmpdir:
# Save uploaded file
input_path = os.path.join(tmpdir, "input." + file.name.split(".")[-1])
with open(input_path, "wb") as f:
f.write(file.read())
output_dir = os.path.join(tmpdir, "output")
os.makedirs(output_dir, exist_ok=True)
try:
demucs.separate.main(
["--model", "htdemucs_ft", "--out", output_dir, input_path]
)
except Exception as e:
raise gr.Error(f"Demucs failed: {str(e)}")
base_name = os.path.splitext(os.path.basename(input_path))[0]
sep_dir = os.path.join(output_dir, "htdemucs_ft", base_name)
vocals_path = os.path.join(sep_dir, "vocals.wav")
instrumental_path = os.path.join(sep_dir, "no_vocals.wav")
if not os.path.exists(vocals_path) or not os.path.exists(instrumental_path):
raise gr.Error("Separation output missing")
def encode_wav(path):
with open(path, "rb") as f:
return base64.b64encode(f.read()).decode("utf-8")
def get_info(path):
y, sr = librosa.load(path, sr=None)
return {"duration": len(y) / sr, "sample_rate": sr}
return {
"instrumental_b64": encode_wav(instrumental_path),
"vocals_b64": encode_wav(vocals_path),
"instrumental_info": get_info(instrumental_path),
"vocals_info": get_info(vocals_path),
}
# Gradio interface
iface = gr.Interface(
fn=separate_audio,
inputs=gr.Audio(type="file", label="Upload your song"),
outputs=gr.JSON(label="Result"),
title="Kaio Vocal Separator",
description="Upload a song, get instrumental and vocals (base64).",
api_name="separate" # endpoint: /api/predict/separate
)
iface.launch()