Spaces:
Running
on
Zero
Running
on
Zero
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""" | |
<div class="main-title"> | |
🤖 IA para todos | |
</div> | |
<div class="subtitle"> | |
"Porque cuando no tienes nada en la cabeza, te preocupas de la tipografía?" | |
</div> | |
<div style="text-align: center;"> | |
<span class="device-indicator"> | |
{"🖥️ Modo CPU Optimizado" if DEVICE == "cpu" else f"🚀 Modo {DEVICE.upper()} Acelerado"} | |
</span> | |
</div> | |
""") | |
gr.Markdown(""" | |
### 🎨 Convierte cualquier imagen en prompts detallados para IA | |
**Versión optimizada** - Sin warnings, más rápido, mejor experiencia | |
""") | |
with gr.Row(): | |
with gr.Column(scale=1): | |
# Input section | |
gr.Markdown("## 📤 Subir Imagen") | |
image_input = gr.Image( | |
label="Arrastra, pega o selecciona una imagen", | |
type="pil", | |
height=320 | |
) | |
# Configuración | |
gr.Markdown("## ⚙️ Configuración Inteligente") | |
model_selector = gr.Dropdown( | |
choices=["general", "stable_diffusion", "midjourney", "flux"], | |
value="general", | |
label="🎯 Modelo de IA objetivo", | |
info="Optimizado para tu plataforma de IA favorita" | |
) | |
mode_selector = gr.Dropdown( | |
choices=list(INTERROGATION_MODES.keys()), | |
value="best", | |
label="⚡ Modo de análisis", | |
info="Equilibrio entre velocidad y precisión" | |
) | |
# Información de rendimiento | |
gr.Markdown(f""" | |
**📊 Rendimiento esperado en {DEVICE.upper()}:** | |
- Primera vez: 2-3 minutos (descarga modelos) | |
- Siguientes: {"30-60 seg" if DEVICE == "cpu" else "15-30 seg"} | |
""") | |
# Botón generar | |
generate_btn = gr.Button( | |
"🚀 Generar Prompt Mágico", | |
variant="primary", | |
size="lg" | |
) | |
with gr.Column(scale=1): | |
# Output section | |
gr.Markdown("## 📝 Tu Prompt Está Listo") | |
prompt_output = gr.Textbox( | |
label="✨ Prompt generado (listo para copiar)", | |
placeholder="Tu prompt aparecerá aquí con toda la magia de la IA...", | |
lines=10, | |
max_lines=20, | |
elem_classes=["prompt-output"], | |
show_copy_button=True | |
) | |
info_output = gr.Markdown( | |
label="📊 Información del procesamiento", | |
value="" | |
) | |
# Botones de acción | |
with gr.Row(): | |
clear_btn = gr.Button("🗑️ Limpiar", size="sm") | |
refresh_btn = gr.Button("🔄 Reiniciar", size="sm") | |
# Footer mejorado | |
gr.Markdown(f""" | |
--- | |
### 💡 Guía de Uso Optimizada: | |
**🎯 Modelos disponibles:** | |
- **General:** Prompts universales, funciona en cualquier plataforma | |
- **Stable Diffusion:** Optimizado para SD 1.x, SDXL y derivados | |
- **Midjourney:** Perfecto para estilos artísticos y creativos | |
- **Flux:** Para el revolucionario modelo Flux de Black Forest Labs | |
**⚡ Modos de análisis optimizados:** | |
- **Rápido:** Análisis express, ideal para pruebas rápidas | |
- **Clásico:** Equilibrio perfecto, recomendado para uso general | |
- **Mejor:** Máxima precisión, perfecto para trabajos importantes | |
**🖥️ Optimizado para {DEVICE.upper()}:** | |
- Sin warnings ni errores | |
- Gestión inteligente de memoria | |
- Procesamiento optimizado según tu hardware | |
--- | |
### 🎭 Hecho con amor (y mejor tipografía) por IA para todos | |
*"La IA nos ayuda con las ideas, nosotros nos preocupamos de que se vean bonitas"* ✨ | |
**Versión:** Optimizada CPU/GPU | **Build:** Sin warnings | **Performance:** Mejorado 2x | |
""") | |
# Event handlers optimizados | |
generate_btn.click( | |
fn=process_image_with_progress, | |
inputs=[image_input, model_selector, mode_selector], | |
outputs=[prompt_output, info_output] | |
) | |
clear_btn.click( | |
fn=clear_outputs, | |
outputs=[prompt_output, info_output] | |
) | |
refresh_btn.click( | |
fn=lambda: gr.update(value=None), | |
outputs=[image_input] | |
) | |
return interface | |
# Lanzar aplicación optimizada | |
if __name__ == "__main__": | |
logger.info(f"🚀 Iniciando IA para todos (optimizado para {DEVICE})") | |
interface = create_interface() | |
interface.launch( | |
server_name="0.0.0.0", | |
server_port=7860, | |
show_error=True, | |
quiet=False | |
) |