gnosticdev commited on
Commit
beea2cf
verified
1 Parent(s): cbab17b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +113 -76
app.py CHANGED
@@ -3,13 +3,16 @@ import math
3
  import tempfile
4
  from pydub import AudioSegment
5
  from moviepy.editor import (
6
- VideoFileClip, AudioFileClip, ImageClip,
7
- concatenate_videoclips, CompositeVideoClip,
8
- concatenate_audioclips
9
  )
10
  import edge_tts
11
  import gradio as gr
12
  import asyncio
 
 
 
 
13
 
14
  # CONSTANTES DE ARCHIVOS
15
  INTRO_VIDEO = "introvideo.mp4"
@@ -21,65 +24,85 @@ WATERMARK = "watermark.png"
21
  # Validar existencia de archivos obligatorios
22
  for file in [INTRO_VIDEO, OUTRO_VIDEO, MUSIC_BG, FX_SOUND, WATERMARK]:
23
  if not os.path.exists(file):
 
24
  raise FileNotFoundError(f"Falta archivo necesario: {file}")
25
 
26
  def cortar_video(video_path, metodo="inteligente", duracion=10):
27
- video = VideoFileClip(video_path)
28
- if metodo == "manual":
29
- return [video.subclip(i*duracion, (i+1)*duracion)
30
- for i in range(math.ceil(video.duration/duracion))]
31
-
32
- # Implementaci贸n b谩sica de cortes por voz (requerir铆a VAD real)
33
- clips = []
34
- ultimo_corte = 0
35
- for i in range(1, math.ceil(video.duration)):
36
- if i % 5 == 0: # Simulaci贸n de detecci贸n de pausas
37
- clips.append(video.subclip(ultimo_corte, i))
38
- ultimo_corte = i
39
- return clips
 
 
 
 
 
 
 
 
40
 
41
  def procesar_audio(texto, voz, clips_duracion):
42
- communicate = edge_tts.Communicate(texto, voz)
43
- with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp:
44
- asyncio.run(communicate.save(tmp.name))
45
- tts_audio = AudioFileClip(tmp.name)
46
-
47
- # Ajustar TTS a duraci贸n de clips
48
- if tts_audio.duration < clips_duracion:
49
- tts_audio = tts_audio.loop(duration=clips_duracion)
50
- else:
51
- tts_audio = tts_audio.subclip(0, clips_duracion)
52
-
53
- # Mezclar con m煤sica de fondo
54
- bg_music = AudioSegment.from_mp3(MUSIC_BG)
55
- if len(bg_music) < clips_duracion*1000:
56
- bg_music = bg_music * math.ceil(clips_duracion*1000 / len(bg_music))
57
- bg_music = bg_music[:clips_duracion*1000].fade_out(3000)
58
-
59
- with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp:
60
- bg_music.export(tmp.name, format="mp3")
61
- bg_audio = AudioFileClip(tmp.name).volumex(0.10)
62
-
63
- return CompositeAudioClip([bg_audio, tts_audio.volumex(0.9)])
 
 
 
 
 
 
64
 
65
  def agregar_transiciones(clips):
66
- fx_audio = AudioFileClip(FX_SOUND).set_duration(2.5)
67
- transicion = ImageClip(WATERMARK).set_duration(2.5)
68
- transicion = transicion.resize(height=clips[0].h).set_position(("center", 0.1))
69
-
70
- clips_con_fx = []
71
- for i, clip in enumerate(clips):
72
- # Agregar watermark
73
- clip_watermarked = CompositeVideoClip([clip, transicion])
74
- clips_con_fx.append(clip_watermarked)
75
 
76
- if i < len(clips)-1:
77
- clips_con_fx.append(
78
- CompositeVideoClip([transicion.set_position("center")])
79
- .set_audio(fx_audio)
80
- )
81
-
82
- return concatenate_videoclips(clips_con_fx)
 
 
 
 
 
 
 
 
 
83
 
