Spaces:
Running
Running
import gradio as gr | |
import numpy as np | |
import tensorflow as tf | |
from tensorflow import keras | |
import torch | |
from huggingface_hub import hf_hub_download | |
from speechbrain.inference.TTS import Tacotron2 | |
import os | |
# Cargar modelo Tacotron2 | |
tacotron2 = Tacotron2.from_hparams( | |
source="speechbrain/tts-tacotron2-ljspeech", | |
savedir="tmpdir_tts", | |
run_opts={"device": "cpu"} | |
) | |
# Diccionario para almacenar los modelos cargados | |
loaded_models = {} | |
# Modelos disponibles - define aquí las épocas que quieres incluir | |
available_models = { | |
"Época 100": "generator_epoch_100.keras", | |
"Época 300": "generator_epoch_300.keras", | |
"Época 400": "generator_epoch_400.keras", | |
"Época 1000": "generator_epoch_1000.keras", | |
"Época 4200": "generator_epoch_4200.keras", | |
"Época 4700": "generator_epoch_4700.keras", | |
"Época 7700": "generator_epoch_7700.keras", | |
} | |
# Función para cargar un modelo específico | |
def load_generator_model(model_name): | |
if model_name in loaded_models: | |
return loaded_models[model_name] | |
try: | |
model_path = hf_hub_download( | |
repo_id="Bmo411/WGAN", | |
filename=model_name | |
) | |
model = keras.models.load_model(model_path, compile=False) | |
loaded_models[model_name] = model | |
print(f"Modelo {model_name} cargado correctamente") | |
return model | |
except Exception as e: | |
print(f"Error al cargar el modelo {model_name}: {e}") | |
# Si falla la carga, intentamos usar el modelo de la época 1000 como fallback | |
try: | |
fallback_model = "generator_epoch_1000.keras" | |
model_path = hf_hub_download( | |
repo_id="Bmo411/WGAN", | |
filename=fallback_model | |
) | |
model = keras.models.load_model(model_path, compile=False) | |
loaded_models[model_name] = model # Guardamos con el nombre original para evitar recargar | |
print(f"Usando modelo fallback {fallback_model}") | |
return model | |
except: | |
print("Error crítico al cargar modelos. No hay modelos disponibles.") | |
return None | |
# Función para convertir texto a audio | |
def text_to_audio(text, model_epoch): | |
# Crear un array vacío por defecto en caso de error | |
default_audio = np.zeros(8000, dtype=np.float32) | |
sample_rate = 8000 # Ajusta según la configuración de tu modelo | |
if not text or not text.strip(): | |
return (sample_rate, default_audio) | |
try: | |
# Obtener el nombre del archivo del modelo seleccionado | |
model_filename = available_models[model_epoch] | |
# Cargar el modelo generador correspondiente | |
generator = load_generator_model(model_filename) | |
if generator is None: | |
print("No se pudo cargar el generador") | |
return (sample_rate, default_audio) | |
# Convertir texto a mel-spectrograma con Tacotron2 | |
mel_output, _, _ = tacotron2.encode_text(text) | |
mel = mel_output.detach().cpu().numpy().astype(np.float32) | |
# Imprimir forma original del mel para debugging | |
print(f"Forma original del mel: {mel.shape}") | |
# Reorganizar el mel para que coincida con la forma esperada (batch, 80, frames, 1) | |
# Si mel tiene forma (80, frames) - lo más probable | |
if len(mel.shape) == 2: | |
mel_input = np.expand_dims(mel, axis=0) # (1, 80, frames) | |
mel_input = np.expand_dims(mel_input, axis=-1) # (1, 80, frames, 1) | |
# Si viene con otra forma, intentamos adaptarla | |
elif len(mel.shape) == 3 and mel.shape[0] == 1: | |
# Si es (1, 80, frames) o (1, frames, 80) | |
if mel.shape[1] == 80: | |
mel_input = np.expand_dims(mel, axis=-1) # (1, 80, frames, 1) | |
else: | |
mel_input = np.expand_dims(np.transpose(mel, (0, 2, 1)), axis=-1) # (1, 80, frames, 1) | |
else: | |
# Intento final de reorganización | |
mel_input = np.expand_dims(np.expand_dims(mel, axis=0), axis=-1) | |
print(f"Forma del mel preparado: {mel_input.shape}") | |
# Generar audio | |
generated_audio = generator(mel_input, training=False) | |
# Procesar el audio generado | |
generated_audio = tf.squeeze(generated_audio).numpy() | |
# Asegurarse de que hay valores no cero antes de normalizar | |
if np.max(np.abs(generated_audio)) > 0: | |
generated_audio = generated_audio / np.max(np.abs(generated_audio)) | |
# Convertir a float32 para gradio | |
generated_audio = generated_audio.astype(np.float32) | |
print(f"Forma del audio generado: {generated_audio.shape}") | |
current_length = len(generated_audio) | |
if current_length > 8000: | |
# Recortar si es más largo de 2 segundos | |
print(f"Recortando audio de {current_length} a {8000} muestras") | |
final_audio = generated_audio[:8000] | |
else: | |
# Rellenar con ceros si es más corto de 2 segundos | |
print(f"Rellenando audio de {current_length} a {8000} muestras") | |
final_audio = np.zeros(8000, dtype=np.float32) | |
final_audio[:current_length] = generated_audio | |
return (sample_rate, final_audio) | |
except Exception as e: | |
print(f"Error en la generación de audio: {e}") | |
# Si hay error, imprimir un traceback completo para mejor diagnóstico | |
import traceback | |
traceback.print_exc() | |
return (sample_rate, default_audio) | |
# Crear interfaz en Gradio | |
with gr.Blocks(title="Demo de TTS con Tacotron2 + Generador") as interface: | |
gr.Markdown("# Demo de TTS con Tacotron2 + Generador") | |
gr.Markdown("Convierte texto en audio usando Tacotron2 + modelo Generator entrenado en diferentes épocas.") | |
with gr.Row(): | |
with gr.Column(scale=3): | |
text_input = gr.Textbox(lines=2, placeholder="Escribe nine-", label="Texto a convertir") | |
with gr.Column(scale=1): | |
model_selection = gr.Dropdown( | |
choices=list(available_models.keys()), | |
value="Época 1000", | |
label="Selecciona la época del modelo" | |
) | |
generate_btn = gr.Button("Generar Audio", variant="primary") | |
audio_output = gr.Audio(label="Audio generado") | |
# Configurar ejemplos | |
examples = gr.Examples( | |
examples=[ | |
["nine", "Época 100"], | |
["nine", "Época 400"], | |
["nine", "Época 4700"] | |
], | |
inputs=[text_input, model_selection], | |
outputs=audio_output | |
) | |
# Conectar botón a la función | |
generate_btn.click(fn=text_to_audio, inputs=[text_input, model_selection], outputs=audio_output) | |
# También permitir enviar con Enter desde el cuadro de texto | |
text_input.submit(fn=text_to_audio, inputs=[text_input, model_selection], outputs=audio_output) | |
# Lanzar aplicación | |
if __name__ == "__main__": | |
# Precargamos el modelo de la época 1000 para tenerlo disponible inmediatamente | |
load_generator_model(available_models["Época 1000"]) | |
# Lanzamos la interfaz | |
interface.launch(debug=True) | |