Update app.py
Browse files
app.py
CHANGED
@@ -6,7 +6,6 @@ from moviepy.editor import *
|
|
6 |
import edge_tts
|
7 |
import gradio as gr
|
8 |
from pydub import AudioSegment
|
9 |
-
import psutil # Para monitoreo de recursos
|
10 |
|
11 |
# Configuraci贸n de Logs
|
12 |
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
|
@@ -25,8 +24,8 @@ for file in [INTRO_VIDEO, OUTRO_VIDEO, MUSIC_BG, GLITCH_SOUND, EJEMPLO_VIDEO]:
|
|
25 |
raise FileNotFoundError(f"Falta: {file}")
|
26 |
|
27 |
# Configuraci贸n de chunks
|
28 |
-
CHUNK_SIZE =
|
29 |
-
MAX_CHUNKS =
|
30 |
|
31 |
def eliminar_archivo_tiempo(ruta, delay=1800):
|
32 |
def eliminar():
|
@@ -46,7 +45,7 @@ async def procesar_audio(texto, voz, duracion_video, audio_original):
|
|
46 |
if not texto.strip():
|
47 |
raise ValueError("El texto para TTS no puede estar vac铆o.")
|
48 |
|
49 |
-
def dividir_texto(texto, max_length=
|
50 |
return [texto[i:i + max_length] for i in range(0, len(texto), max_length)]
|
51 |
|
52 |
fragmentos = dividir_texto(texto)
|
@@ -100,7 +99,7 @@ def aplicar_glitch(video_clip):
|
|
100 |
import numpy as np
|
101 |
frame = frame.copy()
|
102 |
height, width, _ = frame.shape
|
103 |
-
offset = np.random.randint(
|
104 |
if height > 0:
|
105 |
frame[offset:, :] = np.roll(frame[:-offset, :], -offset, axis=0)
|
106 |
return frame
|
@@ -119,13 +118,13 @@ async def procesar_fragmento(chunk, texto_tts, voz_seleccionada, start_time):
|
|
119 |
audio_original
|
120 |
)
|
121 |
|
122 |
-
segment_duration =
|
123 |
-
overlap =
|
124 |
total_segments = int((duracion_chunk) // (segment_duration)) + 1
|
125 |
|
126 |
segments = []
|
127 |
glitch_clips = []
|
128 |
-
glitch_sound = AudioFileClip(GLITCH_SOUND).volumex(0.
|
129 |
|
130 |
current_time = 0
|
131 |
for i in range(total_segments):
|
@@ -135,11 +134,11 @@ async def procesar_fragmento(chunk, texto_tts, voz_seleccionada, start_time):
|
|
135 |
full_segment = chunk.subclip(current_time, end_time)
|
136 |
|
137 |
if i > 0:
|
138 |
-
glitch_part = full_segment.subclip(0, 0.
|
139 |
glitch_part = aplicar_glitch(glitch_part)
|
140 |
processed_segment = concatenate_videoclips([
|
141 |
glitch_part,
|
142 |
-
full_segment.subclip(0.
|
143 |
], method="compose")
|
144 |
|
145 |
glitch_sound_clip = glitch_sound.set_start(start_time + current_time)
|
@@ -157,53 +156,56 @@ async def procesar_fragmento(chunk, texto_tts, voz_seleccionada, start_time):
|
|
157 |
except Exception as e:
|
158 |
logging.error(f"Fallo procesando fragmento: {str(e)}")
|
159 |
raise
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
160 |
|
161 |
async def procesar_video(video_input, texto_tts, voz_seleccionada):
|
162 |
try:
|
163 |
logging.info("Iniciando procesamiento de video")
|
164 |
-
video_original = VideoFileClip(video_input, target_resolution=(
|
165 |
total_duration = video_original.duration
|
166 |
|
167 |
-
#
|
168 |
-
logging.info(f"Memoria inicial: {psutil.virtual_memory().percent}%")
|
169 |
-
logging.info(f"CPU inicial: {psutil.cpu_percent()}%")
|
170 |
-
|
171 |
-
# Dividir en chunks
|
172 |
chunks = []
|
173 |
for start in range(0, int(total_duration), CHUNK_SIZE):
|
174 |
end = min(start + CHUNK_SIZE, total_duration)
|
175 |
chunk = video_original.subclip(start, end)
|
176 |
chunks.append((start, chunk))
|
177 |
|
178 |
-
# Procesar
|
179 |
processed_clips = []
|
180 |
for i, (start_time, chunk) in enumerate(chunks):
|
181 |
logging.info(f"Procesando chunk {i+1}/{len(chunks)}")
|
182 |
processed_chunk = await procesar_fragmento(chunk, texto_tts, voz_seleccionada, start_time)
|
183 |
processed_clips.append(processed_chunk)
|
184 |
|
185 |
-
# Combinar
|
186 |
final_video = concatenate_videoclips(processed_clips, method="compose")
|
187 |
|
188 |
-
# Agregar intro
|
189 |
-
intro = VideoFileClip(INTRO_VIDEO, target_resolution=(
|
190 |
-
outro = VideoFileClip(OUTRO_VIDEO, target_resolution=(
|
191 |
final_video = concatenate_videoclips([intro, final_video, outro], method="compose")
|
192 |
|
193 |
-
# Renderizado
|
194 |
with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as tmp:
|
195 |
final_video.write_videofile(
|
196 |
tmp.name,
|
197 |
-
codec="libx264",
|
198 |
-
preset="ultrafast",
|
199 |
audio_codec="aac",
|
200 |
-
fps=
|
201 |
-
threads=
|
202 |
-
bitrate="
|
203 |
ffmpeg_params=[
|
204 |
-
"-
|
|
|
205 |
"-movflags", "+faststart",
|
206 |
-
"-vf", "scale=
|
207 |
],
|
208 |
verbose=False
|
209 |
)
|
@@ -255,4 +257,4 @@ with gr.Blocks() as demo:
|
|
255 |
)
|
256 |
|
257 |
if __name__ == "__main__":
|
258 |
-
demo.queue().launch() #
|
|
|
6 |
import edge_tts
|
7 |
import gradio as gr
|
8 |
from pydub import AudioSegment
|
|
|
9 |
|
10 |
# Configuraci贸n de Logs
|
11 |
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
|
|
|
24 |
raise FileNotFoundError(f"Falta: {file}")
|
25 |
|
26 |
# Configuraci贸n de chunks
|
27 |
+
CHUNK_SIZE = 60 # 1 minuto por chunk (evita timeouts)
|
28 |
+
MAX_CHUNKS = 50 # L铆mite m谩ximo de chunks
|
29 |
|
30 |
def eliminar_archivo_tiempo(ruta, delay=1800):
|
31 |
def eliminar():
|
|
|
45 |
if not texto.strip():
|
46 |
raise ValueError("El texto para TTS no puede estar vac铆o.")
|
47 |
|
48 |
+
def dividir_texto(texto, max_length=2000): # Texto m谩s corto por fragmento
|
49 |
return [texto[i:i + max_length] for i in range(0, len(texto), max_length)]
|
50 |
|
51 |
fragmentos = dividir_texto(texto)
|
|
|
99 |
import numpy as np
|
100 |
frame = frame.copy()
|
101 |
height, width, _ = frame.shape
|
102 |
+
offset = np.random.randint(3, 8) # Efecto menos intenso
|
103 |
if height > 0:
|
104 |
frame[offset:, :] = np.roll(frame[:-offset, :], -offset, axis=0)
|
105 |
return frame
|
|
|
118 |
audio_original
|
119 |
)
|
120 |
|
121 |
+
segment_duration = 15 # Segmentos m谩s cortos
|
122 |
+
overlap = 1
|
123 |
total_segments = int((duracion_chunk) // (segment_duration)) + 1
|
124 |
|
125 |
segments = []
|
126 |
glitch_clips = []
|
127 |
+
glitch_sound = AudioFileClip(GLITCH_SOUND).volumex(0.3) # Sonido menos intenso
|
128 |
|
129 |
current_time = 0
|
130 |
for i in range(total_segments):
|
|
|
134 |
full_segment = chunk.subclip(current_time, end_time)
|
135 |
|
136 |
if i > 0:
|
137 |
+
glitch_part = full_segment.subclip(0, 0.3) # Glitch de 0.3s
|
138 |
glitch_part = aplicar_glitch(glitch_part)
|
139 |
processed_segment = concatenate_videoclips([
|
140 |
glitch_part,
|
141 |
+
full_segment.subclip(0.3)
|
142 |
], method="compose")
|
143 |
|
144 |
glitch_sound_clip = glitch_sound.set_start(start_time + current_time)
|
|
|
156 |
except Exception as e:
|
157 |
logging.error(f"Fallo procesando fragmento: {str(e)}")
|
158 |
raise
|
159 |
+
finally:
|
160 |
+
try:
|
161 |
+
chunk.close()
|
162 |
+
audio_original.close()
|
163 |
+
audio_final.close()
|
164 |
+
except:
|
165 |
+
pass
|
166 |
|
167 |
async def procesar_video(video_input, texto_tts, voz_seleccionada):
|
168 |
try:
|
169 |
logging.info("Iniciando procesamiento de video")
|
170 |
+
video_original = VideoFileClip(video_input, target_resolution=(720, 1280)) # Resoluci贸n reducida
|
171 |
total_duration = video_original.duration
|
172 |
|
173 |
+
# Dividir en chunks peque帽os
|
|
|
|
|
|
|
|
|
174 |
chunks = []
|
175 |
for start in range(0, int(total_duration), CHUNK_SIZE):
|
176 |
end = min(start + CHUNK_SIZE, total_duration)
|
177 |
chunk = video_original.subclip(start, end)
|
178 |
chunks.append((start, chunk))
|
179 |
|
180 |
+
# Procesar chunks secuencialmente
|
181 |
processed_clips = []
|
182 |
for i, (start_time, chunk) in enumerate(chunks):
|
183 |
logging.info(f"Procesando chunk {i+1}/{len(chunks)}")
|
184 |
processed_chunk = await procesar_fragmento(chunk, texto_tts, voz_seleccionada, start_time)
|
185 |
processed_clips.append(processed_chunk)
|
186 |
|
187 |
+
# Combinar chunks
|
188 |
final_video = concatenate_videoclips(processed_clips, method="compose")
|
189 |
|
190 |
+
# Agregar intro/outro
|
191 |
+
intro = VideoFileClip(INTRO_VIDEO, target_resolution=(720, 1280))
|
192 |
+
outro = VideoFileClip(OUTRO_VIDEO, target_resolution=(720, 1280))
|
193 |
final_video = concatenate_videoclips([intro, final_video, outro], method="compose")
|
194 |
|
195 |
+
# Renderizado ultra optimizado
|
196 |
with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as tmp:
|
197 |
final_video.write_videofile(
|
198 |
tmp.name,
|
199 |
+
codec="libx264",
|
|
|
200 |
audio_codec="aac",
|
201 |
+
fps=24,
|
202 |
+
threads=2, # Menos hilos para evitar saturaci贸n
|
203 |
+
bitrate="3M", # Bitrate reducido
|
204 |
ffmpeg_params=[
|
205 |
+
"-preset", "superfast",
|
206 |
+
"-crf", "28",
|
207 |
"-movflags", "+faststart",
|
208 |
+
"-vf", "scale=1280:720" # Resoluci贸n 720p para mayor velocidad
|
209 |
],
|
210 |
verbose=False
|
211 |
)
|
|
|
257 |
)
|
258 |
|
259 |
if __name__ == "__main__":
|
260 |
+
demo.queue().launch() # Sin par谩metros no soportados
|