jeysshon commited on
Commit
641a69d
·
verified ·
1 Parent(s): 3da772d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +214 -225
app.py CHANGED
@@ -1,325 +1,314 @@
1
  import gradio as gr
2
- import os
 
3
  import tempfile
 
4
  import subprocess
5
  import sys
6
- import librosa
7
- import soundfile as sf
8
  import numpy as np
9
  from pathlib import Path
10
  import warnings
11
  warnings.filterwarnings("ignore")
12
 
13
- def install_spleeter():
14
- """Instala Spleeter de forma segura"""
15
  try:
16
- # Instalar tensorflow primero
17
- subprocess.check_call([sys.executable, "-m", "pip", "install", "tensorflow==2.13.0", "--quiet"])
18
- # Instalar spleeter
19
- subprocess.check_call([sys.executable, "-m", "pip", "install", "spleeter==2.3.0", "--quiet"])
 
 
 
 
 
 
 
 
 
 
20
  return True
21
  except Exception as e:
22
- print(f"Error instalando: {e}")
23
  return False
24
 
25
- # Intentar importar spleeter
26
- try:
27
- from spleeter.separator import Separator
28
- from spleeter.audio.adapter import AudioAdapter
29
- SPLEETER_AVAILABLE = True
30
- print("✅ Spleeter ya disponible")
31
- except ImportError:
32
- print("⚠️ Instalando Spleeter...")
33
- if install_spleeter():
34
- try:
35
- from spleeter.separator import Separator
36
- from spleeter.audio.adapter import AudioAdapter
37
- SPLEETER_AVAILABLE = True
38
- print("✅ Spleeter instalado correctamente")
39
- except Exception as e:
40
- print(f"❌ Error importando Spleeter: {e}")
41
- SPLEETER_AVAILABLE = False
42
- else:
43
- SPLEETER_AVAILABLE = False
44
-
45
- class SimpleAudioSeparator:
46
  def __init__(self):
47
- self.separator_4stems = None
48
- self.separator_2stems = None
49
- self.audio_adapter = None
50
 
51
- if SPLEETER_AVAILABLE:
52
- try:
53
- print("🤖 Inicializando separadores...")
54
- self.audio_adapter = AudioAdapter.default()
55
- print("✅ Audio adapter listo")
56
- except Exception as e:
57
- print(f"❌ Error inicializando: {e}")
58
-
59
- def load_separator(self, stems_count):
60
- """Carga el separador según el número de stems"""
61
- if not SPLEETER_AVAILABLE:
62
- return False
63
-
64
  try:
65
- if stems_count == 4 and self.separator_4stems is None:
66
- print("🔄 Cargando modelo 4-stems...")
67
- self.separator_4stems = Separator('spleeter:4stems-wq')
68
- print("✅ Modelo 4-stems cargado")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
 
70
- elif stems_count == 2 and self.separator_2stems is None:
71
- print("🔄 Cargando modelo 2-stems...")
72
- self.separator_2stems = Separator('spleeter:2stems-wq')
73
- print("✅ Modelo 2-stems cargado")
 
 
 
 
 
 
 
 
 
 
 
74
 
75
- return True
 
 
 
 
 
 
 
76
  except Exception as e:
77
- print(f"❌ Error cargando separador: {e}")
78
- return False
79
 
80
- def separate_audio(self, audio_path, separation_type="4stems"):
81
- """Separa audio usando Spleeter"""
82
- if not SPLEETER_AVAILABLE:
83
- return [], "❌ Spleeter no está disponible"
84
-
85
  try:
86
- print(f"🎵 Procesando: {audio_path}")
87
-
88
- # Verificar archivo
89
- if not os.path.exists(audio_path):
90
- return [], "❌ Archivo no encontrado"
91
-
92
- # Cargar separador
93
- stems_count = 4 if separation_type == "4stems" else 2
94
- if not self.load_separator(stems_count):
95
- return [], "❌ Error cargando el modelo"
96
-
97
- # Seleccionar separador
98
- separator = self.separator_4stems if stems_count == 4 else self.separator_2stems
99
-
100
- # Cargar audio
101
- print("📂 Cargando audio...")
102
- waveform, sample_rate = self.audio_adapter.load(audio_path, sample_rate=44100)
103
-
104
- # Separar
105
- print(f"⚙️ Separando en {stems_count} stems...")
106
- prediction = separator.separate(waveform)
107
-
108
- # Guardar stems
109
- output_files = []
110
- temp_dir = tempfile.mkdtemp()
111
- print(f"📁 Guardando en: {temp_dir}")
112
-
113
- for stem_name, stem_data in prediction.items():
114
- output_path = os.path.join(temp_dir, f"{stem_name}.wav")
115
 
