Spaces:
Running
Running
File size: 5,804 Bytes
43fcbe8 374c72e cbfaa69 374c72e cbfaa69 374c72e cbfaa69 374c72e cbfaa69 374c72e fa201eb 374c72e c9d2e08 374c72e cbfaa69 374c72e cbfaa69 374c72e 77c11ae 374c72e 8337d0b 374c72e 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 |
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
import nest_asyncio
from nltk.tokenize import sent_tokenize
# Setup
nltk.download('punkt', quiet=True)
nest_asyncio.apply()
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
PEXELS_API_KEY = os.getenv("PEXELS_API_KEY")
MODEL_NAME = "DeepESP/gpt2-spanish"
VOICE_NAMES, VOICES = [], []
async def get_voices():
voces = await edge_tts.list_voices()
voice_names = [f"{v['Name']} ({v['Gender']}, {v['LocaleName']})" for v in voces]
return voice_names, voces
async def get_and_set_voices():
global VOICE_NAMES, VOICES
try:
VOICE_NAMES, VOICES = await get_voices()
if not VOICES:
raise Exception("No se encontraron voces.")
except Exception as e:
logger.warning(f"Fallo al cargar voces: {e}")
VOICE_NAMES = ["Voz Predeterminada (Femenino, es-ES)"]
VOICES = [{'ShortName': 'es-ES-ElviraNeural'}]
asyncio.get_event_loop().run_until_complete(get_and_set_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}'. "
"Incluye introducci贸n, desarrollo en 3 secciones y conclusi贸n:",
max_length=1000,
temperature=0.7,
top_k=50,
top_p=0.95,
num_return_sequences=1
)
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: {e}")
return f"""Introducci贸n sobre {prompt}.
Secci贸n 1: Or铆genes e historia.
Secci贸n 2: Estado actual.
Secci贸n 3: Futuro e impacto.
Conclusi贸n reflexiva."""
def buscar_videos_avanzado(prompt, guion, num_videos=5):
try:
oraciones = sent_tokenize(guion)
vectorizer = TfidfVectorizer(stop_words='spanish')
tfidf = vectorizer.fit_transform(oraciones)
palabras = vectorizer.get_feature_names_out()
scores = np.asarray(tfidf.sum(axis=0)).ravel()
top_indices = np.argsort(scores)[-5:]
palabras_clave = [palabras[i] for i in top_indices]
palabras_prompt = re.findall(r'\b\w{4,}\b', prompt.lower())
todas = 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)}&per_page={num_videos}",
headers=headers,
timeout=15
)
return response.json().get('videos', [])
except Exception as e:
logger.error(f"Error buscando videos: {e}")
return []
async def crear_video_profesional(prompt, custom_script, voz_index, musica=None):
voz_archivo = "voz.mp3"
try:
guion = custom_script if custom_script.strip() else generar_guion_profesional(prompt)
voz_seleccionada = VOICES[voz_index]['ShortName'] if VOICES else 'es-ES-ElviraNeural'
# Generar audio
await edge_tts.Communicate(guion, voz_seleccionada).save(voz_archivo)
audio = AudioFileClip(voz_archivo)
# Obtener videos
videos_data = buscar_videos_avanzado(prompt, guion)
if not videos_data:
raise Exception("No se encontraron videos")
# Procesar 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)
# Crear video final
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: {e}")
return None
finally:
if os.path.exists(voz_archivo):
os.remove(voz_archivo)
# Gradio app
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="Gui贸n personalizado (opcional)")
voz = gr.Dropdown(VOICE_NAMES, label="Voz", value=VOICE_NAMES[0])
btn = gr.Button("Generar Video", variant="primary")
with gr.Column():
output = gr.Video(label="Resultado", format="mp4")
async def wrapper(p, cs, v):
return await crear_video_profesional(p, cs, VOICE_NAMES.index(v))
btn.click(
fn=wrapper,
inputs=[prompt, custom_script, voz],
outputs=output
)
if __name__ == "__main__":
app.launch(server_name="0.0.0.0", server_port=7860)
|