dimensionalpulsar commited on
Commit
e940250
·
verified ·
1 Parent(s): 969158e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +73 -265
app.py CHANGED
@@ -1,20 +1,12 @@
1
- """
2
- Clone Vocal - Outil web de clonage vocal base sur Seed-VC (zero-shot).
3
- Interface Gradio en francais, deploye sur HuggingFace Spaces avec ZeroGPU.
4
- """
5
-
6
  import os
7
  import sys
8
  import logging
9
  import tempfile
10
  import shutil
11
-
12
  import gradio as gr
13
 
14
- # Monkey-patch gradio_client to fix "argument of type 'bool' is not iterable"
15
  try:
16
  import gradio_client.utils as _gc_utils
17
-
18
  _orig_get_type = _gc_utils.get_type
19
 
20
  def _patched_get_type(schema, *args, **kwargs):
@@ -23,7 +15,6 @@ try:
23
  return _orig_get_type(schema, *args, **kwargs)
24
 
25
  _gc_utils.get_type = _patched_get_type
26
-
27
  _orig_json_schema = _gc_utils._json_schema_to_python_type
28
 
29
  def _patched_json_schema(schema, *args, **kwargs):
@@ -38,12 +29,9 @@ try:
38
  except Exception:
39
  pass
40
 
41
- # Setup logging
42
  logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
43
- logger = logging.getLogger(__name__)
44
-
45
- # Startup: clone Seed-VC
46
- logger.info("Initialisation de l'application...")
47
 
48
  from pipeline.setup import setup_seed_vc
49
  from pipeline.storage import init_storage, list_models, download_model, delete_model, get_reference_path
@@ -51,29 +39,23 @@ from pipeline.storage import init_storage, list_models, download_model, delete_m
51
  try:
52
  setup_seed_vc()
53
  except Exception as e:
54
- logger.error("Erreur lors du setup: {}".format(e))
55
 
56
- # Initialize model storage
57
  HF_MODELS_REPO = os.environ.get("HF_MODELS_REPO", "")
58
  if HF_MODELS_REPO:
59
  init_storage(HF_MODELS_REPO)
60
- logger.info("Stockage HuggingFace configure: {}".format(HF_MODELS_REPO))
61
 
62
- # Import GPU-decorated functions for ZeroGPU detection
63
  from pipeline.training import save_voice_reference, _gpu_warmup
64
  from pipeline.separation import separate_audio
65
  from pipeline.inference import convert_voice
66
 
67
-
68
- # -- Training Tab --
69
-
70
  def train_voice_model(audio_file, model_name, progress=gr.Progress()):
71
- """Handler: save voice reference."""
72
  if audio_file is None:
73
- return "Erreur : Veuillez uploader un fichier audio.", None
74
 
75
  if not model_name or not model_name.strip():
76
- return "Erreur : Veuillez entrer un nom pour le modele.", None
77
 
78
  model_name = model_name.strip().replace(" ", "_")
79
 
@@ -81,34 +63,28 @@ def train_voice_model(audio_file, model_name, progress=gr.Progress()):
81
  progress(value, desc=desc)
82
 
83
  try:
84
- progress(0.0, desc="Demarrage...")
85
  pth_path, ref_path = save_voice_reference(
86
  audio_path=audio_file,
87
  model_name=model_name,
88
  progress_callback=progress_callback,
89
  )
90
-
91
- return "Reference vocale '{}' sauvegardee avec succes !".format(model_name), ref_path
92
 
93
  except Exception as e:
94
  import traceback
95
  tb = traceback.format_exc()
96
- logger.error("Erreur training: {}".format(tb))
97
- return "Erreur : {}: {}\n\nDetails:\n{}".format(
98
  type(e).__name__, str(e), tb[-500:]
99
  ), None
100
 
101
-
102
- # -- Conversion Tab --
103
-
104
  def get_model_choices():
105
- """Get list of trained model names for dropdown."""
106
  models = list_models()
107
  if not models:
108
- return ["(aucun modele)"]
109
  return models
110
 
