ghostai1 commited on
Commit
943d8ef
Β·
verified Β·
1 Parent(s): 4aa123e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +88 -96
app.py CHANGED
@@ -1,29 +1,28 @@
1
  #!/usr/bin/env python3
2
  """
3
- GhostAI Music Generator – ZeroGPU Edition
4
- β€’ Streams facebook/musicgen-medium from the Hub using your HF_TOKEN
5
- β€’ Runs on a transient GPU provided by the ZeroGPU scheduler
6
- β€’ Keeps your genre prompt builders, EQ / fade FX, neon Gradio UI
7
  """
8
 
9
- # ── ZeroGPU decorator must be imported *before* torch/CUDA ──────────
10
- import spaces # πŸ‘ˆ FIRST import
11
 
12
- # ── Standard libs ───────────────────────────────────────────────────
13
- import os, sys, gc, time, random, warnings, tempfile
14
  import numpy as np, psutil
15
 
16
- # ── Torch (CPU wheels; ZeroGPU moves tensors to the temp GPU) ───────
17
  import torch, torchaudio
18
 
19
- # ── Other deps ──────────────────────────────────────────────────────
20
  import gradio as gr
21
  from pydub import AudioSegment
22
- from audiocraft.models import MusicGen
23
  from huggingface_hub import login
24
  from torch.cuda.amp import autocast
25
 
26
- # ── Torch <2.3 shim (transformers 4.35 calls get_default_device) ───
27
  if not hasattr(torch, "get_default_device"):
