Spaces:
Sleeping
Sleeping
File size: 7,616 Bytes
43fcbe8 374c72e cbfaa69 374c72e cbfaa69 374c72e 9a06bc2 374c72e 5654f17 c9d2e08 5654f17 c95f9ee 374c72e cbfaa69 374c72e 9a06bc2 5654f17 374c72e 5654f17 374c72e 9a06bc2 cbfaa69 5654f17 374c72e 9a06bc2 374c72e 9a06bc2 374c72e 9a06bc2 374c72e 9a06bc2 374c72e 9a06bc2 374c72e 9a06bc2 374c72e 5654f17 374c72e 9a06bc2 374c72e 9a06bc2 374c72e 9a06bc2 374c72e 9a06bc2 374c72e 9a06bc2 374c72e 5654f17 9a06bc2 5654f17 9a06bc2 374c72e 77c11ae 374c72e 5654f17 374c72e 9a06bc2 374c72e 5654f17 8337d0b 5654f17 9a06bc2 d5141b3 9e5ee0a d7f3a60 07b3b3d 374c72e |
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 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
import os
import re
import requests
import gradio as gr
from moviepy.editor import *
import edge_tts
import tempfile
import logging
from datetime import datetime
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
import nltk
import random
from transformers import pipeline
import torch
import asyncio
nltk.download('punkt', quiet=True)
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
PEXELS_API_KEY = os.getenv("PEXELS_API_KEY")
MODEL_NAME = "DeepESP/gpt2-spanish"
# Obtener voces de edge-tts de forma síncrona (wrapper)
def get_voices_sync():
return asyncio.run(edge_tts.list_voices())
VOICES = get_voices_sync()
VOICE_NAMES = [f"{v['Name']} ({v['Gender']}, {v.get('LocaleName', 'Unknown')})" for v in VOICES]
def generar_guion_profesional(prompt):
try:
generator = pipeline(
"text-generation",
model=MODEL_NAME,
device=0 if torch.cuda.is_available() else -1
)
response = generator(
f"Escribe un guion profesional para un video de YouTube sobre '{prompt}'. "
"La estructura debe incluir:\n"
"1. Introducción atractiva\n"
"2. Tres secciones detalladas con subtítulos\n"
"3. Conclusión impactante\n"
"Usa un estilo natural para narración:",
max_length=1000,
temperature=0.7,
top_k=50,
top_p=0.95,
num_return_sequences=1,
truncation=True
)
guion = response[0]['generated_text']
if len(guion.split()) < 100:
raise ValueError("Guion demasiado breve")
return guion
except Exception as e:
logger.error(f"Error generando guion: {str(e)}")
temas = {
"historia": ["orígenes", "eventos clave", "impacto actual"],
"tecnología": ["funcionamiento", "aplicaciones", "futuro"],
"ciencia": ["teorías", "evidencia", "implicaciones"],
"misterio": ["enigma", "teorías", "explicaciones"],
"arte": ["orígenes", "características", "influencia"]
}
categoria = "general"
for key in temas:
if key in prompt.lower():
categoria = key
break
puntos_clave = temas.get(categoria, ["aspectos importantes", "datos relevantes", "conclusiones"])
return f"""
¡Hola a todos! Bienvenidos a este análisis completo sobre {prompt}.
En este video exploraremos a fondo este fascinante tema a través de tres secciones clave.
SECCIÓN 1: {puntos_clave[0].capitalize()}
Comenzaremos analizando los {puntos_clave[0]} fundamentales.
Esto nos permitirá entender mejor la base de {prompt}.
SECCIÓN 2: {puntos_clave[1].capitalize()}
En esta parte, examinaremos los {puntos_clave[1]} más relevantes
y cómo se relacionan con el tema principal.
SECCIÓN 3: {puntos_clave[2].capitalize()}
Finalmente, exploraremos las {puntos_clave[2]}
y qué significan para el futuro de este campo.
¿Listos para profundizar? ¡Empecemos!
"""
from nltk.tokenize import sent_tokenize
def buscar_videos_avanzado(prompt, guion, num_videos=5):
try:
oraciones = sent_tokenize(guion)
vectorizer = TfidfVectorizer(stop_words=['el', 'la', 'los', 'las', 'de', 'en', 'y', 'que'])
tfidf = vectorizer.fit_transform(oraciones)
palabras = vectorizer.get_feature_names_out()
scores = np.asarray(tfidf.sum(axis=0)).ravel()
indices_importantes = np.argsort(scores)[-5:]
palabras_clave = [palabras[i] for i in indices_importantes]
palabras_prompt = re.findall(r'\b\w{4,}\b', prompt.lower())
todas_palabras = list(set(palabras_clave + palabras_prompt))[:5]
headers = {"Authorization": PEXELS_API_KEY}
response = requests.get(
f"https://api.pexels.com/videos/search?query={'+'.join(todas_palabras)}&per_page={num_videos}",
headers=headers,
timeout=15
)
videos = response.json().get('videos', [])
logger.info(f"Palabras clave usadas: {todas_palabras}")
videos_ordenados = sorted(
videos,
key=lambda x: x.get('width', 0) * x.get('height', 0),
reverse=True
)
return videos_ordenados[:num_videos]
except Exception as e:
logger.error(f"Error en búsqueda de videos: {str(e)}")
response = requests.get(
f"https://api.pexels.com/videos/search?query={prompt}&per_page={num_videos}",
headers={"Authorization": PEXELS_API_KEY},
timeout=10
)
return response.json().get('videos', [])[:num_videos]
async def crear_video_profesional(prompt, custom_script, voz_index, musica=None):
voz_archivo = None
try:
guion = custom_script if custom_script else generar_guion_profesional(prompt)
logger.info(f"Guion generado ({len(guion.split())} palabras)")
voz_seleccionada = VOICES[voz_index]['ShortName'] if VOICES else 'es-ES-ElviraNeural'
voz_archivo = "voz.mp3"
await edge_tts.Communicate(guion, voz_seleccionada).save(voz_archivo)
audio = AudioFileClip(voz_archivo)
duracion_total = audio.duration
videos_data = buscar_videos_avanzado(prompt, guion)
if not videos_data:
raise Exception("No se encontraron videos")
clips = []
for video in videos_data[:3]:
video_file = next((vf for vf in video['video_files'] if vf['quality'] == 'sd'), video['video_files'][0])
with tempfile.NamedTemporaryFile(suffix='.mp4', delete=False) as temp_video:
response = requests.get(video_file['link'], stream=True)
for chunk in response.iter_content(chunk_size=1024*1024):
temp_video.write(chunk)
clip = VideoFileClip(temp_video.name).subclip(0, min(10, video['duration']))
clips.append(clip)
video_final = concatenate_videoclips(clips)
video_final = video_final.set_audio(audio)
output_path = f"video_output_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4"
video_final.write_videofile(output_path, fps=24, threads=2)
return output_path
except Exception as e:
logger.error(f"Error crítico: {str(e)}")
return None
finally:
if voz_archivo and os.path.exists(voz_archivo):
os.remove(voz_archivo)
def run_async_wrapper(prompt, custom_script, voz, musica):
voz_index = VOICE_NAMES.index(voz)
return asyncio.run(crear_video_profesional(prompt, custom_script, voz_index, musica))
with gr.Blocks(title="Generador de Videos") as app:
with gr.Row():
with gr.Column():
prompt = gr.Textbox(label="Tema del video")
custom_script = gr.TextArea(label="Guion personalizado (opcional)")
voz = gr.Dropdown(VOICE_NAMES, label="Voz", value=VOICE_NAMES[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="Resultado", format="mp4")
btn.click(
fn=run_async_wrapper,
inputs=[prompt, custom_script, voz, musica],
outputs=output
)
if __name__ == "__main__":
app.launch(server_name="0.0.0.0", server_port=7860)
|