import os import subprocess import requests import gradio as gr from moviepy.editor import * from datetime import datetime import logging import re import torch from transformers import GPT2LMHeadModel, GPT2Tokenizer # Configuración inicial logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) PEXELS_API_KEY = os.getenv("PEXELS_API_KEY") # Lista de voces válidas VOICES = [ "es-MX-DaliaNeural", "es-ES-ElviraNeural", "es-AR-ElenaNeural", "es-MX-JorgeNeural", "es-ES-AlvaroNeural", "es-AR-TomasNeural", "en-US-JennyNeural", "fr-FR-DeniseNeural", "de-DE-KatjaNeural", "it-IT-ElsaNeural", "pt-BR-FranciscaNeural", "ja-JP-NanamiNeural", "en-GB-SoniaNeural", "es-CL-CatalinaNeural", "es-CO-GonzaloNeural" ] # Cargar modelo y tokenizador de GPT-2 en español try: tokenizer = GPT2Tokenizer.from_pretrained("datificate/gpt2-small-spanish") model = GPT2LMHeadModel.from_pretrained("datificate/gpt2-small-spanish") logger.info("Modelo GPT-2 en español cargado correctamente") except Exception as e: logger.error(f"Error cargando el modelo: {str(e)}") model = None tokenizer = None def generar_guion_largo(tema, custom_script=None): """Genera un texto largo sobre el tema usando GPT-2""" if custom_script: return custom_script if model is None or tokenizer is None: return f"Texto generado automáticamente sobre {tema}. " * 50 try: # Prompt directo como solicitaste prompt = f"Escribe un texto largo y detallado sobre {tema}" inputs = tokenizer(prompt, return_tensors="pt", max_length=512, truncation=True) # Generar texto outputs = model.generate( inputs.input_ids, max_length=800, temperature=0.9, top_k=50, top_p=0.95, num_return_sequences=1, pad_token_id=tokenizer.eos_token_id ) guion = tokenizer.decode(outputs[0], skip_special_tokens=True) # Limpiar texto guion = re.sub(r'<.*?>', '', guion) guion = re.sub(r'\n+', '\n', guion) logger.info(f"Guion generado: {len(guion)} caracteres") return guion except Exception as e: logger.error(f"Error generando guion: {str(e)}") return f"Texto generado automáticamente sobre {tema}. " * 50 def buscar_videos_pexels(tema, num_videos=4): """Busca videos en Pexels usando el tema directamente""" try: headers = {"Authorization": PEXELS_API_KEY} logger.info(f"Buscando videos para: {tema}") response = requests.get( f"https://api.pexels.com/videos/search?query={tema}&per_page={num_videos}", headers=headers, timeout=15 ) videos = response.json().get("videos", []) # Filtrar videos de alta calidad return sorted( videos, key=lambda x: (x.get('width', 0) * x.get('height', 0), x.get('duration', 0)), reverse=True )[:num_videos] except Exception as e: logger.error(f"Error buscando videos: {str(e)}") return [] def descargar_video(url, output_path): """Descarga un video de manera eficiente""" try: with requests.get(url, stream=True, timeout=30) as r: r.raise_for_status() with open(output_path, 'wb') as f: for chunk in r.iter_content(chunk_size=8192): f.write(chunk) return True except Exception as e: logger.error(f"Error descargando video: {str(e)}") return False def crear_video(prompt, custom_script, voz_seleccionada, musica=None): try: # 1. Generar guion largo guion = generar_guion_largo(prompt, custom_script) # 2. Generar narración voz_archivo = "voz.mp3" subprocess.run([ 'edge-tts', '--voice', voz_seleccionada, '--text', guion, '--write-media', voz_archivo ], check=True) # 3. Procesar audio principal audio = AudioFileClip(voz_archivo) duracion_total = audio.duration # 4. Buscar videos relevantes videos_data = buscar_videos_pexels(prompt) if not videos_data: logger.warning("No se encontraron videos. Usando videos genéricos...") videos_data = buscar_videos_pexels("nature") # 5. Descargar y preparar videos clips = [] for i, video in enumerate(videos_data): try: # Seleccionar la mejor calidad disponible video_file = max( video['video_files'], key=lambda x: x.get('width', 0) * x.get('height', 0) ) video_url = video_file['link'] temp_path = f"temp_video_{i}.mp4" if descargar_video(video_url, temp_path): clip = VideoFileClip(temp_path) # Calcular duración proporcional para cada clip duracion_clip = duracion_total / len(videos_data) # Ajustar clip a la duración requerida if clip.duration < duracion_clip: clip = clip.loop(duration=duracion_clip) else: clip = clip.subclip(0, duracion_clip) clips.append(clip) except Exception as e: logger.error(f"Error procesando video {i}: {str(e)}") if not clips: raise Exception("No se pudieron cargar videos válidos") # 6. Combinar videos video_final = concatenate_videoclips(clips) video_final = video_final.set_audio(audio) # 7. Exportar video final output_path = f"video_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4" video_final.write_videofile( output_path, fps=24, codec="libx264", audio_codec="aac", threads=4, preset='fast' ) logger.info(f"Video generado exitosamente: {output_path}") return output_path except Exception as e: logger.error(f"ERROR: {str(e)}") return None finally: # Limpieza garantizada if os.path.exists(voz_archivo): os.remove(voz_archivo) for i in range(5): temp_file = f"temp_video_{i}.mp4" if os.path.exists(temp_file): os.remove(temp_file) # Interfaz simplificada y funcional with gr.Blocks(title="Generador de Videos") as app: gr.Markdown("# 🎬 GENERADOR AUTOMÁTICO DE VIDEOS") with gr.Row(): with gr.Column(): prompt = gr.Textbox(label="Tema del video", placeholder="Ej: 'La historia de la inteligencia artificial'") custom_script = gr.TextArea( label="Guion personalizado (opcional)", placeholder="Pega tu guion completo aquí...", lines=5 ) voz = gr.Dropdown(label="Voz Narradora", choices=VOICES, value=VOICES[0]) musica = gr.File(label="Música de fondo (opcional)", file_types=["audio"]) btn = gr.Button("Generar Video", variant="primary") with gr.Column(): output = gr.Video(label="Video Resultado", format="mp4") btn.click( fn=crear_video, inputs=[prompt, custom_script, voz, musica], outputs=output ) if __name__ == "__main__": app.launch(server_name="0.0.0.0", server_port=7860)