| |
| import spaces |
|
|
| import gradio as gr |
| import torch |
| from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline |
| from diffusers import StableDiffusionPipeline, DiffusionPipeline |
| import requests |
| from PIL import Image |
| import io |
| import base64 |
| import os |
| import time |
| import numpy as np |
| import random |
| import json |
| from huggingface_hub import login |
| from fastapi import FastAPI, HTTPException |
| from fastapi.middleware.cors import CORSMiddleware |
| from pydantic import BaseModel |
|
|
| print("🚀 Iniciando NTIA Space Enhanced con ZeroGPU H200...") |
| print(f"📁 Directorio actual: {os.getcwd()}") |
| print(f"🐍 Python version: {os.sys.version}") |
|
|
| |
| os.environ["SPACES_GPU_TIMEOUT"] = "30" |
| os.environ["SPACES_GPU_MEMORY"] = "8" |
|
|
| |
| device = "cuda" if torch.cuda.is_available() else "cpu" |
| print(f"🖥️ Dispositivo detectado: {device}") |
| print(f"🔥 CUDA disponible: {torch.cuda.is_available()}") |
|
|
| if torch.cuda.is_available(): |
| print(f"🎮 GPU: {torch.cuda.get_device_name(0)}") |
| print(f"💾 Memoria GPU: {torch.cuda.get_device_properties(0).total_memory / 1024**3:.1f} GB") |
| print("🚀 ZeroGPU H200 detectado - Optimizando para máximo rendimiento") |
| |
| |
| torch_dtype = torch.float16 |
| print("⚡ Usando torch.float16 para H200") |
| |
| |
| torch.backends.cudnn.benchmark = True |
| torch.backends.cuda.matmul.allow_tf32 = True |
| torch.backends.cudnn.allow_tf32 = True |
| print("🔧 Optimizaciones CUDA habilitadas para H200") |
| else: |
| torch_dtype = torch.float32 |
| print("🐌 Usando torch.float32 para CPU") |
|
|
| |
| HF_TOKEN = os.getenv("HF_TOKEN") or os.getenv("HUGGING_FACE_HUB_TOKEN") |
| if HF_TOKEN: |
| try: |
| print(f"🔑 Token detectado: {HF_TOKEN[:10]}...") |
| login(token=HF_TOKEN) |
| print("✅ Autenticado con Hugging Face") |
| except Exception as e: |
| print(f"⚠️ Error de autenticación: {e}") |
| else: |
| print("⚠️ No se encontró HF_TOKEN - modelos gated no estarán disponibles") |
|
|
| |
| HF_SPACES = { |
| "NTIA-VEO3-Free": { |
| "url": "https://huggingface.co/spaces/Ntdeseb/NTIA-VEO3-Free", |
| "api_url": "https://ntdeseb-ntia-veo3-free.hf.space", |
| "description": "Generación de video con VEO3-Free", |
| "type": "text-to-video", |
| "enabled": True |
| }, |
| "NTIA-animated": { |
| "url": "https://huggingface.co/spaces/Ntdeseb/NTIA-animated", |
| "api_url": "https://ntdeseb-ntia-animated.hf.space", |
| "description": "Animación con wan2-1-fast", |
| "type": "animation", |
| "enabled": True |
| }, |
| "NTIA-LivePortrait": { |
| "url": "https://huggingface.co/spaces/Ntdeseb/NTIA-LivePortrait", |
| "api_url": "https://ntdeseb-ntia-liveportrait.hf.space", |
| "description": "Retratos animados con LivePortrait", |
| "type": "live-portrait", |
| "enabled": False |
| }, |
| "NTIA-stable-video-diffusion": { |
| "url": "https://huggingface.co/spaces/Ntdeseb/NTIA-stable-video-diffusion", |
| "api_url": "https://ntdeseb-ntia-stable-video-diffusion.hf.space", |
| "description": "Video diffusion estable", |
| "type": "stable-video-diffusion", |
| "enabled": True |
| } |
| } |
|
|
| |
| MODELS = { |
| "text": { |
| "microsoft/DialoGPT-medium": "Chat conversacional", |
| "microsoft/DialoGPT-large": "Chat conversacional avanzado", |
| "microsoft/DialoGPT-small": "Chat conversacional rápido", |
| "gpt2": "Generación de texto", |
| "gpt2-medium": "GPT-2 mediano", |
| "gpt2-large": "GPT-2 grande", |
| "distilgpt2": "GPT-2 optimizado", |
| "EleutherAI/gpt-neo-125M": "GPT-Neo pequeño", |
| "EleutherAI/gpt-neo-1.3B": "GPT-Neo mediano", |
| "facebook/opt-125m": "OPT pequeño", |
| "facebook/opt-350m": "OPT mediano", |
| "bigscience/bloom-560m": "BLOOM multilingüe", |
| "bigscience/bloom-1b1": "BLOOM grande", |
| "Helsinki-NLP/opus-mt-es-en": "Traductor español-inglés", |
| "Helsinki-NLP/opus-mt-en-es": "Traductor inglés-español", |
| |
| "mistralai/Voxtral-Mini-3B-2507": "Voxtral Mini 3B - Multimodal", |
| "tiiuae/falcon-7b-instruct": "Falcon 7B Instruct", |
| "google/flan-t5-base": "Flan-T5 Base - Tareas múltiples" |
| }, |
| "image": { |
| |
| "stabilityai/sdxl-turbo": "⚡ SDXL Turbo", |
| "stabilityai/sd-turbo": "⚡ SD Turbo", |
| "ByteDance/SDXL-Lightning": "⚡ SDXL Lightning", |
| |
| |
| "stabilityai/stable-diffusion-3.5-large": "🌟 SD 3.5 Large (Premium)", |
| |
| |
| "stabilityai/stable-diffusion-xl-base-1.0": "SDXL Base", |
| "stabilityai/stable-diffusion-2-1": "Stable Diffusion 2.1", |
| "CompVis/stable-diffusion-v1-4": "Stable Diffusion v1.4 (Libre)", |
| "runwayml/stable-diffusion-v1-5": "Stable Diffusion v1.5", |
| |
| |
| "prompthero/openjourney": "Midjourney Style", |
| "prompthero/openjourney-v4": "OpenJourney v4", |
| "WarriorMama777/OrangeMixs": "Orange Mixs", |
| "hakurei/waifu-diffusion": "Waifu Diffusion", |
| "SG161222/Realistic_Vision_V5.1_noVAE": "Realistic Vision", |
| "Linaqruf/anything-v3.0": "Anything v3", |
| "XpucT/deliberate-v2": "Deliberate v2", |
| "dreamlike-art/dreamlike-diffusion-1.0": "Dreamlike Diffusion", |
| "KBlueLeaf/kohaku-v2.1": "Kohaku V2.1", |
| |
| |
| "black-forest-labs/FLUX.1-dev": "FLUX.1 Dev (Requiere acceso)", |
| "black-forest-labs/FLUX.1-schnell": "FLUX.1 Schnell (Requiere acceso)", |
| |
| |
| "stabilityai/stable-diffusion-3.5-large": "🌟 SD 3.5 Large (Alta Calidad)", |
| |
| |
| "CompVis/ldm-text2im-large-256": "Latent Diffusion Model 256" |
| }, |
| "video": { |
| |
| "damo-vilab/text-to-video-ms-1.7b": "Text-to-Video MS 1.7B (Libre)", |
| "ali-vilab/text-to-video-ms-1.7b": "Text-to-Video MS 1.7B Alt", |
| "cerspense/zeroscope_v2_576w": "Zeroscope v2 576w (Libre)", |
| "cerspense/zeroscope_v2_XL": "Zeroscope v2 XL (Libre)", |
| "ByteDance/AnimateDiff-Lightning": "AnimateDiff Lightning (Libre)", |
| "THUDM/CogVideoX-5b": "CogVideoX 5B (Libre)", |
| "rain1011/pyramid-flow-sd3": "Pyramid Flow SD3 (Libre)", |
| "ali-vilab/modelscope-damo-text-to-video-synthesis": "ModelScope Text-to-Video", |
| |
| |
| "hf-space:NTIA-VEO3-Free": "🎬 VEO3-Free (HF Space)", |
| "hf-space:NTIA-animated": "🎬 Animated (HF Space)", |
| "hf-space:NTIA-stable-video-diffusion": "🎬 Stable Video Diffusion (HF Space)" |
| }, |
| "chat": { |
| "microsoft/DialoGPT-medium": "Chat conversacional", |
| "microsoft/DialoGPT-large": "Chat conversacional avanzado", |
| "microsoft/DialoGPT-small": "Chat conversacional rápido", |
| "facebook/opt-350m": "OPT conversacional", |
| "bigscience/bloom-560m": "BLOOM multilingüe", |
| |
| "mistralai/Voxtral-Mini-3B-2507": "Voxtral Mini 3B - Multimodal", |
| "tiiuae/falcon-7b-instruct": "Falcon 7B Instruct" |
| } |
| } |
|
|
| |
| model_cache = {} |
|
|
| def call_hf_space_api(space_name, prompt, **kwargs): |
| """Llamar a la API de un espacio de Hugging Face""" |
| if space_name not in HF_SPACES: |
| raise ValueError(f"Espacio {space_name} no encontrado") |
| |
| space_config = HF_SPACES[space_name] |
| if not space_config["enabled"]: |
| raise ValueError(f"Espacio {space_name} está deshabilitado") |
| |
| api_url = space_config["api_url"] |
| |
| try: |
| |
| if space_config["type"] == "text-to-video": |
| payload = { |
| "prompt": prompt, |
| "num_frames": kwargs.get("num_frames", 16), |
| "num_inference_steps": kwargs.get("num_inference_steps", 20) |
| } |
| elif space_config["type"] == "animation": |
| payload = { |
| "text": prompt, |
| "steps": kwargs.get("num_inference_steps", 20) |
| } |
| elif space_config["type"] == "stable-video-diffusion": |
| payload = { |
| "prompt": prompt, |
| "video_length": kwargs.get("num_frames", 16), |
| "num_inference_steps": kwargs.get("num_inference_steps", 20) |
| } |
| else: |
| payload = {"prompt": prompt} |
| |
| print(f"🌐 Llamando a {space_name}: {api_url}") |
| print(f"📤 Payload: {payload}") |
| |
| |
| response = requests.post( |
| f"{api_url}/run/predict", |
| json={"data": [payload]}, |
| timeout=60 |
| ) |
| |
| if response.status_code == 200: |
| result = response.json() |
| print(f"✅ Respuesta exitosa de {space_name}") |
| return result |
| else: |
| print(f"❌ Error en {space_name}: {response.status_code}") |
| print(f"📄 Respuesta: {response.text}") |
| raise Exception(f"Error HTTP {response.status_code}") |
| |
| except Exception as e: |
| print(f"❌ Error llamando a {space_name}: {e}") |
| raise |
|
|
| def load_text_model(model_name): |
| """Cargar modelo de texto""" |
| if model_name not in model_cache: |
| print(f"Cargando modelo de texto: {model_name}") |
| |
| try: |
| tokenizer = AutoTokenizer.from_pretrained(model_name) |
| model = AutoModelForCausalLM.from_pretrained(model_name) |
| |
| if "dialogpt" in model_name.lower(): |
| tokenizer.pad_token = tokenizer.eos_token |
| model.config.pad_token_id = model.config.eos_token_id |
| |
| model_cache[model_name] = { |
| "tokenizer": tokenizer, |
| "model": model, |
| "type": "text" |
| } |
| |
| except Exception as e: |
| print(f"Error cargando modelo de texto {model_name}: {e}") |
| |
| tokenizer = AutoTokenizer.from_pretrained("microsoft/DialoGPT-medium") |
| model = AutoModelForCausalLM.from_pretrained("microsoft/DialoGPT-medium") |
| tokenizer.pad_token = tokenizer.eos_token |
| model.config.pad_token_id = model.config.eos_token_id |
| |
| model_cache[model_name] = { |
| "tokenizer": tokenizer, |
| "model": model, |
| "type": "text" |
| } |
| |
| return model_cache[model_name] |
|
|
| def load_image_model(model_name): |
| """Cargar modelo de imagen optimizado para H200""" |
| if model_name not in model_cache: |
| print(f"\n🔄 Iniciando carga del modelo: {model_name}") |
| |
| try: |
| start_time = time.time() |
| |
| |
| use_fp16_variant = False |
| if torch.cuda.is_available(): |
| |
| fp16_supported_models = [ |
| "stabilityai/sdxl-turbo", |
| "stabilityai/sd-turbo", |
| "stabilityai/stable-diffusion-xl-base-1.0", |
| "runwayml/stable-diffusion-v1-5", |
| "CompVis/stable-diffusion-v1-4" |
| ] |
| use_fp16_variant = any(model in model_name for model in fp16_supported_models) |
| |
| |
| if use_fp16_variant: |
| print("⚡ Usando variant fp16 para optimización") |
| pipe = StableDiffusionPipeline.from_pretrained( |
| model_name, |
| torch_dtype=torch_dtype, |
| variant="fp16" |
| ) |
| else: |
| pipe = StableDiffusionPipeline.from_pretrained( |
| model_name, |
| torch_dtype=torch_dtype |
| ) |
| |
| |
| if torch.cuda.is_available(): |
| pipe = pipe.to(device) |
| pipe.enable_attention_slicing() |
| if hasattr(pipe, 'enable_model_cpu_offload'): |
| pipe.enable_model_cpu_offload() |
| if hasattr(pipe, 'enable_vae_slicing'): |
| pipe.enable_vae_slicing() |
| if hasattr(pipe, 'enable_xformers_memory_efficient_attention'): |
| pipe.enable_xformers_memory_efficient_attention() |
| |
| load_time = time.time() - start_time |
| print(f"✅ Modelo cargado en {load_time:.2f} segundos") |
| |
| model_cache[model_name] = { |
| "pipeline": pipe, |
| "type": "image" |
| } |
| |
| except Exception as e: |
| print(f"❌ Error cargando modelo de imagen {model_name}: {e}") |
| |
| try: |
| pipe = StableDiffusionPipeline.from_pretrained( |
| "CompVis/stable-diffusion-v1-4", |
| torch_dtype=torch_dtype |
| ) |
| if torch.cuda.is_available(): |
| pipe = pipe.to(device) |
| pipe.enable_attention_slicing() |
| |
| model_cache[model_name] = { |
| "pipeline": pipe, |
| "type": "image" |
| } |
| except Exception as fallback_error: |
| print(f"❌ Error crítico en fallback de imagen: {fallback_error}") |
| raise |
| |
| return model_cache[model_name] |
|
|
| def load_video_model(model_name): |
| """Cargar modelo de video con soporte para diferentes tipos""" |
| if model_name not in model_cache: |
| print(f"Cargando modelo de video: {model_name}") |
| |
| try: |
| |
| if "text-to-video" in model_name.lower(): |
| |
| from diffusers import DiffusionPipeline |
| pipe = DiffusionPipeline.from_pretrained( |
| model_name, |
| torch_dtype=torch.float32, |
| variant="fp16" |
| ) |
| elif "modelscope" in model_name.lower(): |
| |
| from diffusers import DiffusionPipeline |
| pipe = DiffusionPipeline.from_pretrained( |
| model_name, |
| torch_dtype=torch.float32 |
| ) |
| elif "zeroscope" in model_name.lower(): |
| |
| from diffusers import DiffusionPipeline |
| pipe = DiffusionPipeline.from_pretrained( |
| model_name, |
| torch_dtype=torch.float32 |
| ) |
| elif "animatediff" in model_name.lower(): |
| |
| from diffusers import DiffusionPipeline |
| pipe = DiffusionPipeline.from_pretrained( |
| model_name, |
| torch_dtype=torch.float32 |
| ) |
| elif "cogvideo" in model_name.lower(): |
| |
| from diffusers import DiffusionPipeline |
| pipe = DiffusionPipeline.from_pretrained( |
| model_name, |
| torch_dtype=torch.float32 |
| ) |
| elif "pyramid-flow" in model_name.lower(): |
| |
| from diffusers import DiffusionPipeline |
| pipe = DiffusionPipeline.from_pretrained( |
| model_name, |
| torch_dtype=torch.float32 |
| ) |
| else: |
| |
| from diffusers import DiffusionPipeline |
| pipe = DiffusionPipeline.from_pretrained( |
| model_name, |
| torch_dtype=torch.float32 |
| ) |
| |
| |
| pipe.enable_attention_slicing() |
| if hasattr(pipe, 'enable_model_cpu_offload'): |
| pipe.enable_model_cpu_offload() |
| |
| model_cache[model_name] = { |
| "pipeline": pipe, |
| "type": "video" |
| } |
| |
| except Exception as e: |
| print(f"Error cargando modelo de video {model_name}: {e}") |
| |
| try: |
| from diffusers import DiffusionPipeline |
| pipe = DiffusionPipeline.from_pretrained( |
| "damo-vilab/text-to-video-ms-1.7b", |
| torch_dtype=torch.float32 |
| ) |
| pipe.enable_attention_slicing() |
| |
| model_cache[model_name] = { |
| "pipeline": pipe, |
| "type": "video" |
| } |
| except Exception as fallback_error: |
| print(f"Error crítico en fallback de video: {fallback_error}") |
| raise |
| |
| return model_cache[model_name] |
|
|
| def generate_video_enhanced(prompt, model_name, num_frames=16, num_inference_steps=20): |
| """Generar video con soporte para espacios de HF y modelos locales""" |
| try: |
| print(f"🎬 Generando video con modelo: {model_name}") |
| print(f"📝 Prompt: {prompt}") |
| print(f"🎞️ Frames: {num_frames}") |
| print(f"⚙️ Pasos: {num_inference_steps}") |
| |
| |
| if model_name.startswith("hf-space:"): |
| space_name = model_name.replace("hf-space:", "") |
| print(f"🌐 Usando espacio de HF: {space_name}") |
| |
| |
| result = call_hf_space_api( |
| space_name, |
| prompt, |
| num_frames=num_frames, |
| num_inference_steps=num_inference_steps |
| ) |
| |
| |
| if "data" in result and len(result["data"]) > 0: |
| video_data = result["data"][0] |
| |
| |
| if isinstance(video_data, str) and video_data.startswith("data:video"): |
| |
| return video_data |
| elif isinstance(video_data, list): |
| |
| return video_data |
| else: |
| |
| return video_data |
| else: |
| raise Exception("Respuesta inválida del espacio de HF") |
| |
| else: |
| |
| print("🏠 Usando modelo local") |
| model_data = load_video_model(model_name) |
| pipeline = model_data["pipeline"] |
| |
| |
| if "zeroscope" in model_name.lower(): |
| |
| result = pipeline( |
| prompt, |
| num_inference_steps=num_inference_steps, |
| num_frames=num_frames, |
| height=256, |
| width=256 |
| ) |
| elif "animatediff" in model_name.lower(): |
| |
| result = pipeline( |
| prompt, |
| num_inference_steps=num_inference_steps, |
| num_frames=num_frames |
| ) |
| else: |
| |
| result = pipeline( |
| prompt, |
| num_inference_steps=num_inference_steps, |
| num_frames=num_frames |
| ) |
| |
| print("✅ Video generado exitosamente") |
| |
| |
| if hasattr(result, 'frames'): |
| video_frames = result.frames |
| elif hasattr(result, 'videos'): |
| video_frames = result.videos |
| else: |
| video_frames = result |
| |
| return video_frames |
| |
| except Exception as e: |
| print(f"❌ Error generando video: {e}") |
| raise |
|
|
| def generate_text(prompt, model_name, max_length=100): |
| """Generar texto con el modelo seleccionado""" |
| try: |
| print(f"Generando texto con modelo: {model_name}") |
| print(f"Prompt: {prompt}") |
| |
| model_data = load_text_model(model_name) |
| tokenizer = model_data["tokenizer"] |
| model = model_data["model"] |
| |
| |
| inputs = tokenizer.encode(prompt, return_tensors="pt") |
| |
| |
| with torch.no_grad(): |
| outputs = model.generate( |
| inputs, |
| max_length=max_length, |
| num_return_sequences=1, |
| temperature=0.7, |
| do_sample=True, |
| pad_token_id=tokenizer.eos_token_id |
| ) |
| |
| |
| response = tokenizer.decode(outputs[0], skip_special_tokens=True) |
| |
| print("Texto generado exitosamente") |
| return response |
| |
| except Exception as e: |
| print(f"Error generando texto: {e}") |
| return f"Error: {e}" |
|
|
| @spaces.GPU(compute_unit="gpu.t4.micro", timeout=30) |
| def generate_image(prompt, model_name, negative_prompt="", seed=0, width=1024, height=1024, guidance_scale=7.5, num_inference_steps=20): |
| """Generar imagen con el modelo seleccionado""" |
| try: |
| print(f"🎨 Generando imagen con modelo: {model_name}") |
| print(f"📝 Prompt: {prompt}") |
| print(f"🚫 Negative prompt: {negative_prompt}") |
| print(f"🎲 Seed: {seed}") |
| print(f"📐 Dimensiones: {width}x{height}") |
| print(f"⚙️ Guidance scale: {guidance_scale}") |
| print(f"🔄 Pasos: {num_inference_steps}") |
| |
| |
| if seed > 0: |
| torch.manual_seed(seed) |
| if torch.cuda.is_available(): |
| torch.cuda.manual_seed(seed) |
| |
| model_data = load_image_model(model_name) |
| pipeline = model_data["pipeline"] |
| |
| |
| result = pipeline( |
| prompt=prompt, |
| negative_prompt=negative_prompt, |
| width=width, |
| height=height, |
| guidance_scale=guidance_scale, |
| num_inference_steps=num_inference_steps, |
| generator=torch.Generator(device=device).manual_seed(seed) if seed > 0 else None |
| ) |
| |
| print("✅ Imagen generada exitosamente") |
| return result.images[0] |
| |
| except Exception as e: |
| print(f"❌ Error generando imagen: {e}") |
| |
| error_img = Image.new('RGB', (512, 512), color='red') |
| return error_img |
|
|
| def chat_with_model(message, history, model_name): |
| """Chat con el modelo seleccionado""" |
| try: |
| print(f"Chat con modelo: {model_name}") |
| print(f"Mensaje: {message}") |
| |
| model_data = load_text_model(model_name) |
| tokenizer = model_data["tokenizer"] |
| model = model_data["model"] |
| |
| |
| conversation = "" |
| for user_msg, bot_msg in history: |
| conversation += f"User: {user_msg}\nBot: {bot_msg}\n" |
| conversation += f"User: {message}\nBot:" |
| |
| |
| inputs = tokenizer.encode(conversation, return_tensors="pt", truncation=True, max_length=1000) |
| |
| |
| with torch.no_grad(): |
| outputs = model.generate( |
| inputs, |
| max_length=inputs.shape[1] + 100, |
| num_return_sequences=1, |
| temperature=0.7, |
| do_sample=True, |
| pad_token_id=tokenizer.eos_token_id |
| ) |
| |
| |
| response = tokenizer.decode(outputs[0], skip_special_tokens=True) |
| |
| |
| bot_response = response.split("Bot:")[-1].strip() |
| |
| print("Respuesta generada exitosamente") |
| return bot_response |
| |
| except Exception as e: |
| print(f"Error en chat: {e}") |
| return f"Error: {e}" |
|
|
| def check_gated_model_access(): |
| """Verificar acceso a modelos gated""" |
| gated_models = [] |
| accessible_models = [] |
| |
| for category, models in MODELS.items(): |
| for model_name in models.keys(): |
| if any(keyword in model_name.lower() for keyword in ["flux", "gated", "premium"]): |
| gated_models.append(model_name) |
| |
| try: |
| |
| if category == "image": |
| load_image_model(model_name) |
| elif category == "text": |
| load_text_model(model_name) |
| elif category == "video": |
| load_video_model(model_name) |
| |
| accessible_models.append(model_name) |
| except Exception as e: |
| print(f"❌ Modelo {model_name} no accesible: {e}") |
| |
| return { |
| "gated_models": gated_models, |
| "accessible_models": accessible_models, |
| "hf_token_configured": bool(HF_TOKEN) |
| } |
|
|
| |
| def create_interface(): |
| """Crear la interfaz de Gradio mejorada""" |
| |
| with gr.Blocks( |
| title="NTIA Assistant Enhanced", |
| theme=gr.themes.Soft(), |
| css=""" |
| .gradio-container { |
| max-width: 1200px !important; |
| } |
| .model-button { |
| margin: 5px; |
| border-radius: 10px; |
| } |
| .space-status { |
| padding: 10px; |
| border-radius: 5px; |
| margin: 5px 0; |
| } |
| .space-enabled { |
| background-color: #d4edda; |
| border: 1px solid #c3e6cb; |
| color: #155724; |
| } |
| .space-disabled { |
| background-color: #f8d7da; |
| border: 1px solid #f5c6cb; |
| color: #721c24; |
| } |
| """ |
| ) as demo: |
| |
| gr.Markdown("# 🚀 NTIA Assistant Enhanced") |
| gr.Markdown("### Tu asistente inteligente con soporte para espacios de Hugging Face") |
| |
| |
| with gr.Row(): |
| with gr.Column(): |
| gr.Markdown("### 🌐 Estado de Espacios de HF") |
| space_status_html = gr.HTML() |
| |
| |
| with gr.Tabs(): |
| |
| |
| with gr.Tab("🎬 Video"): |
| with gr.Row(): |
| with gr.Column(scale=2): |
| video_prompt = gr.Textbox( |
| label="Describe el video que quieres crear...", |
| placeholder="Un gato bailando en la luna con estrellas brillantes...", |
| lines=3 |
| ) |
| |
| with gr.Row(): |
| video_model = gr.Dropdown( |
| choices=list(MODELS["video"].keys()), |
| value="damo-vilab/text-to-video-ms-1.7b", |
| label="Modelo de Video", |
| info="Selecciona un modelo local o un espacio de HF" |
| ) |
| video_frames = gr.Slider( |
| minimum=8, maximum=32, value=16, step=4, |
| label="Número de Frames", |
| info="Más frames = video más largo" |
| ) |
| |
| with gr.Row(): |
| video_steps = gr.Slider( |
| minimum=10, maximum=50, value=20, step=5, |
| label="Pasos de Inferencia", |
| info="Más pasos = mejor calidad, más tiempo" |
| ) |
| video_generate_btn = gr.Button("🎬 Generar Video", variant="primary") |
| |
| video_output = gr.Video(label="Video Generado") |
| |
| with gr.Column(scale=1): |
| gr.Markdown("### 📋 Modelos Disponibles") |
| |
| |
| gr.Markdown("#### 🏠 Modelos Locales") |
| local_video_models = [k for k in MODELS["video"].keys() if not k.startswith("hf-space:")] |
| for model in local_video_models: |
| gr.Markdown(f"• **{model}** - {MODELS['video'][model]}") |
| |
| |
| gr.Markdown("#### 🌐 Espacios de Hugging Face") |
| hf_video_models = [k for k in MODELS["video"].keys() if k.startswith("hf-space:")] |
| for model in hf_video_models: |
| space_name = model.replace("hf-space:", "") |
| status = "✅ Habilitado" if HF_SPACES[space_name]["enabled"] else "❌ Deshabilitado" |
| gr.Markdown(f"• **{space_name}** - {status}") |
| |
| |
| with gr.Tab("🎨 Imagen"): |
| with gr.Row(): |
| with gr.Column(scale=2): |
| image_prompt = gr.Textbox( |
| label="Describe la imagen que quieres crear...", |
| placeholder="Un gato espacial con traje de astronauta...", |
| lines=3 |
| ) |
| |
| with gr.Row(): |
| image_model = gr.Dropdown( |
| choices=list(MODELS["image"].keys()), |
| value="stabilityai/sdxl-turbo", |
| label="Modelo de Imagen" |
| ) |
| image_negative = gr.Textbox( |
| label="Prompt Negativo", |
| placeholder="borroso, malo, feo...", |
| lines=2 |
| ) |
| |
| with gr.Row(): |
| image_width = gr.Slider(minimum=256, maximum=1024, value=1024, step=64, label="Ancho") |
| image_height = gr.Slider(minimum=256, maximum=1024, value=1024, step=64, label="Alto") |
| |
| with gr.Row(): |
| image_guidance = gr.Slider(minimum=1, maximum=20, value=7.5, step=0.5, label="Guidance Scale") |
| image_steps = gr.Slider(minimum=10, maximum=50, value=20, step=5, label="Pasos") |
| |
| with gr.Row(): |
| image_seed = gr.Number(value=0, label="Seed (0 = aleatorio)") |
| image_generate_btn = gr.Button("🎨 Generar Imagen", variant="primary") |
| |
| image_output = gr.Image(label="Imagen Generada") |
| |
| with gr.Column(scale=1): |
| gr.Markdown("### 📋 Modelos de Imagen") |
| for model, desc in MODELS["image"].items(): |
| gr.Markdown(f"• **{model}** - {desc}") |
| |
| |
| with gr.Tab("📝 Texto"): |
| with gr.Row(): |
| with gr.Column(scale=2): |
| text_prompt = gr.Textbox( |
| label="Escribe tu prompt...", |
| placeholder="Escribe una historia sobre un robot que aprende a soñar...", |
| lines=5 |
| ) |
| |
| with gr.Row(): |
| text_model = gr.Dropdown( |
| choices=list(MODELS["text"].keys()), |
| value="microsoft/DialoGPT-medium", |
| label="Modelo de Texto" |
| ) |
| text_length = gr.Slider(minimum=50, maximum=500, value=100, step=10, label="Longitud Máxima") |
| |
| text_generate_btn = gr.Button("📝 Generar Texto", variant="primary") |
| text_output = gr.Textbox(label="Texto Generado", lines=10) |
| |
| with gr.Column(scale=1): |
| gr.Markdown("### 📋 Modelos de Texto") |
| for model, desc in MODELS["text"].items(): |
| gr.Markdown(f"• **{model}** - {desc}") |
| |
| |
| with gr.Tab("💬 Chat"): |
| with gr.Row(): |
| with gr.Column(scale=2): |
| chat_model = gr.Dropdown( |
| choices=list(MODELS["chat"].keys()), |
| value="microsoft/DialoGPT-medium", |
| label="Modelo de Chat" |
| ) |
| |
| chatbot = gr.Chatbot(label="Conversación") |
| chat_input = gr.Textbox( |
| label="Tu mensaje...", |
| placeholder="Hola, ¿cómo estás?", |
| lines=2 |
| ) |
| |
| with gr.Row(): |
| chat_send_btn = gr.Button("💬 Enviar", variant="primary") |
| chat_clear_btn = gr.Button("🗑️ Limpiar") |
| |
| with gr.Column(scale=1): |
| gr.Markdown("### 📋 Modelos de Chat") |
| for model, desc in MODELS["chat"].items(): |
| gr.Markdown(f"• **{model}** - {desc}") |
| |
| |
| def update_space_status(): |
| """Actualizar estado de espacios de HF""" |
| status_html = "<div style='margin: 10px 0;'>" |
| for space_name, config in HF_SPACES.items(): |
| status_class = "space-enabled" if config["enabled"] else "space-disabled" |
| status_text = "✅ Habilitado" if config["enabled"] else "❌ Deshabilitado" |
| status_html += f""" |
| <div class='space-status {status_class}'> |
| <strong>{space_name}</strong>: {status_text}<br> |
| <small>{config['description']}</small> |
| </div> |
| """ |
| status_html += "</div>" |
| return status_html |
| |
| |
| video_generate_btn.click( |
| fn=generate_video_enhanced, |
| inputs=[video_prompt, video_model, video_frames, video_steps], |
| outputs=video_output |
| ) |
| |
| |
| image_generate_btn.click( |
| fn=generate_image, |
| inputs=[image_prompt, image_model, image_negative, image_seed, image_width, image_height, image_guidance, image_steps], |
| outputs=image_output |
| ) |
| |
| |
| text_generate_btn.click( |
| fn=generate_text, |
| inputs=[text_prompt, text_model, text_length], |
| outputs=text_output |
| ) |
| |
| |
| chat_send_btn.click( |
| fn=chat_with_model, |
| inputs=[chat_input, chatbot, chat_model], |
| outputs=chatbot |
| ).then( |
| fn=lambda: "", |
| outputs=chat_input |
| ) |
| |
| chat_clear_btn.click( |
| fn=lambda: [], |
| outputs=chatbot |
| ) |
| |
| |
| demo.load(fn=update_space_status, outputs=space_status_html) |
| |
| return demo |
|
|
| |
| if __name__ == "__main__": |
| print("🚀 Iniciando NTIA Assistant Enhanced...") |
| |
| |
| print("\n🔍 Verificando acceso a modelos gated...") |
| access_info = check_gated_model_access() |
| print(f"📊 Modelos gated encontrados: {len(access_info['gated_models'])}") |
| print(f"✅ Modelos accesibles: {len(access_info['accessible_models'])}") |
| print(f"🔑 Token HF configurado: {access_info['hf_token_configured']}") |
| |
| |
| demo = create_interface() |
| |
| |
| print("\n🌐 Lanzando aplicación...") |
| demo.launch( |
| server_name="0.0.0.0", |
| server_port=7860, |
| share=False, |
| debug=True |
| ) |