| import os |
| import tempfile |
| import torch |
| import gradio as gr |
| from huggingface_hub import hf_hub_download, snapshot_download |
| import spaces |
|
|
| |
| def download_models(): |
| """Download all required model files from HuggingFace Hub.""" |
| cache_dir = os.environ.get("HF_HOME", os.path.expanduser("/tmp")) |
| model_dir = os.path.join(cache_dir, "heartmula_models") |
|
|
| if not os.path.exists(model_dir): |
| os.makedirs(model_dir, exist_ok=True) |
|
|
| |
| print("Downloading HeartMuLaGen files...") |
| for filename in ["tokenizer.json", "gen_config.json"]: |
| hf_hub_download( |
| repo_id="HeartMuLa/HeartMuLaGen", |
| filename=filename, |
| local_dir=model_dir, |
| ) |
|
|
| |
| print("Downloading HeartMuLa-oss-3B...") |
| snapshot_download( |
| repo_id="HeartMuLa/HeartMuLa-oss-3B", |
| local_dir=os.path.join(model_dir, "HeartMuLa-oss-3B"), |
| ) |
|
|
| |
| print("Downloading HeartCodec-oss...") |
| snapshot_download( |
| repo_id="HeartMuLa/HeartCodec-oss-20260123", |
| local_dir=os.path.join(model_dir, "HeartCodec-oss"), |
| ) |
|
|
| print("All models downloaded successfully!") |
| return model_dir |
|
|
| from heartlib import HeartMuLaGenPipeline |
|
|
| model_dir = download_models() |
|
|
| |
| if torch.cuda.is_available(): |
| device = torch.device("cuda") |
| dtype = torch.bfloat16 |
| else: |
| device = torch.device("cpu") |
| dtype = torch.float32 |
|
|
| print(f"Loading pipeline on {device} with {dtype}...") |
| pipe = HeartMuLaGenPipeline.from_pretrained( |
| model_dir, |
| device=device, |
| dtype=dtype, |
| version="3B", |
| ) |
| print("Pipeline loaded successfully!") |
|
|
|
|
| @spaces.GPU(duration=120) |
| def generate_music( |
| lyrics: str, |
| tags: str, |
| max_duration_seconds: int, |
| temperature: float, |
| topk: int, |
| cfg_scale: float, |
| progress=gr.Progress(track_tqdm=True), |
| ): |
| """Generate music from lyrics and tags.""" |
| if not lyrics.strip(): |
| raise gr.Error("Please enter some lyrics!") |
|
|
| if not tags.strip(): |
| raise gr.Error("Please enter at least one tag!") |
|
|
| |
| with tempfile.NamedTemporaryFile(suffix=".mp3", delete=False) as f: |
| output_path = f.name |
|
|
| max_audio_length_ms = max_duration_seconds * 1000 |
|
|
| with torch.no_grad(): |
| pipe( |
| { |
| "lyrics": lyrics, |
| "tags": tags, |
| }, |
| max_audio_length_ms=max_audio_length_ms, |
| save_path=output_path, |
| topk=topk, |
| temperature=temperature, |
| cfg_scale=cfg_scale, |
| ) |
|
|
| return output_path |
|
|
|
|
| |
| EXAMPLE_LYRICS = """[Intro] |
| |
| [Verse] |
| The sun creeps in across the floor |
| I hear the traffic outside the door |
| The coffee pot begins to hiss |
| It is another morning just like this |
| |
| [Prechorus] |
| The world keeps spinning round and round |
| Feet are planted on the ground |
| I find my rhythm in the sound |
| |
| [Chorus] |
| Every day the light returns |
| Every day the fire burns |
| We keep on walking down this street |
| Moving to the same steady beat |
| It is the ordinary magic that we meet |
| |
| [Verse] |
| The hours tick deeply into noon |
| Chasing shadows, chasing the moon |
| Work is done and the lights go low |
| Watching the city start to glow |
| |
| [Bridge] |
| It is not always easy, not always bright |
| Sometimes we wrestle with the night |
| But we make it to the morning light |
| |
| [Chorus] |
| Every day the light returns |
| Every day the fire burns |
| We keep on walking down this street |
| Moving to the same steady beat |
| |
| [Outro] |
| Just another day |
| Every single day""" |
|
|
| EXAMPLE_TAGS = "piano,happy,uplifting,pop" |
|
|
| |
| with gr.Blocks( |
| title="HeartMuLa Music Generator", |
| ) as demo: |
| gr.Markdown( |
| """ |
| # HeartMuLa Music Generator |
| |
| Generate music from lyrics and tags using [HeartMuLa](https://github.com/HeartMuLa/heartlib), |
| an open-source music foundation model. |
| |
| **Instructions:** |
| 1. Enter your lyrics with structure tags like `[Verse]`, `[Chorus]`, `[Bridge]`, etc. |
| 2. Add comma-separated tags describing the music style (e.g., `piano,happy,romantic`) |
| 3. Adjust generation parameters as needed |
| 4. Click "Generate Music" and wait for your song! |
| |
| *Note: Generation can take several minutes depending on the duration.* |
| """ |
| ) |
|
|
| with gr.Row(): |
| with gr.Column(scale=1): |
| lyrics_input = gr.Textbox( |
| label="Lyrics", |
| placeholder="Enter lyrics with structure tags like [Verse], [Chorus], etc.", |
| lines=20, |
| value=EXAMPLE_LYRICS, |
| ) |
|
|
| tags_input = gr.Textbox( |
| label="Tags", |
| placeholder="piano,happy,romantic,synthesizer", |
| value=EXAMPLE_TAGS, |
| info="Comma-separated tags describing the music style", |
| ) |
|
|
| with gr.Accordion("Advanced Settings", open=False): |
| max_duration = gr.Slider( |
| minimum=30, |
| maximum=240, |
| value=120, |
| step=10, |
| label="Max Duration (seconds)", |
| info="Maximum length of generated audio", |
| ) |
|
|
| temperature = gr.Slider( |
| minimum=0.1, |
| maximum=2.0, |
| value=1.0, |
| step=0.1, |
| label="Temperature", |
| info="Higher = more creative, Lower = more consistent", |
| ) |
|
|
| topk = gr.Slider( |
| minimum=1, |
| maximum=100, |
| value=50, |
| step=1, |
| label="Top-K", |
| info="Number of top tokens to sample from", |
| ) |
|
|
| cfg_scale = gr.Slider( |
| minimum=1.0, |
| maximum=3.0, |
| value=1.5, |
| step=0.1, |
| label="CFG Scale", |
| info="Classifier-free guidance scale", |
| ) |
|
|
| generate_btn = gr.Button("Generate Music", variant="primary", size="lg") |
|
|
| with gr.Column(scale=1): |
| audio_output = gr.Audio( |
| label="Generated Music", |
| type="filepath", |
| ) |
|
|
| gr.Markdown( |
| """ |
| ### Tips for Better Results |
| - Use structured lyrics with section tags |
| - Be specific with your style tags |
| - Try different temperature values for variety |
| - Shorter durations generate faster |
| |
| ### Example Tags |
| - **Instruments:** piano, guitar, drums, synthesizer, violin, bass |
| - **Mood:** happy, sad, romantic, energetic, calm, melancholic |
| - **Genre:** pop, rock, jazz, classical, electronic, folk |
| - **Tempo:** fast, slow, upbeat, relaxed |
| """ |
| ) |
|
|
| generate_btn.click( |
| fn=generate_music, |
| inputs=[ |
| lyrics_input, |
| tags_input, |
| max_duration, |
| temperature, |
| topk, |
| cfg_scale, |
| ], |
| outputs=audio_output, |
| ) |
|
|
| gr.Markdown( |
| """ |
| --- |
| **Model:** [HeartMuLa-oss-3B](https://huggingface.co/HeartMuLa/HeartMuLa-oss-3B) | |
| **Paper:** [arXiv](https://arxiv.org/abs/2601.10547) | |
| **Code:** [GitHub](https://github.com/HeartMuLa/heartlib) |
| |
| *Licensed under Apache 2.0* |
| """ |
| ) |
|
|
|
|
|
|
| demo.launch() |
|
|