Spaces:
Paused
Paused
File size: 7,318 Bytes
b7661f0 3959a20 b7661f0 3959a20 aa4ca52 b7661f0 aa4ca52 b7661f0 f882299 bf455aa aa4ca52 bf455aa b7661f0 3959a20 f85bfad b7661f0 f85bfad b7661f0 aa4ca52 b7661f0 3959a20 b7661f0 3959a20 ee2ba54 3959a20 aa4ca52 3959a20 aa4ca52 f882299 3959a20 aa4ca52 3959a20 f882299 3959a20 f882299 3959a20 aa4ca52 3959a20 b7661f0 d6ab544 b7661f0 3959a20 b7661f0 3959a20 b7661f0 3959a20 ee2ba54 3959a20 aa4ca52 686a26c aa4ca52 3959a20 aa4ca52 686a26c 3959a20 aa4ca52 b7661f0 d6ab544 bf455aa 54b3296 aa4ca52 a3ffcd6 aa4ca52 9146b4b b7661f0 aa4ca52 7875fb9 aa4ca52 ee2ba54 aa4ca52 d6ab544 aa4ca52 cc0498a f882299 eb50e6c 4ee0f46 bbc5c51 | 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 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | import json
import os
import random
import secrets
import subprocess
from datetime import datetime, timezone
import gradio as gr
import spaces
import torch
COMMUNITY_BUCKET = "directedbykobyperez/YuE2-community"
COMMUNITY_URL = "https://huggingface.co/buckets/directedbykobyperez/YuE2-community"
REPO = "m-a-p/YuE2-3B"
OUT = "/tmp/yue2_out"
os.makedirs(OUT, exist_ok=True)
pipe = None
def _ensure_yue2():
"""Install the vendored yue2-infer wheel at runtime (not build time).
It can't go in requirements.txt: it pins huggingface-hub==0.36.2 /
transformers==4.57.6 which conflict with Gradio 6 (hub>=1.16) and break
the Docker build. --no-deps sidesteps the pins; the package only needs
torch/transformers/hub/safetensors/tiktoken/soundfile which are present.
"""
try:
import yue2 # noqa: F401
return
except ImportError:
pass
import sys
whl = os.path.join(os.path.dirname(os.path.abspath(__file__)), "yue2_infer-0.1.5-py3-none-any.whl")
print(f"[yue2] installing vendored wheel: {whl}")
subprocess.run(
[sys.executable, "-m", "pip", "install", "--no-deps", whl],
check=True, capture_output=True, text=True,
)
print("[yue2] installed.")
def get_pipeline():
global pipe
if pipe is None:
_ensure_yue2()
from yue2 import YuE2Pipeline
print("Loading YuE2-3B pipeline (first run downloads weights)...")
pipe = YuE2Pipeline.from_pretrained(REPO, device="cuda" if torch.cuda.is_available() else "cpu")
print("Pipeline loaded.")
return pipe
def flac_to_mp3(flac_path, mp3_path, bitrate="320k"):
subprocess.run(
["ffmpeg", "-y", "-i", flac_path, "-b:a", bitrate, mp3_path],
capture_output=True, check=True,
)
return mp3_path
def flac_to_wav(flac_path, wav_path):
subprocess.run(
["ffmpeg", "-y", "-i", flac_path, "-c:a", "pcm_s16le", wav_path],
capture_output=True, check=True,
)
return wav_path
def flac_to_ogg(flac_path, ogg_path, bitrate="192k"):
subprocess.run(
["ffmpeg", "-y", "-i", flac_path, "-c:a", "libopus", "-b:a", bitrate, ogg_path],
capture_output=True, check=True,
)
return ogg_path
def get_duration_seconds(audio_path):
try:
import soundfile as sf
return float(sf.info(audio_path).duration)
except Exception:
pass
try:
r = subprocess.run(
["ffprobe", "-v", "error", "-show_entries", "format=duration",
"-of", "default=noprint_wrappers=1:nokey=1", audio_path],
capture_output=True, text=True, check=True,
)
return float(r.stdout.strip())
except Exception:
return 0.0
def _upload_to_community(wav_path, meta_dict, song_id):
"""Silently share songs/<id>/<id>.wav + meta.json to the community bucket. Never raises."""
token = os.environ.get("HF_TOKEN") or os.environ.get("HUGGINGFACE_TOKEN")
if not token:
return
try:
from huggingface_hub import HfFileSystem
fs = HfFileSystem(token=token)
meta_local = os.path.join(OUT, f"{song_id}_meta.json")
with open(meta_local, "w", encoding="utf-8") as f:
json.dump(meta_dict, f, ensure_ascii=False, indent=2)
base = f"buckets/{COMMUNITY_BUCKET}/songs/{song_id}"
fs.put_file(wav_path, f"{base}/{song_id}.wav")
fs.put_file(meta_local, f"{base}/meta.json")
print(f"[community] uploaded {song_id} to bucket")
except Exception as e:
print(f"[community] upload failed: {e}")
@spaces.GPU(duration=120)
def generate(style, lyrics, cot, seed, cfg_scale):
pipeline = get_pipeline()
if seed is None or seed < 1:
try:
seed = int(seed) if seed else random.randint(1, 10**6)
except Exception:
seed = random.randint(1, 10**6)
seed = int(seed)
gen_kwargs = dict(style=style, lyrics=lyrics, cot=cot, seed=seed)
if cfg_scale and float(cfg_scale) != 1.0:
gen_kwargs["cfg_scale"] = float(cfg_scale)
song = pipeline(**gen_kwargs)
song_id = secrets.token_hex(6)
flac_path = os.path.join(OUT, f"song_{song_id}.flac")
mp3_path = os.path.join(OUT, f"song_{song_id}.mp3")
wav_path = os.path.join(OUT, f"{song_id}.wav")
song.save(flac_path)
flac_to_mp3(flac_path, mp3_path)
flac_to_wav(flac_path, wav_path)
ogg_path = os.path.join(OUT, f"{song_id}.ogg")
try:
flac_to_ogg(flac_path, ogg_path)
except Exception as e:
print(f"[ogg] skipped: {e}")
ogg_path = None
words = (style or "").strip().replace("\n", " ").split()[:8]
title = " ".join(words).title()[:80] if words else f"YuE2 Song {song_id[:6]}"
actual = get_duration_seconds(wav_path)
_upload_to_community(wav_path, {
"id": song_id,
"title": title,
"description": (style or "").strip(),
"lyrics": lyrics or "",
"caption": (style or "").strip(),
"bpm": 120,
"language": "",
"duration": actual,
"seed": seed,
"generation_mode": cot or "auto",
"audio_file": f"{song_id}.wav",
"created_at": datetime.now(timezone.utc).isoformat(),
}, song_id)
return flac_path, flac_path, mp3_path, ogg_path, f"seed={seed} | {actual:.0f}s | {os.path.getsize(mp3_path) // 1024}KB MP3 320kbps"
with gr.Blocks(title="YuE2-3B Music") as demo:
gr.Markdown("# YuE2-3B Music Generator\nFull song (vocals + accompaniment) from a style prompt and lyrics.")
with gr.Row():
with gr.Column():
style = gr.Textbox(label="Style prompt", value="Cyber metal, English, aggressive male vocals, distorted guitars, double-kick drums", lines=3)
lyrics = gr.Textbox(label="Lyrics ([verse]/[chorus] etc.)", value="[verse]\nnothing here but static skies\nwe ride the current till it dies", lines=8)
with gr.Row():
cot = gr.Radio(["full", "melody", "off"], value="full", label="CoT mode")
seed = gr.Number(label="Seed", value=0, precision=0)
cfg = gr.Number(label="CFG scale (1.0 = default)", value=1.0, precision=2)
btn = gr.Button("Generate song", variant="primary")
gr.HTML("<div style='text-align:center;margin:-12px 0 -8px;font-size:0.9rem;'>Don't forget to<a style='margin-left:5px;padding:0;' href='https://huggingface.co/m-a-p/YuE2-3B' target='_blank'>like the model ❤️</a></div>")
with gr.Column():
audio = gr.Audio(label="Play song", type="filepath")
flac_file = gr.File(label="Download FLAC")
mp3_file = gr.File(label="Download MP3 320kbps")
ogg_file = gr.File(label="Download OGG (Opus)")
info = gr.Textbox(label="Info")
btn.click(fn=generate, inputs=[style, lyrics, cot, seed, cfg], outputs=[audio, flac_file, mp3_file, ogg_file, info], queue=True)
gr.Markdown(
"---\nPowered by [YuE2](https://huggingface.co/m-a-p/YuE2-3B) · "
"🎶 **Community songs:** every generation is auto-shared to the "
"[YuE2-community bucket](https://huggingface.co/buckets/directedbykobyperez/YuE2-community)"
" · [YuE2 website](https://map-yue2.github.io/)"
)
demo.queue().launch(footer_links=[], favicon_path="favicon.png")
|