File size: 11,861 Bytes
ef47dca
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
"""
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))