Spaces:
Running
Running
File size: 8,848 Bytes
9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e 9019961 595ca9e |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 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 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 |
import io
import base64
import time
import os
import gradio as gr
import torch
import numpy as np
from transformers import (
VitsTokenizer,
VitsModel,
SpeechT5Processor,
SpeechT5ForTextToSpeech,
SpeechT5HifiGan,
set_seed
)
from scipy.io import wavfile
# Configuraciones para optimización
set_seed(42)
torch.set_grad_enabled(False) # Desactivar gradientes para inferencia
torch.set_num_threads(4) # Limitar threads para evitar sobrecargas
# Cache para respuestas frecuentes
CACHE_SIZE = 50 # Número máximo de respuestas cacheadas
cache = {}
# Configuración de modelos disponibles
MODELS = {
"facebook_mms": {
"name": "Facebook MMS (Español)",
"model_id": "facebook/mms-tts-spa",
"type": "vits"
},
"facebook_fast": {
"name": "Facebook FastSpeech2 (Español)",
"model_id": "facebook/fastspeech2-es-cv",
"type": "vits"
},
"microsoft_female": {
"name": "Microsoft SpeechT5 (Femenina)",
"model_id": "microsoft/speecht5_tts",
"speaker_embeddings": "microsoft/speecht5_tts",
"speaker_id": "es_female",
"type": "speecht5"
},
"microsoft_male": {
"name": "Microsoft SpeechT5 (Masculino)",
"model_id": "microsoft/speecht5_tts",
"speaker_embeddings": "microsoft/speecht5_tts",
"speaker_id": "es_male",
"type": "speecht5"
}
}
# Carga diferida de modelos
models = {}
tokenizers = {}
processors = {}
vocoders = {}
def load_model(model_key):
"""Carga el modelo solo cuando es necesario"""
start_time = time.time()
if model_key not in models:
model_info = MODELS[model_key]
if model_info["type"] == "vits":
tokenizers[model_key] = VitsTokenizer.from_pretrained(model_info["model_id"])
models[model_key] = VitsModel.from_pretrained(model_info["model_id"])
elif model_info["type"] == "speecht5":
processors[model_key] = SpeechT5Processor.from_pretrained(model_info["model_id"])
models[model_key] = SpeechT5ForTextToSpeech.from_pretrained(model_info["model_id"])
vocoders[model_key] = SpeechT5HifiGan.from_pretrained("microsoft/speecht5_hifigan")
load_time = time.time() - start_time
print(f"Modelo {model_key} cargado en {load_time:.2f} segundos")
# Función para generar el hash de caché
def get_cache_key(text, model_key):
return f"{text}_{model_key}"
def text_to_speech(text, model_key="facebook_mms"):
"""
Convierte texto en español a audio usando el modelo seleccionado
"""
if not text or text.strip() == "":
return {
"audio": None,
"error": "El texto no puede estar vacío",
"model": model_key
}
# Verificar en caché primero
cache_key = get_cache_key(text, model_key)
if cache_key in cache:
print(f"Resultado recuperado de caché para: {text[:20]}...")
return cache[cache_key]
try:
# Cargar modelo si no está en memoria
load_model(model_key)
model_info = MODELS[model_key]
start_time = time.time()
if model_info["type"] == "vits":
# Usar modelo VITS (Facebook MMS o FastSpeech2)
inputs = tokenizers[model_key](text=text, return_tensors="pt")
with torch.no_grad():
output = models[model_key](**inputs).waveform
audio_data = output.squeeze().numpy()
sample_rate = 16000
elif model_info["type"] == "speecht5":
# Usar modelo SpeechT5 (Microsoft)
processor = processors[model_key]
model = models[model_key]
vocoder = vocoders[model_key]
# Preprocesar texto
inputs = processor(text=text, return_tensors="pt")
# Generar embeddings del hablante (según idioma/género)
speaker_id = model_info["speaker_id"]
if speaker_id == "es_female":
speaker_embeddings = torch.tensor([[0.0, 1.0, 0.0, 0.0, 0.0]]) # Vector para mujer en español
elif speaker_id == "es_male":
speaker_embeddings = torch.tensor([[0.0, 0.0, 0.0, 1.0, 0.0]]) # Vector para hombre en español
# Generar codificación de audio
with torch.no_grad():
speech = model.generate_speech(inputs["input_ids"], speaker_embeddings)
audio_data = vocoder(speech).numpy()
sample_rate = 16000
# Normalizar audio para evitar distorsiones
audio_data = np.clip(audio_data, -1.0, 1.0)
# Si es float, convertir a int16 para el archivo WAV
if audio_data.dtype in [np.float32, np.float64]:
audio_data = (audio_data * 32767).astype(np.int16)
# Guardar como WAV
buffer = io.BytesIO()
wavfile.write(buffer, sample_rate, audio_data)
buffer.seek(0)
# Codificar en base64 para la API
audio_base64 = base64.b64encode(buffer.read()).decode('utf-8')
# Crear resultado
result = {
"audio": audio_base64,
"format": "wav",
"sampling_rate": sample_rate,
"model": model_key,
"processing_time": round(time.time() - start_time, 2)
}
# Guardar en caché
if len(cache) >= CACHE_SIZE:
# Eliminar entrada más antigua si se alcanza el límite
oldest_key = next(iter(cache))
del cache[oldest_key]
cache[cache_key] = result
return result
except Exception as e:
return {
"audio": None,
"error": str(e),
"model": model_key
}
# Lista de modelos para la interfaz
model_choices = [info["name"] for _, info in MODELS.items()]
model_keys = list(MODELS.keys())
# Configurar la interfaz Gradio
with gr.Blocks(title="Text-to-Speech en Español - Múltiples Voces") as demo:
gr.Markdown("# Conversor de Texto a Voz en Español")
gr.Markdown("### Genere audio en español con diferentes voces")
with gr.Row():
with gr.Column():
text_input = gr.Textbox(
label="Texto a convertir en voz",
lines=5,
placeholder="Escribe aquí el texto en español que quieres convertir a voz..."
)
model_dropdown = gr.Dropdown(
choices=model_choices,
value=model_choices[0],
label="Selecciona la voz"
)
generate_btn = gr.Button("Generar audio")
with gr.Column():
audio_output = gr.Audio(label="Audio generado", type="numpy")
json_output = gr.JSON(label="Respuesta API (para desarrolladores)")
# Función para manejar la interfaz gráfica
def generate_for_ui(text, model_choice):
# Convertir la selección del dropdown al key del modelo
selected_idx = model_choices.index(model_choice)
model_key = model_keys[selected_idx]
# Llamar a la función de generación
result = text_to_speech(text, model_key)
# Si hay error, mostrarlo
if not result.get("audio") or "error" in result:
return None, result
# Decodificar el audio para la interfaz
try:
audio_bytes = base64.b64decode(result["audio"])
buffer = io.BytesIO(audio_bytes)
sr, audio_array = wavfile.read(buffer)
# Convertir a float para Gradio si es necesario
if audio_array.dtype == np.int16:
audio_array = audio_array.astype(np.float32) / 32768.0
return (sr, audio_array), result
except Exception as e:
return None, {"error": str(e), "model": model_key}
# Conectar eventos
generate_btn.click(
fn=generate_for_ui,
inputs=[text_input, model_dropdown],
outputs=[audio_output, json_output]
)
# Agregar ejemplos
gr.Examples(
examples=[
["Hola, este es un ejemplo de texto a voz en español usando inteligencia artificial.", model_choices[0]],
["La inteligencia artificial ha avanzado significativamente en los últimos años.", model_choices[1]],
["Me gustaría reservar una mesa para dos personas en el restaurante esta noche.", model_choices[2]],
["El tiempo estará soleado mañana, con temperaturas máximas de 25 grados.", model_choices[3]]
],
inputs=[text_input, model_dropdown]
)
# Configurar API
demo.queue(max_size=10).launch(debug=True, share=False, show_api=True) |