84
  async def procesar_video(
85
  video_input,
@@ -88,28 +111,41 @@ async def procesar_video(
88
  metodo_corte,
89
  duracion_corte
90
  ):
91
- # Procesar video principal
92
- clips = cortar_video(video_input, metodo_corte, duracion_corte)
93
- video_editado = agregar_transiciones(clips)
94
-
95
- # Agregar intro/outro
96
- intro = VideoFileClip(INTRO_VIDEO)
97
- outro = VideoFileClip(OUTRO_VIDEO)
98
- video_final = concatenate_videoclips([intro, video_editado, outro])
99
-
100
- # Procesar audio
101
- audio_final = procesar_audio(
102
- texto_tts,
103
- voz_seleccionada,
104
- video_editado.duration
105
- )
106
-
107
- # Combinar y renderizar
108
- video_final = video_final.set_audio(audio_final)
109
-
110
- with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as tmp:
111
- video_final.write_videofile(tmp.name, codec="libx264", fps=24)
112
- return tmp.name
 
 
 
 
 
 
 
 
 
 
 
 
 
113
 
114
  # Interfaz Gradio
115
  with gr.Blocks() as demo:
@@ -149,4 +185,5 @@ with gr.Blocks() as demo:
149
  )
150
 
151
  if __name__ == "__main__":
 
152
  demo.queue().launch()
 
3
  import tempfile
4
  from pydub import AudioSegment
5
  from moviepy.editor import (
6
+ VideoFileClip, AudioFileClip, ImageClip,
7
+ concatenate_videoclips, CompositeVideoClip
 
8
  )
9
  import edge_tts
10
  import gradio as gr
11
  import asyncio
12
+ import logging
13
+
14
+ # Configuraci贸n de Logs
15
+ logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
16
 
17
  # CONSTANTES DE ARCHIVOS
18
  INTRO_VIDEO = "introvideo.mp4"
 
24
  # Validar existencia de archivos obligatorios
25
  for file in [INTRO_VIDEO, OUTRO_VIDEO, MUSIC_BG, FX_SOUND, WATERMARK]:
26
  if not os.path.exists(file):
27
+ logging.error(f"Falta archivo necesario: {file}")
28
  raise FileNotFoundError(f"Falta archivo necesario: {file}")
29
 
30
  def cortar_video(video_path, metodo="inteligente", duracion=10):
31
+ try:
32
+ logging.info("Iniciando corte de video...")
33
+ video = VideoFileClip(video_path)
34
+ if metodo == "manual":
35
+ clips = [video.subclip(i * duracion, (i + 1) * duracion)
36
+ for i in range(math.ceil(video.duration / duracion))]
37
+ logging.info(f"Video cortado en {len(clips)} clips manuales.")
38
+ return clips
39
+
40
+ # Simulaci贸n b谩sica de cortes autom谩ticos (puedes mejorar esto con VAD)
41
+ clips = []
42
+ ultimo_corte = 0
43
+ for i in range(1, math.ceil(video.duration)):
44
+ if i % 5 == 0: # Simulaci贸n de pausas
45
+ clips.append(video.subclip(ultimo_corte, i))
46
+ ultimo_corte = i
47
+ logging.info(f"Video cortado en {len(clips)} clips autom谩ticos.")
48
+ return clips
49
+ except Exception as e:
50
+ logging.error(f"Error al cortar video: {e}")
51
+ raise
52
 
53
  def procesar_audio(texto, voz, clips_duracion):
