import gradio as gr import torch from PIL import Image import numpy as np from clip_interrogator import Config, Interrogator, LabelTable, load_list import logging import os import warnings from datetime import datetime import json import gc # Suprimir warnings específicos warnings.filterwarnings("ignore", category=FutureWarning) warnings.filterwarnings("ignore", category=UserWarning) os.environ["TOKENIZERS_PARALLELISM"] = "false" # Configurar logging logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) # Detectar dispositivo disponible def get_device(): if torch.cuda.is_available(): return "cuda" elif torch.backends.mps.is_available(): return "mps" else: return "cpu" DEVICE = get_device() logger.info(f"🖥️ Usando dispositivo: {DEVICE}") # Configuración optimizada CLIP_MODELS = { "general": "ViT-L-14/openai", "stable_diffusion": "ViT-L-14/openai", "midjourney": "ViT-H-14/laion2b_s32b_b79k", "flux": "ViT-L-14/openai" } INTERROGATION_MODES = { "fast": "⚡ Rápido (30 seg)", "classic": "⚖️ Clásico (1 min)", "best": "⭐ Mejor (2 min)" } class OptimizedImagePromptGenerator: def __init__(self): self.interrogator = None self.usage_count = 0 self.device = DEVICE self.is_initialized = False logger.info("🚀 Inicializando generador optimizado...") def initialize_model(self, progress_callback=None): """Inicialización lazy del modelo""" if self.is_initialized: return True try: if progress_callback: progress_callback("🔄 Configurando modelo CLIP...") # Configuración optimizada según dispositivo config = Config( clip_model_name="ViT-L-14/openai", download_cache=True, chunk_size=1024 if self.device == "cpu" else 2048, quiet=True, device=self.device ) if progress_callback: progress_callback("📥 Descargando modelos (primera vez)...") self.interrogator = Interrogator(config) if progress_callback: progress_callback("✅ Modelo inicializado correctamente") self.is_initialized = True logger.info("✅ Modelo CLIP inicializado correctamente") # Limpiar memoria if self.device == "cpu": gc.collect() else: torch.cuda.empty_cache() return True except Exception as e: logger.error(f"❌ Error inicializando modelo: {e}") if progress_callback: progress_callback(f"❌ Error: {str(e)}") return False def optimize_image(self, image): """Optimizar imagen para procesamiento""" if image is None: return None # Convertir a PIL si es necesario if isinstance(image, np.ndarray): image = Image.fromarray(image) elif not isinstance(image, Image.Image): image = Image.open(image) # Asegurar RGB if image.mode != 'RGB': image = image.convert('RGB') # Redimensionar para optimizar velocidad en CPU max_size = 768 if self.device != "cpu" else 512 if image.size[0] > max_size or image.size[1] > max_size: image.thumbnail((max_size, max_size), Image.Resampling.LANCZOS) logger.info(f"🖼️ Imagen redimensionada a {image.size}") return image def generate_prompt(self, image, model_type="general", mode="best", progress_callback=None): """Generar prompt optimizado""" try: # Inicializar modelo si es necesario if not self.is_initialized: if not self.initialize_model(progress_callback): return "❌ Error inicializando el modelo.", "" if image is None: return "❌ Por favor, sube una imagen primero.", "" # Incrementar contador self.usage_count += 1 if progress_callback: progress_callback("🖼️ Optimizando imagen...") # Optimizar imagen image = self.optimize_image(image) if image is None: return "❌ Error procesando la imagen.", "" if progress_callback: progress_callback("🧠 Analizando contenido visual...") # Generar prompt según modo start_time = datetime.now() try: if mode == "fast": prompt = self.interrogator.interrogate_fast(image) elif mode == "classic": prompt = self.interrogator.interrogate_classic(image) else: # best prompt = self.interrogator.interrogate(image) except Exception as e: logger.error(f"Error en interrogación: {e}") # Fallback a modo rápido prompt = self.interrogator.interrogate_fast(image) end_time = datetime.now() duration = (end_time - start_time).total_seconds() # Limpiar memoria después del procesamiento if self.device == "cpu": gc.collect() else: torch.cuda.empty_cache() # Información detallada device_emoji = "🖥️" if self.device == "cpu" else "🚀" info = f""" **✅ Prompt generado exitosamente con IA para todos** {device_emoji} **Información del procesamiento:** - **Dispositivo:** {self.device.upper()} - **Modelo:** {model_type.replace('_', ' ').title()} - **Modo:** {INTERROGATION_MODES.get(mode, mode)} - **Tiempo:** {duration:.1f} segundos - **Tamaño imagen:** {image.size[0]}x{image.size[1]} - **Usos totales:** {self.usage_count} - **Hora:** {datetime.now().strftime('%H:%M:%S')} *"Porque cuando no tienes nada en la cabeza, te preocupas de la tipografía?"* 😄 💡 **Tip:** Los siguientes análisis serán más rápidos (modelo ya cargado) """ if progress_callback: progress_callback("✨ ¡Prompt listo!") return prompt, info except Exception as e: logger.error(f"Error generando prompt: {e}") error_msg = f"❌ Error: {str(e)}" error_info = f""" **❌ Error en el procesamiento** *Cuando falla la IA, al menos la tipografía sigue siendo bonita* 📝 💡 **Sugerencias:** - Intenta con una imagen más pequeña - Usa el modo "Rápido" - Verifica que la imagen sea válida """ return error_msg, error_info # Inicializar generador generator = OptimizedImagePromptGenerator() def process_image_with_progress(image, model_type, mode): """Función con indicadores de progreso""" progress_updates = [] def progress_callback(message): progress_updates.append(message) return message # Mostrar progreso inicial yield "🔄 Iniciando procesamiento...", """ **🚀 IA para todos está trabajando** ⏳ **Preparando análisis inteligente...** *Primera vez puede tardar 2-3 minutos (descarga de modelos)* *Siguientes análisis: 30-60 segundos* """ # Procesar imagen prompt, info = generator.generate_prompt(image, model_type, mode, progress_callback) # Resultado final yield prompt, info def clear_outputs(): """Limpiar outputs y memoria""" gc.collect() if torch.cuda.is_available(): torch.cuda.empty_cache() return "", "" # Crear interfaz optimizada def create_interface(): # CSS mejorado custom_css = """ .gradio-container { max-width: 1400px !important; font-family: 'Inter', 'Segoe UI', system-ui, sans-serif; } .prompt-output { font-family: 'SF Mono', 'Monaco', 'Cascadia Code', 'Roboto Mono', monospace !important; font-size: 14px !important; line-height: 1.6 !important; background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%) !important; border-radius: 12px !important; padding: 20px !important; border: 1px solid #dee2e6 !important; box-shadow: 0 2px 4px rgba(0,0,0,0.1) !important; } .main-title { text-align: center; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; font-size: 3em !important; font-weight: 800 !important; margin-bottom: 0.3em !important; letter-spacing: -0.02em; } .subtitle { text-align: center; font-style: italic; color: #6c757d; font-size: 1.2em; margin-bottom: 2em; font-weight: 300; } .device-indicator { background: linear-gradient(90deg, #28a745, #20c997); color: white; padding: 8px 16px; border-radius: 20px; font-size: 0.9em; display: inline-block; margin: 10px 0; } """ with gr.Blocks( theme=gr.themes.Soft(), title="IA para todos - Image to Prompt Optimizado", css=custom_css ) as interface: # Header personalizado gr.HTML(f"""