116
- # Guardar usando soundfile
117
- sf.write(output_path, stem_data, sample_rate)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
 
119
- if os.path.exists(output_path):
120
- output_files.append(output_path)
121
- print(f"✅ {stem_name}.wav guardado")
122
-
123
- success_msg = f"✅ Separación completada: {len(output_files)} stems generados"
124
- print(success_msg)
125
-
126
- return output_files, success_msg
127
-
128
  except Exception as e:
129
- error_msg = f"❌ Error durante la separación: {str(e)}"
130
- print(error_msg)
131
- return [], error_msg
132
 
133
- # Inicializar separador
134
- print("🚀 Inicializando Audio Separator...")
135
- separator = SimpleAudioSeparator()
136
 
137
- def process_audio(audio_file, separation_type, progress=gr.Progress()):
138
- """Función principal para procesar audio"""
139
  if audio_file is None:
140
- return [], "⚠️ Por favor, sube un archivo de audio", "Ningún archivo seleccionado"
141
 
142
  # Verificar tamaño
143
  try:
144
- file_size = os.path.getsize(audio_file) / 1024 / 1024 # MB
145
- if file_size > 20:
146
- return [], "❌ Archivo muy grande. Máximo 20MB", f"Archivo: {file_size:.1f}MB"
147
  except:
148
- return [], "❌ Error leyendo el archivo", "Error de archivo"
 
 
149
 
150
- # Información del tipo de separación
151
- separation_info = {
152
- "4stems": "🎵 4 Stems: Separa en Voces, Batería, Bajo, Otros",
153
- "2stems": "🎤 2 Stems: Separa en Voces e Instrumental"
 
154
  }
155
 
156
- info_text = separation_info.get(separation_type, "Separación desconocida")
157
 
158
- # Mostrar progreso
159
- progress(0.1, desc="Iniciando separación...")
160
- progress(0.3, desc="Cargando modelo IA...")
161
 
162
- # Separar audio
163
- output_files, status = separator.separate_audio(audio_file, separation_type)
 
 
 
 
 
164
 
165
  progress(1.0, desc="¡Completado!")
166
 
167
- return output_files, status, info_text
168
 
169
- def get_audio_info(audio_file):
170
- """Obtiene información básica del audio"""
171
- if audio_file is None:
172
- return "Ningún archivo seleccionado"
173
-
174
  try:
175
- # Cargar solo para obtener info
176
- y, sr = librosa.load(audio_file, duration=1) # Solo 1 segundo para info
177
- duration = librosa.get_duration(path=audio_file)
178
-
179
- file_size = os.path.getsize(audio_file) / 1024 / 1024
180
-
181
- return f"""
182
- 📊 **Info del archivo:**
183
- ⏱️ Duración: {duration/60:.1f} minutos
184
- 📏 Tamaño: {file_size:.1f} MB
185
- 🎵 Sample Rate: {sr} Hz
186
- """
187
  except:
188
- return "No se pudo analizar el archivo"
189
 
190
  # Crear interfaz
191
- def create_interface():
 
 
 
192
  with gr.Blocks(
193
- title="🎵 Audio Separator - Spleeter",
194
  theme=gr.themes.Soft(),
195
  css="""
196
  .gradio-container { max-width: 1200px !important; }
197
- .info-box {
198
  background: linear-gradient(45deg, #667eea 0%, #764ba2 100%);
199
- color: white; padding: 15px; border-radius: 10px; margin: 10px 0;
200
- }
201
- .success-box {
202
- background: linear-gradient(45deg, #56ab2f 0%, #a8e6cf 100%);
203
- padding: 15px; border-radius: 10px;
204
  }
 
 
205
  """
206
  ) as demo:
207
 
 
 
 
 
 
 
 
 
208
  gr.Markdown("""
209
- # 🎵 Audio Separator Pro (Spleeter)
210
 
211
- **Separa canciones como Moises - 100% GRATIS**
212
 
213
- 🚀 **Tecnología**: Spleeter (Deezer AI) - El mismo que usa Moises
 
 
 
 
214
 
215
- 🎯 **Opciones de separación:**
216
- - 🎵 **4 Stems**: Voces, Batería, Bajo, Otros instrumentos
217
- - 🎤 **2 Stems**: Voces e Instrumental (karaoke)
218
  """)
