INVIDEO_BASIC / app.py
gnosticdev's picture
Update app.py
cbfaa69 verified
raw
history blame
5.62 kB
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
from nltk.tokenize import sent_tokenize
from transformers import pipeline
import torch
import asyncio
# Configuraci贸n inicial
nltk.download('punkt', quiet=True)
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# Configuraci贸n de modelos
PEXELS_API_KEY = os.getenv("PEXELS_API_KEY")
MODEL_NAME = "DeepESP/gpt2-spanish"
# Soluci贸n robusta para obtener voces
async def get_voices():
try:
voices = await edge_tts.list_voices()
voice_names = []
for v in voices:
try:
name = v.get('Name', v.get('ShortName', 'Desconocido'))
gender = v.get('Gender', 'Desconocido')
locale = v.get('Locale', v.get('Language', 'Desconocido'))
voice_names.append(f"{name} ({gender}, {locale})")
except Exception as e:
logger.warning(f"Error procesando voz: {v} - {str(e)}")
continue
return voice_names, voices
except Exception as e:
logger.error(f"Error al obtener voces: {str(e)}")
return [], []
# Obtener voces de forma s铆ncrona para la inicializaci贸n
import nest_asyncio
nest_asyncio.apply()
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 obtuvieron voces.")
except Exception as e:
logging.warning(f"No se pudieron cargar voces din谩micamente: {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):
"""Genera guiones con respaldo robusto"""
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}':\n\n1. Introducci贸n\n2. Desarrollo\n3. Conclusi贸n\n\n",
max_length=800,
temperature=0.7,
num_return_sequences=1
)
return response[0]['generated_text']
except Exception as e:
logger.error(f"Error generando guion: {str(e)}")
return f"""Gui贸n de respaldo sobre {prompt}:
1. INTRODUCCI脫N: Hoy exploraremos {prompt}
2. DESARROLLO: Aspectos clave sobre el tema
3. CONCLUSI脫N: Resumen y cierre"""
def buscar_videos_avanzado(prompt, guion, num_videos=3):
"""B煤squeda con m煤ltiples respaldos"""
try:
palabras = re.findall(r'\b\w{4,}\b', prompt.lower())[:5]
response = requests.get(
f"https://api.pexels.com/videos/search?query={'+'.join(palabras)}&per_page={num_videos}",
headers={"Authorization": PEXELS_API_KEY},
timeout=10
)
return response.json().get('videos', [])[:num_videos]
except Exception as e:
logger.error(f"Error buscando videos: {str(e)}")
return []
async def crear_video_profesional(prompt, custom_script, voz_index, musica=None):
try:
# 1. Generar gui贸n
guion = custom_script if custom_script else generar_guion_profesional(prompt)
# 2. Configurar voz
voz_seleccionada = VOICES[voz_indimport os
import asyncio
from concurrent.futures import ThreadPoolExecutor
import gradio as gr
# Configuraci贸n CR脥TICA para evitar timeouts
GRADIO_TIMEOUT = 600 # 10 minutos (en segundos)
MAX_VIDEO_DURATION = 120 # 2 minutos (evita procesos eternos)
async def crear_video_profesional(prompt, custom_script, voz_index, musica=None):
try:
# 1. Simulamos un proceso largo (隆esto es lo que causa el timeout!)
# Reemplaza esto con tu l贸gica real de generaci贸n
await asyncio.sleep(30) # Solo para prueba
# 2. Devuelve un video de prueba (eliminar en producci贸n)
return "video_prueba.mp4"
except Exception as e:
print(f"ERROR: {str(e)}")
return None
# 馃憞 **Soluci贸n M谩gica**: Ejecuci贸n en hilos separados
def run_async_with_timeout(prompt, script, voz_index, musica=None):
with ThreadPoolExecutor() as executor:
future = executor.submit(
lambda: asyncio.run(crear_video_profesional(prompt, script, voz_index, musica))
)
return future.result(timeout=GRADIO_TIMEOUT)
# Interfaz Minimalista (para enfocarnos en el timeout)
with gr.Blocks() as app:
with gr.Row():
prompt = gr.Textbox(label="Tema")
btn = gr.Button("Generar")
output = gr.Video()
btn.click(
fn=run_async_with_timeout, # 馃憟 Usamos el wrapper anti-timeout
inputs=[prompt, gr.Textbox(visible=False), gr.Number(visible=False)],
outputs=output
)
if __name__ == "__main__":
app.launch(
server_name="0.0.0.0",
server_port=7860,
# 鈿狅笍 Configuraci贸n CLAVE para el timeout
app_kwargs={"timeout": GRADIO_TIMEOUT}
)