Update app.py
Browse files
app.py
CHANGED
|
@@ -1,11 +1,10 @@
|
|
| 1 |
-
# app.py
|
| 2 |
-
|
| 3 |
import subprocess
|
| 4 |
import os
|
| 5 |
import shutil
|
| 6 |
from pathlib import Path
|
| 7 |
from datasets import load_dataset, Audio
|
| 8 |
import gradio as gr
|
|
|
|
| 9 |
|
| 10 |
# ----------------------------------------------------------------------
|
| 11 |
# 1. FUNCIONES DE DESCARGA Y PROCESAMIENTO
|
|
@@ -16,13 +15,12 @@ def download_clip(
|
|
| 16 |
output_filename,
|
| 17 |
start_time,
|
| 18 |
end_time,
|
| 19 |
-
num_attempts=
|
| 20 |
url_base='https://www.youtube.com/watch?v='
|
| 21 |
):
|
| 22 |
-
"""Descarga un clip de YouTube usando yt-dlp."""
|
| 23 |
-
status = False
|
| 24 |
|
| 25 |
-
# Comando
|
| 26 |
command = [
|
| 27 |
"yt-dlp",
|
| 28 |
"--quiet",
|
|
@@ -30,28 +28,44 @@ def download_clip(
|
|
| 30 |
"--no-warnings",
|
| 31 |
"-x",
|
| 32 |
"--audio-format", "wav",
|
| 33 |
-
"-f", "bestaudio",
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
"-o", output_filename,
|
| 35 |
"--download-sections", f"*{start_time}-{end_time}",
|
| 36 |
f"{url_base}{video_identifier}"
|
| 37 |
]
|
| 38 |
|
| 39 |
-
|
| 40 |
-
while True:
|
| 41 |
try:
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
|
| 56 |
|
| 57 |
def main(
|
|
@@ -60,7 +74,6 @@ def main(
|
|
| 60 |
limit: int = None,
|
| 61 |
num_proc: int = 1,
|
| 62 |
writer_batch_size: int = 1000,
|
| 63 |
-
cast_audio: bool = True # Nuevo parámetro
|
| 64 |
):
|
| 65 |
"""
|
| 66 |
Descarga los clips de MusicCaps, procesa el dataset y maneja la limpieza.
|
|
@@ -68,7 +81,7 @@ def main(
|
|
| 68 |
|
| 69 |
data_dir_path = Path(data_dir)
|
| 70 |
|
| 71 |
-
#
|
| 72 |
if data_dir_path.exists():
|
| 73 |
shutil.rmtree(data_dir_path)
|
| 74 |
print(f"Limpiando el directorio {data_dir} para liberar espacio.")
|
|
@@ -93,13 +106,17 @@ def main(
|
|
| 93 |
example['start_s'],
|
| 94 |
example['end_s'],
|
| 95 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 96 |
|
| 97 |
-
example['audio'] = outfile_path
|
| 98 |
example['download_status'] = status
|
| 99 |
return example
|
| 100 |
|
| 101 |
-
#
|
| 102 |
-
# En esta etapa, 'audio' es solo una cadena (str) de la ruta.
|
| 103 |
ds = ds.map(
|
| 104 |
process,
|
| 105 |
num_proc=num_proc,
|
|
@@ -107,28 +124,53 @@ def main(
|
|
| 107 |
keep_in_memory=False
|
| 108 |
)
|
| 109 |
|
| 110 |
-
# Aplicar cast_column SÓLO si se solicita. Ahora lo haremos fuera de main.
|
| 111 |
-
if cast_audio:
|
| 112 |
-
ds = ds.cast_column('audio', Audio(sampling_rate=sampling_rate))
|
| 113 |
-
|
| 114 |
return ds
|
| 115 |
|
| 116 |
# ----------------------------------------------------------------------
|
| 117 |
# 2. CARGA DEL DATASET AL INICIO Y FILTRADO
|
| 118 |
# ----------------------------------------------------------------------
|
| 119 |
|
| 120 |
-
|
| 121 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 122 |
print(f"Dataset cargado. Total de ejemplos antes del filtro: {len(ds)}")
|
| 123 |
|
| 124 |
-
#
|
| 125 |
-
# datasets no intenta decodificar archivos inexistentes.
|
| 126 |
ds = ds.filter(lambda example: example['download_status'] == True)
|
| 127 |
-
print(f"Ejemplos válidos después del filtro: {len(ds)}")
|
| 128 |
|
| 129 |
-
#
|
| 130 |
-
ds
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 131 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
|
| 133 |
# ----------------------------------------------------------------------
|
| 134 |
# 3. INTERFAZ GRADIO
|
|
@@ -136,36 +178,56 @@ ds = ds.cast_column('audio', Audio(sampling_rate=44100))
|
|
| 136 |
|
| 137 |
def get_example(idx):
|
| 138 |
"""Función que Gradio llama al mover el slider."""
|
| 139 |
-
# Convertir a entero es crucial
|
| 140 |
idx = int(idx)
|
| 141 |
-
|
|
|
|
| 142 |
|
| 143 |
-
|
| 144 |
return ex['audio']['path'], ex['caption']
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import subprocess
|
| 2 |
import os
|
| 3 |
import shutil
|
| 4 |
from pathlib import Path
|
| 5 |
from datasets import load_dataset, Audio
|
| 6 |
import gradio as gr
|
| 7 |
+
import time
|
| 8 |
|
| 9 |
# ----------------------------------------------------------------------
|
| 10 |
# 1. FUNCIONES DE DESCARGA Y PROCESAMIENTO
|
|
|
|
| 15 |
output_filename,
|
| 16 |
start_time,
|
| 17 |
end_time,
|
| 18 |
+
num_attempts=3,
|
| 19 |
url_base='https://www.youtube.com/watch?v='
|
| 20 |
):
|
| 21 |
+
"""Descarga un clip de YouTube usando yt-dlp con mejor manejo de errores."""
|
|
|
|
| 22 |
|
| 23 |
+
# Comando mejorado con más opciones de compatibilidad
|
| 24 |
command = [
|
| 25 |
"yt-dlp",
|
| 26 |
"--quiet",
|
|
|
|
| 28 |
"--no-warnings",
|
| 29 |
"-x",
|
| 30 |
"--audio-format", "wav",
|
| 31 |
+
"-f", "bestaudio/best",
|
| 32 |
+
"--no-check-certificate", # Evita problemas de SSL
|
| 33 |
+
"--prefer-insecure",
|
| 34 |
+
"--socket-timeout", "30",
|
| 35 |
+
"--retries", "3",
|
| 36 |
"-o", output_filename,
|
| 37 |
"--download-sections", f"*{start_time}-{end_time}",
|
| 38 |
f"{url_base}{video_identifier}"
|
| 39 |
]
|
| 40 |
|
| 41 |
+
for attempt in range(num_attempts):
|
|
|
|
| 42 |
try:
|
| 43 |
+
result = subprocess.run(
|
| 44 |
+
command,
|
| 45 |
+
capture_output=True,
|
| 46 |
+
text=True,
|
| 47 |
+
timeout=60 # Timeout de 60 segundos
|
| 48 |
+
)
|
| 49 |
+
|
| 50 |
+
# Verificar si el archivo existe y tiene tamaño > 0
|
| 51 |
+
if os.path.exists(output_filename) and os.path.getsize(output_filename) > 0:
|
| 52 |
+
return True, 'Downloaded successfully'
|
| 53 |
+
|
| 54 |
+
if attempt < num_attempts - 1:
|
| 55 |
+
time.sleep(2) # Esperar antes de reintentar
|
| 56 |
+
|
| 57 |
+
except subprocess.TimeoutExpired:
|
| 58 |
+
print(f"Timeout en intento {attempt + 1} para {video_identifier}")
|
| 59 |
+
if attempt < num_attempts - 1:
|
| 60 |
+
time.sleep(2)
|
| 61 |
+
except Exception as e:
|
| 62 |
+
print(f"Error en intento {attempt + 1} para {video_identifier}: {str(e)}")
|
| 63 |
+
if attempt < num_attempts - 1:
|
| 64 |
+
time.sleep(2)
|
| 65 |
+
|
| 66 |
+
# Si llegamos aquí, la descarga falló
|
| 67 |
+
error_msg = f"Failed after {num_attempts} attempts"
|
| 68 |
+
return False, error_msg
|
| 69 |
|
| 70 |
|
| 71 |
def main(
|
|
|
|
| 74 |
limit: int = None,
|
| 75 |
num_proc: int = 1,
|
| 76 |
writer_batch_size: int = 1000,
|
|
|
|
| 77 |
):
|
| 78 |
"""
|
| 79 |
Descarga los clips de MusicCaps, procesa el dataset y maneja la limpieza.
|
|
|
|
| 81 |
|
| 82 |
data_dir_path = Path(data_dir)
|
| 83 |
|
| 84 |
+
# Limpieza de disco
|
| 85 |
if data_dir_path.exists():
|
| 86 |
shutil.rmtree(data_dir_path)
|
| 87 |
print(f"Limpiando el directorio {data_dir} para liberar espacio.")
|
|
|
|
| 106 |
example['start_s'],
|
| 107 |
example['end_s'],
|
| 108 |
)
|
| 109 |
+
if not status:
|
| 110 |
+
print(f"❌ Falló descarga de {example['ytid']}: {log}")
|
| 111 |
+
else:
|
| 112 |
+
# Si el archivo existe, verificar que tenga contenido
|
| 113 |
+
status = os.path.getsize(outfile_path) > 0
|
| 114 |
|
| 115 |
+
example['audio'] = outfile_path if status else ""
|
| 116 |
example['download_status'] = status
|
| 117 |
return example
|
| 118 |
|
| 119 |
+
# Descargar y actualizar el dataset
|
|
|
|
| 120 |
ds = ds.map(
|
| 121 |
process,
|
| 122 |
num_proc=num_proc,
|
|
|
|
| 124 |
keep_in_memory=False
|
| 125 |
)
|
| 126 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
return ds
|
| 128 |
|
| 129 |
# ----------------------------------------------------------------------
|
| 130 |
# 2. CARGA DEL DATASET AL INICIO Y FILTRADO
|
| 131 |
# ----------------------------------------------------------------------
|
| 132 |
|
| 133 |
+
print("=" * 60)
|
| 134 |
+
print("INICIANDO APLICACIÓN MUSICCAPS DEMO")
|
| 135 |
+
print("=" * 60)
|
| 136 |
+
|
| 137 |
+
# Intentar con más ejemplos para aumentar probabilidad de éxito
|
| 138 |
+
ds = main('./music_data', num_proc=1, limit=30) # Aumentado a 30
|
| 139 |
print(f"Dataset cargado. Total de ejemplos antes del filtro: {len(ds)}")
|
| 140 |
|
| 141 |
+
# Filtrar ejemplos válidos
|
|
|
|
| 142 |
ds = ds.filter(lambda example: example['download_status'] == True)
|
| 143 |
+
print(f"✅ Ejemplos válidos después del filtro: {len(ds)}")
|
| 144 |
|
| 145 |
+
# Si no hay ejemplos válidos, intentar con otro rango
|
| 146 |
+
if len(ds) == 0:
|
| 147 |
+
print("⚠️ Primer intento falló. Intentando con ejemplos 100-130...")
|
| 148 |
+
full_ds = load_dataset('google/MusicCaps', split='train')
|
| 149 |
+
ds = full_ds.select(range(100, 130))
|
| 150 |
+
|
| 151 |
+
data_dir_path = Path('./music_data')
|
| 152 |
+
def process(example):
|
| 153 |
+
outfile_path = str(data_dir_path / f"{example['ytid']}.wav")
|
| 154 |
+
status = False
|
| 155 |
+
if not os.path.exists(outfile_path):
|
| 156 |
+
status, log = download_clip(
|
| 157 |
+
example['ytid'],
|
| 158 |
+
outfile_path,
|
| 159 |
+
example['start_s'],
|
| 160 |
+
example['end_s'],
|
| 161 |
+
)
|
| 162 |
+
example['audio'] = outfile_path if status else ""
|
| 163 |
+
example['download_status'] = status
|
| 164 |
+
return example
|
| 165 |
+
|
| 166 |
+
ds = ds.map(process, num_proc=1, keep_in_memory=False)
|
| 167 |
+
ds = ds.filter(lambda example: example['download_status'] == True)
|
| 168 |
+
print(f"✅ Ejemplos válidos en segundo intento: {len(ds)}")
|
| 169 |
|
| 170 |
+
# Aplicar tipo Audio solo si hay ejemplos válidos
|
| 171 |
+
if len(ds) > 0:
|
| 172 |
+
ds = ds.cast_column('audio', Audio(sampling_rate=44100))
|
| 173 |
+
print(f"🎵 Dataset preparado con {len(ds)} ejemplos")
|
| 174 |
|
| 175 |
# ----------------------------------------------------------------------
|
| 176 |
# 3. INTERFAZ GRADIO
|
|
|
|
| 178 |
|
| 179 |
def get_example(idx):
|
| 180 |
"""Función que Gradio llama al mover el slider."""
|
|
|
|
| 181 |
idx = int(idx)
|
| 182 |
+
if idx >= len(ds):
|
| 183 |
+
idx = len(ds) - 1
|
| 184 |
|
| 185 |
+
ex = ds[idx]
|
| 186 |
return ex['audio']['path'], ex['caption']
|
| 187 |
|
| 188 |
+
# Crear interfaz solo si hay datos
|
| 189 |
+
if len(ds) > 0:
|
| 190 |
+
demo = gr.Interface(
|
| 191 |
+
get_example,
|
| 192 |
+
inputs=gr.Slider(
|
| 193 |
+
0,
|
| 194 |
+
len(ds) - 1,
|
| 195 |
+
value=0,
|
| 196 |
+
step=1,
|
| 197 |
+
label=f"Índice del Ejemplo (0 a {len(ds) - 1})"
|
| 198 |
+
),
|
| 199 |
+
outputs=[
|
| 200 |
+
gr.Audio(label="🎵 Muestra de Audio"),
|
| 201 |
+
gr.Textbox(label="📝 Descripción (Caption)", lines=3)
|
| 202 |
+
],
|
| 203 |
+
title="🎵 MusicCaps Dataset Explorer",
|
| 204 |
+
description=f"Explora {len(ds)} clips de música con sus descripciones. Mueve el slider para cambiar de ejemplo.",
|
| 205 |
+
live=True,
|
| 206 |
+
)
|
| 207 |
+
|
| 208 |
+
print("🚀 Lanzando aplicación Gradio...")
|
| 209 |
+
demo.launch()
|
| 210 |
+
else:
|
| 211 |
+
print("=" * 60)
|
| 212 |
+
print("❌ ERROR CRÍTICO")
|
| 213 |
+
print("=" * 60)
|
| 214 |
+
print("No se pudo descargar ningún ejemplo válido del dataset.")
|
| 215 |
+
print("Posibles causas:")
|
| 216 |
+
print("1. Problemas de conectividad en Hugging Face Spaces")
|
| 217 |
+
print("2. YouTube bloqueando las descargas")
|
| 218 |
+
print("3. Videos no disponibles o privados")
|
| 219 |
+
print("\nSugerencias:")
|
| 220 |
+
print("- Verificar que yt-dlp esté actualizado")
|
| 221 |
+
print("- Intentar con un VPN o proxy")
|
| 222 |
+
print("- Usar un dataset pre-descargado")
|
| 223 |
+
print("=" * 60)
|
| 224 |
+
|
| 225 |
+
# Crear una interfaz mínima de error
|
| 226 |
+
demo = gr.Interface(
|
| 227 |
+
lambda: ("⚠️ No hay datos disponibles", "No se pudieron descargar clips de audio"),
|
| 228 |
+
inputs=None,
|
| 229 |
+
outputs=[gr.Textbox(label="Estado"), gr.Textbox(label="Mensaje")],
|
| 230 |
+
title="❌ MusicCaps Demo - Error",
|
| 231 |
+
description="No se pudieron descargar ejemplos del dataset. Verifica los logs para más detalles."
|
| 232 |
+
)
|
| 233 |
+
demo.launch()
|