219
 
220
  with gr.Row():
221
  with gr.Column(scale=2):
222
  audio_input = gr.Audio(
223
- label="🎵 Sube tu archivo de audio (máx 20MB)",
224
  type="filepath",
225
  sources=["upload"]
226
  )
227
 
228
- separation_type = gr.Radio(
229
- label="🎛️ Tipo de Separación",
230
- choices=[
231
- ("🎵 4 Stems (Voces, Batería, Bajo, Otros)", "4stems"),
232
- ("🎤 2 Stems (Voces, Instrumental)", "2stems")
233
- ],
234
- value="4stems"
235
- )
 
 
 
 
 
 
 
236
 
237
  process_btn = gr.Button(
238
- "🚀 Separar Audio",
239
  variant="primary",
240
  size="lg"
241
  )
242
 
243
- with gr.Column(scale=1):
244
- audio_info = gr.Markdown(
245
- "📊 Sube un archivo para ver información",
246
- elem_classes=["info-box"]
247
- )
248
 
249
- separation_info = gr.Markdown(
250
- "🎵 4 Stems: Separa en Voces, Batería, Bajo, Otros",
251
- elem_classes=["info-box"]
 
252
  )
253
 
254
  status_output = gr.Textbox(
255
  label="📊 Estado",
256
  interactive=False,
257
- lines=3
258
  )
259
 
260
  download_files = gr.File(
261
- label="📥 Descargar Stems Separados",
262
- file_count="multiple",
263
- interactive=False
264
  )
265
 
266
- # Comparación y consejos
267
  gr.Markdown("""
268
- ### 🆚 **vs Moises:**
269
 
270
- | Característica | **Nuestro Separador** | **Moises Gratuito** | **Moises Premium** |
271
- |----------------|----------------------|---------------------|-------------------|
272
- | **4 Stems** | Ilimitado | 5/mes | Ilimitado |
273
- | **Calidad** | Profesional | Buena | Profesional |
274
- | **Velocidad** | 2-5 min | 2-5 min | 1-3 min |
275
- | **Límites** | Solo tamaño archivo | 5 canciones/mes | ✅ Sin límites |
276
- | **Costo** | 🆓 **GRATIS** | 🆓 Muy limitado | 💰 **$24.99/mes** |
277
 
278
- ### 💡 **Consejos:**
279
- - 🎵 **Formatos**: MP3, WAV, FLAC, M4A, OGG
280
- - ⚡ **Velocidad**: 2-5 minutos por canción en CPU
281
- - 🎧 **Mejor calidad**: Archivos WAV o FLAC de alta calidad
282
- - 📱 **Tamaño máximo**: 20MB por archivo
283
- - 🎯 **Uso**: Karaoke, remixes, aprendizaje musical
284
-
285
- ### 🎼 **Resultados esperados:**
286
- - **Voces**: Limpias para karaoke o acapella
287
- - **Batería**: Perfecta para beats y loops
288
- - **Bajo**: Ideal para líneas de bajo aisladas
289
- - **Otros**: Melodías e instrumentos restantes
290
  """)
291
 
292
  # Event handlers
293
- audio_input.change(
294
- fn=get_audio_info,
295
- inputs=[audio_input],
296
- outputs=[audio_info]
297
- )
298
-
299
- separation_type.change(
300
- fn=lambda sep_type: {
301
- "4stems": "🎵 4 Stems: Separa en Voces, Batería, Bajo, Otros",
302
- "2stems": "🎤 2 Stems: Separa en Voces e Instrumental"
303
- }.get(sep_type),
304
- inputs=[separation_type],
305
- outputs=[separation_info]
306
  )
307
 
308
  process_btn.click(
309
- fn=process_audio,
310
- inputs=[audio_input, separation_type],
311
- outputs=[download_files, status_output, separation_info],
312
  show_progress=True
313
  )
 
 
 
 
 
 
314
 
315
  return demo
316
 
317
- # Estado del sistema
318
- if SPLEETER_AVAILABLE:
319
- print("✅ Sistema listo para separar audio!")
320
- else:
321
- print("❌ Spleeter no disponible. Reinicia el Space.")
322
-
323
  if __name__ == "__main__":
324
- demo = create_interface()
325
  demo.launch()
 
1
  import gradio as gr
2
+ import torch
3
+ import torchaudio
4
  import tempfile