111
-
112
  def convert_song(
113
  model_choice,
114
  song_file,
@@ -119,34 +95,29 @@ def convert_song(
119
  instrumental_volume,
120
  progress=gr.Progress(),
121
  ):
122
- """Full pipeline: separate + convert + mix."""
123
  if song_file is None:
124
- return "Erreur : Veuillez uploader un fichier audio.", None, None, None
125
 
126
- if model_choice == "(aucun modele)" or not model_choice:
127
- return "Erreur : Veuillez d'abord enregistrer une reference vocale.", None, None, None
128
 
129
  from pipeline.mixing import mix_audio
130
 
131
  try:
132
- # Step 1: Download model / find reference audio
133
- progress(0.05, desc="Chargement du modele...")
134
  pth_path, ref_or_index = download_model(model_choice)
135
  if not pth_path:
136
- return "Erreur : Modele '{}' introuvable.".format(model_choice), None, None, None
137
 
138
- # Find the reference audio path
139
  reference_path = get_reference_path(model_choice)
140
  if not reference_path:
141
- return "Erreur : Audio de reference introuvable pour '{}'.".format(model_choice), None, None, None
142
 
143
- # Step 2: Separate vocals from instruments
144
- progress(0.10, desc="Separation des pistes (Demucs)...")
145
  vocals_path, instruments_path = separate_audio(song_file)
146
 
147
- progress(0.40, desc="Conversion vocale (Seed-VC)...")
148
 
149
- # Step 3: Convert vocals with Seed-VC
150
  converted_path = convert_voice(
151
  audio_path=vocals_path,
152
  reference_path=reference_path,
@@ -155,9 +126,8 @@ def convert_song(
155
  similarity=float(similarity),
156
  )
157
 
158
- progress(0.85, desc="Mixage final...")
159
 
160
- # Step 4: Mix converted vocals with instruments
161
  final_path = mix_audio(
162
  vocals_path=converted_path,
163
  instruments_path=instruments_path,
@@ -165,10 +135,10 @@ def convert_song(
165
  instrumental_volume=float(instrumental_volume),
166
  )
167
 
168
- progress(1.0, desc="Termine !")
169
 
170
  return (
171
- "Conversion terminee avec succes !",
172
  vocals_path,
173
  converted_path,
174
  final_path,
@@ -177,104 +147,48 @@ def convert_song(
177
  except Exception as e:
178
  import traceback
179
  tb = traceback.format_exc()
180
- logger.error("Erreur conversion: {}".format(tb))
181
- return "Erreur : {}: {}\n\nDetails:\n{}".format(
182
  type(e).__name__, str(e), tb[-500:]
183
  ), None, None, None
184
 
185
-
186
- # -- Models Tab --
187
-
188
  def refresh_models():
189
- """Refresh the model list as HTML."""
190
  models = list_models()
191
  if not models:
192
- return "<p style='color:gray;'>Aucun modele enregistre</p>"
193
  rows = "".join(
194
- "<tr><td>{}</td><td>Disponible</td></tr>".format(m) for m in models
195
- )
196
- return (
197
- "<table style='width:100%;border-collapse:collapse;'>"
198
- "<tr><th style='text-align:left;border-bottom:1px solid #555;padding:8px;'>Nom</th>"
199
- "<th style='text-align:left;border-bottom:1px solid #555;padding:8px;'>Statut</th></tr>"
200
- "{}</table>".format(rows)
201
  )
202
-
203
 
204
  def delete_selected_model(model_name_to_delete):
205
- """Delete a model."""
206
- if not model_name_to_delete or model_name_to_delete == "(aucun modele)":
207
- return "Veuillez selectionner un modele a supprimer.", refresh_models()
208
  try:
209
  delete_model(model_name_to_delete)
210
- return "Modele '{}' supprime.".format(model_name_to_delete), refresh_models()
211
  except Exception as e:
212
- return "Erreur : {}".format(e), refresh_models()
213
-
214
-
215
- # -- Build Gradio UI --
216
 
217
  DESCRIPTION = """
218
- # Clone Vocal
219
-
220
- Outil de clonage vocal **zero-shot** base sur **Seed-VC** (Diffusion Transformer).
221
-
222
- **Comment utiliser :**
223
- 1. **Onglet "Ma voix"** : Uploadez un court extrait de votre voix (3-30 sec) pour creer votre profil vocal
224
- 2. **Onglet "Convertir"** : Uploadez un morceau de musique, l'outil remplace la voix par la votre
225
- 3. **Onglet "Modeles"** : Gerez vos profils vocaux
226
-
227
- > **Zero-shot** : pas d'entrainement necessaire ! Juste 3-30 secondes de votre voix suffisent.
228
  """
229
 
230
- with gr.Blocks(
231
- title="Clone Vocal",
232
- theme=gr.themes.Soft(),
233
- ) as app:
234
-
235
  gr.Markdown(DESCRIPTION)
236
 
237
  with gr.Tabs():
238
- # Tab 1: Voice Reference
239
- with gr.TabItem("Ma voix"):
240
- gr.Markdown("### Enregistrer votre reference vocale")
241
-
242
  with gr.Row():
243
  with gr.Column(scale=2):
244
- train_audio = gr.Audio(
245
- label="Extrait de votre voix (WAV ou MP3, 3-30 secondes)",
246
- type="filepath",
247
- sources=["upload"],
248
- )
249
- train_model_name = gr.Textbox(
250
- label="Nom du profil",
251
- placeholder="ex: ma_voix",
252
- max_lines=1,
253
- )
254
- train_btn = gr.Button(
255
- "Sauvegarder",
256
- variant="primary",
257
- size="lg",
258
- )
259
-
260
  with gr.Column(scale=1):
261
- train_status = gr.Textbox(
262
- label="Statut",
263
- interactive=False,
264
- lines=3,
265
- )
266
- train_download = gr.File(
267
- label="Fichier de reference",
268
- interactive=False,
269
- )
270
-
271
- gr.Markdown(
272
- "**Conseils :**\n"
273
- "- Utilisez un enregistrement propre (pas de bruit de fond, pas de musique)\n"
274
- "- Parlez ou chantez naturellement pendant 3 a 30 secondes\n"
275
- "- Plus l'extrait est long et varie, meilleur sera le resultat\n"
276
- "- Format WAV ou MP3 accepte"
277
- )
278
 
279
  train_btn.click(
280
  fn=train_voice_model,
@@ -282,161 +196,55 @@ with gr.Blocks(
282
  outputs=[train_status, train_download],
283
  )
284
 
285
- # Tab 2: Conversion
286
- with gr.TabItem("Convertir un morceau"):
287
- gr.Markdown("### Remplacer la voix d'un morceau par la votre")
288
-
289
  with gr.Row():
290
  with gr.Column(scale=2):
291
- convert_model = gr.Dropdown(
292
- choices=get_model_choices(),
293
- label="Profil vocal",
294
- interactive=True,
295
- )
296
- refresh_btn = gr.Button("Rafraichir la liste", size="sm")
297
- convert_audio = gr.Audio(
298
- label="Morceau a convertir (WAV ou MP3)",
299
- type="filepath",
300
- sources=["upload"],
301
- )
302
-
303
- with gr.Accordion("Parametres avances", open=False):
304
- convert_pitch = gr.Slider(
305
- minimum=-24,
306
- maximum=24,
307
- value=0,
308
- step=1,
309
- label="Transposition (demi-tons)",
310
- )
311
- convert_similarity = gr.Slider(
312
- minimum=0.0,
313
- maximum=1.0,
314
- value=0.7,
315
- step=0.05,
316
- label="Similarite vocale (0.5=naturel, 0.7=equilibre, 0.9=plus fidele)",
317
- )
318
- convert_diffusion = gr.Slider(
319
- minimum=5,
320
- maximum=100,
321
- value=25,
322
- step=5,
323
- label="Qualite (10=rapide, 25=equilibre, 50=haute qualite)",
324
- )
325
- convert_vocal_vol = gr.Slider(
326
- minimum=0.0,
327
- maximum=2.0,
328
- value=1.0,
329
- step=0.1,
330
- label="Volume de la voix",
331
- )
332
- convert_inst_vol = gr.Slider(
333
- minimum=0.0,
334
- maximum=2.0,
335
- value=1.0,
336
- step=0.1,
337
- label="Volume des instruments",
338
- )
339
-
340
- convert_btn = gr.Button(
341
- "Convertir et mixer",
342
- variant="primary",
343
- size="lg",
344
- )
345
 
346
  with gr.Column(scale=1):
347
- convert_status = gr.Textbox(
348
- label="Statut",
349
- interactive=False,
350
- lines=3,
351
- )
352
- gr.Markdown("**Apercu des pistes :**")
353
- preview_vocals = gr.Audio(
354
- label="Voix originale (separee)",
355
- interactive=False,
356
- )
357
- preview_converted = gr.Audio(
358
- label="Voix convertie",
359
- interactive=False,
360
- )
361
- gr.Markdown("**Resultat final :**")
362
- final_output = gr.Audio(
363
- label="Morceau final (voix + instruments)",
364
- interactive=False,
365
- )
366
-
367
- refresh_btn.click(
368
- fn=lambda: gr.Dropdown(choices=get_model_choices()),
369
- outputs=[convert_model],
370
- )
371
 
 
372
  convert_btn.click(
373
  fn=convert_song,
374
- inputs=[
375
- convert_model,
376
- convert_audio,
377
- convert_pitch,
378
- convert_similarity,
379
- convert_diffusion,
380
- convert_vocal_vol,
381
- convert_inst_vol,
382
- ],
383
  outputs=[convert_status, preview_vocals, preview_converted, final_output],
384
  )
385
 
386
- # Tab 3: Models
387
- with gr.TabItem("Mes modeles"):
388
- gr.Markdown("### Gerer vos profils vocaux")
389
-
390
- models_table = gr.HTML(
391
- value=refresh_models(),
392
- label="Modeles enregistres",
393
- )
394
-
395
  with gr.Row():
396
- models_refresh_btn = gr.Button("Rafraichir", size="sm")
397
- models_delete_name = gr.Dropdown(
398
- choices=get_model_choices(),
399
- label="Modele a supprimer",
400
- interactive=True,
401
- )
402
- models_delete_btn = gr.Button("Supprimer", variant="stop", size="sm")
403
-
404
- models_delete_status = gr.Textbox(label="Statut", interactive=False)
405
-
406
- models_refresh_btn.click(
407
- fn=refresh_models,
408
- outputs=[models_table],
409
- )
410
- models_refresh_btn.click(
411
- fn=lambda: gr.Dropdown(choices=get_model_choices()),
412
- outputs=[models_delete_name],
413
- )
414
 
415
- models_delete_btn.click(
416
- fn=delete_selected_model,
417
- inputs=[models_delete_name],
418
- outputs=[models_delete_status, models_table],
419
- )
420
 
421
- # Tab 4: Debug (temporary)
422
- with gr.TabItem("Debug GPU"):
423
- gr.Markdown("### Logs GPU Worker (pour diagnostic)")
424
- debug_output = gr.Textbox(
425
- label="Derniers logs GPU",
426
- interactive=False,
427
- lines=20,
428
- )
429
- debug_btn = gr.Button("Lire les logs", size="sm")
430
 
431
  def read_debug_log():
432
  log_path = "/home/user/app/debug_gpu.log"
433
- if os.path.exists(log_path):
434
- with open(log_path, "r") as f:
435
- return f.read()
436
- return "Aucun log disponible. Lancez d'abord une conversion."
437
 
438
  debug_btn.click(fn=read_debug_log, outputs=[debug_output])
439
 
440
-
441
  if __name__ == "__main__":
442
- app.launch(server_name="0.0.0.0")
 
 
 
 
 
 
1
  import os
2
  import sys
3
  import logging
4
  import tempfile
5
  import shutil
 
6
  import gradio as gr
7
 
 
8
  try:
9
  import gradio_client.utils as _gc_utils
 
10
  _orig_get_type = _gc_utils.get_type
11
 
12
  def _patched_get_type(schema, *args, **kwargs):
 
15
  return _orig_get_type(schema, *args, **kwargs)
16
 
17
  _gc_utils.get_type = _patched_get_type
 
18
  _orig_json_schema = _gc_utils._json_schema_to_python_type
19
 
20
  def _patched_json_schema(schema, *args, **kwargs):
 
29
  except Exception:
30
  pass
31
 
 
32
  logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
33
+ logger = logging.getLogger(__name__) # Corregido: usualmente es __name__
34
+ logger.info("Inicializando la aplicación...")
 
 
35
 
36
  from pipeline.setup import setup_seed_vc
37
  from pipeline.storage import init_storage, list_models, download_model, delete_model, get_reference_path
 
39
  try:
40
  setup_seed_vc()
41
  except Exception as e:
42
+ logger.error("Error durante la configuración: {}".format(e))
43
 
 
44
  HF_MODELS_REPO = os.environ.get("HF_MODELS_REPO", "")
45
  if HF_MODELS_REPO:
46
  init_storage(HF_MODELS_REPO)
47
+ logger.info("Almacenamiento HuggingFace configurado: {}".format(HF_MODELS_REPO))
48
 
 
49
  from pipeline.training import save_voice_reference, _gpu_warmup
50
  from pipeline.separation import separate_audio
51
  from pipeline.inference import convert_voice
52
 
 
 
 
53
  def train_voice_model(audio_file, model_name, progress=gr.Progress()):
 
54
  if audio_file is None:
55
+ return "Error: Por favor suba un archivo de audio.", None
56
 
57
  if not model_name or not model_name.strip():
58
+ return "Error: Por favor ingrese un nombre para el modelo.", None
59
 
60
  model_name = model_name.strip().replace(" ", "_")
61
 
 
63
  progress(value, desc=desc)
64
 
65
  try:
66
+ progress(0.0, desc="Iniciando...")
67
  pth_path, ref_path = save_voice_reference(
68
  audio_path=audio_file,
69
  model_name=model_name,
70
  progress_callback=progress_callback,
71
  )
72
+ return "Referencia de voz '{}' guardada con éxito".format(model_name), ref_path
 
73
 
74
  except Exception as e:
75
  import traceback
76
  tb = traceback.format_exc()
77
+ logger.error("Error en entrenamiento: {}".format(tb))
78
+ return "Error: {}: {}\n\nDetalles:\n{}".format(
79
  type(e).__name__, str(e), tb[-500:]
80
  ), None
81
 
 
 
 
82
  def get_model_choices():
 
83
  models = list_models()
84
  if not models:
85
+ return ["(ningún modelo)"]
86
  return models
87
 
 
88
  def convert_song(
89
  model_choice,
90
  song_file,
 
95
  instrumental_volume,
96
  progress=gr.Progress(),
97
  ):
 
98
  if song_file is None:
99
+ return "Error: Por favor suba un archivo de audio.", None, None, None
100
 
101
+ if model_choice == "(ningún modelo)" or not model_choice:
102
+ return "Error: Por favor, registre una referencia de voz primero.", None, None, None
103
 
104
  from pipeline.mixing import mix_audio
105
 
106
  try:
107
+ progress(0.05, desc="Cargando el modelo...")
 
108
  pth_path, ref_or_index = download_model(model_choice)
109
  if not pth_path:
110
+ return "Error: Modelo '{}' no encontrado.".format(model_choice), None, None, None
111
 
 
112
  reference_path = get_reference_path(model_choice)
113
  if not reference_path:
114
+ return "Error: Audio de referencia no encontrado para '{}'.".format(model_choice), None, None, None
115
 
116
+ progress(0.10, desc="Separación de pistas (Demucs)...")
 
117
  vocals_path, instruments_path = separate_audio(song_file)
118
 
119
+ progress(0.40, desc="Conversión de voz (Seed-VC)...")
120
 
 
121
  converted_path = convert_voice(
122
  audio_path=vocals_path,
123
  reference_path=reference_path,
 
126
  similarity=float(similarity),
127
  )
128
 
129
+ progress(0.85, desc="Mezcla final...")
130
 
 
131
  final_path = mix_audio(
132
  vocals_path=converted_path,
133
  instruments_path=instruments_path,
 
135
  instrumental_volume=float(instrumental_volume),
136
  )
137
 
138
+ progress(1.0, desc="Terminado")
139
 
140
  return (
141
+ "Conversión terminada con éxito",
142
  vocals_path,
143
  converted_path,
144
  final_path,
 
147
  except Exception as e:
148
  import traceback
149
  tb = traceback.format_exc()
150
+ logger.error("Error en conversión: {}".format(tb))
151
+ return "Error: {}: {}\n\nDetalles:\n{}".format(
152
  type(e).__name__, str(e), tb[-500:]
153
  ), None, None, None
154
 
 
 
 
155
  def refresh_models():
 
156
  models = list_models()
157
  if not models:
158
+ return "Ningún modelo registrado"
159
  rows = "".join(
160
+ "{} Disponible".format(m) for m in models
 
 
 
 
 
 
161
  )
162
+ return "Nombre | Estado\n" + rows # Simplificado para el ejemplo
163
 
164
  def delete_selected_model(model_name_to_delete):
165
+ if not model_name_to_delete or model_name_to_delete == "(ningún modelo)":
166
+ return "Por favor seleccione un modelo para eliminar.", refresh_models()
 
167
  try:
168
  delete_model(model_name_to_delete)
169
+ return "Modelo '{}' eliminado.".format(model_name_to_delete), refresh_models()
170
  except Exception as e:
171
+ return "Error: {}".format(e), refresh_models()
 
 
 
172
 
173
  DESCRIPTION = """
174
+ # Clon Vocal
175
+ Herramienta de clonación de voz zero-shot basada en Seed-VC.
 
 
 
 
 
 
 
 
176
  """
177
 
178
+ with gr.Blocks(title="Clon Vocal", theme=gr.themes.Soft()) as app:
 
 
 
 
179
  gr.Markdown(DESCRIPTION)
180
 
181
  with gr.Tabs():
182
+ with gr.TabItem("Mi voz"):
183
+ gr.Markdown("Registrar su referencia de voz")
 
 
184
  with gr.Row():
185
  with gr.Column(scale=2):
186
+ train_audio = gr.Audio(label="Extracto de su voz", type="filepath", sources=["upload"])
187
+ train_model_name = gr.Textbox(label="Nombre del perfil", placeholder="ej: mi_voz")
188
+ train_btn = gr.Button("Guardar", variant="primary", size="lg")
 
 
 
 
 
 
 
 
 
 
 
 
 
189
  with gr.Column(scale=1):
190
+ train_status = gr.Textbox(label="Estado", interactive=False, lines=3)
191
+ train_download = gr.File(label="Archivo de referencia", interactive=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192
 
193
  train_btn.click(
194
  fn=train_voice_model,
 
196
  outputs=[train_status, train_download],
197
  )
198
 
199
+ with gr.TabItem("Convertir una canción"):
 
 
 
200
  with gr.Row():
201
  with gr.Column(scale=2):
202
+ convert_model = gr.Dropdown(choices=get_model_choices(), label="Perfil vocal")
203
+ refresh_btn = gr.Button("Actualizar la lista", size="sm")
204
+ convert_audio = gr.Audio(label="Canción a convertir", type="filepath")
205
+
206
+ with gr.Accordion("Parámetros avanzados", open=False):
207
+ convert_pitch = gr.Slider(minimum=-24, maximum=24, value=0, step=1, label="Pitch")
208
+ convert_similarity = gr.Slider(minimum=0.0, maximum=1.0, value=0.7, step=0.05, label="Similitud")
209
+ convert_diffusion = gr.Slider(minimum=5, maximum=100, value=25, step=5, label="Calidad")
210
+ convert_vocal_vol = gr.Slider(minimum=0.0, maximum=2.0, value=1.0, step=0.1, label="Vol. Voz")
211
+ convert_inst_vol = gr.Slider(minimum=0.0, maximum=2.0, value=1.0, step=0.1, label="Vol. Inst")
212
+
213
+ convert_btn = gr.Button("Convertir", variant="primary", size="lg")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
 
215
  with gr.Column(scale=1):
216
+ convert_status = gr.Textbox(label="Estado", interactive=False)
217
+ preview_vocals = gr.Audio(label="Original", interactive=False)
218
+ preview_converted = gr.Audio(label="Convertida", interactive=False)
219
+ final_output = gr.Audio(label="Final", interactive=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
 
221
+ refresh_btn.click(fn=lambda: gr.Dropdown(choices=get_model_choices()), outputs=[convert_model])
222
  convert_btn.click(
223
  fn=convert_song,
224
+ inputs=[convert_model, convert_audio, convert_pitch, convert_similarity, convert_diffusion, convert_vocal_vol, convert_inst_vol],
 
 
 
 
 
 
 
 
225
  outputs=[convert_status, preview_vocals, preview_converted, final_output],
226
  )
227
 
228
+ with gr.TabItem("Mis modelos"):
229
+ models_table = gr.HTML(value=refresh_models())
 
 
 
 
 
 
 
230
  with gr.Row():
231
+ models_refresh_btn = gr.Button("Actualizar")
232
+ models_delete_name = gr.Dropdown(choices=get_model_choices(), label="Modelo a eliminar")
233
+ models_delete_btn = gr.Button("Eliminar", variant="stop")
234
+ models_delete_status = gr.Textbox(label="Estado")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
 
236
+ models_refresh_btn.click(fn=refresh_models, outputs=[models_table])
237
+ models_delete_btn.click(fn=delete_selected_model, inputs=[models_delete_name], outputs=[models_delete_status, models_table])
 
 
 
238
 
239
+ with gr.TabItem("Depuración GPU"):
240
+ debug_output = gr.Textbox(label="Registros", interactive=False, lines=20)
241
+ debug_btn = gr.Button("Leer")
 
 
 
 
 
 
242
 
243
  def read_debug_log():
244
  log_path = "/home/user/app/debug_gpu.log"
245
+ return open(log_path, "r").read() if os.path.exists(log_path) else "Sin registros."
 
 
 
246
 
247
  debug_btn.click(fn=read_debug_log, outputs=[debug_output])
248
 
 
249
  if __name__ == "__main__":
250
+ app.launch(server_name="0.0.0.0")