noel-yeshcube commited on
Commit
b81be73
·
1 Parent(s): fd21f76

Add F5-TTS voice cloning app

Browse files
Files changed (5) hide show
  1. .gitignore +6 -0
  2. app.py +211 -0
  3. f5-test.py +32 -0
  4. f5-tts_tests.ipynb +0 -0
  5. requirements.txt +21 -0
.gitignore ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ .venv/
2
+ __pycache__/
3
+ *.pyc
4
+ *.pyo
5
+ .env
6
+ .DS_Store
app.py ADDED
@@ -0,0 +1,211 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import time
3
+ import os
4
+ from pathlib import Path
5
+
6
+ # Configuración
7
+ MODEL_NAME = "F5-TTS"
8
+ SUPPORTED_LANGUAGES = ["es", "en"]
9
+ MAX_AUDIO_SIZE = 10 * 1024 * 1024 # 10MB
10
+
11
+ # Variables globales para el modelo (se cargan una vez)
12
+ model = None
13
+ vocoder = None
14
+ model_loaded = False
15
+
16
+ def load_models():
17
+ """Cargar F5-TTS y vocoder (solo una vez al iniciar)"""
18
+ global model, vocoder, model_loaded
19
+
20
+ if model_loaded:
21
+ return True
22
+
23
+ try:
24
+ print("⏳ Cargando F5-TTS y vocoder...")
25
+
26
+ from f5_tts.infer.utils_infer import load_model, load_vocoder
27
+ from f5_tts.model.cfm import CFM
28
+
29
+ # Cargar vocoder
30
+ print("📥 Descargando vocoder (puede tardar la primera vez)...")
31
+ vocoder = load_vocoder(
32
+ vocoder_name="vocos",
33
+ is_local=False,
34
+ device="cpu" # HF Space CPU
35
+ )
36
+ print("✅ Vocoder cargado")
37
+
38
+ # Cargar modelo F5-TTS
39
+ print("📥 Descargando modelo F5-TTS...")
40
+ model = load_model(
41
+ model_cls=CFM,
42
+ model_cfg={}, # Configuración por defecto
43
+ ckpt_path="", # Se descarga automáticamente de HF
44
+ device="cpu"
45
+ )
46
+ print("✅ Modelo F5-TTS cargado")
47
+
48
+ model_loaded = True
49
+ return True
50
+
51
+ except Exception as e:
52
+ print(f"❌ Error cargando modelos: {e}")
53
+ import traceback
54
+ traceback.print_exc()
55
+ return False
56
+
57
+ def validate_audio(audio_file):
58
+ """Validar archivo de audio"""
59
+ if audio_file is None:
60
+ return False, "Por favor, sube un archivo de audio"
61
+
62
+ try:
63
+ file_size = os.path.getsize(audio_file)
64
+ if file_size > MAX_AUDIO_SIZE:
65
+ return False, f"Archivo muy grande. Máximo 10MB"
66
+ return True, "Audio válido"
67
+ except Exception as e:
68
+ return False, f"Error validando audio: {e}"
69
+
70
+ def generate_voice(reference_audio, ref_text, gen_text, language):
71
+ """Generar voz con F5-TTS"""
72
+
73
+ # Validar entrada
74
+ is_valid, msg = validate_audio(reference_audio)
75
+ if not is_valid:
76
+ return None, f"❌ {msg}", ""
77
+
78
+ if not ref_text or not ref_text.strip():
79
+ return None, "❌ Debes escribir la transcripción del audio de referencia", ""
80
+
81
+ if not gen_text or not gen_text.strip():
82
+ return None, "❌ Debes escribir el texto a generar", ""
83
+
84
+ # Verificar que los modelos estén cargados
85
+ if not model_loaded:
86
+ success = load_models()
87
+ if not success:
88
+ return None, "❌ Error cargando modelos. Intenta recargar la página.", ""
89
+
90
+ try:
91
+ start_time = time.time()
92
+
93
+ from f5_tts.infer.utils_infer import infer_process
94
+
95
+ print(f"🎤 Generando audio...")
96
+ print(f" Ref text: {ref_text[:50]}...")
97
+ print(f" Gen text: {gen_text[:50]}...")
98
+
99
+ # Procesar con F5-TTS
100
+ result = infer_process(
101
+ ref_audio=reference_audio,
102
+ ref_text=ref_text,
103
+ gen_text=gen_text,
104
+ model_obj=model,
105
+ vocoder=vocoder,
106
+ device="cpu"
107
+ )
108
+
109
+ end_time = time.time()
110
+ processing_time = end_time - start_time
111
+
112
+ # result debería ser el audio generado
113
+ output_path = "generated_audio.wav"
114
+
115
+ success_msg = f"✅ Audio generado exitosamente"
116
+ time_msg = f"⏱️ Tiempo: {processing_time:.2f}s"
117
+
118
+ return output_path, success_msg, time_msg
119
+
120
+ except Exception as e:
121
+ print(f"❌ Error en generación: {e}")
122
+ import traceback
123
+ traceback.print_exc()
124
+ return None, f"❌ Error: {str(e)}", ""
125
+
126
+ # Crear interfaz Gradio
127
+ def create_interface():
128
+ with gr.Blocks(
129
+ title="F5-TTS Voice Cloning",
130
+ theme=gr.themes.Soft()
131
+ ) as demo:
132
+
133
+ gr.Markdown("# 🎤 F5-TTS Voice Cloning")
134
+ gr.Markdown("Clona cualquier voz con solo 5-30 segundos de audio de referencia")
135
+
136
+ with gr.Row():
137
+ with gr.Column(scale=1):
138
+ gr.Markdown("## 📁 Entrada")
139
+
140
+ reference_audio = gr.Audio(
141
+ label="Audio de Referencia (5-30 segundos)",
142
+ type="filepath",
143
+ sources=["upload", "microphone"]
144
+ )
145
+
146
+ ref_text = gr.Textbox(
147
+ label="Transcripción del Audio de Referencia",
148
+ placeholder="Escribe exactamente lo que dice el audio de referencia...",
149
+ lines=2,
150
+ info="Importante: Debe coincidir con lo que dice el audio"
151
+ )
152
+
153
+ gen_text = gr.Textbox(
154
+ label="Texto a Generar",
155
+ placeholder="Escribe el texto que quieres que diga con la voz clonada...",
156
+ lines=3
157
+ )
158
+
159
+ language = gr.Dropdown(
160
+ choices=SUPPORTED_LANGUAGES,
161
+ value="es",
162
+ label="Idioma",
163
+ info="Idioma del texto a generar"
164
+ )
165
+
166
+ generate_btn = gr.Button("🚀 Generar Voz", variant="primary", size="lg")
167
+
168
+ with gr.Row():
169
+ status_msg = gr.Textbox(label="Estado", interactive=False, show_label=False)
170
+
171
+ with gr.Row():
172
+ time_msg = gr.Textbox(label="Tiempo de Procesamiento", interactive=False)
173
+
174
+ with gr.Row():
175
+ output_audio = gr.Audio(label="🔊 Audio Generado", type="filepath")
176
+
177
+ # Event handlers
178
+ generate_btn.click(
179
+ fn=generate_voice,
180
+ inputs=[reference_audio, ref_text, gen_text, language],
181
+ outputs=[output_audio, status_msg, time_msg]
182
+ )
183
+
184
+ gr.Markdown("""
185
+ ## 💡 Consejos para Mejores Resultados
186
+
187
+ - **Audio limpio:** Sin ruido de fondo, música o eco
188
+ - **Duración:** 5-30 segundos es ideal
189
+ - **Transcripción exacta:** La transcripción debe coincidir exactamente con el audio
190
+ - **Habla clara:** Volumen constante y pronunciación clara
191
+ - **Idioma:** El audio de referencia y el texto pueden estar en idiomas diferentes
192
+
193
+ ## 🔧 Información Técnica
194
+
195
+ - **Modelo:** F5-TTS (Flow Matching Text-to-Speech)
196
+ - **Vocoder:** Vocos
197
+ - **Dispositivo:** CPU (puede tardar ~30-60 segundos)
198
+ """)
199
+
200
+ return demo
201
+
202
+ if __name__ == "__main__":
203
+ # Pre-cargar modelos al iniciar (opcional, mejora primera experiencia)
204
+ print("🚀 Iniciando F5-TTS Voice Cloning App")
205
+ print("=" * 50)
206
+
207
+ # Comentar la siguiente línea si quieres carga bajo demanda
208
+ # load_models()
209
+
210
+ demo = create_interface()
211
+ demo.launch()
f5-test.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Prueba simple: Solo verificar que F5-TTS se puede importar
4
+ """
5
+
6
+ def test_basic_imports():
7
+ """Probar imports básicos"""
8
+ print("🔍 Probando imports básicos...")
9
+
10
+ try:
11
+ import torch
12
+ print(f" ✅ PyTorch: {torch.__version__}")
13
+
14
+ import torchaudio
15
+ print(f" ✅ TorchAudio: {torchaudio.__version__}")
16
+
17
+ print(" 📦 Importando F5-TTS...")
18
+ import f5_tts
19
+ print(f" ✅ F5-TTS importado correctamente")
20
+
21
+ return True
22
+
23
+ except ImportError as e:
24
+ print(f" ❌ Error: {e}")
25
+ return False
26
+
27
+ if __name__ == "__main__":
28
+ success = test_basic_imports()
29
+ if success:
30
+ print("\n🎉 Imports funcionan correctamente!")
31
+ else:
32
+ print("\n❌ Hay problemas con los imports")
f5-tts_tests.ipynb ADDED
File without changes
requirements.txt ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Interfaz web
2
+ gradio>=4.0.0
3
+
4
+ # F5-TTS local
5
+ torch>=2.0.0
6
+ torchaudio>=2.0.0
7
+ librosa>=0.10.0
8
+ soundfile>=0.12.0
9
+ numpy>=1.24.0
10
+
11
+ # APIs de HuggingFace
12
+ huggingface_hub>=0.19.0
13
+ requests>=2.31.0
14
+
15
+ # Procesamiento de audio
16
+ pydub>=0.25.0
17
+
18
+ # Utilidades
19
+ python-dotenv>=1.0.0
20
+
21
+ f5_tts>=1.1.0