5
+ import os
6
  import subprocess
7
  import sys
 
 
8
  import numpy as np
9
  from pathlib import Path
10
  import warnings
11
  warnings.filterwarnings("ignore")
12
 
13
+ def install_demucs_properly():
14
+ """Instala demucs de la forma correcta para HF"""
15
  try:
16
+ # Instalar dependencias una por una
17
+ print("📦 Instalando PyTorch...")
18
+ subprocess.check_call([sys.executable, "-m", "pip", "install", "torch", "torchaudio", "--quiet"])
19
+
20
+ print("📦 Instalando dependencias de audio...")
21
+ subprocess.check_call([sys.executable, "-m", "pip", "install", "julius", "--quiet"])
22
+ subprocess.check_call([sys.executable, "-m", "pip", "install", "openunmix", "--quiet"])
23
+
24
+ print("📦 Instalando Demucs...")
25
+ subprocess.check_call([sys.executable, "-m", "pip", "install", "demucs", "--quiet", "--no-deps"])
26
+
27
+ # Instalar dependencias restantes
28
+ subprocess.check_call([sys.executable, "-m", "pip", "install", "hydra-core", "omegaconf", "--quiet"])
29
+
30
  return True
31
  except Exception as e:
32
+ print(f"Error en instalación: {e}")
33
  return False
34
 
35
+ # Intentar usar demucs directamente con subprocess
36
+ class DemucsWrapper:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  def __init__(self):
38
+ self.device = "cuda" if torch.cuda.is_available() else "cpu"
39
+ self.models_available = ["htdemucs", "htdemucs_ft", "mdx_extra"]
40
+ print(f"🔧 Dispositivo: {self.device}")
41
 
42
+ def separate_with_subprocess(self, audio_path, model="htdemucs"):
43
+ """Usa demucs vía subprocess (método más estable)"""
 
 
 
 
 
 
 
 
 
 
 
44
  try:
45
+ # Crear directorio temporal
46
+ output_dir = tempfile.mkdtemp()
47
+ print(f"📁 Directorio de salida: {output_dir}")
48
+
49
+ # Comando demucs
50
+ cmd = [
51
+ sys.executable, "-m", "demucs.separate",
52
+ audio_path,
53
+ "-n", model,
54
+ "-o", output_dir,
55
+ "--device", self.device
56
+ ]
57
+
58
+ print(f"🚀 Ejecutando: {' '.join(cmd)}")
59
+
60
+ # Ejecutar comando
61
+ result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
62
+
63
+ if result.returncode == 0:
64
+ print("✅ Demucs ejecutado exitosamente")
65
 
66
+ # Buscar archivos de salida
67
+ model_dir = os.path.join(output_dir, model)
68
+ if os.path.exists(model_dir):
69
+ song_dirs = [d for d in os.listdir(model_dir) if os.path.isdir(os.path.join(model_dir, d))]
70
+ if song_dirs:
71
+ song_dir = os.path.join(model_dir, song_dirs[0])
72
+ output_files = []
73
+
74
+ for file in os.listdir(song_dir):
75
+ if file.endswith('.wav'):
76
+ file_path = os.path.join(song_dir, file)
77
+ output_files.append(file_path)
78
+ print(f"✅ Encontrado: {file}")
79
+
80
+ return output_files, f"✅ Separación completada: {len(output_files)} stems"
81
 
82
+ return [], "❌ No se encontraron archivos de salida"
83
+ else:
84
+ error_msg = result.stderr if result.stderr else "Error desconocido"
85
+ print(f"❌ Error en demucs: {error_msg}")
86
+ return [], f"❌ Error: {error_msg[:100]}..."
87
+
88
+ except subprocess.TimeoutExpired:
89
+ return [], "❌ Timeout: El procesamiento tomó demasiado tiempo"
90
  except Exception as e:
91
+ return [], f"❌ Error inesperado: {str(e)}"
 
92
 
93
+ def separate_manual(self, audio_path, model="htdemucs"):
94
+ """Método manual si subprocess falla"""
 
 
 
95
  try:
