Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
@@ -12,26 +12,7 @@ from transformers import GPT2Tokenizer, GPT2LMHeadModel
|
|
12 |
from keybert import KeyBERT
|
13 |
import subprocess
|
14 |
import sys
|
15 |
-
|
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", "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 |
-
raise
|
29 |
-
import re
|
30 |
-
import math
|
31 |
-
import shutil
|
32 |
-
import json
|
33 |
-
from collections import Counter
|
34 |
-
import time
|
35 |
|
36 |
# Configuraci贸n de logging
|
37 |
logging.basicConfig(
|
@@ -47,6 +28,31 @@ logger.info("="*80)
|
|
47 |
logger.info("INICIO DE EJECUCI脫N - GENERADOR DE VIDEOS")
|
48 |
logger.info("="*80)
|
49 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
# Diccionario de voces TTS disponibles organizadas por idioma
|
51 |
VOCES_DISPONIBLES = {
|
52 |
"Espa帽ol (Espa帽a)": {
|
@@ -120,7 +126,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,6 +312,9 @@ def download_video_file(url, temp_dir):
|
|
306 |
return None
|
307 |
|
308 |
def loop_audio_to_length(audio_clip, target_duration):
|
|
|
|
|
|
|
309 |
logger.debug(f"Ajustando audio | Duraci贸n actual: {audio_clip.duration:.2f}s | Objetivo: {target_duration:.2f}s")
|
310 |
if audio_clip is None or audio_clip.duration is None or audio_clip.duration <= 0:
|
311 |
logger.warning("Input audio clip is invalid")
|
@@ -409,12 +418,19 @@ async def crear_video_async(prompt_type, input_text, selected_voice, musica_file
|
|
409 |
logger.warning(f"TTS fall贸 para fragmento {i} con voz: {current_voice}")
|
410 |
break
|
411 |
if len(temp_audio_files) == len(text_chunks):
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
clip
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
418 |
tts_success = os.path.exists(voz_path) and os.path.getsize(voz_path) > 100
|
419 |
temp_intermediate_files.extend(temp_audio_files)
|
420 |
if tts_success:
|
@@ -427,11 +443,15 @@ async def crear_video_async(prompt_type, input_text, selected_voice, musica_file
|
|
427 |
raise ValueError(f"Error generando voz. Intentos con {tts_voices_to_try} y gTTS fallaron.")
|
428 |
|
429 |
temp_intermediate_files.append(voz_path)
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
|
|
|
|
|
|
|
|
435 |
logger.info(f"Duraci贸n audio voz: {audio_duration:.2f} segundos")
|
436 |
if audio_duration < 1.0:
|
437 |
raise ValueError("Audio de voz demasiado corto.")
|
@@ -478,6 +498,15 @@ async def crear_video_async(prompt_type, input_text, selected_voice, musica_file
|
|
478 |
raise ValueError("No se descargaron videos utilizables.")
|
479 |
|
480 |
# 5. Procesar y concatenar clips de video
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
481 |
current_duration = 0
|
482 |
min_clip_duration = 0.5
|
483 |
max_clip_segment = 10.0
|
|
|
12 |
from keybert import KeyBERT
|
13 |
import subprocess
|
14 |
import sys
|
15 |
+
import importlib.util
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
|
17 |
# Configuraci贸n de logging
|
18 |
logging.basicConfig(
|
|
|
28 |
logger.info("INICIO DE EJECUCI脫N - GENERADOR DE VIDEOS")
|
29 |
logger.info("="*80)
|
30 |
|
31 |
+
# Forzar reinstalaci贸n de moviepy e imageio-ffmpeg
|
32 |
+
logger.info("Verificando moviepy e imageio-ffmpeg...")
|
33 |
+
try:
|
34 |
+
import moviepy
|
35 |
+
from moviepy.editor import VideoFileClip, concatenate_videoclips, AudioFileClip, CompositeAudioClip, concatenate_audioclips, AudioClip
|
36 |
+
logger.info(f"MoviePy importado correctamente: {moviepy.__version__}")
|
37 |
+
except ImportError:
|
38 |
+
logger.info("MoviePy no encontrado, intentando reinstalar...")
|
39 |
+
try:
|
40 |
+
subprocess.check_call([sys.executable, "-m", "pip", "install", "--no-cache-dir", "moviepy>=1.0.3", "imageio-ffmpeg>=0.5.1"])
|
41 |
+
import moviepy
|
42 |
+
from moviepy.editor import VideoFileClip, concatenate_videoclips, AudioFileClip, CompositeAudioClip, concatenate_audioclips, AudioClip
|
43 |
+
logger.info(f"MoviePy instalado tras reintento: {moviepy.__version__}")
|
44 |
+
except Exception as e:
|
45 |
+
logger.critical(f"Fallo al instalar moviepy: {str(e)}")
|
46 |
+
logger.info("Continuando con placeholder para pruebas...")
|
47 |
+
moviepy = None # Placeholder para evitar errores
|
48 |
+
|
49 |
+
import re
|
50 |
+
import math
|
51 |
+
import shutil
|
52 |
+
import json
|
53 |
+
from collections import Counter
|
54 |
+
import time
|
55 |
+
|
56 |
# Diccionario de voces TTS disponibles organizadas por idioma
|
57 |
VOCES_DISPONIBLES = {
|
58 |
"Espa帽ol (Espa帽a)": {
|
|
|
126 |
|
127 |
# Obtener las voces al inicio del script
|
128 |
AVAILABLE_VOICES = get_voice_choices()
|
129 |
+
DEFAULT_VOICE_ID = "es-MX-DaliaNeural" # Voz m谩s estable
|
130 |
DEFAULT_VOICE_NAME = DEFAULT_VOICE_ID
|
131 |
for text, voice_id in AVAILABLE_VOICES:
|
132 |
if voice_id == DEFAULT_VOICE_ID:
|
|
|
312 |
return None
|
313 |
|
314 |
def loop_audio_to_length(audio_clip, target_duration):
|
315 |
+
if not moviepy:
|
316 |
+
logger.warning("MoviePy no disponible, retornando audio vac铆o")
|
317 |
+
return AudioClip(lambda t: 0, duration=target_duration, fps=44100) if 'AudioClip' in globals() else None
|
318 |
logger.debug(f"Ajustando audio | Duraci贸n actual: {audio_clip.duration:.2f}s | Objetivo: {target_duration:.2f}s")
|
319 |
if audio_clip is None or audio_clip.duration is None or audio_clip.duration <= 0:
|
320 |
logger.warning("Input audio clip is invalid")
|
|
|
418 |
logger.warning(f"TTS fall贸 para fragmento {i} con voz: {current_voice}")
|
419 |
break
|
420 |
if len(temp_audio_files) == len(text_chunks):
|
421 |
+
if moviepy:
|
422 |
+
audio_clips = [AudioFileClip(f) for f in temp_audio_files]
|
423 |
+
concatenated_audio = concatenate_audioclips(audio_clips)
|
424 |
+
concatenated_audio.write_audiofile(voz_path, codec='mp3')
|
425 |
+
concatenated_audio.close()
|
426 |
+
for clip in audio_clips:
|
427 |
+
clip.close()
|
428 |
+
else:
|
429 |
+
logger.warning("MoviePy no disponible, uniendo audios con fallback...")
|
430 |
+
with open(voz_path, 'wb') as outfile:
|
431 |
+
for fname in temp_audio_files:
|
432 |
+
with open(fname, 'rb') as infile:
|
433 |
+
outfile.write(infile.read())
|
434 |
tts_success = os.path.exists(voz_path) and os.path.getsize(voz_path) > 100
|
435 |
temp_intermediate_files.extend(temp_audio_files)
|
436 |
if tts_success:
|
|
|
443 |
raise ValueError(f"Error generando voz. Intentos con {tts_voices_to_try} y gTTS fallaron.")
|
444 |
|
445 |
temp_intermediate_files.append(voz_path)
|
446 |
+
if moviepy:
|
447 |
+
audio_tts_original = AudioFileClip(voz_path)
|
448 |
+
if audio_tts_original.duration is None or audio_tts_original.duration <= 0:
|
449 |
+
raise ValueError("Audio de voz generado es inv谩lido.")
|
450 |
+
audio_tts = audio_tts_original
|
451 |
+
audio_duration = audio_tts_original.duration
|
452 |
+
else:
|
453 |
+
logger.warning("MoviePy no disponible, asumiendo duraci贸n m铆nima para audio")
|
454 |
+
audio_duration = 1.0 # Valor placeholder
|
455 |
logger.info(f"Duraci贸n audio voz: {audio_duration:.2f} segundos")
|
456 |
if audio_duration < 1.0:
|
457 |
raise ValueError("Audio de voz demasiado corto.")
|
|
|
498 |
raise ValueError("No se descargaron videos utilizables.")
|
499 |
|
500 |
# 5. Procesar y concatenar clips de video
|
501 |
+
if not moviepy:
|
502 |
+
logger.warning("MoviePy no disponible, retornando placeholder...")
|
503 |
+
output_filename = f"video_{int(datetime.now().timestamp())}.mp4"
|
504 |
+
persistent_path = os.path.join("/data", output_filename)
|
505 |
+
os.makedirs("/data", exist_ok=True)
|
506 |
+
open(persistent_path, 'a').close() # Crea archivo vac铆o como placeholder
|
507 |
+
download_url = f"https://gnosticdev-invideo-basic.hf.space/file={persistent_path}"
|
508 |
+
return persistent_path, download_url
|
509 |
+
|
510 |
current_duration = 0
|
511 |
min_clip_duration = 0.5
|
512 |
max_clip_segment = 10.0
|