Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
@@ -10,23 +10,7 @@ import gradio as gr
|
|
10 |
import torch
|
11 |
from transformers import GPT2Tokenizer, GPT2LMHeadModel
|
12 |
from keybert import KeyBERT
|
13 |
-
import
|
14 |
-
import sys
|
15 |
-
try:
|
16 |
-
from moviepy.editor import VideoFileClip, concatenate_videoclips, AudioFileClip, CompositeAudioClip, concatenate_audioclips, AudioClip
|
17 |
-
logger = logging.getLogger(__name__)
|
18 |
-
logger.info("MoviePy importado correctamente")
|
19 |
-
except ImportError:
|
20 |
-
logger = logging.getLogger(__name__)
|
21 |
-
logger.info("Intentando instalar moviepy e imageio-ffmpeg...")
|
22 |
-
try:
|
23 |
-
subprocess.check_call([sys.executable, "-m", "pip", "install", "--no-cache-dir", "moviepy>=1.0.3", "imageio-ffmpeg>=0.5.1"])
|
24 |
-
from moviepy.editor import VideoFileClip, concatenate_videoclips, AudioFileClip, CompositeAudioClip, concatenate_audioclips, AudioClip
|
25 |
-
logger.info("MoviePy instalado tras reintento")
|
26 |
-
except Exception as e:
|
27 |
-
logger.critical(f"Fallo al instalar moviepy: {str(e)}")
|
28 |
-
logger.info("Continuando con placeholder para pruebas...")
|
29 |
-
moviepy = None # Placeholder para evitar errores
|
30 |
import re
|
31 |
import math
|
32 |
import shutil
|
@@ -43,6 +27,7 @@ logging.basicConfig(
|
|
43 |
logging.FileHandler('video_generator_full.log', encoding='utf-8')
|
44 |
]
|
45 |
)
|
|
|
46 |
logger.info("="*80)
|
47 |
logger.info("INICIO DE EJECUCI脫N - GENERADOR DE VIDEOS")
|
48 |
logger.info("="*80)
|
@@ -120,7 +105,7 @@ def get_voice_choices():
|
|
120 |
|
121 |
# Obtener las voces al inicio del script
|
122 |
AVAILABLE_VOICES = get_voice_choices()
|
123 |
-
DEFAULT_VOICE_ID = "es-MX-DaliaNeural" #
|
124 |
DEFAULT_VOICE_NAME = DEFAULT_VOICE_ID
|
125 |
for text, voice_id in AVAILABLE_VOICES:
|
126 |
if voice_id == DEFAULT_VOICE_ID:
|
@@ -306,9 +291,6 @@ def download_video_file(url, temp_dir):
|
|
306 |
return None
|
307 |
|
308 |
def loop_audio_to_length(audio_clip, target_duration):
|
309 |
-
if not moviepy:
|
310 |
-
logger.warning("MoviePy no disponible, retornando audio vac铆o")
|
311 |
-
return AudioClip(lambda t: 0, duration=target_duration, fps=44100) if 'AudioClip' in globals() else None
|
312 |
logger.debug(f"Ajustando audio | Duraci贸n actual: {audio_clip.duration:.2f}s | Objetivo: {target_duration:.2f}s")
|
313 |
if audio_clip is None or audio_clip.duration is None or audio_clip.duration <= 0:
|
314 |
logger.warning("Input audio clip is invalid")
|
@@ -412,19 +394,12 @@ async def crear_video_async(prompt_type, input_text, selected_voice, musica_file
|
|
412 |
logger.warning(f"TTS fall贸 para fragmento {i} con voz: {current_voice}")
|
413 |
break
|
414 |
if len(temp_audio_files) == len(text_chunks):
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
clip.close()
|
422 |
-
else:
|
423 |
-
logger.warning("MoviePy no disponible, uniendo audios con fallback...")
|
424 |
-
with open(voz_path, 'wb') as outfile:
|
425 |
-
for fname in temp_audio_files:
|
426 |
-
with open(fname, 'rb') as infile:
|
427 |
-
outfile.write(infile.read())
|
428 |
tts_success = os.path.exists(voz_path) and os.path.getsize(voz_path) > 100
|
429 |
temp_intermediate_files.extend(temp_audio_files)
|
430 |
if tts_success:
|
@@ -437,15 +412,11 @@ async def crear_video_async(prompt_type, input_text, selected_voice, musica_file
|
|
437 |
raise ValueError(f"Error generando voz. Intentos con {tts_voices_to_try} y gTTS fallaron.")
|
438 |
|
439 |
temp_intermediate_files.append(voz_path)
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
audio_duration = audio_tts_original.duration
|
446 |
-
else:
|
447 |
-
logger.warning("MoviePy no disponible, asumiendo duraci贸n m铆nima para audio")
|
448 |
-
audio_duration = 1.0 # Valor placeholder
|
449 |
logger.info(f"Duraci贸n audio voz: {audio_duration:.2f} segundos")
|
450 |
if audio_duration < 1.0:
|
451 |
raise ValueError("Audio de voz demasiado corto.")
|
@@ -492,15 +463,6 @@ async def crear_video_async(prompt_type, input_text, selected_voice, musica_file
|
|
492 |
raise ValueError("No se descargaron videos utilizables.")
|
493 |
|
494 |
# 5. Procesar y concatenar clips de video
|
495 |
-
if not moviepy:
|
496 |
-
logger.warning("MoviePy no disponible, retornando placeholder...")
|
497 |
-
output_filename = f"video_{int(datetime.now().timestamp())}.mp4"
|
498 |
-
persistent_path = os.path.join("/data", output_filename)
|
499 |
-
os.makedirs("/data", exist_ok=True)
|
500 |
-
open(persistent_path, 'a').close() # Crea archivo vac铆o como placeholder
|
501 |
-
download_url = f"https://gnosticdev-invideo-basic.hf.space/file={persistent_path}"
|
502 |
-
return persistent_path, download_url
|
503 |
-
|
504 |
current_duration = 0
|
505 |
min_clip_duration = 0.5
|
506 |
max_clip_segment = 10.0
|
@@ -766,6 +728,15 @@ with gr.Blocks(title="Generador de Videos con IA", theme=gr.themes.Soft()) as ap
|
|
766 |
""")
|
767 |
|
768 |
if __name__ == "__main__":
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
769 |
os.environ['GRADIO_SERVER_TIMEOUT'] = '3600'
|
770 |
logger.info("Iniciando aplicaci贸n Gradio...")
|
771 |
try:
|
|
|
10 |
import torch
|
11 |
from transformers import GPT2Tokenizer, GPT2LMHeadModel
|
12 |
from keybert import KeyBERT
|
13 |
+
from moviepy.editor import VideoFileClip, concatenate_videoclips, AudioFileClip, CompositeAudioClip, concatenate_audioclips, AudioClip
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
import re
|
15 |
import math
|
16 |
import shutil
|
|
|
27 |
logging.FileHandler('video_generator_full.log', encoding='utf-8')
|
28 |
]
|
29 |
)
|
30 |
+
logger = logging.getLogger(__name__)
|
31 |
logger.info("="*80)
|
32 |
logger.info("INICIO DE EJECUCI脫N - GENERADOR DE VIDEOS")
|
33 |
logger.info("="*80)
|
|
|
105 |
|
106 |
# Obtener las voces al inicio del script
|
107 |
AVAILABLE_VOICES = get_voice_choices()
|
108 |
+
DEFAULT_VOICE_ID = "es-MX-DaliaNeural" # Cambiado a una voz m谩s estable
|
109 |
DEFAULT_VOICE_NAME = DEFAULT_VOICE_ID
|
110 |
for text, voice_id in AVAILABLE_VOICES:
|
111 |
if voice_id == DEFAULT_VOICE_ID:
|
|
|
291 |
return None
|
292 |
|
293 |
def loop_audio_to_length(audio_clip, target_duration):
|
|
|
|
|
|
|
294 |
logger.debug(f"Ajustando audio | Duraci贸n actual: {audio_clip.duration:.2f}s | Objetivo: {target_duration:.2f}s")
|
295 |
if audio_clip is None or audio_clip.duration is None or audio_clip.duration <= 0:
|
296 |
logger.warning("Input audio clip is invalid")
|
|
|
394 |
logger.warning(f"TTS fall贸 para fragmento {i} con voz: {current_voice}")
|
395 |
break
|
396 |
if len(temp_audio_files) == len(text_chunks):
|
397 |
+
audio_clips = [AudioFileClip(f) for f in temp_audio_files]
|
398 |
+
concatenated_audio = concatenate_audioclips(audio_clips)
|
399 |
+
concatenated_audio.write_audiofile(voz_path, codec='mp3')
|
400 |
+
concatenated_audio.close()
|
401 |
+
for clip in audio_clips:
|
402 |
+
clip.close()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
403 |
tts_success = os.path.exists(voz_path) and os.path.getsize(voz_path) > 100
|
404 |
temp_intermediate_files.extend(temp_audio_files)
|
405 |
if tts_success:
|
|
|
412 |
raise ValueError(f"Error generando voz. Intentos con {tts_voices_to_try} y gTTS fallaron.")
|
413 |
|
414 |
temp_intermediate_files.append(voz_path)
|
415 |
+
audio_tts_original = AudioFileClip(voz_path)
|
416 |
+
if audio_tts_original.duration is None or audio_tts_original.duration <= 0:
|
417 |
+
raise ValueError("Audio de voz generado es inv谩lido.")
|
418 |
+
audio_tts = audio_tts_original
|
419 |
+
audio_duration = audio_tts_original.duration
|
|
|
|
|
|
|
|
|
420 |
logger.info(f"Duraci贸n audio voz: {audio_duration:.2f} segundos")
|
421 |
if audio_duration < 1.0:
|
422 |
raise ValueError("Audio de voz demasiado corto.")
|
|
|
463 |
raise ValueError("No se descargaron videos utilizables.")
|
464 |
|
465 |
# 5. Procesar y concatenar clips de video
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
466 |
current_duration = 0
|
467 |
min_clip_duration = 0.5
|
468 |
max_clip_segment = 10.0
|
|
|
728 |
""")
|
729 |
|
730 |
if __name__ == "__main__":
|
731 |
+
logger.info("Verificando dependencias...")
|
732 |
+
try:
|
733 |
+
from moviepy.editor import ColorClip
|
734 |
+
temp_clip = ColorClip((100,100), color=(255,0,0), duration=0.1)
|
735 |
+
temp_clip.close()
|
736 |
+
logger.info("MoviePy y FFmpeg accesibles.")
|
737 |
+
except Exception as e:
|
738 |
+
logger.critical(f"Fallo en dependencias: {e}")
|
739 |
+
raise
|
740 |
os.environ['GRADIO_SERVER_TIMEOUT'] = '3600'
|
741 |
logger.info("Iniciando aplicaci贸n Gradio...")
|
742 |
try:
|