96
+ # Intentar importar demucs directamente
97
+ try:
98
+ from demucs.api import Separator
99
+ separator = Separator(model=model, device=self.device)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
101
+ print("🎵 Separando con API directa...")
102
+ waveform, sources = separator.separate_audio_file(audio_path)
103
+
104
+ # Guardar archivos
105
+ output_files = []
106
+ temp_dir = tempfile.mkdtemp()
107
+ stem_names = ["drums", "bass", "other", "vocals"]
108
+
109
+ for i, stem_name in enumerate(stem_names):
110
+ if i < len(sources):
111
+ output_path = os.path.join(temp_dir, f"{stem_name}.wav")
112
+ torchaudio.save(output_path, sources[i], separator.samplerate)
113
+ output_files.append(output_path)
114
+ print(f"✅ {stem_name}.wav guardado")
115
+
116
+ return output_files, f"✅ Separación completada: {len(output_files)} stems"
117
+
118
+ except ImportError:
119
+ return [], "❌ Demucs no está instalado correctamente"
120
 
 
 
 
 
 
 
 
 
 
121
  except Exception as e:
122
+ return [], f"❌ Error en separación manual: {str(e)}"
 
 
123
 
124
+ # Inicializar wrapper
125
+ print("🚀 Inicializando Demucs Wrapper...")
126
+ demucs = DemucsWrapper()
127
 
128
+ def process_audio_demucs(audio_file, model_choice, use_subprocess, progress=gr.Progress()):
129
+ """Función principal para procesar con Demucs"""
130
  if audio_file is None:
131
+ return [], "⚠️ Por favor, sube un archivo de audio", ""
132
 
133
  # Verificar tamaño
134
  try:
135
+ file_size = os.path.getsize(audio_file) / 1024 / 1024
136
+ if file_size > 25:
137
+ return [], f"❌ Archivo muy grande: {file_size:.1f}MB. Máximo 25MB", ""
138
  except:
139
+ return [], "❌ Error leyendo archivo", ""
140
+
141
+ progress(0.1, desc="Iniciando Demucs...")
142
 
143
+ # Información del modelo
144
+ model_info = {
145
+ "htdemucs": "🏆 Hybrid Transformer: Mejor calidad general",
146
+ "htdemucs_ft": "🥇 Fine-tuned: Estado del arte",
147
+ "mdx_extra": "🎤 MDX Extra: Especializado en voces"
148
  }
149
 
150
+ info = model_info.get(model_choice, "Modelo desconocido")
151
 
152
+ progress(0.3, desc=f"Cargando modelo {model_choice}...")
 
 
153
 
154
+ # Intentar separación
155
+ if use_subprocess:
156
+ print("🔄 Usando método subprocess...")
157
+ output_files, status = demucs.separate_with_subprocess(audio_file, model_choice)
158
+ else:
159
+ print("🔄 Usando método directo...")
160
+ output_files, status = demucs.separate_manual(audio_file, model_choice)
161
 
162
  progress(1.0, desc="¡Completado!")
163
 
164
+ return output_files, status, info
165
 
166
+ def check_demucs_installation():
167
+ """Verifica si demucs está instalado"""
 
 
 
168
  try:
169
+ result = subprocess.run([sys.executable, "-m", "demucs.separate", "--help"],
170
+ capture_output=True, timeout=10)
171
+ return result.returncode == 0
 
 
 
 
 
 
 
 
 
172
  except:
173
+ return False
174
 
175
  # Crear interfaz
176
+ def create_demucs_interface():
177
+ # Verificar instalación
178
+ demucs_installed = check_demucs_installation()
179
+
180
  with gr.Blocks(
181
+ title="🎵 Demucs Audio Separator",
182
  theme=gr.themes.Soft(),
183
  css="""
184
  .gradio-container { max-width: 1200px !important; }
185
+ .model-info {
186
  background: linear-gradient(45deg, #667eea 0%, #764ba2 100%);
187
+ color: white; padding: 15px; border-radius: 10px;
 
 
 
 
188
  }
189
+ .status-error { background-color: #ff6b6b; color: white; }
190
+ .status-success { background-color: #51cf66; color: white; }
191
  """
192
  ) as demo:
193
 
194
+ if not demucs_installed:
195
+ gr.Markdown("""
196
+ # ⚠️ Demucs Installation Required
197
+
198
+ Demucs is not installed. The Space will attempt to install it on first use.
199
+ This may take several minutes.
200
+ """)
201
+
202
  gr.Markdown("""
203
+ # 🎵 Demucs Audio Separator
204
 
205
+ **El separador más avanzado - Tecnología de Facebook/Meta**
206
 
207
+ 🧠 **Demucs v4**: Estado del arte en separación de audio
208
+ - 🥁 **Batería** - Elementos percusivos limpios
209
+ - 🎸 **Bajo** - Líneas de bajo precisas
210
+ - 🎵 **Otros** - Melodías e instrumentos
211
+ - 🎤 **Voces** - Voces cristalinas
212
 
213
+ **Superior a Moises**: Mejor tecnología, 100% gratis
 
 
214
  """)
