gnosticdev commited on
Commit
8eb6c1b
verified
1 Parent(s): f9e7c43

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +43 -108
app.py CHANGED
@@ -14,11 +14,10 @@ logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(
14
  INTRO_VIDEO = "introvideo.mp4"
15
  OUTRO_VIDEO = "outrovideo.mp4"
16
  MUSIC_BG = "musicafondo.mp3"
17
- GLITCH_SOUND = "fxsound.mp3"
18
  EJEMPLO_VIDEO = "ejemplo.mp4"
19
 
20
  # Validar existencia de archivos
21
- for file in [INTRO_VIDEO, OUTRO_VIDEO, MUSIC_BG, GLITCH_SOUND, EJEMPLO_VIDEO]:
22
  if not os.path.exists(file):
23
  logging.error(f"Falta archivo necesario: {file}")
24
  raise FileNotFoundError(f"Falta: {file}")
@@ -38,50 +37,26 @@ def eliminar_archivo_tiempo(ruta, delay=1800):
38
  from threading import Timer
39
  Timer(delay, eliminar).start()
40
 
41
- async def procesar_audio_tts(texto, voz, duracion_video):
42
- temp_files = []
43
  try:
44
- logging.info("Iniciando procesamiento de TTS")
45
- if not texto.strip():
46
- raise ValueError("El texto para TTS no puede estar vac铆o.")
47
-
48
- # Dividir texto en fragmentos manejables
49
- def dividir_texto(texto, max_length=2000):
50
- return [texto[i:i + max_length] for i in range(0, len(texto), max_length)]
51
-
52
- fragmentos = dividir_texto(texto)
53
- audios_tts = []
54
-
55
- for fragmento in fragmentos:
56
- communicate = edge_tts.Communicate(fragmento, voz)
57
- with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp_tts:
58
- await communicate.save(tmp_tts.name)
59
- tts_audio = AudioFileClip(tmp_tts.name)
60
- temp_files.append(tmp_tts.name)
61
- audios_tts.append(tts_audio)
62
-
63
- tts_audio_final = concatenate_audioclips(audios_tts)
64
-
65
- if tts_audio_final.duration > duracion_video:
66
- tts_audio_final = tts_audio_final.subclip(0, duracion_video)
67
-
68
- logging.info("TTS procesado exitosamente")
69
- return tts_audio_final, temp_files
70
-
71
  except Exception as e:
72
- logging.error(f"Fallo en procesamiento de TTS: {str(e)}")
73
  raise
74
- finally:
75
- for file in temp_files:
76
- try:
77
- os.remove(file)
78
- except Exception as e:
79
- logging.warning(f"Error limpiando {file}: {e}")
80
 
81
- def crear_musica_fondo(duracion_video):
82
- """Crea un loop continuo de m煤sica de fondo."""
83
  bg_music = AudioSegment.from_mp3(MUSIC_BG)
84
- needed_ms = int(duracion_video * 1000)
85
  repeticiones = needed_ms // len(bg_music) + 1
86
  bg_music = bg_music * repeticiones
87
  bg_music = bg_music[:needed_ms].fade_out(1000)
@@ -90,91 +65,51 @@ def crear_musica_fondo(duracion_video):
90
  bg_music.export(tmp_bg.name, format="mp3")
91
  return AudioFileClip(tmp_bg.name).volumex(0.15), tmp_bg.name
92
 
93
- async def procesar_fragmento(chunk, texto_tts, voz_seleccionada, start_time):
94
- try:
95
- duracion_chunk = chunk.duration
96
-
97
- # Procesar TTS para este chunk
98
- tts_audio_final, tts_temp_files = await procesar_audio_tts(
99
- texto_tts,
100
- voz_seleccionada,
101
- duracion_chunk
102
- )
103
-
104
- # Crear m煤sica de fondo continua
105
- bg_audio, bg_temp_file = crear_musica_fondo(duracion_chunk)
106
-
107
- # Combinar pistas de audio
108
- audio_original = chunk.audio
109
- audios = [bg_audio.set_duration(duracion_chunk)]
110
- if audio_original:
111
- audios.append(audio_original.volumex(0.7))
112
- audios.append(tts_audio_final.volumex(0.85).set_start(0))
113
-
114
- audio_final = CompositeAudioClip(audios).set_duration(duracion_chunk)
115
-
116
- # Dividir el chunk en segmentos con cortes de 2 segundos
117
- segment_duration = 18
118
- overlap = 2
119
- segments = []
120
-
121
- current_time = 0
122
- while current_time < duracion_chunk:
123
- end_time = current_time + segment_duration
124
- end_time = min(end_time, duracion_chunk)
125
-
126
- full_segment = chunk.subclip(current_time, end_time)
127
- segments.append(full_segment)
128
- current_time += (segment_duration - overlap)
129
-
130
- # Asegurar que haya al menos un segmento
131
- if not segments:
132
- logging.warning("Chunk demasiado corto, devolviendo el chunk original.")
133
- video_chunk = chunk.set_audio(audio_final)
134
- else:
135
- video_chunk = concatenate_videoclips(segments, method="compose")
136
- video_chunk = video_chunk.set_audio(audio_final)
137
-
138
- return video_chunk, tts_temp_files + [bg_temp_file]
139
-
140
- except Exception as e:
141
- logging.error(f"Fallo procesando fragmento: {str(e)}")
142
- raise
143
-
144
  async def procesar_video(video_input, texto_tts, voz_seleccionada):
145
  temp_files = []
146
- intro, outro = None, None # Inicializar variables para evitar errores
147
  try:
148
- logging.info("Iniciando procesamiento de video")
149
  video_original = VideoFileClip(video_input, target_resolution=(720, 1280))
150
- total_duration = video_original.duration
 
 
 
 
 
 
 
 
 
 
 
 
 
151
 
152
- # Dividir en chunks
153
  chunks = []
154
- for start in range(0, int(total_duration), CHUNK_SIZE):
155
- end = min(start + CHUNK_SIZE, total_duration)
156
  chunk = video_original.subclip(start, end)
157
- chunks.append((start, chunk))
158
 
159
  # Procesar cada chunk
160
  processed_clips = []
161
- for i, (start_time, chunk) in enumerate(chunks):
162
- logging.info(f"Procesando chunk {i+1}/{len(chunks)}")
163
- processed_chunk, chunk_temp_files = await procesar_fragmento(chunk, texto_tts, voz_seleccionada, start_time)
164
- processed_clips.append(processed_chunk)
165
- temp_files.extend(chunk_temp_files)
166
 
167
- # Combinar chunks
168
- final_video = concatenate_videoclips(processed_clips, method="compose")
 
169
 
170
  # Agregar intro y outro
171
  intro = VideoFileClip(INTRO_VIDEO, target_resolution=(720, 1280))
172
  outro = VideoFileClip(OUTRO_VIDEO, target_resolution=(720, 1280))
173
- final_video = concatenate_videoclips([intro, final_video, outro], method="compose")
174
 
175
  # Renderizado final
176
  with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as tmp:
177
- final_video.write_videofile(
178
  tmp.name,
179
  codec="libx264",
180
  audio_codec="aac",
 
14
  INTRO_VIDEO = "introvideo.mp4"
15
  OUTRO_VIDEO = "outrovideo.mp4"
16
  MUSIC_BG = "musicafondo.mp3"
 
17
  EJEMPLO_VIDEO = "ejemplo.mp4"
18
 
19
  # Validar existencia de archivos
20
+ for file in [INTRO_VIDEO, OUTRO_VIDEO, MUSIC_BG, EJEMPLO_VIDEO]:
21
  if not os.path.exists(file):
22
  logging.error(f"Falta archivo necesario: {file}")
23
  raise FileNotFoundError(f"Falta: {file}")
 
37
  from threading import Timer
38
  Timer(delay, eliminar).start()
39
 
40
+ async def generar_tts(texto, voz, duracion_total):
 
41
  try:
42
+ logging.info("Generando TTS")
43
+ communicate = edge_tts.Communicate(texto, voz)
44
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp_tts:
45
+ await communicate.save(tmp_tts.name)
46
+ tts_audio = AudioFileClip(tmp_tts.name)
47
+
48
+ # Asegurar que el TTS no exceda la duraci贸n del video
49
+ if tts_audio.duration > duracion_total:
50
+ tts_audio = tts_audio.subclip(0, duracion_total)
51
+
52
+ return tts_audio, tmp_tts.name
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  except Exception as e:
54
+ logging.error(f"Fallo en TTS: {str(e)}")
55
  raise
 
 
 
 
 
 
56
 
57
+ def crear_musica_fondo(duracion_total):
 
58
  bg_music = AudioSegment.from_mp3(MUSIC_BG)
59
+ needed_ms = int(duracion_total * 1000)
60
  repeticiones = needed_ms // len(bg_music) + 1
61
  bg_music = bg_music * repeticiones
62
  bg_music = bg_music[:needed_ms].fade_out(1000)
 
65
  bg_music.export(tmp_bg.name, format="mp3")
66
  return AudioFileClip(tmp_bg.name).volumex(0.15), tmp_bg.name
67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  async def procesar_video(video_input, texto_tts, voz_seleccionada):
69
  temp_files = []
70
+ intro, outro, video_original = None, None, None
71
  try:
72
+ logging.info("Iniciando procesamiento")
73
  video_original = VideoFileClip(video_input, target_resolution=(720, 1280))
74
+ duracion_video = video_original.duration
75
+
76
+ # Generar TTS y m煤sica de fondo para todo el video
77
+ tts_audio, tts_path = await generar_tts(texto_tts, voz_seleccionada, duracion_video)
78
+ bg_audio, bg_path = crear_musica_fondo(duracion_video)
79
+ temp_files.extend([tts_path, bg_path])
80
+
81
+ # Combinar audios
82
+ audio_original = video_original.audio.volumex(0.7) if video_original.audio else None
83
+ audios = [bg_audio.set_duration(duracion_video)]
84
+ if audio_original:
85
+ audios.append(audio_original)
86
+ audios.append(tts_audio.set_start(0).volumex(0.85))
87
+ audio_final = CompositeAudioClip(audios).set_duration(duracion_video)
88
 
89
+ # Dividir video en chunks para procesamiento
90
  chunks = []
91
+ for start in range(0, int(duracion_video), CHUNK_SIZE):
92
+ end = min(start + CHUNK_SIZE, duracion_video)
93
  chunk = video_original.subclip(start, end)
94
+ chunks.append(chunk)
95
 
96
  # Procesar cada chunk
97
  processed_clips = []
98
+ for chunk in chunks:
99
+ processed_clips.append(chunk)
 
 
 
100
 
101
+ # Combinar chunks (sin efectos)
102
+ video_final = concatenate_videoclips(processed_clips, method="compose")
103
+ video_final = video_final.set_audio(audio_final)
104
 
105
  # Agregar intro y outro
106
  intro = VideoFileClip(INTRO_VIDEO, target_resolution=(720, 1280))
107
  outro = VideoFileClip(OUTRO_VIDEO, target_resolution=(720, 1280))
108
+ video_final = concatenate_videoclips([intro, video_final, outro], method="compose")
109
 
110
  # Renderizado final
111
  with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as tmp:
112
+ video_final.write_videofile(
113
  tmp.name,
114
  codec="libx264",
115
  audio_codec="aac",