Cristobal299 commited on
Commit
394433f
·
verified ·
1 Parent(s): 302f70b

Upload 2 files

Browse files
Files changed (1) hide show
  1. app (1) (18).py +110 -0
app (1) (18).py ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import spaces
3
+ import tempfile
4
+ import numpy as np
5
+ import scipy.io.wavfile
6
+ import torch
7
+
8
+ print("Cargando modelo...")
9
+ from transformers import AutoProcessor, MusicgenForConditionalGeneration
10
+ processor = AutoProcessor.from_pretrained("facebook/musicgen-medium")
11
+ modelo = MusicgenForConditionalGeneration.from_pretrained("facebook/musicgen-medium")
12
+ SR = modelo.config.audio_encoder.sampling_rate # 32000
13
+ print("Modelo listo")
14
+
15
+ FRAME = SR // 50 # muestras por token (musicgen va a 50 Hz)
16
+ MAX_TOKENS = 1500 # tope fisico de musicgen (~30s)
17
+ CONTEXT_SEG = 5 # segundos de "arranque" que damos para continuar
18
+ CHUNK_MAX_SEG = 25 # maximo que puede generar por pasada con ese contexto
19
+
20
+
21
+ def _a_numpy(audio_values):
22
+ a = audio_values[0].cpu().numpy()
23
+ return np.squeeze(a).astype(np.float32)
24
+
25
+
26
+ def _crossfade_join(a, b, sr, xf_seg=0.4):
27
+ """Une a + b con un cruce corto para tapar la costura."""
28
+ xf = min(int(xf_seg * sr), len(a), len(b))
29
+ if xf <= 0:
30
+ return np.concatenate([a, b])
31
+ fade_out = np.linspace(1.0, 0.0, xf)
32
+ fade_in = np.linspace(0.0, 1.0, xf)
33
+ mezcla = a[-xf:] * fade_out + b[:xf] * fade_in
34
+ return np.concatenate([a[:-xf], mezcla, b[xf:]])
35
+
36
+
37
+ @spaces.GPU(duration=300)
38
+ def generar_musica(prompt: str, duracion: int = 30) -> str:
39
+ if not prompt.strip():
40
+ raise gr.Error("El prompt no puede estar vacio.")
41
+ duracion = max(5, min(60, int(duracion)))
42
+ print(f"Generando: {prompt} | objetivo {duracion}s")
43
+
44
+ device = "cuda" if torch.cuda.is_available() else "cpu"
45
+ modelo.to(device)
46
+
47
+ # --- Pasada 1: generacion inicial solo con texto ---
48
+ base_seg = min(duracion, 30)
49
+ inputs = processor(text=[prompt], padding=True, return_tensors="pt").to(device)
50
+ with torch.no_grad():
51
+ salida = modelo.generate(**inputs, max_new_tokens=min(int(base_seg * 50), MAX_TOKENS))
52
+ audio = _a_numpy(salida)
53
+
54
+ # --- Pasadas de continuacion hasta llegar a la duracion ---
55
+ while len(audio) < int(duracion * SR):
56
+ restante_seg = duracion - len(audio) / SR
57
+ nuevos_seg = min(CHUNK_MAX_SEG, restante_seg + 1) # +1 de margen para el cruce
58
+ nuevos_tokens = int(nuevos_seg * 50)
59
+
60
+ # cogemos la cola como arranque
61
+ cola = audio[-int(CONTEXT_SEG * SR):]
62
+ inputs = processor(
63
+ audio=cola,
64
+ sampling_rate=SR,
65
+ text=[prompt],
66
+ padding=True,
67
+ return_tensors="pt",
68
+ ).to(device)
69
+ with torch.no_grad():
70
+ cont = modelo.generate(**inputs, max_new_tokens=nuevos_tokens)
71
+ cont_audio = _a_numpy(cont)
72
+
73
+ # la salida incluye la cola que le dimos: la quitamos y nos quedamos lo nuevo
74
+ n_prompt = (len(cola) // FRAME) * FRAME
75
+ parte_nueva = cont_audio[n_prompt:]
76
+ if len(parte_nueva) < FRAME: # por si acaso no genero nada nuevo
77
+ break
78
+ audio = _crossfade_join(audio, parte_nueva, SR)
79
+
80
+ audio = audio[: int(duracion * SR)]
81
+
82
+ # --- Limpieza final: normalizar, seguridad, headroom, fade-out ---
83
+ pico = np.max(np.abs(audio))
84
+ if pico > 0:
85
+ audio = audio / pico
86
+ audio = np.clip(audio, -1.0, 1.0) * 0.97
87
+ fade_len = min(len(audio), int(SR * 0.15))
88
+ if fade_len > 0:
89
+ audio[-fade_len:] = audio[-fade_len:] * np.linspace(1.0, 0.0, fade_len)
90
+
91
+ audio = (audio * 32767).astype(np.int16)
92
+ tmp = tempfile.NamedTemporaryFile(suffix=".wav", delete=False)
93
+ scipy.io.wavfile.write(tmp.name, SR, audio)
94
+ print(f"Audio listo ({len(audio)/SR:.1f}s): {tmp.name}")
95
+ return tmp.name
96
+
97
+
98
+ with gr.Blocks(title="Fabrica de Musica") as demo:
99
+ gr.Markdown("# Fabrica de Musica Teshua")
100
+ gr.Markdown("Melodias continuas de hasta 60s con musicgen-medium (el modelo continua la composicion, no la repite).")
101
+ with gr.Row():
102
+ with gr.Column():
103
+ prompt_input = gr.Textbox(label="Prompt en ingles", placeholder="mystical ambient music, spiritual, no vocals", lines=2)
104
+ duracion_input = gr.Slider(label="Duracion segundos", minimum=5, maximum=60, value=30, step=1)
105
+ btn = gr.Button("Generar Musica", variant="primary")
106
+ with gr.Column():
107
+ audio_output = gr.Audio(label="Musica generada", type="filepath")
108
+ btn.click(fn=generar_musica, inputs=[prompt_input, duracion_input], outputs=audio_output, api_name="generar_musica")
109
+
110
+ demo.launch(server_name="0.0.0.0", server_port=7860)