from __future__ import annotations import uuid from pathlib import Path from tempfile import gettempdir import gradio as gr import soundfile as sf try: import spaces except ImportError: class spaces: class GPU: def __init__(self, func=None, duration=60): self.func = func def __call__(self, *args, **kwargs): if self.func is not None: return self.func(*args, **kwargs) return args[0] from pyharp import ModelCard, build_endpoint from pyharp.tags import Subcategory from musicgen_runtime import generate, warmup warmup() MAX_INPUT_SECONDS = 30 OUTPUT_ROOT = Path(gettempdir()) / "musicgen_outputs" model_card = ModelCard( name="MusicGen", description=( "Generate music from a text prompt with melody conditioning. The code " "is MIT, but Meta's MusicGen weights are CC-BY-NC-4.0, so results " "cannot be used commercially. Repository: " "https://github.com/facebookresearch/audiocraft Paper: " "https://arxiv.org/abs/2306.05284" ), author="Jade Copet, Felix Kreuk, Itai Gat, et al.", tags=[Subcategory.HOLISTIC, 'melody-conditioning'], ) def _validate_audio(path: str | None) -> str | None: if not path: return None try: duration = sf.info(path).duration except Exception as exc: raise gr.Error(f"Could not read the audio file: {exc}") from exc if duration > MAX_INPUT_SECONDS: raise gr.Error( f"Melody audio must be no longer than {MAX_INPUT_SECONDS} seconds. " f"Received {duration:.1f} seconds." ) return path @spaces.GPU(duration=120) def process_fn( audio_path: str | None, prompt: str, duration: str, ) -> str: prompt = (prompt or "").strip() if not prompt: raise gr.Error("Please enter a text description.") melody_path = _validate_audio(audio_path) duration_seconds = int(duration) try: audio, sample_rate = generate( prompt=prompt, duration_seconds=duration_seconds, audio_path=melody_path, ) except Exception as exc: raise gr.Error(f"MusicGen generation failed: {exc}") from exc output_dir = OUTPUT_ROOT / uuid.uuid4().hex output_dir.mkdir(parents=True, exist_ok=True) output_path = output_dir / "musicgen_output.wav" sf.write(str(output_path), audio.numpy(), sample_rate) return str(output_path) if __name__ == "__main__": with gr.Blocks(title="MusicGen") as demo: input_components = [ gr.Audio(type="filepath", label="Melody (optional)") .set_info("Melody audio to condition on, up to 30 seconds."), gr.Textbox( label="Text Description", placeholder="e.g. An upbeat electronic dance track with heavy bass", info=( "Describe the music to generate: genre, instrumentation, mood, " "tempo." ), ), gr.Dropdown( choices=["5", "10", "15", "20"], value="10", label="Duration (seconds)", info=( "Length of the result. Longer generations drift further from the " "prompt." ), ), ] output_components = [ gr.Audio(type="filepath", label="Generated Music").set_info(( "The generated music, at 32 kHz mono." )), ] build_endpoint( model_card=model_card, input_components=input_components, output_components=output_components, process_fn=process_fn, ) demo.queue(default_concurrency_limit=1).launch(show_error=True, pwa=True, ssr_mode=False)