28
  torch.get_default_device = lambda: torch.device(
29
  "cuda" if torch.cuda.is_available() else "cpu"
@@ -32,130 +31,125 @@ if not hasattr(torch, "get_default_device"):
32
  warnings.filterwarnings("ignore")
33
  os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "max_split_size_mb:128"
34
 
35
- # ────────────────────────── HF authentication ──────────────────────
 
 
 
 
 
 
 
 
 
36
  HF_TOKEN = os.getenv("HF_TOKEN")
37
  if not HF_TOKEN:
38
- sys.exit("ERROR: add HF_TOKEN as a secret in your Space settings.")
39
  login(HF_TOKEN)
40
 
41
- print("πŸ”„ Loading facebook/musicgen-medium (first build β‰ˆ 6 GB)…")
 
42
  musicgen = MusicGen.get_pretrained("facebook/musicgen-medium")
43
- musicgen.to(torch.get_default_device()) # move entire model
44
  musicgen.set_generation_params(duration=10, two_step_cfg=False)
45
  SR = musicgen.sample_rate
46
 
47
- # ────────────────────────── Prompt helpers ─────────────────────────
48
  def _p(base,bpm,dr,syn,st,bass,gtr,db,dg,flow):
49
- step = f" with {st}" if st!="none" else flow.format(bpm=bpm)
50
- return (f"{base}"
51
- f"{', '+bass if bass!='none' else db}"
52
- f"{', '+gtr+' guitar riffs' if gtr!='none' else dg}"
53
- f"{', '+dr+' drums' if dr!='none' else ''}"
54
- f"{', '+syn+' accents' if syn!='none' else ''}"
55
- f"{step} at {bpm} BPM.")
56
-
57
- def set_red_hot_chili_peppers_prompt(bpm,dr,syn,st,bass,gtr):
58
  return _p("Instrumental funk rock",bpm,dr,syn,st,bass,gtr,
59
  ", groovy basslines",", syncopated guitar riffs",
60
  "{bpm} BPM funky flow" if bpm>120 else "groovy rhythmic flow")
61
- def set_nirvana_grunge_prompt(bpm,dr,syn,st,bass,gtr):
 
62
  return _p("Instrumental grunge",bpm,dr,syn,st,bass,gtr,
63
  ", melodic basslines",", raw distorted guitar riffs",
64
  "{bpm} BPM grungy pulse" if bpm>120 else "grungy rhythmic pulse")
65
- # πŸ‘‰ add your other genre prompt functions here exactly as before …
66
 
67
- # ────────────────────────── Audio FX helpers ───────────────────────
68
- def apply_eq(s): return s.low_pass_filter(8000).high_pass_filter(80)
69
- def apply_fade(s): return s.fade_in(1000).fade_out(1000)
 
 
70
 
71
  def log(stage=""):
72
  if stage: print(f"── {stage} ──")
73
  if torch.cuda.is_available():
74
  a = torch.cuda.memory_allocated()/1024**3
75
  r = torch.cuda.memory_reserved()/1024**3
76
- print(f"GPU mem alloc {a:.2f} GB reserved {r:.2f} GB")
77
- print(f"CPU mem {psutil.virtual_memory().percent}% used")
78
-
79
- # ──────────────────────── Core generator API ───────────────────────
80
- @spaces.GPU # 🟒 ZeroGPU will allocate a GPU per call
81
- def generate_music(prompt,cfg,k,p,temp,
82
- total_len,chunk_len,xfade,
83
- bpm,dr,syn,step,bass,gtr):
84
-
85
  if not prompt.strip():
86
- return None, "⚠️ Prompt is empty."
87
-
88
- total_len = int(total_len)
89
- chunk_len = max(5, min(int(chunk_len), 15))
90
- n_chunks = max(1, total_len // chunk_len)
91
- chunk_len = total_len / n_chunks
92
- overlap = min(1.0, xfade / 1000.0)
93
- render_len = chunk_len + overlap
94
- pieces = []
95
-
96
  torch.manual_seed(42); np.random.seed(42)
97
- t0 = time.time()
98
 
99
  for i in range(n_chunks):
100
- log(f"before chunk {i+1}")
101
- musicgen.set_generation_params(
102
- duration=render_len, use_sampling=True,
103
- top_k=k, top_p=p, temperature=temp, cfg_coef=cfg
104
- )
105
  with torch.no_grad(), autocast():
106
  audio = musicgen.generate([prompt], progress=False)[0]
107
-
108
  audio = audio.cpu().float()
109
  if audio.dim()==1 or audio.shape[0]==1:
110
  audio = audio.repeat(2,1)
111
  with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp:
112
  torchaudio.save(tmp.name, audio, SR)
113
- seg = AudioSegment.from_wav(tmp.name)
114
  os.unlink(tmp.name)
115
- pieces.append(seg)
116
 
117
- torch.cuda.empty_cache(); gc.collect()
118
- log(f"after chunk {i+1}")
119
-
120
- track = pieces[0]
121
- for seg in pieces[1:]:
122
  track = track.append(seg, crossfade=xfade)
123
- track = track[: total_len*1000]
124
  track = apply_fade(apply_eq(track).normalize(headroom=-9.0))
125
 
126
- out_path = "output_cleaned.mp3"
127
- track.export(out_path, format="mp3", bitrate="128k",
128
  tags={"title":"GhostAI Track","artist":"GhostAI"})
129
- log("final"); print(f"⏱ {time.time()-t0:.1f}s total")
130
- return out_path, "βœ… Done!"
131
 
132
  def clear_inputs():
133
  return ("",3.0,250,0.9,1.0,30,10,1000,
134
  120,"none","none","none","none","none")
135
 
136
- # ────────────────────────── Gradio UI ──────────────────────────────
137
- css = "body{background:#0A0A0A;color:#E0E0E0;font-family:'Orbitron',sans-serif}"
138
-
139
- with gr.Blocks(css=css) as demo:
140
- gr.HTML("<h1 style='text-align:center'>πŸ‘» GhostAI Music Generator</h1>")
141
- prompt = gr.Textbox(lines=4, label="Instrumental Prompt")
142
  with gr.Row():
143
- gr.Button("RHCP 🌢️").click(set_red_hot_chili_peppers_prompt,
144
  inputs=[gr.State(120),"none","none","none","none","none"],
145
  outputs=prompt)
146
- gr.Button("Nirvana 🎸").click(set_nirvana_grunge_prompt,
147
  inputs=[gr.State(120),"none","none","none","none","none"],
148
  outputs=prompt)
149
- # πŸ“Œ add remaining genre buttons here …
150
-
151
- cfg = gr.Slider(1,10,3,label="CFG Scale")
152
- top_k = gr.Slider(10,500,250,step=10,label="Top-K")
153
- top_p = gr.Slider(0,1,0.9,step=0.05,label="Top-P")
154
- temp = gr.Slider(0.1,2,1,step=0.1,label="Temperature")
155
- length= gr.Radio([30,60,90,120], value=30, label="Length (s)")
156
- chunk = gr.Slider(5,15,10,step=1,label="Chunk (s)")
157
- xfade = gr.Slider(100,2000,1000,step=100,label="Cross-fade (ms)")
158
 
 
 
 
 
 
 
 
159
  bpm = gr.Slider(60,180,120,label="BPM")
160
  drum = gr.Dropdown(["none","standard rock","funk groove","techno kick","jazz swing"],"none","Drum")
161
  synth = gr.Dropdown(["none","analog synth","digital pad","arpeggiated synth"],"none","Synth")
@@ -165,15 +159,13 @@ with gr.Blocks(css=css) as demo:
165
 
166
  gen = gr.Button("Generate πŸš€")
167
  clr = gr.Button("Clear 🧹")
168
- audio_out = gr.Audio(type="filepath")
169
- status = gr.Textbox(interactive=False)
170
-
171
- gen.click(generate_music,
172
- inputs=[prompt,cfg,top_k,top_p,temp,length,chunk,xfade,
173
- bpm,drum,synth,steps,bass,gtr],
174
- outputs=[audio_out,status])
175
- clr.click(clear_inputs,None,
176
- [prompt,cfg,top_k,top_p,temp,length,chunk,xfade,
177
- bpm,drum,synth,steps,bass,gtr])
178
 
179
  demo.launch(share=False)
 
1
  #!/usr/bin/env python3
2
  """
3
+ GhostAI Music Generator β€” ZeroGPU Space
4
+ β€’ Pulls facebook/musicgen-medium from the Hub (needs HF_TOKEN)
5
+ β€’ Installs audiocraft==1.3.0 *at runtime* ( --no-deps ) to dodge spaCy/typer clash
6
+ β€’ Decorated with @spaces.GPU so each call gets a transient GPU
7
  """
8
 
9
+ # ── ZERO-GPU decorator must come BEFORE torch/CUDA ────────────────
10
+ import spaces # β‘  import first
11
 
12
+ # ── Standard libs ─────────────────────────────────────────────────
13
+ import os, sys, gc, time, warnings, tempfile, subprocess, random
14
  import numpy as np, psutil
15
 
16
+ # ── Torch (CPU wheels already in container; tensors move to GPU) ──
17
  import torch, torchaudio
18
 
19
+ # ── Other deps ────────────────────────────────────────────────────
20
  import gradio as gr
21
  from pydub import AudioSegment
 
22
  from huggingface_hub import login
23
  from torch.cuda.amp import autocast
24
 
25
+ # ── tiny shim for transformers on Torch <2.3 ──────────────────────
26
  if not hasattr(torch, "get_default_device"):
27
  torch.get_default_device = lambda: torch.device(
28
  "cuda" if torch.cuda.is_available() else "cpu"
 
31
  warnings.filterwarnings("ignore")
32
  os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "max_split_size_mb:128"
33
 
34
+ # ── 1. make sure audiocraft is present (no deps) ──────────────────
35
+ try:
36
+ from audiocraft.models import MusicGen
37
+ except ModuleNotFoundError:
38
+ print("πŸ”§ Installing audiocraft 1.3.0 (no-deps)…")
39
+ subprocess.check_call([sys.executable, "-m", "pip", "install",
40
+ "audiocraft==1.3.0", "--no-deps", "--quiet"])
41
+ from audiocraft.models import MusicGen
42
+
43
+ # ── 2. HF authentication ─────────────────────────────────────────
44
  HF_TOKEN = os.getenv("HF_TOKEN")
45
  if not HF_TOKEN:
46
+ sys.exit("ERROR: Please add HF_TOKEN secret in your Space.")
47
  login(HF_TOKEN)
48
 
49
+ # ── 3. load model from Hub ────────────────────────────────────────
50
+ print("⏬ Loading facebook/musicgen-medium (first run β‰ˆβ€†6 GB)…")
51
  musicgen = MusicGen.get_pretrained("facebook/musicgen-medium")
52
+ musicgen.to(torch.get_default_device())
53
  musicgen.set_generation_params(duration=10, two_step_cfg=False)
54
  SR = musicgen.sample_rate
55
 
56
+ # ── 4. prompt helpers (two shown; add the rest as before) ─────────
57
  def _p(base,bpm,dr,syn,st,bass,gtr,db,dg,flow):
58
+ stxt = f" with {st}" if st!="none" else flow.format(bpm=bpm)
59
+ return (f"{base}{db if bass=='none' else ', '+bass}"
60
+ f"{dg if gtr=='none' else ', '+gtr+' guitar riffs'}"
61
+ f"{'' if dr=='none' else ', '+dr+' drums'}"
62
+ f"{'' if syn=='none' else ', '+syn+' accents'}{stxt} at {bpm} BPM.")
63
+
64
+ def set_red_hot_chili(bpm,dr,syn,st,bass,gtr):
 
 
65
  return _p("Instrumental funk rock",bpm,dr,syn,st,bass,gtr,
66
  ", groovy basslines",", syncopated guitar riffs",
67
  "{bpm} BPM funky flow" if bpm>120 else "groovy rhythmic flow")
68
+
69
+ def set_nirvana_grunge(bpm,dr,syn,st,bass,gtr):
70
  return _p("Instrumental grunge",bpm,dr,syn,st,bass,gtr,
71
  ", melodic basslines",", raw distorted guitar riffs",
72
  "{bpm} BPM grungy pulse" if bpm>120 else "grungy rhythmic pulse")
 
73
 
74
+ # (… add your remaining genre prompt functions unchanged …)
75
+
76
+ # ── 5. audio FX helpers ───────────────────────────────────────────
77
+ def apply_eq(seg): return seg.low_pass_filter(8000).high_pass_filter(80)
78
+ def apply_fade(seg): return seg.fade_in(1000).fade_out(1000)
79
 
80
  def log(stage=""):
81
  if stage: print(f"── {stage} ──")
82
  if torch.cuda.is_available():
83
  a = torch.cuda.memory_allocated()/1024**3
84
  r = torch.cuda.memory_reserved()/1024**3
85
+ print(f"GPU alloc {a:.2f} GB reserved {r:.2f} GB")
86
+ print(f"CPU {psutil.virtual_memory().percent}%")
87
+
88
+ # ── 6. main generation API (ZeroGPU wrapper) ───────────────────────
89
+ @spaces.GPU
90
+ def generate(prompt,cfg,k,p,temp,
91
+ total_len,chunk_len,xfade,
92
+ bpm,dr,syn,step,bass,gtr):
 
93
  if not prompt.strip():
94
+ return None, "⚠️ Empty prompt."
95
+
96
+ total_len, chunk_len = int(total_len), max(5, min(int(chunk_len), 15))
97
+ n_chunks = max(1, total_len // chunk_len)
98
+ chunk_len = total_len / n_chunks
99
+ overlap = min(1.0, xfade / 1000.0)
100
+ render = chunk_len + overlap
101
+ parts = []
 
 
102
  torch.manual_seed(42); np.random.seed(42)
 
103
 
104
  for i in range(n_chunks):
105
+ log(f"chunk {i+1} start")
106
+ musicgen.set_generation_params(duration=render,use_sampling=True,
107
+ top_k=k,top_p=p,temperature=temp,cfg_coef=cfg)
 
 
108
  with torch.no_grad(), autocast():
109
  audio = musicgen.generate([prompt], progress=False)[0]
 
110
  audio = audio.cpu().float()
111
  if audio.dim()==1 or audio.shape[0]==1:
112
  audio = audio.repeat(2,1)
113
  with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp:
114
  torchaudio.save(tmp.name, audio, SR)
115
+ parts.append(AudioSegment.from_wav(tmp.name))
116
  os.unlink(tmp.name)
117
+ torch.cuda.empty_cache(); gc.collect(); log(f"chunk {i+1} done")
118
 
119
+ track = parts[0]
120
+ for seg in parts[1:]:
 
 
 
121
  track = track.append(seg, crossfade=xfade)
122
+ track = track[:total_len*1000]
123
  track = apply_fade(apply_eq(track).normalize(headroom=-9.0))
124
 
125
+ out_f = "output_cleaned.mp3"
126
+ track.export(out_f, format="mp3", bitrate="128k",
127
  tags={"title":"GhostAI Track","artist":"GhostAI"})
128
+ return out_f, "βœ… Done!"
 
129
 
130
  def clear_inputs():
131
  return ("",3.0,250,0.9,1.0,30,10,1000,
132
  120,"none","none","none","none","none")
133
 
134
+ # ── 7. minimal Gradio 4 UI (add more buttons if needed) ───────────
135
+ with gr.Blocks(css="body{background:#0A0A0A;color:#E0E0E0;font-family:'Orbitron',sans-serif}") as demo:
136
+ gr.HTML("<h1 style='text-align:center'>πŸ‘» GhostAI MusicGen</h1>")
137
+ prompt = gr.Textbox(lines=4, label="Prompt")
 
 
138
  with gr.Row():
139
+ gr.Button("RHCP 🌢️").click(set_red_hot_chili,
140
  inputs=[gr.State(120),"none","none","none","none","none"],
141
  outputs=prompt)
142
+ gr.Button("Nirvana 🎸").click(set_nirvana_grunge,
143
  inputs=[gr.State(120),"none","none","none","none","none"],
144
  outputs=prompt)
 
 
 
 
 
 
 
 
 
145
 
146
+ cfg = gr.Slider(1,10,3,label="CFG")
147
+ k = gr.Slider(10,500,250,step=10,label="Top-K")
148
+ p = gr.Slider(0,1,0.9,step=0.05,label="Top-P")
149
+ temp = gr.Slider(0.1,2,1,label="Temp")
150
+ length= gr.Radio([30,60,90,120],value=30,label="Length")
151
+ chunk = gr.Slider(5,15,10,label="Chunk")
152
+ xfade = gr.Slider(100,2000,1000,label="Cross-fade")
153
  bpm = gr.Slider(60,180,120,label="BPM")
154
  drum = gr.Dropdown(["none","standard rock","funk groove","techno kick","jazz swing"],"none","Drum")
155
  synth = gr.Dropdown(["none","analog synth","digital pad","arpeggiated synth"],"none","Synth")
 
159
 
160
  gen = gr.Button("Generate πŸš€")
161
  clr = gr.Button("Clear 🧹")
162
+ out = gr.Audio(type="filepath")
163
+ status = gr.Textbox(interactive=False)
164
+
165
+ gen.click(generate,
166
+ [prompt,cfg,k,p,temp,length,chunk,xfade,bpm,drum,synth,steps,bass,gtr],
167
+ [out,status])
168
+ clr.click(clear_inputs, None,
169
+ [prompt,cfg,k,p,temp,length,chunk,xfade,bpm,drum,synth,steps,bass,gtr])
 
 
170
 
171
  demo.launch(share=False)