Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -47,46 +47,35 @@ def validar_texto(texto):
|
|
47 |
raise gr.Error("⚠️ Caracteres no permitidos detectados")
|
48 |
|
49 |
async def procesar_audio(texto, voz, duracion_total, duracion_intro):
|
50 |
-
"""Genera TTS y mezcla con música"""
|
51 |
temp_files = []
|
52 |
try:
|
53 |
-
#
|
54 |
-
|
55 |
-
raise ValueError("Texto vacío")
|
56 |
-
if voz not in ["es-ES-AlvaroNeural", "es-MX-BeatrizNeural"]:
|
57 |
-
raise ValueError(f"Voz no soportada: {voz}")
|
58 |
|
59 |
# Generar TTS
|
60 |
communicate = edge_tts.Communicate(texto, voz)
|
61 |
with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp:
|
62 |
await communicate.save(tmp.name)
|
63 |
tts_audio = AudioFileClip(tmp.name)
|
|
|
64 |
|
65 |
# Verificar audio válido
|
66 |
if tts_audio.duration < 0.5:
|
67 |
raise RuntimeError(f"Audio TTS inválido ({tts_audio.duration}s)")
|
68 |
-
|
69 |
-
temp_files.append(tmp.name)
|
70 |
-
|
71 |
# Procesar música de fondo
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
if len(bg_music) == 0:
|
78 |
-
raise ValueError("Música de fondo vacía")
|
79 |
-
|
80 |
-
# Ajustar duración
|
81 |
-
needed_ms = duracion_total * 1000
|
82 |
-
bg_music = bg_music * (needed_ms // len(bg_music) + 1)
|
83 |
bg_music = bg_music[:needed_ms].fade_out(5000)
|
84 |
|
85 |
with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp:
|
86 |
bg_music.export(tmp.name, format="mp3")
|
87 |
bg_audio = AudioFileClip(tmp.name).volumex(0.15)
|
88 |
temp_files.append(tmp.name)
|
89 |
-
|
90 |
# Combinar audios
|
91 |
audio_final = CompositeAudioClip([
|
92 |
bg_audio,
|
@@ -132,9 +121,6 @@ def agregar_transiciones(clips):
|
|
132 |
|
133 |
async def procesar_video(video_input, texto_tts, voz_seleccionada, metodo_corte, duracion_corte):
|
134 |
try:
|
135 |
-
# Validar texto antes de procesar
|
136 |
-
validar_texto(texto_tts)
|
137 |
-
|
138 |
# Cargar video con audio original
|
139 |
video_original = VideoFileClip(video_input)
|
140 |
audio_original = video_original.audio.volumex(0.7) if video_original.audio else None
|
@@ -186,11 +172,11 @@ with gr.Blocks() as demo:
|
|
186 |
gr.Markdown("# Editor de Video con IA")
|
187 |
|
188 |
with gr.Tab("Principal"):
|
189 |
-
video_input = gr.Video(label="Subir video"
|
190 |
texto_tts = gr.Textbox(
|
191 |
label="Texto para TTS",
|
192 |
lines=3,
|
193 |
-
|
194 |
)
|
195 |
voz_seleccionada = gr.Dropdown(
|
196 |
label="Voz",
|
@@ -211,6 +197,16 @@ with gr.Blocks() as demo:
|
|
211 |
label="Segundos por corte (manual)"
|
212 |
)
|
213 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
214 |
procesar_btn.click(
|
215 |
procesar_video,
|
216 |
inputs=[
|
|
|
47 |
raise gr.Error("⚠️ Caracteres no permitidos detectados")
|
48 |
|
49 |
async def procesar_audio(texto, voz, duracion_total, duracion_intro):
|
50 |
+
"""Genera TTS y mezcla con música (versión corregida)"""
|
51 |
temp_files = []
|
52 |
try:
|
53 |
+
# Validar texto
|
54 |
+
validar_texto(texto)
|
|
|
|
|
|
|
55 |
|
56 |
# Generar TTS
|
57 |
communicate = edge_tts.Communicate(texto, voz)
|
58 |
with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp:
|
59 |
await communicate.save(tmp.name)
|
60 |
tts_audio = AudioFileClip(tmp.name)
|
61 |
+
temp_files.append(tmp.name)
|
62 |
|
63 |
# Verificar audio válido
|
64 |
if tts_audio.duration < 0.5:
|
65 |
raise RuntimeError(f"Audio TTS inválido ({tts_audio.duration}s)")
|
66 |
+
|
|
|
|
|
67 |
# Procesar música de fondo
|
68 |
+
bg_music = AudioSegment.from_mp3(MUSIC_BG)
|
69 |
+
needed_ms = int(duracion_total * 1000) # <-- Convertir a entero
|
70 |
+
repeticiones = needed_ms // len(bg_music) + 1
|
71 |
+
bg_music = bg_music * repeticiones # <-- Ahora es multiplicación entera
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
72 |
bg_music = bg_music[:needed_ms].fade_out(5000)
|
73 |
|
74 |
with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp:
|
75 |
bg_music.export(tmp.name, format="mp3")
|
76 |
bg_audio = AudioFileClip(tmp.name).volumex(0.15)
|
77 |
temp_files.append(tmp.name)
|
78 |
+
|
79 |
# Combinar audios
|
80 |
audio_final = CompositeAudioClip([
|
81 |
bg_audio,
|
|
|
121 |
|
122 |
async def procesar_video(video_input, texto_tts, voz_seleccionada, metodo_corte, duracion_corte):
|
123 |
try:
|
|
|
|
|
|
|
124 |
# Cargar video con audio original
|
125 |
video_original = VideoFileClip(video_input)
|
126 |
audio_original = video_original.audio.volumex(0.7) if video_original.audio else None
|
|
|
172 |
gr.Markdown("# Editor de Video con IA")
|
173 |
|
174 |
with gr.Tab("Principal"):
|
175 |
+
video_input = gr.Video(label="Subir video")
|
176 |
texto_tts = gr.Textbox(
|
177 |
label="Texto para TTS",
|
178 |
lines=3,
|
179 |
+
placeholder="Escribe aquí tu texto..."
|
180 |
)
|
181 |
voz_seleccionada = gr.Dropdown(
|
182 |
label="Voz",
|
|
|
197 |
label="Segundos por corte (manual)"
|
198 |
)
|
199 |
|
200 |
+
# Ejemplos en footer
|
201 |
+
with gr.Accordion("Ejemplos de Uso", open=False):
|
202 |
+
gr.Examples(
|
203 |
+
examples=[
|
204 |
+
[EJEMPLO_VIDEO, "¡Hola! Esto es una prueba. Suscríbete al canal y activa la campanita."],
|
205 |
+
],
|
206 |
+
inputs=[video_input, texto_tts],
|
207 |
+
label="Ejemplos"
|
208 |
+
)
|
209 |
+
|
210 |
procesar_btn.click(
|
211 |
procesar_video,
|
212 |
inputs=[
|