File size: 5,418 Bytes
43fcbe8
d68572a
38ff849
8337d0b
fa691a5
d68572a
38ff849
d68572a
9143db2
 
fa691a5
7c87717
d68572a
38ff849
 
7c87717
 
ab6a3fb
7c87717
 
38ff849
7c87717
 
 
d68572a
30c3706
7c87717
9143db2
7c87717
 
9143db2
 
 
30c3706
ae19496
60e6f97
7c87717
60e6f97
9143db2
 
30c3706
 
7c87717
9143db2
7c87717
 
38ff849
7c87717
 
07b3b3d
d68572a
 
60e6f97
d68572a
60e6f97
d68572a
60e6f97
d68572a
7c87717
d68572a
 
7c87717
 
c7b9a72
30c3706
7c87717
60e6f97
7c87717
 
d68572a
 
 
30c3706
7c87717
d68572a
 
7c87717
 
 
9143db2
7c87717
 
d68572a
60e6f97
7c87717
9143db2
7c87717
 
60e6f97
7c87717
 
 
60e6f97
 
 
 
d68572a
7c87717
60e6f97
7c87717
 
30c3706
9143db2
7c87717
38ff849
7c87717
9143db2
7c87717
60e6f97
7c87717
9143db2
7c87717
d68572a
7c87717
 
 
 
3e716f3
38ff849
d68572a
60e6f97
ab6a3fb
38ff849
fa201eb
7c87717
 
fa201eb
7c87717
720c3d5
7c87717
07b3b3d
30c3706
7c87717
 
 
 
 
 
c9d2e08
7c87717
30c3706
7c87717
 
d7f3a60
7c87717
 
 
 
 
 
8337d0b
d68572a
30c3706
7c87717
9e5ee0a
d7f3a60
07b3b3d
7c87717
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
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 básica
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# Configuración de entorno (usa tu propia API key de Pexels)
PEXELS_API_KEY = os.getenv("PEXELS_API_KEY") or "TU_API_KEY_AQUI"

# Voces disponibles (Edge-TTS)
VOICES = ["es-MX-DaliaNeural", "es-ES-ElviraNeural", "en-US-JennyNeural"]

# Carga el modelo GPT-2 en español (ligero y rápido)
tokenizer = GPT2Tokenizer.from_pretrained("datificate/gpt2-small-spanish")
model = GPT2LMHeadModel.from_pretrained("datificate/gpt2-small-spanish")

def generar_texto(tema):
    """Genera un texto largo y natural sobre el tema (sin estructuras forzadas)."""
    try:
        prompt = f"Habla extensamente sobre {tema} en un tono natural y detallado:"
        inputs = tokenizer(prompt, return_tensors="pt", truncation=True, max_length=512)
        
        outputs = model.generate(
            inputs.input_ids,
            max_length=800,
            do_sample=True,
            temperature=0.7,
            top_k=50,
            pad_token_id=tokenizer.eos_token_id
        )
        
        texto = tokenizer.decode(outputs[0], skip_special_tokens=True)
        return re.sub(r'\s+', ' ', texto).strip()
    
    except Exception as e:
        logger.error(f"Error generando texto: {e}")
        return f"Contenido generado sobre {tema}."

def buscar_videos(tema):
    """Busca videos en Pexels y devuelve los 3 más relevantes."""
    try:
        headers = {"Authorization": PEXELS_API_KEY}
        response = requests.get(
            f"https://api.pexels.com/videos/search?query={tema}&per_page=3",
            headers=headers,
            timeout=10
        )
        return response.json().get("videos", [])[:3]
    except Exception as e:
        logger.error(f"Error buscando videos: {e}")
        return []

def crear_video(tema, voz_seleccionada):
    """Genera el video final con voz y clips de video."""
    try:
        # 1. Generar texto
        texto = generar_texto(tema)
        
        # 2. Convertir texto a voz (Edge-TTS)
        voz_archivo = "narracion.mp3"
        subprocess.run([
            'edge-tts',
            '--voice', voz_seleccionada,
            '--text', texto,
            '--write-media', voz_archivo
        ], check=True)
        
        # 3. Procesar audio
        audio = AudioFileClip(voz_archivo)
        duracion_total = audio.duration
        
        # 4. Buscar y descargar videos
        videos = buscar_videos(tema) or buscar_videos("nature")
        clips = []
        
        for i, video in enumerate(videos[:3]):  # Máximo 3 videos
            try:
                mejor_calidad = max(video['video_files'], key=lambda x: x.get('width', 0))
                url_video = mejor_calidad['link']
                
                # Descargar video temporal
                temp_file = f"temp_video_{i}.mp4"
                with requests.get(url_video, stream=True) as r:
                    r.raise_for_status()
                    with open(temp_file, 'wb') as f:
                        for chunk in r.iter_content(chunk_size=8192):
                            f.write(chunk)
                
                # Ajustar duración del clip
                clip = VideoFileClip(temp_file)
                duracion_clip = min(duracion_total / len(videos), clip.duration)
                clips.append(clip.subclip(0, duracion_clip))
                
            except Exception as e:
                logger.error(f"Error procesando video {i}: {e}")
        
        # 5. Combinar clips (o usar fondo negro si no hay videos)
        if not clips:
            video_final = ColorClip((1280, 720), (0, 0, 0), duration=duracion_total)
        else:
            video_final = concatenate_videoclips(clips, method="compose")
        
        video_final = video_final.set_audio(audio)
        
        # 6. Exportar video
        nombre_archivo = f"video_final_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4"
        video_final.write_videofile(
            nombre_archivo,
            fps=24,
            codec="libx264",
            audio_codec="aac",
            threads=2,
            preset='fast'
        )
        
        return nombre_archivo
    
    except Exception as e:
        logger.error(f"Error crítico: {e}")
        return None
    
    finally:
        # Limpieza de archivos temporales
        if os.path.exists(voz_archivo):
            os.remove(voz_archivo)
        for i in range(3):
            temp_file = f"temp_video_{i}.mp4"
            if os.path.exists(temp_file):
                os.remove(temp_file)

# Interfaz de Gradio (sencilla y funcional)
with gr.Blocks() as app:
    gr.Markdown("# 🎬 Generador Automático de Videos")
    
    with gr.Row():
        tema = gr.Textbox(label="Tema del video", placeholder="Ej: 'Historia de la inteligencia artificial'")
        voz = gr.Dropdown(label="Voz", choices=VOICES, value=VOICES[0])
        btn = gr.Button("Generar Video", variant="primary")
    
    salida = gr.Video(label="Resultado")
    
    btn.click(
        fn=crear_video,
        inputs=[tema, voz],
        outputs=salida
    )

if __name__ == "__main__":
    app.launch(server_name="0.0.0.0", server_port=7860)