INVIDEO_BASIC / app.py
gnosticdev's picture
Update app.py
d68572a verified
raw
history blame
7.57 kB
import os
import subprocess
import requests
import gradio as gr
from moviepy.editor import *
from datetime import datetime
import tempfile
import logging
from transformers import pipeline
import nltk
from nltk.tokenize import sent_tokenize
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
import re
# Configuraci贸n inicial
nltk.download('punkt', quiet=True)
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",
"en-US-JennyNeural", "fr-FR-DeniseNeural", "de-DE-KatjaNeural",
"it-IT-ElsaNeural", "pt-BR-FranciscaNeural", "ja-JP-NanamiNeural"
]
# Inicializar el generador de texto
try:
script_generator = pipeline(
"text-generation",
model="gpt2", # Modelo m谩s flexible
device=0 if torch.cuda.is_available() else -1
)
except:
logger.warning("No se pudo cargar el modelo de generaci贸n de texto")
script_generator = None
def generar_guion(prompt):
"""Genera un guion natural y extenso basado en el prompt"""
if script_generator:
try:
result = script_generator(
f"Genera un texto detallado y bien estructurado sobre '{prompt}' para un video de YouTube:",
max_length=500, # Texto m谩s largo
temperature=0.9, # M谩s creatividad
num_return_sequences=1
)
guion = result[0]['generated_text']
# Limpiar el guion generado
guion = re.sub(r'<.*?>', '', guion)
guion = re.sub(r'\n+', '\n', guion)
return guion.strip()
except Exception as e:
logger.error(f"Error generando guion: {str(e)}")
# Fallback natural
return f"En este video exploraremos en profundidad el tema de {prompt}. " \
"Analizaremos diversos aspectos y perspectivas para ofrecer una visi贸n completa. " \
"Veremos c贸mo este tema se relaciona con nuestra vida cotidiana y su impacto en la sociedad actual."
def extraer_palabras_clave(texto, n=7):
"""Extrae palabras clave relevantes usando TF-IDF"""
# Preprocesamiento del texto
texto = re.sub(r'[^\w\s]', '', texto.lower())
# Tokenizar en oraciones
oraciones = sent_tokenize(texto)
# Crear matriz TF-IDF
vectorizer = TfidfVectorizer(
stop_words=['el', 'la', 'los', 'las', 'de', 'en', 'y', 'que', 'un', 'una', 'con', 'para'],
max_features=500
)
X = vectorizer.fit_transform(oraciones)
# Obtener palabras con mayor puntuaci贸n TF-IDF
suma_scores = np.asarray(X.sum(axis=0)).ravel()
indices = np.argsort(suma_scores)[::-1][:n]
palabras = vectorizer.get_feature_names_out()
return [palabras[i] for i in indices]
def buscar_videos_pexels(palabras_clave, num_videos=3):
"""Busca videos en Pexels usando palabras clave con enfoque en relevancia"""
try:
headers = {"Authorization": PEXELS_API_KEY}
query = "+".join(palabras_clave[:3]) # Usar las 3 palabras m谩s relevantes
logger.info(f"Buscando videos con palabras clave: {query}")
response = requests.get(
f"https://api.pexels.com/videos/search?query={query}&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('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=25) 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 natural
guion = custom_script if custom_script else generar_guion(prompt)
logger.info(f"Guion generado ({len(guion)} caracteres)")
# 2. Extraer palabras clave del guion completo
palabras_clave = extraer_palabras_clave(guion)
logger.info(f"Palabras clave extra铆das: {', '.join(palabras_clave)}")
# 3. Buscar videos relevantes usando IA
videos_data = buscar_videos_pexels(palabras_clave)
if not videos_data:
raise Exception("No se encontraron videos relevantes. Usando backup...")
# 4. Generar narraci贸n
voz_archivo = "voz.mp3"
subprocess.run([
'edge-tts',
'--voice', voz_seleccionada,
'--text', guion,
'--write-media', voz_archivo
], check=True)
# 5. Procesar audio
audio = AudioFileClip(voz_archivo)
duracion_total = audio.duration
# 6. Descargar y preparar videos
clips = []
for i, video in enumerate(videos_data):
# Seleccionar la mejor calidad
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)
# Ajustar duraci贸n proporcional
duracion_clip = min(duracion_total / len(videos_data), clip.duration)
clips.append(clip.subclip(0, duracion_clip))
# 7. Combinar videos
video_final = concatenate_videoclips(clips)
video_final = video_final.set_audio(audio)
# 8. Exportar
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=2
)
return output_path
except Exception as e:
logger.error(f"ERROR: {str(e)}")
return None
finally:
# Limpieza
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 simplificada y funcional
with gr.Blocks(title="Generador de Videos") as app:
gr.Markdown("# 馃帴 Generador Autom谩tico de Videos")
with gr.Row():
prompt = gr.Textbox(label="Tema del video", placeholder="Ej: Exploraci贸n espacial")
voz = gr.Dropdown(label="Voz Narradora", choices=VOICES, value=VOICES[0])
btn = gr.Button("Generar Video", variant="primary")
output = gr.Video(label="Resultado", format="mp4")
btn.click(
fn=crear_video,
inputs=[prompt, gr.Textbox(visible=False), voz, gr.File(visible=False)],
outputs=output
)
if __name__ == "__main__":
app.launch(server_name="0.0.0.0", server_port=7860)