Javijavigon commited on
Commit
ef47dca
·
verified ·
1 Parent(s): e26326c

Upload prompt_engine.py

Browse files
Files changed (1) hide show
  1. prompt_engine.py +302 -0
prompt_engine.py ADDED
@@ -0,0 +1,302 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Motor de procesamiento y mejora de prompts
3
+ """
4
+
5
+ import re
6
+ from typing import Dict, List, Tuple, Optional
7
+ from model_configs import MODEL_CONFIGS, ENHANCEMENT_RULES, ARTIST_STYLES
8
+
9
+
10
+ class PromptAnalyzer:
11
+ """Analiza prompts para identificar problemas y oportunidades de mejora"""
12
+
13
+ def __init__(self):
14
+ self.common_issues = {
15
+ "muy_corto": lambda p: len(p.split()) < 5,
16
+ "sin_estilo": lambda p: not any(word in p.lower() for word in
17
+ ["style", "estilo", "art", "photo", "painting", "render", "illustration"]),
18
+ "sin_calidad": lambda p: not any(word in p.lower() for word in
19
+ ["quality", "detailed", "hd", "4k", "8k", "masterpiece", "professional"]),
20
+ "sin_iluminacion": lambda p: not any(word in p.lower() for word in
21
+ ["light", "lighting", "luz", "iluminación", "bright", "dark", "shadow"]),
22
+ "sin_composicion": lambda p: not any(word in p.lower() for word in
23
+ ["shot", "view", "angle", "close", "wide", "portrait", "landscape"]),
24
+ "palabras_vagas": lambda p: any(word in p.lower() for word in
25
+ ["nice", "good", "beautiful", "cool", "bonito", "lindo", "bueno"])
26
+ }
27
+
28
+ def analyze(self, prompt: str) -> Dict:
29
+ """Analiza el prompt y retorna un reporte"""
30
+ issues = []
31
+ suggestions = []
32
+ score = 100
33
+
34
+ for issue_name, check_func in self.common_issues.items():
35
+ if check_func(prompt):
36
+ issues.append(issue_name)
37
+ score -= 15
38
+
39
+ if "muy_corto" in issues:
40
+ suggestions.append("🔸 Añade más detalles descriptivos al prompt")
41
+ if "sin_estilo" in issues:
42
+ suggestions.append("🎨 Especifica un estilo artístico (ej: 'oil painting', 'digital art')")
43
+ if "sin_calidad" in issues:
44
+ suggestions.append("✨ Añade modificadores de calidad (ej: 'highly detailed', '8k')")
45
+ if "sin_iluminacion" in issues:
46
+ suggestions.append("💡 Describe la iluminación (ej: 'dramatic lighting', 'golden hour')")
47
+ if "sin_composicion" in issues:
48
+ suggestions.append("📷 Especifica el encuadre o ángulo de cámara")
49
+ if "palabras_vagas" in issues:
50
+ suggestions.append("📝 Reemplaza palabras vagas por descripciones específicas")
51
+
52
+ return {
53
+ "score": max(0, score),
54
+ "issues": issues,
55
+ "suggestions": suggestions,
56
+ "word_count": len(prompt.split()),
57
+ "char_count": len(prompt)
58
+ }
59
+
60
+
61
+ class PromptEnhancer:
62
+ """Mejora prompts para modelos de generación de imágenes"""
63
+
64
+ def __init__(self):
65
+ self.analyzer = PromptAnalyzer()
66
+
67
+ def translate_basic_terms(self, prompt: str) -> str:
68
+ """Traduce términos básicos del español al inglés"""
69
+ translations = {
70
+ "mujer": "woman", "hombre": "man", "niño": "child", "niña": "girl",
71
+ "perro": "dog", "gato": "cat", "casa": "house", "árbol": "tree",
72
+ "montaña": "mountain", "mar": "sea", "cielo": "sky", "bosque": "forest",
73
+ "ciudad": "city", "calle": "street", "grande": "large", "pequeño": "small",
74
+ "hermoso": "beautiful", "hermosa": "beautiful", "antiguo": "ancient",
75
+ "moderno": "modern", "oscuro": "dark", "brillante": "bright",
76
+ "colorido": "colorful", "misterioso": "mysterious", "rojo": "red",
77
+ "azul": "blue", "verde": "green", "amarillo": "yellow", "negro": "black",
78
+ "blanco": "white", "dorado": "golden", "plateado": "silver",
79
+ "realista": "realistic", "fantástico": "fantasy", "futurista": "futuristic",
80
+ "retro": "retro", "minimalista": "minimalist"
81
+ }
82
+
83
+ result = prompt
84
+ for es, en in translations.items():
85
+ result = re.sub(rf'\b{es}\b', en, result, flags=re.IGNORECASE)
86
+
87
+ return result
88
+
89
+ def enhance_for_model(self, prompt: str, model: str, style: str = None,
90
+ add_quality: bool = True, add_negative: bool = True) -> Dict:
91
+ """Mejora el prompt para un modelo específico"""
92
+
93
+ config = MODEL_CONFIGS.get(model, MODEL_CONFIGS["stable-diffusion-1.5"])
94
+
95
+ enhanced = self.translate_basic_terms(prompt)
96
+
97
+ if style and style in config["style_modifiers"]:
98
+ style_tokens = config["style_modifiers"][style]
99
+ enhanced = f"{enhanced}, {', '.join(style_tokens)}"
100
+
101
+ if add_quality and config["quality_tokens"]:
102
+ quality_str = ", ".join(config["quality_tokens"][:4])
103
+ enhanced = f"{quality_str}, {enhanced}"
104
+
105
+ if model == "dall-e-3":
106
+ enhanced = self._format_for_dalle(enhanced)
107
+ elif model == "flux":
108
+ enhanced = self._format_for_flux(enhanced)
109
+ elif model == "midjourney":
110
+ enhanced = self._format_for_midjourney(enhanced, config)
111
+
112
+ negative = ""
113
+ if add_negative and config["negative_default"]:
114
+ negative = ", ".join(config["negative_default"])
115
+
116
+ analysis = self.analyzer.analyze(enhanced)
117
+
118
+ return {
119
+ "original": prompt,
120
+ "enhanced": enhanced,
121
+ "negative_prompt": negative,
122
+ "model": config["name"],
123
+ "analysis": analysis,
124
+ "tokens_estimate": len(enhanced.split()),
125
+ "max_tokens": config["max_tokens"]
126
+ }
127
+
128
+ def _format_for_dalle(self, prompt: str) -> str:
129
+ """Formatea el prompt para DALL-E 3"""
130
+ prompt = prompt.replace(", ", " with ")
131
+ prompt = prompt.replace(" ", " ")
132
+
133
+ if not any(prompt.lower().startswith(x) for x in ["a ", "an ", "the "]):
134
+ prompt = f"A detailed image of {prompt}"
135
+
136
+ return prompt
137
+
138
+ def _format_for_flux(self, prompt: str) -> str:
139
+ """Formatea el prompt para FLUX"""
140
+ prompt = re.sub(r'\([^)]+:\d+\.?\d*\)', '', prompt)
141
+ prompt = re.sub(r'\s+', ' ', prompt).strip()
142
+ return prompt
143
+
144
+ def _format_for_midjourney(self, prompt: str, config: Dict) -> str:
145
+ """Formatea el prompt para Midjourney"""
146
+ params = config.get("parameters", {})
147
+ param_str = f" {params.get('version', '--v 6')} {params.get('quality', '--q 2')}"
148
+ return f"{prompt}{param_str}"
149
+
150
+ def suggest_variations(self, prompt: str, num_variations: int = 3) -> List[str]:
151
+ """Genera variaciones del prompt"""
152
+ variations = []
153
+
154
+ art_styles = ["oil painting style", "digital art", "watercolor painting"]
155
+ lighting = ["dramatic lighting", "soft natural light", "neon lights"]
156
+ mood = ["ethereal atmosphere", "moody and dark", "vibrant and colorful"]
157
+
158
+ variations.append(f"{prompt}, {art_styles[0]}, masterpiece")
159
+ variations.append(f"{prompt}, {lighting[0]}, detailed")
160
+ variations.append(f"{prompt}, {mood[0]}, high quality")
161
+
162
+ return variations[:num_variations]
163
+
164
+ def fix_common_errors(self, prompt: str) -> Tuple[str, List[str]]:
165
+ """Corrige errores comunes en prompts"""
166
+ fixes = []
167
+ result = prompt
168
+
169
+ if " " in result:
170
+ result = re.sub(r'\s+', ' ', result)
171
+ fixes.append("Espacios múltiples eliminados")
172
+
173
+ if ",," in result or ", ," in result:
174
+ result = re.sub(r',\s*,', ',', result)
175
+ fixes.append("Comas duplicadas corregidas")
176
+
177
+ if "()" in result or "( )" in result:
178
+ result = re.sub(r'\(\s*\)', '', result)
179
+ fixes.append("Paréntesis vacíos eliminados")
180
+
181
+ open_count = result.count('(')
182
+ close_count = result.count(')')
183
+ if open_count != close_count:
184
+ if open_count > close_count:
185
+ result += ')' * (open_count - close_count)
186
+ else:
187
+ result = '(' * (close_count - open_count) + result
188
+ fixes.append("Paréntesis balanceados")
189
+
190
+ problematic = ['|', '\\', '`', '~']
191
+ for char in problematic:
192
+ if char in result:
193
+ result = result.replace(char, '')
194
+ fixes.append(f"Carácter '{char}' eliminado")
195
+
196
+ def fix_weight(match):
197
+ weight = float(match.group(2))
198
+ if weight < 0.1:
199
+ weight = 0.1
200
+ elif weight > 2.0:
201
+ weight = 2.0
202
+ return f"({match.group(1)}:{weight})"
203
+
204
+ result = re.sub(r'\(([^:]+):(\d+\.?\d*)\)', fix_weight, result)
205
+
206
+ return result.strip(), fixes
207
+
208
+
209
+ class PromptBuilder:
210
+ """Constructor interactivo de prompts"""
211
+
212
+ def __init__(self):
213
+ self.reset()
214
+
215
+ def reset(self):
216
+ self.components = {
217
+ "subject": "",
218
+ "style": "",
219
+ "quality": [],
220
+ "lighting": "",
221
+ "mood": "",
222
+ "camera": "",
223
+ "colors": [],
224
+ "details": []
225
+ }
226
+ return self
227
+
228
+ def set_subject(self, subject: str):
229
+ self.components["subject"] = subject
230
+ return self
231
+
232
+ def set_style(self, style: str):
233
+ if style in ARTIST_STYLES:
234
+ self.components["style"] = ", ".join(ARTIST_STYLES[style])
235
+ else:
236
+ self.components["style"] = style
237
+ return self
238
+
239
+ def add_quality(self, quality_terms: List[str]):
240
+ self.components["quality"].extend(quality_terms)
241
+ return self
242
+
243
+ def set_lighting(self, lighting: str):
244
+ for category, data in ENHANCEMENT_RULES.items():
245
+ if category == "lighting" and lighting in data["enhancements"]:
246
+ self.components["lighting"] = ", ".join(data["enhancements"][lighting])
247
+ break
248
+ else:
249
+ self.components["lighting"] = lighting
250
+ return self
251
+
252
+ def set_mood(self, mood: str):
253
+ if "mood" in ENHANCEMENT_RULES and mood in ENHANCEMENT_RULES["mood"]["enhancements"]:
254
+ self.components["mood"] = ", ".join(ENHANCEMENT_RULES["mood"]["enhancements"][mood])
255
+ else:
256
+ self.components["mood"] = mood
257
+ return self
258
+
259
+ def set_camera(self, camera: str):
260
+ if "camera" in ENHANCEMENT_RULES and camera in ENHANCEMENT_RULES["camera"]["enhancements"]:
261
+ self.components["camera"] = ", ".join(ENHANCEMENT_RULES["camera"]["enhancements"][camera])
262
+ else:
263
+ self.components["camera"] = camera
264
+ return self
265
+
266
+ def add_colors(self, colors: List[str]):
267
+ self.components["colors"].extend(colors)
268
+ return self
269
+
270
+ def add_details(self, details: List[str]):
271
+ self.components["details"].extend(details)
272
+ return self
273
+
274
+ def build(self) -> str:
275
+ """Construye el prompt final"""
276
+ parts = []
277
+
278
+ if self.components["quality"]:
279
+ parts.append(", ".join(self.components["quality"]))
280
+
281
+ if self.components["subject"]:
282
+ parts.append(self.components["subject"])
283
+
284
+ if self.components["style"]:
285
+ parts.append(self.components["style"])
286
+
287
+ if self.components["colors"]:
288
+ parts.append(", ".join(self.components["colors"]))
289
+
290
+ if self.components["lighting"]:
291
+ parts.append(self.components["lighting"])
292
+
293
+ if self.components["mood"]:
294
+ parts.append(self.components["mood"])
295
+
296
+ if self.components["camera"]:
297
+ parts.append(self.components["camera"])
298
+
299
+ if self.components["details"]:
300
+ parts.append(", ".join(self.components["details"]))
301
+
302
+ return ", ".join(filter(None, parts))