# ── 0. ZeroGPU decorator (must be first) ─────────────────────────── import spaces # <-- leave this as the very first import # ── 1. Standard libs ─────────────────────────────────────────────── import os, sys, gc, time, warnings, tempfile, subprocess, random import numpy as np, psutil # ── 2. Torch stack (torch 2.1.0 / torchaudio 2.1.0 from requirements) ─ import torch, torchaudio # ── 3. Misc deps ────────────────────────────────────────────────── import gradio as gr from pydub import AudioSegment from huggingface_hub import login from torch.cuda.amp import autocast # ── 4. Torch <2.3 shim (transformers 4.38 expects it) ───────────── if not hasattr(torch, "get_default_device"): torch.get_default_device = lambda: torch.device( "cuda" if torch.cuda.is_available() else "cpu" ) warnings.filterwarnings("ignore") os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "max_split_size_mb:128" # ── 5. Install audiocraft 1.3.0 (no deps) at runtime ────────────── try: from audiocraft.models import MusicGen except ModuleNotFoundError: print("🔧 Installing audiocraft 1.3.0 (no-deps)…") subprocess.check_call( [sys.executable, "-m", "pip", "install", "audiocraft==1.3.0", "--no-deps", "-q"] ) from audiocraft.models import MusicGen # ── 6. Hugging Face authentication ──────────────────────────────── HF_TOKEN = os.getenv("HF_TOKEN") if not HF_TOKEN: sys.exit("ERROR: Add HF_TOKEN as a secret in your Space settings.") login(HF_TOKEN) # ── 7. Load MusicGen model ──────────────────────────────────────── print("⏬ Loading facebook/musicgen-medium (first load ≈ 6 GB)…") musicgen = MusicGen.get_pretrained("facebook/musicgen-medium") musicgen.to(torch.get_default_device()) musicgen.set_generation_params(duration=10, two_step_cfg=False) SR = musicgen.sample_rate # ── 8. Prompt builders (add more as needed) ─────────────────────── def _build(base,bpm,dr,syn,st,bass,gtr,def_bass,def_gtr,flow): step = f" with {st}" if st!="none" else flow.format(bpm=bpm) return (f"{base}" f"{def_bass if bass=='none' else ', '+bass}" f"{def_gtr if gtr=='none' else ', '+gtr+' guitar riffs'}" f"{'' if dr=='none' else ', '+dr+' drums'}" f"{'' if syn=='none' else ', '+syn+' accents'}" f"{step} at {bpm} BPM.") def set_rhcp(bpm,dr,syn,st,bass,gtr): return _build("Instrumental funk rock",bpm,dr,syn,st,bass,gtr, ", groovy basslines",", syncopated guitar riffs", "{bpm} BPM funky flow" if bpm>120 else "groovy rhythmic flow") def set_nirvana(bpm,dr,syn,st,bass,gtr): return _build("Instrumental grunge",bpm,dr,syn,st,bass,gtr, ", melodic basslines",", raw distorted guitar riffs", "{bpm} BPM grungy pulse" if bpm>120 else "grungy rhythmic pulse") # (➕ Add remaining genre prompt functions here the same way.) # ── 9. Audio post-FX helpers ────────────────────────────────────── def apply_eq(seg): return seg.low_pass_filter(8000).high_pass_filter(80) def apply_fade(seg): return seg.fade_in(1000).fade_out(1000) def log(stage=""): if stage: print(f"── {stage} ──") if torch.cuda.is_available(): a = torch.cuda.memory_allocated()/1024**3 r = torch.cuda.memory_reserved()/1024**3 print(f"GPU alloc {a:.2f} GB reserved {r:.2f} GB") print(f"CPU {psutil.virtual_memory().percent}%") # ── 10. Core generator (ZeroGPU wrapper) ────────────────────────── @spaces.GPU def generate(prompt,cfg,k,p,temp, total_len,chunk_len,xfade, bpm,dr,syn,step,bass,gtr): if not prompt.strip(): return None, "⚠️ Empty prompt." total_len = int(total_len) chunk_len = max(5, min(int(chunk_len), 15)) n_chunks = max(1, total_len // chunk_len) chunk_len = total_len / n_chunks overlap = min(1.0, xfade / 1000.0) render = chunk_len + overlap segments = [] torch.manual_seed(42); np.random.seed(42) for i in range(n_chunks): log(f"chunk {i+1}") musicgen.set_generation_params(duration=render,use_sampling=True, top_k=k,top_p=p,temperature=temp,cfg_coef=cfg) with torch.no_grad(), autocast(): audio = musicgen.generate([prompt], progress=False)[0] audio = audio.cpu().float() if audio.dim()==1 or audio.shape[0]==1: audio = audio.repeat(2,1) with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp: torchaudio.save(tmp.name, audio, SR) segments.append(AudioSegment.from_wav(tmp.name)) os.unlink(tmp.name) torch.cuda.empty_cache(); gc.collect() track = segments[0] for seg in segments[1:]: track = track.append(seg, crossfade=xfade) track = track[: total_len*1000] track = apply_fade(apply_eq(track).normalize(headroom=-9.0)) out_f = "output_cleaned.mp3" track.export(out_f, format="mp3", bitrate="128k", tags={"title":"GhostAI Track","artist":"GhostAI"}) return out_f, "✅ Done!" def clear_inputs(): return ("",3.0,250,0.9,1.0,30,10,1000, 120,"none","none","none","none","none") # ── 11. Gradio UI ───────────────────────────────────────────────── with gr.Blocks(css="body{background:#0A0A0A;color:#E0E0E0;font-family:'Orbitron',sans-serif}") as demo: gr.Markdown("

👻 GhostAI MusicGen

") prompt = gr.Textbox(lines=4, label="Instrumental Prompt") with gr.Row(): gr.Button("RHCP 🌶️").click(set_rhcp, inputs=[gr.State(120),"none","none","none","none","none"], outputs=prompt) gr.Button("Nirvana 🎸").click(set_nirvana, inputs=[gr.State(120),"none","none","none","none","none"], outputs=prompt) # ➕ add more genre buttons … cfg = gr.Slider(1,10,3,label="CFG") k = gr.Slider(10,500,250,step=10,label="Top-K") p = gr.Slider(0,1,0.9,step=0.05,label="Top-P") temp = gr.Slider(0.1,2,1,label="Temp") length= gr.Radio([30,60,90,120],value=30,label="Length (s)") chunk = gr.Slider(5,15,10,label="Chunk (s)") xfade = gr.Slider(100,2000,1000,label="Cross-fade (ms)") bpm = gr.Slider(60,180,120,label="BPM") drum = gr.Dropdown(["none","standard rock","funk groove","techno kick","jazz swing"],"none","Drums") synth = gr.Dropdown(["none","analog synth","digital pad","arpeggiated synth"],"none","Synth") steps = gr.Dropdown(["none","syncopated steps","steady steps","complex steps"],"none","Steps") bass = gr.Dropdown(["none","slap bass","deep bass","melodic bass"],"none","Bass") gtr = gr.Dropdown(["none","distorted","clean","jangle"],"none","Guitar") gen = gr.Button("Generate 🚀") clr = gr.Button("Clear 🧹") audio = gr.Audio(type="filepath") status= gr.Textbox(interactive=False) gen.click(generate, [prompt,cfg,k,p,temp,length,chunk,xfade,bpm,drum,synth,steps,bass,gtr], [audio,status]) clr.click(clear_inputs, None, [prompt,cfg,k,p,temp,length,chunk,xfade,bpm,drum,synth,steps,bass,gtr]) demo.launch(share=False)