gnosticdev commited on
Commit
ffed29f
verified
1 Parent(s): e9c1d02

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +139 -70
app.py CHANGED
@@ -15,7 +15,8 @@ from moviepy.editor import (
15
  TextClip,
16
  CompositeVideoClip,
17
  VideoClip,
18
- ColorClip
 
19
  )
20
  import numpy as np
21
  import json
@@ -291,6 +292,72 @@ def create_video(script_text: str, generate_script: bool, music_path: str | None
291
  logger.error(f"Error normalizando clip: {e}")
292
  return None
293
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
294
  try:
295
  # Paso 1: Generar o usar gui贸n
296
  update_task_progress(task_id, "Paso 1/7: Preparando gui贸n...")
@@ -323,10 +390,14 @@ def create_video(script_text: str, generate_script: bool, music_path: str | None
323
  video_paths = []
324
  keywords = extract_keywords(script)
325
 
 
 
326
  for i, keyword in enumerate(keywords[:3]):
327
  update_task_progress(task_id, f"Paso 3/7: Buscando videos para '{keyword}' ({i+1}/{len(keywords[:3])})")
328
 
329
  videos = search_pexels_videos(keyword, 2)
 
 
330
  for video_data in videos:
331
  if len(video_paths) >= 6:
332
  break
@@ -335,95 +406,93 @@ def create_video(script_text: str, generate_script: bool, music_path: str | None
335
  if video_files:
336
  best_file = max(video_files, key=lambda f: f.get("width", 0))
337
  video_url = best_file.get("link")
 
 
 
338
 
339
  if video_url:
340
  downloaded_path = download_video(video_url, temp_dir)
341
  if downloaded_path:
342
  video_paths.append(downloaded_path)
 
343
 
344
- if not video_paths:
345
- raise RuntimeError("No se pudieron descargar videos de Pexels")
346
 
347
- # Paso 4: Procesar videos - MANEJO CORRECTO DE CLIPS NULOS
348
  update_task_progress(task_id, f"Paso 4/7: Procesando {len(video_paths)} videos...")
349
  video_clips = []
350
 
351
- for i, path in enumerate(video_paths):
352
- clip = None
353
- try:
354
- # Cargar el video - SI FALLA, CONTINUAR CON EL SIGUIENTE
355
- clip = VideoFileClip(path)
356
- if clip is None:
357
- logger.error(f"Video {i+1} no se pudo cargar: {path}")
358
- continue
359
-
360
- # Verificar que el clip tenga duraci贸n
361
- if clip.duration <= 0:
362
- logger.error(f"Video {i+1} tiene duraci贸n inv谩lida: {path}")
363
- clip.close()
364
- continue
365
-
366
- # Tomar m谩ximo 8 segundos - SI FALLA, CONTINUAR
367
- duration = min(8, clip.duration)
368
- processed_clip = clip.subclip(0, duration)
369
-
370
- if processed_clip is None:
371
- logger.error(f"No se pudo recortar el video {i+1}: {path}")
372
- clip.close()
373
- continue
374
-
375
- # Normalizar el clip - SI FALLA, CONTINUAR
376
- processed_clip = normalize_clip(processed_clip)
377
-
378
- if processed_clip is not None:
379
- video_clips.append(processed_clip)
380
- logger.info(f"Video {i+1} procesado exitosamente: {path}")
381
- else:
382
- logger.error(f"No se pudo normalizar el video {i+1}: {path}")
383
- processed_clip.close()
384
- clip.close()
385
 
386
- except Exception as e:
387
- logger.error(f"Error procesando video {i+1} {path}: {e}")
388
- finally:
389
- # Asegurarse de cerrar el clip original si existe
390
- if clip is not None:
391
- clip.close()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
392
 
393
  logger.info(f"Videos procesados exitosamente: {len(video_clips)} de {len(video_paths)}")
394
 
395
- # Si no hay videos v谩lidos, crear video de respaldo
396
- if not video_clips:
397
- logger.warning("No se procesaron videos v谩lidos, creando video de respaldo...")
398
- base_video = ColorClip(
399
- size=TARGET_RESOLUTION,
400
- color=(0, 0, 0),
401
- duration=video_duration
402
- )
403
- base_video.fps = TARGET_FPS
404
- else:
405
- # Concatenar videos - MANEJO DE ERROR
406
  try:
407
  base_video = concatenate_videoclips(video_clips, method="chain")
408
- if base_video is None:
409
- raise RuntimeError("La concatenaci贸n devolvi贸 None")
410
- logger.info(f"Videos concatenados exitosamente. Duraci贸n: {base_video.duration}s")
411
  except Exception as e:
412
- logger.error(f"Error concatenando videos: {e}")
413
- # Cerrar todos los clips antes de crear respaldo
414
- for clip in video_clips:
415
- if clip is not None:
416
- clip.close()
417
- # Crear video de respaldo
418
- base_video = ColorClip(
419
- size=TARGET_RESOLUTION,
420
- color=(0, 0, 0),
421
- duration=video_duration
422
- )
423
- base_video.fps = TARGET_FPS
424
 
425
  # Extender video si es m谩s corto que el audio
426
  if base_video.duration < video_duration:
 
427
  loops_needed = math.ceil(video_duration / base_video.duration)
428
  base_video = concatenate_videoclips([base_video] * loops_needed)
429
 
 
15
  TextClip,
16
  CompositeVideoClip,
17
  VideoClip,
18
+ ColorClip,
19
+ ImageClip
20
  )
21
  import numpy as np
22
  import json
 
292
  logger.error(f"Error normalizando clip: {e}")
293
  return None
294
 
295
+ def create_visual_video(script: str, duration: float):
296
+ """Crea un video visual con texto cuando no hay videos de Pexels"""
297
+ try:
298
+ logger.info("Creando video visual con texto...")
299
+
300
+ # Crear clips de texto para cada frase
301
+ sentences = [s.strip() for s in re.split(r"[.!?驴隆]", script) if s.strip()]
302
+ if not sentences:
303
+ sentences = [script]
304
+
305
+ clips = []
306
+ sentence_duration = duration / len(sentences)
307
+
308
+ for i, sentence in enumerate(sentences):
309
+ try:
310
+ # Crear fondo con color cambiante
311
+ color_intensity = int(255 * (i / len(sentences)))
312
+ bg_color = (color_intensity, 50, 150 - color_intensity//2)
313
+
314
+ bg_clip = ColorClip(
315
+ size=TARGET_RESOLUTION,
316
+ color=bg_color,
317
+ duration=sentence_duration
318
+ )
319
+ bg_clip.fps = TARGET_FPS
320
+
321
+ # Crear texto
322
+ txt_clip = TextClip(
323
+ sentence,
324
+ fontsize=60,
325
+ color="white",
326
+ stroke_color="black",
327
+ stroke_width=3,
328
+ method="caption",
329
+ size=(int(TARGET_RESOLUTION[0] * 0.9), None),
330
+ font="Arial-Bold",
331
+ align="center"
332
+ ).set_position("center")
333
+
334
+ # Combinar fondo y texto
335
+ composite = CompositeVideoClip([bg_clip, txt_clip])
336
+ clips.append(composite)
337
+
338
+ except Exception as e:
339
+ logger.error(f"Error creando clip visual para '{sentence}': {e}")
340
+ continue
341
+
342
+ if clips:
343
+ return concatenate_videoclips(clips)
344
+ else:
345
+ # Si falla, crear un video simple con color
346
+ return ColorClip(
347
+ size=TARGET_RESOLUTION,
348
+ color=(50, 50, 150),
349
+ duration=duration
350
+ )
351
+
352
+ except Exception as e:
353
+ logger.error(f"Error creando video visual: {e}")
354
+ # 脷ltimo recurso: video de color s贸lido
355
+ return ColorClip(
356
+ size=TARGET_RESOLUTION,
357
+ color=(50, 50, 150),
358
+ duration=duration
359
+ )
360
+
361
  try:
362
  # Paso 1: Generar o usar gui贸n
363
  update_task_progress(task_id, "Paso 1/7: Preparando gui贸n...")
 
390
  video_paths = []
391
  keywords = extract_keywords(script)
392
 
393
+ logger.info(f"Palabras clave: {keywords}")
394
+
395
  for i, keyword in enumerate(keywords[:3]):
396
  update_task_progress(task_id, f"Paso 3/7: Buscando videos para '{keyword}' ({i+1}/{len(keywords[:3])})")
397
 
398
  videos = search_pexels_videos(keyword, 2)
399
+ logger.info(f"Encontrados {len(videos)} videos para '{keyword}'")
400
+
401
  for video_data in videos:
402
  if len(video_paths) >= 6:
403
  break
 
406
  if video_files:
407
  best_file = max(video_files, key=lambda f: f.get("width", 0))
408
  video_url = best_file.get("link")
409
+ video_quality = f"{best_file.get('width', 0)}x{best_file.get('height', 0)}"
410
+
411
+ logger.info(f"Intentando descargar video {video_quality}: {video_url}")
412
 
413
  if video_url:
414
  downloaded_path = download_video(video_url, temp_dir)
415
  if downloaded_path:
416
  video_paths.append(downloaded_path)
417
+ logger.info(f"Video descargado: {downloaded_path}")
418
 
419
+ logger.info(f"Total videos descargados: {len(video_paths)}")
 
420
 
421
+ # Paso 4: Procesar videos o crear video visual
422
  update_task_progress(task_id, f"Paso 4/7: Procesando {len(video_paths)} videos...")
423
  video_clips = []
424
 
425
+ if video_paths:
426
+ for i, path in enumerate(video_paths):
427
+ clip = None
428
+ try:
429
+ logger.info(f"Procesando video {i+1}/{len(video_paths)}: {path}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
430
 
431
+ # Verificar archivo
432
+ if not os.path.exists(path):
433
+ logger.error(f"Archivo no existe: {path}")
434
+ continue
435
+
436
+ file_size = os.path.getsize(path)
437
+ logger.info(f"Tama帽o del archivo: {file_size} bytes")
438
+
439
+ if file_size < 1000:
440
+ logger.error(f"Archivo demasiado peque帽o: {path}")
441
+ continue
442
+
443
+ # Intentar cargar el video
444
+ clip = VideoFileClip(path)
445
+ if clip is None:
446
+ logger.error(f"No se pudo cargar el video: {path}")
447
+ continue
448
+
449
+ logger.info(f"Video cargado: duraci贸n={clip.duration}s, tama帽o={clip.size}")
450
+
451
+ # Tomar m谩ximo 8 segundos
452
+ duration = min(8, clip.duration)
453
+ processed_clip = clip.subclip(0, duration)
454
+
455
+ if processed_clip is None:
456
+ logger.error(f"No se pudo recortar el video: {path}")
457
+ clip.close()
458
+ continue
459
+
460
+ # Normalizar
461
+ processed_clip = normalize_clip(processed_clip)
462
+
463
+ if processed_clip is not None:
464
+ video_clips.append(processed_clip)
465
+ logger.info(f"Video {i+1} procesado exitosamente")
466
+ else:
467
+ logger.error(f"No se pudo normalizar el video {i+1}")
468
+ processed_clip.close()
469
+ clip.close()
470
+
471
+ except Exception as e:
472
+ logger.error(f"Error procesando video {i+1}: {str(e)}")
473
+ finally:
474
+ if clip is not None:
475
+ clip.close()
476
 
477
  logger.info(f"Videos procesados exitosamente: {len(video_clips)} de {len(video_paths)}")
478
 
479
+ # Decidir qu茅 video usar
480
+ if video_clips:
481
+ # Usar videos de Pexels
 
 
 
 
 
 
 
 
482
  try:
483
  base_video = concatenate_videoclips(video_clips, method="chain")
484
+ logger.info(f"Videos de Pexels concatenados. Duraci贸n: {base_video.duration}s")
 
 
485
  except Exception as e:
486
+ logger.error(f"Error concatenando videos de Pexels: {e}")
487
+ base_video = create_visual_video(script, video_duration)
488
+ else:
489
+ # Crear video visual si no hay videos de Pexels
490
+ logger.warning("No hay videos v谩lidos de Pexels, creando video visual...")
491
+ base_video = create_visual_video(script, video_duration)
 
 
 
 
 
 
492
 
493
  # Extender video si es m谩s corto que el audio
494
  if base_video.duration < video_duration:
495
+ logger.info(f"Extendiendo video de {base_video.duration}s a {video_duration}s")
496
  loops_needed = math.ceil(video_duration / base_video.duration)
497
  base_video = concatenate_videoclips([base_video] * loops_needed)
498