Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
@@ -1,596 +1,462 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
import os
|
2 |
-
import torch
|
3 |
-
import torchaudio
|
4 |
-
import psutil
|
5 |
-
import time
|
6 |
import sys
|
7 |
-
import numpy as np
|
8 |
import gc
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
import gradio as gr
|
10 |
from pydub import AudioSegment
|
11 |
-
from audiocraft.models import MusicGen
|
12 |
from torch.cuda.amp import autocast
|
13 |
-
import
|
14 |
-
import random
|
15 |
from huggingface_hub import login
|
16 |
-
import tempfile
|
17 |
|
18 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
warnings.filterwarnings("ignore")
|
20 |
-
|
21 |
-
# Set PYTORCH_CUDA_ALLOC_CONF to manage memory fragmentation
|
22 |
os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "max_split_size_mb:128"
|
23 |
|
24 |
-
#
|
|
|
|
|
25 |
hf_token = os.getenv("HF_TOKEN")
|
26 |
if not hf_token:
|
27 |
-
print("ERROR: HF_TOKEN environment variable not set. Please set it
|
28 |
sys.exit(1)
|
|
|
29 |
try:
|
30 |
login(hf_token)
|
31 |
except Exception as e:
|
32 |
print(f"ERROR: Failed to authenticate with Hugging Face: {e}")
|
33 |
sys.exit(1)
|
34 |
|
35 |
-
#
|
|
|
|
|
36 |
if np.__version__ != "1.23.5":
|
37 |
-
print(f"WARNING: NumPy version {np.__version__}
|
38 |
if not torch.__version__.startswith("2.3.1"):
|
39 |
-
print(f"WARNING: PyTorch version {torch.__version__}
|
40 |
|
41 |
-
#
|
42 |
-
|
|
|
|
|
43 |
print(f"PyTorch CUDA available: {torch.cuda.is_available()}")
|
44 |
if torch.cuda.is_available():
|
45 |
-
print(f"CUDA device count: {torch.cuda.device_count()}")
|
46 |
-
print(f"CUDA
|
47 |
-
print(f"CUDA
|
48 |
-
print(f"CUDA version: {torch.version.cuda}")
|
49 |
else:
|
50 |
-
print("
|
51 |
-
print(f"CUDA library loaded: {torch._C._cuda_getCompiledVersion() > 0}")
|
52 |
-
print("Please ensure the Hugging Face Space is configured to use a GPU runtime.")
|
53 |
-
print("Falling back to CPU rendering. Note: Performance may be significantly slower.")
|
54 |
|
55 |
device = "cuda" if torch.cuda.is_available() else "cpu"
|
56 |
-
if device != "cuda":
|
57 |
-
print("WARNING: Running on CPU. This is a fallback due to CUDA unavailability. GPU rendering is strongly recommended for performance.")
|
58 |
|
59 |
-
# Pre-run memory cleanup
|
60 |
if device == "cuda":
|
61 |
torch.cuda.empty_cache()
|
62 |
gc.collect()
|
63 |
torch.cuda.ipc_collect()
|
64 |
torch.cuda.synchronize()
|
65 |
|
66 |
-
#
|
|
|
|
|
67 |
try:
|
68 |
-
print("Loading MusicGen medium model
|
69 |
musicgen_model = MusicGen.get_pretrained("facebook/musicgen-medium", device=device)
|
70 |
-
musicgen_model.set_generation_params(
|
71 |
-
duration=10, # Default chunk duration
|
72 |
-
two_step_cfg=False # Disable two-step CFG for stability
|
73 |
-
)
|
74 |
except Exception as e:
|
75 |
print(f"ERROR: Failed to load MusicGen model: {e}")
|
76 |
-
print("
|
77 |
sys.exit(1)
|
78 |
|
79 |
-
#
|
|
|
|
|
80 |
def print_resource_usage(stage: str):
|
81 |
print(f"--- {stage} ---")
|
82 |
if device == "cuda":
|
83 |
print(f"GPU Memory Allocated: {torch.cuda.memory_allocated() / (1024**3):.2f} GB")
|
84 |
-
print(f"GPU Memory Reserved: {torch.cuda.memory_reserved()
|
85 |
-
print(f"CPU Memory Used: {psutil.virtual_memory().percent}%")
|
86 |
-
print("
|
87 |
|
88 |
-
|
89 |
-
def check_vram_availability(required_gb=3.5):
|
90 |
if device != "cuda":
|
91 |
-
print("Skipping VRAM check as running on CPU.")
|
92 |
return True
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
if
|
97 |
-
print(f"WARNING:
|
98 |
-
return
|
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 |
styles = ["anthemic", "gritty", "melodic", "fast-paced", "driving"]
|
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 |
-
guitar = f", {guitar_style} guitars" if guitar_style != "none" else ", jangly guitars"
|
193 |
-
return f"Instrumental indie rock{bass}{guitar}{drum}{synth}, Arctic Monkeys-inspired blend of catchy riffs, {rhythm} at {bpm} BPM."
|
194 |
-
|
195 |
-
def set_funk_rock_prompt(bpm, drum_beat, synthesizer, rhythmic_steps, bass_style, guitar_style):
|
196 |
-
rhythm = f" with {rhythmic_steps}" if rhythmic_steps != "none" else ("aggressive rhythmic steps" if bpm > 120 else "funky rhythmic groove")
|
197 |
-
drum = f", {drum_beat} drums" if drum_beat != "none" else ""
|
198 |
-
synth = f", {synthesizer} accents" if synthesizer != "none" else ""
|
199 |
-
bass = f", {bass_style}" if bass_style != "none" else ", slap bass"
|
200 |
-
guitar = f", {guitar_style} guitar chords" if guitar_style != "none" else ", funky guitar chords"
|
201 |
-
return f"Instrumental funk rock{bass}{guitar}{drum}{synth}, Rage Against the Machine-inspired mix of groove and aggression, {rhythm} at {bpm} BPM."
|
202 |
-
|
203 |
-
def set_detroit_techno_prompt(bpm, drum_beat, synthesizer, rhythmic_steps, bass_style, guitar_style):
|
204 |
-
rhythm = f" with {rhythmic_steps}" if rhythmic_steps != "none" else ("pulsing rhythmic steps" if bpm > 120 else "deep rhythmic groove")
|
205 |
-
drum = f", {drum_beat} drums" if drum_beat != "none" else ", crisp hi-hats"
|
206 |
-
synth = f", {synthesizer} accents" if synthesizer != "none" else ", deep pulsing synths"
|
207 |
-
bass = f", {bass_style}" if bass_style != "none" else ", driving basslines"
|
208 |
-
guitar = f", {guitar_style} guitars" if guitar_style != "none" else ""
|
209 |
-
return f"Instrumental Detroit techno{bass}{guitar}{drum}{synth}, Juan Atkins-inspired rhythmic groove, {rhythm} at {bpm} BPM."
|
210 |
-
|
211 |
-
def set_deep_house_prompt(bpm, drum_beat, synthesizer, rhythmic_steps, bass_style, guitar_style):
|
212 |
-
rhythm = f" with {rhythmic_steps}" if rhythmic_steps != "none" else ("soulful rhythmic steps" if bpm > 120 else "laid-back rhythmic flow")
|
213 |
-
drum = f", {drum_beat} drums" if drum_beat != "none" else ""
|
214 |
-
synth = f", {synthesizer} accents" if synthesizer != "none" else ", warm analog synth chords"
|
215 |
-
bass = f", {bass_style}" if bass_style != "none" else ", deep basslines"
|
216 |
-
guitar = f", {guitar_style} guitars" if guitar_style != "none" else ""
|
217 |
-
return f"Instrumental deep house{bass}{guitar}{drum}{synth}, Larry Heard-inspired laid-back groove, {rhythm} at {bpm} BPM."
|
218 |
-
|
219 |
-
# 5) AUDIO PROCESSING FUNCTIONS
|
220 |
-
def apply_eq(segment):
|
221 |
-
segment = segment.low_pass_filter(8000)
|
222 |
-
segment = segment.high_pass_filter(80)
|
223 |
-
return segment
|
224 |
-
|
225 |
-
def apply_fade(segment, fade_in_duration=1000, fade_out_duration=1000):
|
226 |
-
segment = segment.fade_in(fade_in_duration)
|
227 |
-
segment = segment.fade_out(fade_out_duration)
|
228 |
-
return segment
|
229 |
-
|
230 |
-
# 6) GENERATION & I/O FUNCTIONS
|
231 |
-
def generate_music(instrumental_prompt: str, cfg_scale: float, top_k: int, top_p: float, temperature: float, total_duration: int, chunk_duration: int, crossfade_duration: int, bpm: int, drum_beat: str, synthesizer: str, rhythmic_steps: str, bass_style: str, guitar_style: str):
|
232 |
-
global musicgen_model
|
233 |
-
if not instrumental_prompt.strip():
|
234 |
-
return None, "β οΈ Please enter a valid instrumental prompt!"
|
235 |
-
try:
|
236 |
-
start_time = time.time()
|
237 |
-
total_duration = total_duration # Validated by radio button (30, 60, 90, 120)
|
238 |
-
chunk_duration = min(max(chunk_duration, 5), 15)
|
239 |
-
num_chunks = max(1, total_duration // chunk_duration)
|
240 |
-
chunk_duration = total_duration / num_chunks
|
241 |
-
overlap_duration = min(1.0, crossfade_duration / 1000.0)
|
242 |
-
generation_duration = chunk_duration + overlap_duration
|
243 |
-
sample_rate = musicgen_model.sample_rate
|
244 |
-
audio_segments = []
|
245 |
-
|
246 |
-
if not check_vram_availability(required_gb=3.5):
|
247 |
-
return None, "β οΈ Insufficient VRAM for generation. Reduce total_duration or chunk_duration."
|
248 |
-
|
249 |
-
print("Generating audio...")
|
250 |
-
seed = 42
|
251 |
-
torch.manual_seed(seed)
|
252 |
-
np.random.seed(seed)
|
253 |
-
|
254 |
-
for i in range(num_chunks):
|
255 |
-
chunk_prompt = instrumental_prompt
|
256 |
-
print(f"Generating chunk {i+1}/{num_chunks} on {device} (prompt: {chunk_prompt})...")
|
257 |
-
musicgen_model.set_generation_params(
|
258 |
-
duration=generation_duration,
|
259 |
-
use_sampling=True,
|
260 |
-
top_k=top_k,
|
261 |
-
top_p=top_p,
|
262 |
-
temperature=temperature,
|
263 |
-
cfg_coef=cfg_scale
|
264 |
-
)
|
265 |
-
|
266 |
-
print_resource_usage(f"Before Chunk {i+1} Generation")
|
267 |
-
|
268 |
-
with torch.no_grad():
|
269 |
-
with autocast():
|
270 |
-
audio_chunk = musicgen_model.generate([chunk_prompt], progress=True)[0]
|
271 |
-
|
272 |
-
audio_chunk = audio_chunk.cpu().to(dtype=torch.float32)
|
273 |
-
if audio_chunk.dim() == 1:
|
274 |
-
audio_chunk = torch.stack([audio_chunk, audio_chunk], dim=0)
|
275 |
-
elif audio_chunk.dim() == 2 and audio_chunk.shape[0] == 1:
|
276 |
-
audio_chunk = torch.cat([audio_chunk, audio_chunk], dim=0)
|
277 |
-
elif audio_chunk.dim() == 2 and audio_chunk.shape[0] != 2:
|
278 |
-
audio_chunk = audio_chunk[:1, :]
|
279 |
-
audio_chunk = torch.cat([audio_chunk, audio_chunk], dim=0)
|
280 |
-
elif audio_chunk.dim() > 2:
|
281 |
-
audio_chunk = audio_chunk.view(2, -1)
|
282 |
-
|
283 |
-
if audio_chunk.shape[0] != 2:
|
284 |
-
raise ValueError(f"Expected stereo audio with shape (2, samples), got shape {audio_chunk.shape}")
|
285 |
-
|
286 |
-
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as temp_wav:
|
287 |
-
temp_wav_path = temp_wav.name
|
288 |
-
torchaudio.save(temp_wav_path, audio_chunk, sample_rate, bits_per_sample=24)
|
289 |
-
segment = AudioSegment.from_wav(temp_wav_path)
|
290 |
-
os.unlink(temp_wav_path)
|
291 |
-
audio_segments.append(segment)
|
292 |
-
|
293 |
-
if device == "cuda":
|
294 |
-
torch.cuda.empty_cache()
|
295 |
-
gc.collect()
|
296 |
-
torch.cuda.ipc_collect()
|
297 |
-
torch.cuda.synchronize()
|
298 |
-
time.sleep(0.5)
|
299 |
-
print_resource_usage(f"After Chunk {i+1} Generation")
|
300 |
-
|
301 |
-
print("Combining audio chunks...")
|
302 |
-
final_segment = audio_segments[0]
|
303 |
-
for i in range(1, len(audio_segments)):
|
304 |
-
next_segment = audio_segments[i]
|
305 |
-
next_segment = next_segment + 1
|
306 |
-
final_segment = final_segment.append(next_segment, crossfade=crossfade_duration)
|
307 |
-
|
308 |
-
final_segment = final_segment[:total_duration * 1000]
|
309 |
-
|
310 |
-
print("Post-processing final track...")
|
311 |
-
final_segment = apply_eq(final_segment)
|
312 |
-
final_segment = final_segment.normalize(headroom=-9.0)
|
313 |
-
final_segment = apply_fade(final_segment)
|
314 |
-
|
315 |
-
mp3_path = "output_cleaned.mp3"
|
316 |
-
final_segment.export(
|
317 |
-
mp3_path,
|
318 |
-
format="mp3",
|
319 |
-
bitrate="128k",
|
320 |
-
tags={"title": "GhostAI Instrumental", "artist": "GhostAI"}
|
321 |
-
)
|
322 |
-
print(f"Saved final audio to {mp3_path}")
|
323 |
|
324 |
-
|
325 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
326 |
|
327 |
-
return mp3_path, "β
Done! Generated instrumental audio."
|
328 |
-
except Exception as e:
|
329 |
-
return None, f"β Generation failed: {e}"
|
330 |
-
finally:
|
331 |
if device == "cuda":
|
332 |
torch.cuda.empty_cache()
|
333 |
gc.collect()
|
334 |
torch.cuda.ipc_collect()
|
335 |
torch.cuda.synchronize()
|
336 |
|
337 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
338 |
def clear_inputs():
|
339 |
-
return "", 3.0, 250, 0.9, 1.0, 30, 10, 1000,
|
|
|
340 |
|
341 |
-
#
|
|
|
|
|
342 |
css = """
|
343 |
-
body
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
}
|
348 |
-
.
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
}
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
}
|
358 |
-
h1 {
|
359 |
-
color: #A100FF;
|
360 |
-
font-size: 24px;
|
361 |
-
animation: glitch-text 2s infinite;
|
362 |
-
}
|
363 |
-
p {
|
364 |
-
color: #E0E0E0;
|
365 |
-
font-size: 12px;
|
366 |
-
}
|
367 |
-
.input-container, .settings-container, .output-container {
|
368 |
-
max-width: 1200px;
|
369 |
-
margin: 20px auto;
|
370 |
-
padding: 20px;
|
371 |
-
background: rgba(28, 37, 38, 0.8);
|
372 |
-
border-radius: 10px;
|
373 |
-
}
|
374 |
-
.textbox {
|
375 |
-
background: #1A1A1A;
|
376 |
-
border: 1px solid #A100FF;
|
377 |
-
color: #E0E0E0;
|
378 |
-
}
|
379 |
-
.genre-buttons {
|
380 |
-
display: flex;
|
381 |
-
justify-content: center;
|
382 |
-
flex-wrap: wrap;
|
383 |
-
gap: 15px;
|
384 |
-
}
|
385 |
-
.genre-btn, button {
|
386 |
-
background: linear-gradient(45deg, #A100FF, #00FF9F);
|
387 |
-
border: none;
|
388 |
-
color: #0A0A0A;
|
389 |
-
padding: 10px 20px;
|
390 |
-
border-radius: 5px;
|
391 |
-
}
|
392 |
-
.gradio-container {
|
393 |
-
padding: 20px;
|
394 |
-
}
|
395 |
-
.group-container {
|
396 |
-
margin-bottom: 20px;
|
397 |
-
padding: 15px;
|
398 |
-
border: 1px solid #00FF9F;
|
399 |
-
border-radius: 8px;
|
400 |
-
}
|
401 |
-
@keyframes glitch-ghost {
|
402 |
-
0% { transform: translate(0, 0); opacity: 1; }
|
403 |
-
20% { transform: translate(-5px, 2px); opacity: 0.8; }
|
404 |
-
100% { transform: translate(0, 0); opacity: 1; }
|
405 |
-
}
|
406 |
-
@keyframes glitch-text {
|
407 |
-
0% { transform: translate(0, 0); }
|
408 |
-
20% { transform: translate(-2px, 1px); }
|
409 |
-
100% { transform: translate(0, 0); }
|
410 |
-
}
|
411 |
-
@font-face {
|
412 |
-
font-family: 'Orbitron';
|
413 |
-
src: url('https://fonts.gstatic.com/s/orbitron/v29/yMJRMIlzdpvBhQQL_Qq7dy0.woff2') format('woff2');
|
414 |
-
}
|
415 |
"""
|
416 |
|
417 |
-
#
|
|
|
|
|
418 |
with gr.Blocks(css=css) as demo:
|
419 |
gr.Markdown("""
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
""")
|
426 |
-
|
|
|
427 |
with gr.Column(elem_classes="input-container"):
|
428 |
gr.Markdown("### πΈ Prompt Settings")
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
lines=4,
|
433 |
-
elem_classes="textbox"
|
434 |
-
)
|
435 |
with gr.Row(elem_classes="genre-buttons"):
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
451 |
with gr.Column(elem_classes="settings-container"):
|
452 |
gr.Markdown("### βοΈ API Settings")
|
453 |
with gr.Group(elem_classes="group-container"):
|
454 |
-
cfg_scale
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
)
|
462 |
-
top_k = gr.Slider(
|
463 |
-
label="Top-K Sampling π’",
|
464 |
-
minimum=10,
|
465 |
-
maximum=500,
|
466 |
-
value=250,
|
467 |
-
step=10,
|
468 |
-
info="Limits sampling to the top k most likely tokens."
|
469 |
-
)
|
470 |
-
top_p = gr.Slider(
|
471 |
-
label="Top-P Sampling π°",
|
472 |
-
minimum=0.0,
|
473 |
-
maximum=1.0,
|
474 |
-
value=0.9,
|
475 |
-
step=0.05,
|
476 |
-
info="Keeps tokens with cumulative probability above p."
|
477 |
-
)
|
478 |
-
temperature = gr.Slider(
|
479 |
-
label="Temperature π₯",
|
480 |
-
minimum=0.1,
|
481 |
-
maximum=2.0,
|
482 |
-
value=1.0,
|
483 |
-
step=0.1,
|
484 |
-
info="Controls randomness; higher values increase diversity."
|
485 |
-
)
|
486 |
-
total_duration = gr.Radio(
|
487 |
-
label="Song Length β³ (seconds)",
|
488 |
-
choices=[30, 60, 90, 120],
|
489 |
-
value=30,
|
490 |
-
info="Select the total duration of the track."
|
491 |
-
)
|
492 |
-
chunk_duration = gr.Slider(
|
493 |
-
label="Chunk Duration β±οΈ (seconds)",
|
494 |
-
minimum=5,
|
495 |
-
maximum=15,
|
496 |
-
value=10,
|
497 |
-
step=1,
|
498 |
-
info="Duration of each chunk to render (5 to 15 seconds)."
|
499 |
-
)
|
500 |
-
crossfade_duration = gr.Slider(
|
501 |
-
label="Crossfade Duration πΆ (ms)",
|
502 |
-
minimum=100,
|
503 |
-
maximum=2000,
|
504 |
-
value=1000,
|
505 |
-
step=100,
|
506 |
-
info="Crossfade duration between chunks."
|
507 |
-
)
|
508 |
|
509 |
gr.Markdown("### π΅ Musical Controls")
|
510 |
with gr.Group(elem_classes="group-container"):
|
511 |
-
bpm
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
value="none",
|
523 |
-
info="Select a drum beat style to influence the rhythm."
|
524 |
-
)
|
525 |
-
synthesizer = gr.Dropdown(
|
526 |
-
label="Synthesizer πΉ",
|
527 |
-
choices=["none", "analog synth", "digital pad", "arpeggiated synth"],
|
528 |
-
value="none",
|
529 |
-
info="Select a synthesizer style for electronic accents."
|
530 |
-
)
|
531 |
-
rhythmic_steps = gr.Dropdown(
|
532 |
-
label="Rhythmic Steps π£",
|
533 |
-
choices=["none", "syncopated steps", "steady steps", "complex steps"],
|
534 |
-
value="none",
|
535 |
-
info="Select a rhythmic step style to enhance the beat."
|
536 |
-
)
|
537 |
-
bass_style = gr.Dropdown(
|
538 |
-
label="Bass Style πΈ",
|
539 |
-
choices=["none", "slap bass", "deep bass", "melodic bass"],
|
540 |
-
value="none",
|
541 |
-
info="Select a bass style to shape the low end."
|
542 |
-
)
|
543 |
-
guitar_style = gr.Dropdown(
|
544 |
-
label="Guitar Style πΈ",
|
545 |
-
choices=["none", "distorted", "clean", "jangle"],
|
546 |
-
value="none",
|
547 |
-
info="Select a guitar style to define the riffs."
|
548 |
-
)
|
549 |
|
550 |
with gr.Row(elem_classes="action-buttons"):
|
551 |
gen_btn = gr.Button("Generate Music π")
|
552 |
clr_btn = gr.Button("Clear Inputs π§Ή")
|
553 |
-
|
|
|
554 |
with gr.Column(elem_classes="output-container"):
|
555 |
gr.Markdown("### π§ Output")
|
556 |
-
out_audio = gr.Audio(label="Generated
|
557 |
-
status
|
558 |
-
|
559 |
-
|
560 |
-
nirvana_btn.click(set_nirvana_grunge_prompt, inputs=[bpm, drum_beat, synthesizer, rhythmic_steps, bass_style, guitar_style], outputs=instrumental_prompt)
|
561 |
-
pearl_jam_btn.click(set_pearl_jam_grunge_prompt, inputs=[bpm, drum_beat, synthesizer, rhythmic_steps, bass_style, guitar_style], outputs=instrumental_prompt)
|
562 |
-
soundgarden_btn.click(set_soundgarden_grunge_prompt, inputs=[bpm, drum_beat, synthesizer, rhythmic_steps, bass_style, guitar_style], outputs=instrumental_prompt)
|
563 |
-
foo_fighters_btn.click(set_foo_fighters_prompt, inputs=[bpm, drum_beat, synthesizer, rhythmic_steps, bass_style, guitar_style], outputs=instrumental_prompt)
|
564 |
-
smashing_pumpkins_btn.click(set_smashing_pumpkins_prompt, inputs=[bpm, drum_beat, synthesizer, rhythmic_steps, bass_style, guitar_style], outputs=instrumental_prompt)
|
565 |
-
radiohead_btn.click(set_radiohead_prompt, inputs=[bpm, drum_beat, synthesizer, rhythmic_steps, bass_style, guitar_style], outputs=instrumental_prompt)
|
566 |
-
classic_rock_btn.click(set_classic_rock_prompt, inputs=[bpm, drum_beat, synthesizer, rhythmic_steps, bass_style, guitar_style], outputs=instrumental_prompt)
|
567 |
-
alternative_rock_btn.click(set_alternative_rock_prompt, inputs=[bpm, drum_beat, synthesizer, rhythmic_steps, bass_style, guitar_style], outputs=instrumental_prompt)
|
568 |
-
post_punk_btn.click(set_post_punk_prompt, inputs=[bpm, drum_beat, synthesizer, rhythmic_steps, bass_style, guitar_style], outputs=instrumental_prompt)
|
569 |
-
indie_rock_btn.click(set_indie_rock_prompt, inputs=[bpm, drum_beat, synthesizer, rhythmic_steps, bass_style, guitar_style], outputs=instrumental_prompt)
|
570 |
-
funk_rock_btn.click(set_funk_rock_prompt, inputs=[bpm, drum_beat, synthesizer, rhythmic_steps, bass_style, guitar_style], outputs=instrumental_prompt)
|
571 |
-
detroit_techno_btn.click(set_detroit_techno_prompt, inputs=[bpm, drum_beat, synthesizer, rhythmic_steps, bass_style, guitar_style], outputs=instrumental_prompt)
|
572 |
-
deep_house_btn.click(set_deep_house_prompt, inputs=[bpm, drum_beat, synthesizer, rhythmic_steps, bass_style, guitar_style], outputs=instrumental_prompt)
|
573 |
gen_btn.click(
|
574 |
generate_music,
|
575 |
-
inputs=[
|
|
|
|
|
576 |
outputs=[out_audio, status]
|
577 |
)
|
578 |
clr_btn.click(
|
579 |
clear_inputs,
|
580 |
inputs=None,
|
581 |
-
outputs=[
|
|
|
|
|
582 |
)
|
583 |
|
584 |
-
#
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
)
|
590 |
try:
|
591 |
fastapi_app = demo._server.app
|
592 |
-
fastapi_app.docs_url
|
593 |
-
fastapi_app.redoc_url
|
594 |
fastapi_app.openapi_url = None
|
595 |
except Exception:
|
596 |
-
pass
|
|
|
1 |
+
#!/usr/bin/env python3
|
2 |
+
# -*- coding: utf-8 -*-
|
3 |
+
"""
|
4 |
+
GhostAI Music Generator
|
5 |
+
Full script with compatibility fixes for environments running
|
6 |
+
PyTorch < 2.3 (adds torch.get_default_device shim).
|
7 |
+
|
8 |
+
Last updated: 2025-05-29
|
9 |
+
"""
|
10 |
+
|
11 |
import os
|
|
|
|
|
|
|
|
|
12 |
import sys
|
|
|
13 |
import gc
|
14 |
+
import time
|
15 |
+
import random
|
16 |
+
import warnings
|
17 |
+
import tempfile
|
18 |
+
import psutil
|
19 |
+
import numpy as np
|
20 |
+
import torch
|
21 |
+
import torchaudio
|
22 |
import gradio as gr
|
23 |
from pydub import AudioSegment
|
|
|
24 |
from torch.cuda.amp import autocast
|
25 |
+
from audiocraft.models import MusicGen
|
|
|
26 |
from huggingface_hub import login
|
|
|
27 |
|
28 |
+
# ----------------------------------------------------------------------
|
29 |
+
# PYTORCH COMPATIBILITY SHIM (for versions < 2.3)
|
30 |
+
# ----------------------------------------------------------------------
|
31 |
+
if not hasattr(torch, "get_default_device"):
|
32 |
+
def _get_default_device():
|
33 |
+
return torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
34 |
+
torch.get_default_device = _get_default_device
|
35 |
+
|
36 |
+
# ----------------------------------------------------------------------
|
37 |
+
# WARNING SUPPRESSION & ENV TUNING
|
38 |
+
# ----------------------------------------------------------------------
|
39 |
warnings.filterwarnings("ignore")
|
|
|
|
|
40 |
os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "max_split_size_mb:128"
|
41 |
|
42 |
+
# ----------------------------------------------------------------------
|
43 |
+
# HUGGING FACE AUTH
|
44 |
+
# ----------------------------------------------------------------------
|
45 |
hf_token = os.getenv("HF_TOKEN")
|
46 |
if not hf_token:
|
47 |
+
print("ERROR: HF_TOKEN environment variable not set. Please set it.")
|
48 |
sys.exit(1)
|
49 |
+
|
50 |
try:
|
51 |
login(hf_token)
|
52 |
except Exception as e:
|
53 |
print(f"ERROR: Failed to authenticate with Hugging Face: {e}")
|
54 |
sys.exit(1)
|
55 |
|
56 |
+
# ----------------------------------------------------------------------
|
57 |
+
# VERSION CHECKS
|
58 |
+
# ----------------------------------------------------------------------
|
59 |
if np.__version__ != "1.23.5":
|
60 |
+
print(f"WARNING: NumPy version {np.__version__} detected (expected 1.23.5).")
|
61 |
if not torch.__version__.startswith("2.3.1"):
|
62 |
+
print(f"WARNING: PyTorch version {torch.__version__} detected (expected 2.3.1).")
|
63 |
|
64 |
+
# ----------------------------------------------------------------------
|
65 |
+
# DEVICE SETUP
|
66 |
+
# ----------------------------------------------------------------------
|
67 |
+
print("Debugging GPU and CUDA setupβ¦")
|
68 |
print(f"PyTorch CUDA available: {torch.cuda.is_available()}")
|
69 |
if torch.cuda.is_available():
|
70 |
+
print(f"CUDA device count : {torch.cuda.device_count()}")
|
71 |
+
print(f"CUDA device name : {torch.cuda.get_device_name(0)}")
|
72 |
+
print(f"CUDA version : {torch.version.cuda}")
|
|
|
73 |
else:
|
74 |
+
print("CUDA unavailable; falling back to CPU (performance will suffer).")
|
|
|
|
|
|
|
75 |
|
76 |
device = "cuda" if torch.cuda.is_available() else "cpu"
|
|
|
|
|
77 |
|
78 |
+
# Pre-run memory cleanup (GPU)
|
79 |
if device == "cuda":
|
80 |
torch.cuda.empty_cache()
|
81 |
gc.collect()
|
82 |
torch.cuda.ipc_collect()
|
83 |
torch.cuda.synchronize()
|
84 |
|
85 |
+
# ----------------------------------------------------------------------
|
86 |
+
# LOAD MUSICGEN
|
87 |
+
# ----------------------------------------------------------------------
|
88 |
try:
|
89 |
+
print("Loading MusicGen medium modelβ¦")
|
90 |
musicgen_model = MusicGen.get_pretrained("facebook/musicgen-medium", device=device)
|
91 |
+
musicgen_model.set_generation_params(duration=10, two_step_cfg=False)
|
|
|
|
|
|
|
92 |
except Exception as e:
|
93 |
print(f"ERROR: Failed to load MusicGen model: {e}")
|
94 |
+
print("Check HF access and PyTorch version compatibility.")
|
95 |
sys.exit(1)
|
96 |
|
97 |
+
# ----------------------------------------------------------------------
|
98 |
+
# HELPER: RESOURCE MONITOR
|
99 |
+
# ----------------------------------------------------------------------
|
100 |
def print_resource_usage(stage: str):
|
101 |
print(f"--- {stage} ---")
|
102 |
if device == "cuda":
|
103 |
print(f"GPU Memory Allocated: {torch.cuda.memory_allocated() / (1024**3):.2f} GB")
|
104 |
+
print(f"GPU Memory Reserved : {torch.cuda.memory_reserved() / (1024**3):.2f} GB")
|
105 |
+
print(f"CPU Memory Used : {psutil.virtual_memory().percent}%")
|
106 |
+
print("--------------------")
|
107 |
|
108 |
+
def check_vram(required_gb=3.5):
|
|
|
109 |
if device != "cuda":
|
|
|
110 |
return True
|
111 |
+
total = torch.cuda.get_device_properties(0).total_memory / (1024**3)
|
112 |
+
used = torch.cuda.memory_allocated() / (1024**3)
|
113 |
+
avail = total - used
|
114 |
+
if avail < required_gb:
|
115 |
+
print(f"WARNING: Only {avail:.2f} GB VRAM free (need β₯ {required_gb} GB).")
|
116 |
+
return avail >= required_gb
|
117 |
+
|
118 |
+
# ----------------------------------------------------------------------
|
119 |
+
# PROMPT BUILDERS (UNCHANGED)
|
120 |
+
# ----------------------------------------------------------------------
|
121 |
+
def _prompt(base, bpm, drum, synth, steps, bass, guitar, default_bass, default_gtr, vibe):
|
122 |
+
rhythm = f" with {steps}" if steps != "none" else vibe.format(bpm=bpm)
|
123 |
+
drum = f", {drum} drums" if drum != "none" else ""
|
124 |
+
synth = f", {synth} accents" if synth != "none" else ""
|
125 |
+
bass = f", {bass}" if bass != "none" else default_bass
|
126 |
+
guitar = f", {guitar} guitar riffs" if guitar != "none" else default_gtr
|
127 |
+
return f"{base}{bass}{guitar}{drum}{synth}{rhythm} at {bpm} BPM."
|
128 |
+
|
129 |
+
def set_red_hot_chili_peppers_prompt(bpm, drum, synth, steps, bass, guitar):
|
130 |
+
return _prompt(
|
131 |
+
"Instrumental funk rock",
|
132 |
+
bpm, drum, synth, steps, bass, guitar,
|
133 |
+
", groovy basslines", ", syncopated guitar riffs",
|
134 |
+
"{bpm} BPM funky flow" if bpm > 120 else "groovy rhythmic flow"
|
135 |
+
)
|
136 |
+
|
137 |
+
def set_nirvana_grunge_prompt(bpm, drum, synth, steps, bass, guitar):
|
138 |
+
return _prompt(
|
139 |
+
"Instrumental grunge",
|
140 |
+
bpm, drum, synth, steps, bass, guitar,
|
141 |
+
", melodic basslines", ", raw distorted guitar riffs",
|
142 |
+
"{bpm} BPM grungy pulse" if bpm > 120 else "grungy rhythmic pulse"
|
143 |
+
)
|
144 |
+
|
145 |
+
def set_pearl_jam_grunge_prompt(bpm, drum, synth, steps, bass, guitar):
|
146 |
+
return _prompt(
|
147 |
+
"Instrumental grunge",
|
148 |
+
bpm, drum, synth, steps, bass, guitar,
|
149 |
+
", deep bass", ", soulful guitar leads",
|
150 |
+
"{bpm} BPM driving flow" if bpm > 120 else "driving rhythmic flow"
|
151 |
+
)
|
152 |
+
|
153 |
+
def set_soundgarden_grunge_prompt(bpm, drum, synth, steps, bass, guitar):
|
154 |
+
return _prompt(
|
155 |
+
"Instrumental grunge",
|
156 |
+
bpm, drum, synth, steps, bass, guitar,
|
157 |
+
"", ", heavy sludgy guitar riffs",
|
158 |
+
"{bpm} BPM heavy groove" if bpm > 120 else "sludgy rhythmic groove"
|
159 |
+
)
|
160 |
+
|
161 |
+
def set_foo_fighters_prompt(bpm, drum, synth, steps, bass, guitar):
|
162 |
styles = ["anthemic", "gritty", "melodic", "fast-paced", "driving"]
|
163 |
+
moods = ["energetic", "introspective", "rebellious", "uplifting"]
|
164 |
+
style = random.choice(styles)
|
165 |
+
mood = random.choice(moods)
|
166 |
+
return _prompt(
|
167 |
+
"Instrumental alternative rock",
|
168 |
+
bpm, drum, synth, steps, bass, guitar,
|
169 |
+
"", f", {style} guitar riffs",
|
170 |
+
"{bpm} BPM powerful groove" if bpm > 120 else "catchy rhythmic groove"
|
171 |
+
) + f", Foo Fighters-inspired {mood} vibe"
|
172 |
+
|
173 |
+
def set_smashing_pumpkins_prompt(bpm, drum, synth, steps, bass, guitar):
|
174 |
+
return _prompt(
|
175 |
+
"Instrumental alternative rock",
|
176 |
+
bpm, drum, synth, steps, bass, guitar,
|
177 |
+
"", ", dreamy guitar textures",
|
178 |
+
"{bpm} BPM dynamic flow" if bpm > 120 else "dreamy rhythmic flow"
|
179 |
+
)
|
180 |
+
|
181 |
+
def set_radiohead_prompt(bpm, drum, synth, steps, bass, guitar):
|
182 |
+
return _prompt(
|
183 |
+
"Instrumental experimental rock",
|
184 |
+
bpm, drum, synth, steps, bass, guitar,
|
185 |
+
"", ", intricate guitar layers",
|
186 |
+
"{bpm} BPM intricate pulse" if bpm > 120 else "intricate rhythmic pulse"
|
187 |
+
)
|
188 |
+
|
189 |
+
def set_classic_rock_prompt(bpm, drum, synth, steps, bass, guitar):
|
190 |
+
return _prompt(
|
191 |
+
"Instrumental classic rock",
|
192 |
+
bpm, drum, synth, steps, bass, guitar,
|
193 |
+
", groovy bass", ", bluesy electric guitars",
|
194 |
+
"{bpm} BPM bluesy steps" if bpm > 120 else "steady rhythmic groove"
|
195 |
+
)
|
196 |
+
|
197 |
+
def set_alternative_rock_prompt(bpm, drum, synth, steps, bass, guitar):
|
198 |
+
return _prompt(
|
199 |
+
"Instrumental alternative rock",
|
200 |
+
bpm, drum, synth, steps, bass, guitar,
|
201 |
+
", melodic basslines", ", distorted guitar riffs",
|
202 |
+
"{bpm} BPM quirky steps" if bpm > 120 else "energetic rhythmic flow"
|
203 |
+
)
|
204 |
+
|
205 |
+
def set_post_punk_prompt(bpm, drum, synth, steps, bass, guitar):
|
206 |
+
return _prompt(
|
207 |
+
"Instrumental post-punk",
|
208 |
+
bpm, drum, synth, steps, bass, guitar,
|
209 |
+
", driving basslines", ", jangly guitars",
|
210 |
+
"{bpm} BPM sharp steps" if bpm > 120 else "moody rhythmic pulse"
|
211 |
+
)
|
212 |
+
|
213 |
+
def set_indie_rock_prompt(bpm, drum, synth, steps, bass, guitar):
|
214 |
+
return _prompt(
|
215 |
+
"Instrumental indie rock",
|
216 |
+
bpm, drum, synth, steps, bass, guitar,
|
217 |
+
"", ", jangly guitars",
|
218 |
+
"{bpm} BPM catchy steps" if bpm > 120 else "jangly rhythmic flow"
|
219 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
220 |
|
221 |
+
def set_funk_rock_prompt(bpm, drum, synth, steps, bass, guitar):
|
222 |
+
return _prompt(
|
223 |
+
"Instrumental funk rock",
|
224 |
+
bpm, drum, synth, steps, bass, guitar,
|
225 |
+
", slap bass", ", funky guitar chords",
|
226 |
+
"{bpm} BPM aggressive steps" if bpm > 120 else "funky rhythmic groove"
|
227 |
+
)
|
228 |
+
|
229 |
+
def set_detroit_techno_prompt(bpm, drum, synth, steps, bass, guitar):
|
230 |
+
return _prompt(
|
231 |
+
"Instrumental Detroit techno",
|
232 |
+
bpm, drum, synth, steps, bass, guitar,
|
233 |
+
", driving basslines", "",
|
234 |
+
"{bpm} BPM pulsing steps" if bpm > 120 else "deep rhythmic groove"
|
235 |
+
)
|
236 |
+
|
237 |
+
def set_deep_house_prompt(bpm, drum, synth, steps, bass, guitar):
|
238 |
+
return _prompt(
|
239 |
+
"Instrumental deep house",
|
240 |
+
bpm, drum, synth, steps, bass, guitar,
|
241 |
+
", deep basslines", "",
|
242 |
+
"{bpm} BPM soulful steps" if bpm > 120 else "laid-back rhythmic flow"
|
243 |
+
)
|
244 |
+
|
245 |
+
# ----------------------------------------------------------------------
|
246 |
+
# AUDIO POST-PROCESSING
|
247 |
+
# ----------------------------------------------------------------------
|
248 |
+
def apply_eq(seg: AudioSegment):
|
249 |
+
return seg.low_pass_filter(8000).high_pass_filter(80)
|
250 |
+
|
251 |
+
def apply_fade(seg: AudioSegment, fin=1000, fout=1000):
|
252 |
+
return seg.fade_in(fin).fade_out(fout)
|
253 |
+
|
254 |
+
# ----------------------------------------------------------------------
|
255 |
+
# CORE GENERATION
|
256 |
+
# ----------------------------------------------------------------------
|
257 |
+
def generate_music(prompt, cfg, k, p, temp,
|
258 |
+
total_dur, chunk_dur, crossfade,
|
259 |
+
bpm, drum, synth, steps, bass, guitar):
|
260 |
+
|
261 |
+
if not prompt.strip():
|
262 |
+
return None, "β οΈ Please enter a prompt."
|
263 |
+
|
264 |
+
if not check_vram(3.5):
|
265 |
+
return None, "β οΈ Insufficient VRAM. Lower duration."
|
266 |
+
|
267 |
+
total_dur = int(total_dur)
|
268 |
+
chunk_dur = int(max(5, min(chunk_dur, 15)))
|
269 |
+
num_chunks = max(1, total_dur // chunk_dur)
|
270 |
+
chunk_dur = total_dur / num_chunks
|
271 |
+
overlap = min(1.0, crossfade / 1000.0)
|
272 |
+
render_len = chunk_dur + overlap
|
273 |
+
sr = musicgen_model.sample_rate
|
274 |
+
segments = []
|
275 |
+
|
276 |
+
torch.manual_seed(42)
|
277 |
+
np.random.seed(42)
|
278 |
+
|
279 |
+
start = time.time()
|
280 |
+
for i in range(num_chunks):
|
281 |
+
print_resource_usage(f"Before chunk {i+1}")
|
282 |
+
musicgen_model.set_generation_params(
|
283 |
+
duration=render_len,
|
284 |
+
use_sampling=True,
|
285 |
+
top_k=k, top_p=p,
|
286 |
+
temperature=temp,
|
287 |
+
cfg_coef=cfg
|
288 |
+
)
|
289 |
+
with torch.no_grad(), autocast():
|
290 |
+
chunk = musicgen_model.generate([prompt], progress=False)[0]
|
291 |
+
|
292 |
+
chunk = chunk.cpu().float()
|
293 |
+
if chunk.dim() == 1:
|
294 |
+
chunk = torch.stack([chunk, chunk])
|
295 |
+
elif chunk.shape[0] == 1:
|
296 |
+
chunk = torch.cat([chunk, chunk], dim=0)
|
297 |
+
elif chunk.shape[0] != 2:
|
298 |
+
chunk = chunk[:1]
|
299 |
+
chunk = torch.cat([chunk, chunk], dim=0)
|
300 |
+
|
301 |
+
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp:
|
302 |
+
torchaudio.save(tmp.name, chunk, sr, bits_per_sample=24)
|
303 |
+
seg = AudioSegment.from_wav(tmp.name)
|
304 |
+
os.unlink(tmp.name)
|
305 |
+
segments.append(seg)
|
306 |
|
|
|
|
|
|
|
|
|
307 |
if device == "cuda":
|
308 |
torch.cuda.empty_cache()
|
309 |
gc.collect()
|
310 |
torch.cuda.ipc_collect()
|
311 |
torch.cuda.synchronize()
|
312 |
|
313 |
+
print_resource_usage(f"After chunk {i+1}")
|
314 |
+
|
315 |
+
final = segments[0]
|
316 |
+
for seg in segments[1:]:
|
317 |
+
final = final.append(seg + 1, crossfade=crossfade)
|
318 |
+
final = final[:total_dur * 1000]
|
319 |
+
final = apply_fade(apply_eq(final).normalize(headroom=-9.0))
|
320 |
+
|
321 |
+
out_path = "output_cleaned.mp3"
|
322 |
+
final.export(out_path, format="mp3", bitrate="128k",
|
323 |
+
tags={"title": "GhostAI Instrumental", "artist": "GhostAI"})
|
324 |
+
print_resource_usage("After final")
|
325 |
+
print(f"Total time: {time.time() - start:.2f}s")
|
326 |
+
return out_path, "β
Done!"
|
327 |
+
|
328 |
+
# ----------------------------------------------------------------------
|
329 |
+
# CLEAR INPUTS
|
330 |
+
# ----------------------------------------------------------------------
|
331 |
def clear_inputs():
|
332 |
+
return ("", 3.0, 250, 0.9, 1.0, 30, 10, 1000,
|
333 |
+
120, "none", "none", "none", "none", "none")
|
334 |
|
335 |
+
# ----------------------------------------------------------------------
|
336 |
+
# CSS
|
337 |
+
# ----------------------------------------------------------------------
|
338 |
css = """
|
339 |
+
body{background:linear-gradient(135deg,#0A0A0A 0%,#1C2526 100%);color:#E0E0E0;font-family:'Orbitron',sans-serif}
|
340 |
+
.header-container{text-align:center;padding:10px 20px;background:rgba(0,0,0,.9);border-bottom:1px solid #00FF9F}
|
341 |
+
#ghost-logo{font-size:40px;animation:glitch-ghost 1.5s infinite}
|
342 |
+
h1{color:#A100FF;font-size:24px;animation:glitch-text 2s infinite}
|
343 |
+
p{color:#E0E0E0;font-size:12px}
|
344 |
+
.input-container,.settings-container,.output-container{max-width:1200px;margin:20px auto;padding:20px;background:rgba(28,37,38,.8);border-radius:10px}
|
345 |
+
.textbox{background:#1A1A1A;border:1px solid #A100FF;color:#E0E0E0}
|
346 |
+
.genre-buttons{display:flex;justify-content:center;flex-wrap:wrap;gap:15px}
|
347 |
+
.genre-btn,button{background:linear-gradient(45deg,#A100FF,#00FF9F);border:none;color:#0A0A0A;padding:10px 20px;border-radius:5px}
|
348 |
+
.gradio-container{padding:20px}
|
349 |
+
.group-container{margin-bottom:20px;padding:15px;border:1px solid #00FF9F;border-radius:8px}
|
350 |
+
@keyframes glitch-ghost{0%{transform:translate(0,0);opacity:1}20%{transform:translate(-5px,2px);opacity:.8}100%{transform:translate(0,0);opacity:1}}
|
351 |
+
@keyframes glitch-text{0%{transform:translate(0,0)}20%{transform:translate(-2px,1px)}100%{transform:translate(0,0)}}
|
352 |
+
@font-face{font-family:'Orbitron';src:url('https://fonts.gstatic.com/s/orbitron/v29/yMJRMIlzdpvBhQQL_Qq7dy0.woff2') format('woff2')}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
353 |
"""
|
354 |
|
355 |
+
# ----------------------------------------------------------------------
|
356 |
+
# GRADIO UI
|
357 |
+
# ----------------------------------------------------------------------
|
358 |
with gr.Blocks(css=css) as demo:
|
359 |
gr.Markdown("""
|
360 |
+
<div class="header-container">
|
361 |
+
<div id="ghost-logo">π»</div>
|
362 |
+
<h1>GhostAI Music Generator πΉ</h1>
|
363 |
+
<p>Summon the Sound of the Unknown</p>
|
364 |
+
</div>
|
365 |
""")
|
366 |
+
|
367 |
+
# INPUT
|
368 |
with gr.Column(elem_classes="input-container"):
|
369 |
gr.Markdown("### πΈ Prompt Settings")
|
370 |
+
prompt_box = gr.Textbox(label="Instrumental Prompt βοΈ",
|
371 |
+
placeholder="Click a genre button or type your own prompt",
|
372 |
+
lines=4, elem_classes="textbox")
|
|
|
|
|
|
|
373 |
with gr.Row(elem_classes="genre-buttons"):
|
374 |
+
buttons = {
|
375 |
+
"Red Hot Chili Peppers πΆοΈ" : set_red_hot_chili_peppers_prompt,
|
376 |
+
"Nirvana Grunge πΈ" : set_nirvana_grunge_prompt,
|
377 |
+
"Pearl Jam Grunge π¦ͺ" : set_pearl_jam_grunge_prompt,
|
378 |
+
"Soundgarden Grunge π" : set_soundgarden_grunge_prompt,
|
379 |
+
"Foo Fighters π€" : set_foo_fighters_prompt,
|
380 |
+
"Smashing Pumpkins π" : set_smashing_pumpkins_prompt,
|
381 |
+
"Radiohead π§ " : set_radiohead_prompt,
|
382 |
+
"Classic Rock πΈ" : set_classic_rock_prompt,
|
383 |
+
"Alternative Rock π΅" : set_alternative_rock_prompt,
|
384 |
+
"Post-Punk π€" : set_post_punk_prompt,
|
385 |
+
"Indie Rock π€" : set_indie_rock_prompt,
|
386 |
+
"Funk Rock πΊ" : set_funk_rock_prompt,
|
387 |
+
"Detroit Techno ποΈ" : set_detroit_techno_prompt,
|
388 |
+
"Deep House π " : set_deep_house_prompt
|
389 |
+
}
|
390 |
+
for label, fn in buttons.items():
|
391 |
+
gr.Button(label, elem_classes="genre-btn").click(
|
392 |
+
fn,
|
393 |
+
inputs=[gr.State("bpm"), gr.State("drum"), gr.State("synth"),
|
394 |
+
gr.State("steps"), gr.State("bass"), gr.State("guitar")],
|
395 |
+
outputs=prompt_box
|
396 |
+
)
|
397 |
+
|
398 |
+
# SETTINGS
|
399 |
with gr.Column(elem_classes="settings-container"):
|
400 |
gr.Markdown("### βοΈ API Settings")
|
401 |
with gr.Group(elem_classes="group-container"):
|
402 |
+
cfg_scale = gr.Slider(label="CFG Scale π―", minimum=1, maximum=10, value=3, step=0.1)
|
403 |
+
top_k = gr.Slider(label="Top-K π’", minimum=10, maximum=500,value=250, step=10)
|
404 |
+
top_p = gr.Slider(label="Top-P π°", minimum=0, maximum=1, value=0.9, step=0.05)
|
405 |
+
temperature = gr.Slider(label="Temperature π₯",minimum=0.1,maximum=2, value=1, step=0.1)
|
406 |
+
total_duration = gr.Radio (label="Length β³ (s)", choices=[30,60,90,120], value=30)
|
407 |
+
chunk_duration = gr.Slider(label="Chunk β±οΈ (s)", minimum=5, maximum=15, value=10, step=1)
|
408 |
+
crossfade_duration= gr.Slider(label="Crossfade πΆ (ms)",minimum=100,maximum=2000,value=1000,step=100)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
409 |
|
410 |
gr.Markdown("### π΅ Musical Controls")
|
411 |
with gr.Group(elem_classes="group-container"):
|
412 |
+
bpm = gr.Slider(label="Tempo π΅ (BPM)", minimum=60, maximum=180, value=120, step=1)
|
413 |
+
drum_beat = gr.Dropdown(label="Drum Beat π₯",
|
414 |
+
choices=["none","standard rock","funk groove","techno kick","jazz swing"], value="none")
|
415 |
+
synthesizer= gr.Dropdown(label="Synthesizer πΉ",
|
416 |
+
choices=["none","analog synth","digital pad","arpeggiated synth"], value="none")
|
417 |
+
rhythmic_steps=gr.Dropdown(label="Rhythmic Steps π£",
|
418 |
+
choices=["none","syncopated steps","steady steps","complex steps"], value="none")
|
419 |
+
bass_style = gr.Dropdown(label="Bass Style πΈ",
|
420 |
+
choices=["none","slap bass","deep bass","melodic bass"], value="none")
|
421 |
+
guitar_style=gr.Dropdown(label="Guitar Style πΈ",
|
422 |
+
choices=["none","distorted","clean","jangle"], value="none")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
423 |
|
424 |
with gr.Row(elem_classes="action-buttons"):
|
425 |
gen_btn = gr.Button("Generate Music π")
|
426 |
clr_btn = gr.Button("Clear Inputs π§Ή")
|
427 |
+
|
428 |
+
# OUTPUT
|
429 |
with gr.Column(elem_classes="output-container"):
|
430 |
gr.Markdown("### π§ Output")
|
431 |
+
out_audio = gr.Audio(label="Generated Track π΅", type="filepath")
|
432 |
+
status = gr.Textbox(label="Status π’", interactive=False)
|
433 |
+
|
434 |
+
# ACTIONS
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
435 |
gen_btn.click(
|
436 |
generate_music,
|
437 |
+
inputs=[prompt_box, cfg_scale, top_k, top_p, temperature,
|
438 |
+
total_duration, chunk_duration, crossfade_duration,
|
439 |
+
bpm, drum_beat, synthesizer, rhythmic_steps, bass_style, guitar_style],
|
440 |
outputs=[out_audio, status]
|
441 |
)
|
442 |
clr_btn.click(
|
443 |
clear_inputs,
|
444 |
inputs=None,
|
445 |
+
outputs=[prompt_box, cfg_scale, top_k, top_p, temperature,
|
446 |
+
total_duration, chunk_duration, crossfade_duration,
|
447 |
+
bpm, drum_beat, synthesizer, rhythmic_steps, bass_style, guitar_style]
|
448 |
)
|
449 |
|
450 |
+
# ----------------------------------------------------------------------
|
451 |
+
# LAUNCH
|
452 |
+
# ----------------------------------------------------------------------
|
453 |
+
app = demo.launch(share=False, inbrowser=False, show_error=True)
|
454 |
+
|
455 |
+
# Disable OpenAPI docs (HF Spaces hardening)
|
456 |
try:
|
457 |
fastapi_app = demo._server.app
|
458 |
+
fastapi_app.docs_url = None
|
459 |
+
fastapi_app.redoc_url = None
|
460 |
fastapi_app.openapi_url = None
|
461 |
except Exception:
|
462 |
+
pass
|