Spaces:
Build error
Build error
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} | |
) |