215
 
216
  with gr.Row():
217
  with gr.Column(scale=2):
218
  audio_input = gr.Audio(
219
+ label="🎵 Sube tu archivo (máx 25MB)",
220
  type="filepath",
221
  sources=["upload"]
222
  )
223
 
224
+ with gr.Row():
225
+ model_choice = gr.Dropdown(
226
+ label="🤖 Modelo Demucs",
227
+ choices=[
228
+ ("🏆 Hybrid Transformer (Recomendado)", "htdemucs"),
229
+ ("🥇 Fine-tuned (Mejor calidad)", "htdemucs_ft"),
230
+ ("🎤 MDX Extra (Voces)", "mdx_extra")
231
+ ],
232
+ value="htdemucs"
233
+ )
234
+
235
+ use_subprocess = gr.Checkbox(
236
+ label="🔧 Usar método subprocess (más estable)",
237
+ value=True
238
+ )
239
 
240
  process_btn = gr.Button(
241
+ "🚀 Separar con Demucs",
242
  variant="primary",
243
  size="lg"
244
  )
245
 
246
+ if not demucs_installed:
247
+ install_btn = gr.Button(
248
+ "📦 Instalar Demucs",
249
+ variant="secondary"
250
+ )
251
 
252
+ with gr.Column(scale=1):
253
+ model_info = gr.Markdown(
254
+ "🏆 Hybrid Transformer: Mejor calidad general",
255
+ elem_classes=["model-info"]
256
  )
257
 
258
  status_output = gr.Textbox(
259
  label="📊 Estado",
260
  interactive=False,
261
+ lines=4
262
  )
263
 
264
  download_files = gr.File(
265
+ label="📥 Descargar Stems de Demucs",
266
+ file_count="multiple"
 
267
  )
268
 
 
269
  gr.Markdown("""
270
+ ### 🏆 **¿Por qué Demucs es superior?**
271
 
272
+ | Característica | **Demucs v4** | **Spleeter** | **Moises** |
273
+ |----------------|---------------|---------------|------------|
274
+ | **Tecnología** | 🧠 Transformer Híbrido | 🤖 U-Net básico | 🤖 Spleeter |
275
+ | **Calidad SDR** | 🥇 9.0+ dB | 🥉 6.5 dB | 🥈 7.5 dB |
276
+ | **Desarrollador** | 🏢 Facebook/Meta | 🎵 Deezer | 🎵 Moises |
277
+ | **Costo** | 🆓 **GRATIS** | 🆓 Gratis | 💰 $24.99/mes |
 
278
 
279
+ ### 💡 **Consejos Demucs:**
280
+ - 🎵 **Mejor con**: Música moderna, bien producida
281
+ - ⚡ **Tiempo**: 3-8 minutos en CPU, 1-2 min en GPU
282
+ - 🎧 **Calidad óptima**: WAV o FLAC de alta calidad
283
+ - 🔧 **Si falla**: Prueba modo subprocess
 
 
 
 
 
 
 
284
  """)
285
 
286
  # Event handlers
287
+ model_choice.change(
288
+ fn=lambda model: {
289
+ "htdemucs": "🏆 Hybrid Transformer: Mejor calidad general",
290
+ "htdemucs_ft": "🥇 Fine-tuned: Estado del arte",
291
+ "mdx_extra": "🎤 MDX Extra: Especializado en voces"
292
+ }.get(model, ""),
293
+ inputs=[model_choice],
294
+ outputs=[model_info]
 
 
 
 
 
295
  )
296
 
297
  process_btn.click(
298
+ fn=process_audio_demucs,
299
+ inputs=[audio_input, model_choice, use_subprocess],
300
+ outputs=[download_files, status_output, model_info],
301
  show_progress=True
302
  )
303
+
304
+ if not demucs_installed:
305
+ install_btn.click(
306
+ fn=lambda: ("Instalando Demucs..." if install_demucs_properly() else "Error en instalación"),
307
+ outputs=[status_output]
308
+ )
309
 
310
  return demo
311
 
 
 
 
 
 
 
312
  if __name__ == "__main__":
313
+ demo = create_demucs_interface()
314
  demo.launch()