Text-To-Speech / app.py
Bmo411's picture
Update app.py
d0fe171 verified
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)