""" Motor de procesamiento y mejora de prompts """ import re from typing import Dict, List, Tuple, Optional from model_configs import MODEL_CONFIGS, ENHANCEMENT_RULES, ARTIST_STYLES class PromptAnalyzer: """Analiza prompts para identificar problemas y oportunidades de mejora""" def __init__(self): self.common_issues = { "muy_corto": lambda p: len(p.split()) < 5, "sin_estilo": lambda p: not any(word in p.lower() for word in ["style", "estilo", "art", "photo", "painting", "render", "illustration"]), "sin_calidad": lambda p: not any(word in p.lower() for word in ["quality", "detailed", "hd", "4k", "8k", "masterpiece", "professional"]), "sin_iluminacion": lambda p: not any(word in p.lower() for word in ["light", "lighting", "luz", "iluminación", "bright", "dark", "shadow"]), "sin_composicion": lambda p: not any(word in p.lower() for word in ["shot", "view", "angle", "close", "wide", "portrait", "landscape"]), "palabras_vagas": lambda p: any(word in p.lower() for word in ["nice", "good", "beautiful", "cool", "bonito", "lindo", "bueno"]) } def analyze(self, prompt: str) -> Dict: """Analiza el prompt y retorna un reporte""" issues = [] suggestions = [] score = 100 for issue_name, check_func in self.common_issues.items(): if check_func(prompt): issues.append(issue_name) score -= 15 if "muy_corto" in issues: suggestions.append("🔸 Añade más detalles descriptivos al prompt") if "sin_estilo" in issues: suggestions.append("🎨 Especifica un estilo artístico (ej: 'oil painting', 'digital art')") if "sin_calidad" in issues: suggestions.append("✨ Añade modificadores de calidad (ej: 'highly detailed', '8k')") if "sin_iluminacion" in issues: suggestions.append("💡 Describe la iluminación (ej: 'dramatic lighting', 'golden hour')") if "sin_composicion" in issues: suggestions.append("📷 Especifica el encuadre o ángulo de cámara") if "palabras_vagas" in issues: suggestions.append("📝 Reemplaza palabras vagas por descripciones específicas") return { "score": max(0, score), "issues": issues, "suggestions": suggestions, "word_count": len(prompt.split()), "char_count": len(prompt) } class PromptEnhancer: """Mejora prompts para modelos de generación de imágenes""" def __init__(self): self.analyzer = PromptAnalyzer() def translate_basic_terms(self, prompt: str) -> str: """Traduce términos básicos del español al inglés""" translations = { "mujer": "woman", "hombre": "man", "niño": "child", "niña": "girl", "perro": "dog", "gato": "cat", "casa": "house", "árbol": "tree", "montaña": "mountain", "mar": "sea", "cielo": "sky", "bosque": "forest", "ciudad": "city", "calle": "street", "grande": "large", "pequeño": "small", "hermoso": "beautiful", "hermosa": "beautiful", "antiguo": "ancient", "moderno": "modern", "oscuro": "dark", "brillante": "bright", "colorido": "colorful", "misterioso": "mysterious", "rojo": "red", "azul": "blue", "verde": "green", "amarillo": "yellow", "negro": "black", "blanco": "white", "dorado": "golden", "plateado": "silver", "realista": "realistic", "fantástico": "fantasy", "futurista": "futuristic", "retro": "retro", "minimalista": "minimalist" } result = prompt for es, en in translations.items(): result = re.sub(rf'\b{es}\b', en, result, flags=re.IGNORECASE) return result def enhance_for_model(self, prompt: str, model: str, style: str = None, add_quality: bool = True, add_negative: bool = True) -> Dict: """Mejora el prompt para un modelo específico""" config = MODEL_CONFIGS.get(model, MODEL_CONFIGS["stable-diffusion-1.5"]) enhanced = self.translate_basic_terms(prompt) if style and style in config["style_modifiers"]: style_tokens = config["style_modifiers"][style] enhanced = f"{enhanced}, {', '.join(style_tokens)}" if add_quality and config["quality_tokens"]: quality_str = ", ".join(config["quality_tokens"][:4]) enhanced = f"{quality_str}, {enhanced}" if model == "dall-e-3": enhanced = self._format_for_dalle(enhanced) elif model == "flux": enhanced = self._format_for_flux(enhanced) elif model == "midjourney": enhanced = self._format_for_midjourney(enhanced, config) negative = "" if add_negative and config["negative_default"]: negative = ", ".join(config["negative_default"]) analysis = self.analyzer.analyze(enhanced) return { "original": prompt, "enhanced": enhanced, "negative_prompt": negative, "model": config["name"], "analysis": analysis, "tokens_estimate": len(enhanced.split()), "max_tokens": config["max_tokens"] } def _format_for_dalle(self, prompt: str) -> str: """Formatea el prompt para DALL-E 3""" prompt = prompt.replace(", ", " with ") prompt = prompt.replace(" ", " ") if not any(prompt.lower().startswith(x) for x in ["a ", "an ", "the "]): prompt = f"A detailed image of {prompt}" return prompt def _format_for_flux(self, prompt: str) -> str: """Formatea el prompt para FLUX""" prompt = re.sub(r'\([^)]+:\d+\.?\d*\)', '', prompt) prompt = re.sub(r'\s+', ' ', prompt).strip() return prompt def _format_for_midjourney(self, prompt: str, config: Dict) -> str: """Formatea el prompt para Midjourney""" params = config.get("parameters", {}) param_str = f" {params.get('version', '--v 6')} {params.get('quality', '--q 2')}" return f"{prompt}{param_str}" def suggest_variations(self, prompt: str, num_variations: int = 3) -> List[str]: """Genera variaciones del prompt""" variations = [] art_styles = ["oil painting style", "digital art", "watercolor painting"] lighting = ["dramatic lighting", "soft natural light", "neon lights"] mood = ["ethereal atmosphere", "moody and dark", "vibrant and colorful"] variations.append(f"{prompt}, {art_styles[0]}, masterpiece") variations.append(f"{prompt}, {lighting[0]}, detailed") variations.append(f"{prompt}, {mood[0]}, high quality") return variations[:num_variations] def fix_common_errors(self, prompt: str) -> Tuple[str, List[str]]: """Corrige errores comunes en prompts""" fixes = [] result = prompt if " " in result: result = re.sub(r'\s+', ' ', result) fixes.append("Espacios múltiples eliminados") if ",," in result or ", ," in result: result = re.sub(r',\s*,', ',', result) fixes.append("Comas duplicadas corregidas") if "()" in result or "( )" in result: result = re.sub(r'\(\s*\)', '', result) fixes.append("Paréntesis vacíos eliminados") open_count = result.count('(') close_count = result.count(')') if open_count != close_count: if open_count > close_count: result += ')' * (open_count - close_count) else: result = '(' * (close_count - open_count) + result fixes.append("Paréntesis balanceados") problematic = ['|', '\\', '`', '~'] for char in problematic: if char in result: result = result.replace(char, '') fixes.append(f"Carácter '{char}' eliminado") def fix_weight(match): weight = float(match.group(2)) if weight < 0.1: weight = 0.1 elif weight > 2.0: weight = 2.0 return f"({match.group(1)}:{weight})" result = re.sub(r'\(([^:]+):(\d+\.?\d*)\)', fix_weight, result) return result.strip(), fixes class PromptBuilder: """Constructor interactivo de prompts""" def __init__(self): self.reset() def reset(self): self.components = { "subject": "", "style": "", "quality": [], "lighting": "", "mood": "", "camera": "", "colors": [], "details": [] } return self def set_subject(self, subject: str): self.components["subject"] = subject return self def set_style(self, style: str): if style in ARTIST_STYLES: self.components["style"] = ", ".join(ARTIST_STYLES[style]) else: self.components["style"] = style return self def add_quality(self, quality_terms: List[str]): self.components["quality"].extend(quality_terms) return self def set_lighting(self, lighting: str): for category, data in ENHANCEMENT_RULES.items(): if category == "lighting" and lighting in data["enhancements"]: self.components["lighting"] = ", ".join(data["enhancements"][lighting]) break else: self.components["lighting"] = lighting return self def set_mood(self, mood: str): if "mood" in ENHANCEMENT_RULES and mood in ENHANCEMENT_RULES["mood"]["enhancements"]: self.components["mood"] = ", ".join(ENHANCEMENT_RULES["mood"]["enhancements"][mood]) else: self.components["mood"] = mood return self def set_camera(self, camera: str): if "camera" in ENHANCEMENT_RULES and camera in ENHANCEMENT_RULES["camera"]["enhancements"]: self.components["camera"] = ", ".join(ENHANCEMENT_RULES["camera"]["enhancements"][camera]) else: self.components["camera"] = camera return self def add_colors(self, colors: List[str]): self.components["colors"].extend(colors) return self def add_details(self, details: List[str]): self.components["details"].extend(details) return self def build(self) -> str: """Construye el prompt final""" parts = [] if self.components["quality"]: parts.append(", ".join(self.components["quality"])) if self.components["subject"]: parts.append(self.components["subject"]) if self.components["style"]: parts.append(self.components["style"]) if self.components["colors"]: parts.append(", ".join(self.components["colors"])) if self.components["lighting"]: parts.append(self.components["lighting"]) if self.components["mood"]: parts.append(self.components["mood"]) if self.components["camera"]: parts.append(self.components["camera"]) if self.components["details"]: parts.append(", ".join(self.components["details"])) return ", ".join(filter(None, parts))