54
+ try:
55
+ logging.info("Generando TTS y mezclando audio...")
56
+ communicate = edge_tts.Communicate(texto, voz)
57
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp:
58
+ asyncio.run(communicate.save(tmp.name))
59
+ tts_audio = AudioFileClip(tmp.name)
60
+
61
+ # Ajustar TTS a duraci贸n de clips
62
+ if tts_audio.duration < clips_duracion:
63
+ tts_audio = tts_audio.loop(duration=clips_duracion)
64
+ else:
65
+ tts_audio = tts_audio.subclip(0, clips_duracion)
66
+
67
+ # Mezclar con m煤sica de fondo
68
+ bg_music = AudioSegment.from_mp3(MUSIC_BG)
69
+ if len(bg_music) < clips_duracion * 1000:
70
+ bg_music = bg_music * math.ceil(clips_duracion * 1000 / len(bg_music))
71
+ bg_music = bg_music[:clips_duracion * 1000].fade_out(3000)
72
+
73
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp:
74
+ bg_music.export(tmp.name, format="mp3")
75
+ bg_audio = AudioFileClip(tmp.name).volumex(0.10)
76
+
77
+ logging.info("Audio procesado correctamente.")
78
+ return CompositeAudioClip([bg_audio, tts_audio.volumex(0.9)])
79
+ except Exception as e:
80
+ logging.error(f"Error al procesar audio: {e}")
81
+ raise
82
 
83
  def agregar_transiciones(clips):
84
+ try:
85
+ logging.info("Agregando transiciones...")
86
+ fx_audio = AudioFileClip(FX_SOUND).set_duration(2.5)
87
+ transicion = ImageClip(WATERMARK).set_duration(2.5)
88
+ transicion = transicion.resize(height=clips[0].h, resample=Image.Resampling.LANCZOS).set_position(("center", 0.1))
 
 
 
 
89
 
90
+ clips_con_fx = []
91
+ for i, clip in enumerate(clips):
92
+ # Agregar watermark
93
+ clip_watermarked = CompositeVideoClip([clip, transicion])
94
+ clips_con_fx.append(clip_watermarked)
95
+
96
+ if i < len(clips) - 1:
97
+ clips_con_fx.append(
98
+ CompositeVideoClip([transicion.set_position("center")])
99
+ .set_audio(fx_audio)
100
+ )
101
+ logging.info("Transiciones agregadas correctamente.")
102
+ return concatenate_videoclips(clips_con_fx)
103
+ except Exception as e:
104
+ logging.error(f"Error al agregar transiciones: {e}")
105
+ raise
106
 
107
  async def procesar_video(
108
  video_input,
 
111
  metodo_corte,
112
  duracion_corte
113
  ):
114
+ temp_files = []
115
+ try:
116
+ logging.info("Iniciando procesamiento de video...")
117
+ # Procesar video principal
118
+ clips = cortar_video(video_input, metodo_corte, duracion_corte)
119
+ video_editado = agregar_transiciones(clips)
120
+
121
+ # Agregar intro/outro
122
+ intro = VideoFileClip(INTRO_VIDEO)
123
+ outro = VideoFileClip(OUTRO_VIDEO)
124
+ video_final = concatenate_videoclips([intro, video_editado, outro])
125
+
126
+ # Procesar audio
127
+ audio_final = procesar_audio(texto_tts, voz_seleccionada, video_editado.duration)
128
+
129
+ # Combinar y renderizar
130
+ video_final = video_final.set_audio(audio_final)
131
+
132
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as tmp:
133
+ video_final.write_videofile(tmp.name, codec="libx264", fps=24)
134
+ logging.info("Video procesado y guardado temporalmente.")
135
+ temp_files.append(tmp.name)
136
+ return tmp.name
137
+ except Exception as e:
138
+ logging.error(f"Error durante el procesamiento: {e}")
139
+ raise
140
+ finally:
141
+ # Eliminar archivos temporales
142
+ for file in temp_files:
143
+ try:
144
+ if os.path.exists(file):
145
+ os.remove(file)
146
+ logging.info(f"Archivo temporal eliminado: {file}")
147
+ except Exception as e:
148
+ logging.warning(f"No se pudo eliminar el archivo temporal {file}: {e}")
149
 
150
  # Interfaz Gradio
151
  with gr.Blocks() as demo:
 
185
  )
186
 
187
  if __name__ == "__main__":
188
+ logging.info("Iniciando aplicaci贸n Gradio...")
189
  demo.queue().launch()