File size: 8,096 Bytes
fdc5f70
545f8e1
943d8ef
 
 
 
545f8e1
 
943d8ef
 
545f8e1
943d8ef
 
545f8e1
 
943d8ef
545f8e1
 
943d8ef
545f8e1
87e4401
857db5b
545f8e1
87e4401
943d8ef
80cc045
 
 
 
 
87e4401
80cc045
87e4401
943d8ef
 
 
 
 
 
 
 
 
 
779076d
 
943d8ef
e05183d
857db5b
943d8ef
 
545f8e1
943d8ef
545f8e1
52fbb1b
545f8e1
943d8ef
52fbb1b
943d8ef
 
 
 
 
 
 
80cc045
 
 
943d8ef
 
545f8e1
 
 
 
943d8ef
 
 
 
 
545f8e1
 
 
 
52fbb1b
 
943d8ef
 
 
 
 
 
 
 
2c690c6
943d8ef
 
 
 
 
 
 
 
545f8e1
52fbb1b
80cc045
943d8ef
 
 
80cc045
545f8e1
80cc045
52fbb1b
 
c3aa73a
52fbb1b
943d8ef
2c690c6
943d8ef
52fbb1b
943d8ef
 
80cc045
943d8ef
80cc045
c3aa73a
943d8ef
 
80cc045
943d8ef
fdc5f70
80cc045
 
 
 
943d8ef
 
 
 
80cc045
943d8ef
80cc045
545f8e1
943d8ef
80cc045
545f8e1
 
943d8ef
 
 
 
 
 
 
545f8e1
 
 
 
 
 
 
52fbb1b
80cc045
943d8ef
 
 
 
 
 
 
 
e05183d
 
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
#!/usr/bin/env python3
"""
GhostAI Music Generator β€” ZeroGPU Space
β€’ Pulls facebook/musicgen-medium from the Hub (needs HF_TOKEN)
β€’ Installs audiocraft==1.3.0 *at runtime* ( --no-deps ) to dodge spaCy/typer clash
β€’ Decorated with @spaces.GPU so each call gets a transient GPU
"""

# ── ZERO-GPU decorator must come BEFORE torch/CUDA ────────────────
import spaces                  # β‘  import first

# ── Standard libs ─────────────────────────────────────────────────
import os, sys, gc, time, warnings, tempfile, subprocess, random
import numpy as np, psutil

# ── Torch (CPU wheels already in container; tensors move to GPU) ──
import torch, torchaudio

# ── Other deps ────────────────────────────────────────────────────
import gradio as gr
from pydub import AudioSegment
from huggingface_hub import login
from torch.cuda.amp import autocast

# ── tiny shim for transformers on Torch <2.3 ──────────────────────
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"

# ── 1. make sure audiocraft is present (no deps) ──────────────────
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", "--quiet"])
    from audiocraft.models import MusicGen

# ── 2. HF authentication ─────────────────────────────────────────
HF_TOKEN = os.getenv("HF_TOKEN")
if not HF_TOKEN:
    sys.exit("ERROR: Please add HF_TOKEN secret in your Space.")
login(HF_TOKEN)

# ── 3. load model from Hub ────────────────────────────────────────
print("⏬  Loading facebook/musicgen-medium (first run β‰ˆβ€†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

# ── 4. prompt helpers (two shown; add the rest as before) ─────────
def _p(base,bpm,dr,syn,st,bass,gtr,db,dg,flow):
    stxt = f" with {st}" if st!="none" else flow.format(bpm=bpm)
    return (f"{base}{db if bass=='none' else ', '+bass}"
            f"{dg if gtr=='none' else ', '+gtr+' guitar riffs'}"
            f"{'' if dr=='none' else ', '+dr+' drums'}"
            f"{'' if syn=='none' else ', '+syn+' accents'}{stxt} at {bpm} BPM.")

def set_red_hot_chili(bpm,dr,syn,st,bass,gtr):
    return _p("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_grunge(bpm,dr,syn,st,bass,gtr):
    return _p("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 your remaining genre prompt functions unchanged …)

# ── 5. audio 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}%")

# ── 6. main generation API (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, chunk_len = int(total_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
    parts     = []
    torch.manual_seed(42); np.random.seed(42)

    for i in range(n_chunks):
        log(f"chunk {i+1} start")
        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)
            parts.append(AudioSegment.from_wav(tmp.name))
        os.unlink(tmp.name)
        torch.cuda.empty_cache(); gc.collect(); log(f"chunk {i+1} done")

    track = parts[0]
    for seg in parts[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")

# ── 7. minimal Gradio 4 UI (add more buttons if needed) ───────────
with gr.Blocks(css="body{background:#0A0A0A;color:#E0E0E0;font-family:'Orbitron',sans-serif}") as demo:
    gr.HTML("<h1 style='text-align:center'>πŸ‘» GhostAI MusicGen</h1>")
    prompt = gr.Textbox(lines=4, label="Prompt")
    with gr.Row():
        gr.Button("RHCP 🌢️").click(set_red_hot_chili,
            inputs=[gr.State(120),"none","none","none","none","none"],
            outputs=prompt)
        gr.Button("Nirvana 🎸").click(set_nirvana_grunge,
            inputs=[gr.State(120),"none","none","none","none","none"],
            outputs=prompt)

    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")
    chunk = gr.Slider(5,15,10,label="Chunk")
    xfade = gr.Slider(100,2000,1000,label="Cross-fade")
    bpm   = gr.Slider(60,180,120,label="BPM")
    drum  = gr.Dropdown(["none","standard rock","funk groove","techno kick","jazz swing"],"none","Drum")
    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 🧹")
    out = 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],
              [out,status])
    clr.click(clear_inputs, None,
              [prompt,cfg,k,p,temp,length,chunk,xfade,bpm,drum,synth,steps,bass,gtr])

demo.launch(share=False)