Spaces:
Running
Running
| import gradio as gr | |
| import json | |
| import sys | |
| sys.path.insert(0, ".") | |
| # Models are loaded at startup, not per-request. | |
| # Cold start time on CPU Basic: 3β8 min. This cost is paid once per Space | |
| # wake-up, not on every extraction call. | |
| from feature_extractor_cpu import extract_mir_features, ENG_DIMS | |
| from clap_embedder import get_clap_embedding | |
| print("[startup] All models loaded. Space ready.") | |
| def extract(audio_file_path: str) -> str: | |
| """ | |
| Receives a local file path from Gradio (gr.File type='filepath'). | |
| Returns JSON with keys: l3, clap, eng_raw, true_peak_dbfs. | |
| Any exception propagates to gradio_client as a job error β no silent failures. | |
| """ | |
| if audio_file_path is None: | |
| raise ValueError("No audio file received.") | |
| l3, eng_raw, true_peak = extract_mir_features(audio_file_path) | |
| clap = get_clap_embedding(audio_file_path) | |
| if len(eng_raw) != len(ENG_DIMS): | |
| raise ValueError( | |
| f"eng_raw length mismatch: got {len(eng_raw)}, expected {len(ENG_DIMS)}" | |
| ) | |
| return json.dumps({ | |
| "l3": l3.tolist(), | |
| "clap": clap.tolist(), | |
| "eng_raw": eng_raw.tolist(), | |
| "true_peak_dbfs": float(true_peak), | |
| }) | |
| # demo.queue() is REQUIRED β not optional. | |
| # Without it, Gradio's async event loop kills any function that runs longer | |
| # than a few seconds. CPU demucs with shifts=5 runs for 33β136 min per track. | |
| # queue() enables proper long-running background job execution. | |
| demo = gr.Interface( | |
| fn=extract, | |
| inputs=gr.File(label="Audio file (.mp3 or .wav)", type="filepath"), | |
| outputs=gr.Textbox(label="Feature JSON"), | |
| title="Playlisting Feature Extractor (CPU Basic)", | |
| ) | |
| demo.queue(max_size=50) | |
| if __name__ == "__main__": | |
| demo.launch(show_error=True) | |