BATUTO-ART commited on
Commit
40cf66e
·
verified ·
1 Parent(s): 100a9b7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +516 -237
app.py CHANGED
@@ -1,139 +1,227 @@
1
- import random
2
- import datetime
3
- import json
4
  import os
5
  import base64
6
  import requests
7
  import time
 
 
 
 
8
  from io import BytesIO
9
  from PIL import Image
10
  import gradio as gr
11
- from openai import OpenAI
 
 
12
 
13
  # --------------------------
14
- # Configuración Sambanova Maverick AI
15
  # --------------------------
16
- api_key_sambanova = os.getenv("SAMBANOVA_API_KEY")
17
- client_sambanova = OpenAI(api_key=api_key_sambanova, base_url="https://api.sambanova.ai/v1")
 
 
 
18
 
19
- MODELS = {
20
- "general_fast": "Meta-Llama-3.1-8B-Instruct",
21
- "general_smart": "Meta-Llama-3.3-70B-Instruct",
22
- "coding_expert": "DeepSeek-V3.1",
23
- "coding_alt": "DeepSeek-V3-0324",
24
- "massive_brain": "gpt-oss-120b",
25
- "specialized_1": "DeepSeek-V3.1-Terminus",
26
- "specialized_2": "Llama-3.3-Swallow-70B-Instruct-v0.4",
27
- "multilingual": "Qwen3-32B",
28
- "arabic_special": "ALLaM-7B-Instruct-preview",
29
- "vision_expert": "Llama-4-Maverick-17B-128E-Instruct"
30
- }
31
 
32
- def select_best_model(user_prompt):
33
- router_system_prompt = (
34
- "You are an AI router. Analyze the user's request and select the best ID from this list:\n"
35
- f"{list(MODELS.values())}\n"
36
- "Rules:\n"
37
- "- For coding/math: Choose 'DeepSeek-V3.1' or 'DeepSeek-V3-0324'.\n"
38
- "- For complex logic: Choose 'Meta-Llama-3.3-70B-Instruct' or 'gpt-oss-120b'.\n"
39
- "- For Japanese/Cultural: Choose 'Llama-3.3-Swallow-70B-Instruct-v0.4'.\n"
40
- "- For Arabic/Middle East: Choose 'ALLaM-7B-Instruct-preview'.\n"
41
- "- For General/Fast chat: Choose 'Meta-Llama-3.1-8B-Instruct'.\n"
42
- "- For Multilingual/Chinese: Choose 'Qwen3-32B'.\n"
43
- "Reply ONLY with the exact model name strings from the list. Nothing else."
44
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  try:
46
  response = client_sambanova.chat.completions.create(
47
- model="Meta-Llama-3.1-8B-Instruct",
48
  messages=[
49
- {"role": "system", "content": router_system_prompt},
50
- {"role": "user", "content": f"User request: {user_prompt}"}
51
  ],
52
- temperature=0.0,
53
- max_tokens=50
 
54
  )
55
- selected_model = response.choices[0].message.content.strip().replace('"', '').replace("'", "")
56
- if selected_model not in MODELS.values():
57
- return "Meta-Llama-3.3-70B-Instruct"
58
- return selected_model
59
  except Exception as e:
60
- print(f"Error en router Maverick: {e}")
61
- return "Meta-Llama-3.3-70B-Instruct"
62
 
63
- def smart_prompt_suggestions(input_text):
64
- target_model = select_best_model(input_text)
65
- messages = [
66
- {"role": "system", "content": "You are a helpful assistant."},
67
- {"role": "user", "content": input_text}
68
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  try:
70
- stream = client_sambanova.chat.completions.create(
71
- model=target_model,
72
- messages=messages,
73
- temperature=0.2,
74
- top_p=0.9,
75
- stream=True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  )
77
- response_text = ""
78
- for chunk in stream:
79
- content = chunk.choices[0].delta.content
80
- if content:
81
- response_text += content
82
- return response_text
83
  except Exception as e:
84
- return f"Error en Maverick IA: {str(e)}"
85
 
86
  # --------------------------
87
- # GENERADOR PROMPTS SIN ETNIAS
88
  # --------------------------
89
  class HyperRealisticConfig:
90
- BODY_TYPES = [
91
- "athletic slender", "voluptuous curves", "petite feminine",
92
- "toned hourglass", "soft natural", "elegant tall"
93
- ]
94
- SKIN_DETAILS = [
95
- "with subtle freckles and skin texture", "with dewy natural complexion",
96
- "showing realistic skin pores and veins", "with natural skin imperfections",
97
- "with subsurface scattering effect", "with delicate skin translucency"
98
- ]
99
- LACE_BIKINI_STYLES = [
100
- "delicate black Chantilly lace bikini with floral embroidery and sheer panels",
101
- "sheer nude illusion bikini with scalloped lace edges and ribbon ties"
102
- ]
103
- HOSIERY_STYLES = [
104
- "black sheer thigh-high stockings with lace tops and stay-up silicone",
105
- "nude ultra-sheer stockings with reinforced toes and back seam"
106
- ]
107
- HEEL_STYLES = [
108
- "black patent leather stilettos with pointed toe and slim heel",
109
- "nude pumps with platform and ankle strap for stability"
110
- ]
111
- HAIRSTYLES = [
112
- "long wavy hair with natural volume and soft highlights",
113
- "sleek straight hair with middle part and glossy finish"
114
- ]
115
- MAKEUP_STYLES = [
116
- "natural glam with dewy skin, soft contour, and nude lips",
117
- "smoky eye with winged liner and voluminous lashes"
118
- ]
119
- LIGHTING_DETAILS = [
120
- "soft diffused lighting with a warm golden glow",
121
- "dramatic chiaroscuro lighting with deep shadows"
122
- ]
123
- PHOTOGRAPHY_STYLES = [
124
- "cinematic lighting with rim light and soft shadows",
125
- "natural window light with lens flare and soft focus"
126
- ]
127
- CAMERAS = [
128
- "Canon EOS R5", "Sony A7R IV", "Nikon Z7 II"
129
- ]
130
- LENSES = [
131
- "Canon RF 85mm f/1.2L", "Sony FE 50mm f/1.2 GM"
132
- ]
133
  PROFESSIONAL_ROLES = [
134
- {"role": "Executive Secretary", "uniform": "form-fitting tailored black dress with silk blouse slightly unbuttoned", "environment": "luxurious corporate office with marble floors", "accessories": "slim tablet and leather portfolio", "pose": "bending over conference table arranging documents", "accidental_hint": "causing the hem to naturally ride up just enough to reveal a delicate lace edge"},
135
- {"role": "Luxury Hotel Manager", "uniform": "elegant navy blue blazer and pencil skirt that shifts slightly when seated", "environment": "five-star hotel lobby with golden lighting", "accessories": "gold name tag and master key cards", "pose": "leaning forward to assist guest at reception", "accidental_hint": "causing the skirt to hug the hips and subtly outline lace beneath"},
136
- {"role": "Fashion Boutique Manager", "uniform": "chic black designer dress with elegant draping that accents curves", "environment": "high-end boutique with minimalist decor and spotlights", "accessories": "designer handbag and inventory clipboard", "pose": "kneeling to adjust mannequin display", "accidental_hint": "causing the fabric to stretch gently across the hips, revealing faint lace texture"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  ]
138
 
139
  class HyperRealisticPromptGenerator:
@@ -141,94 +229,80 @@ class HyperRealisticPromptGenerator:
141
  self.config = HyperRealisticConfig()
142
  self.history = []
143
 
144
- def _random_style(self):
145
- return (
146
- random.choice(self.config.BODY_TYPES),
147
- random.choice(self.config.SKIN_DETAILS),
148
- random.choice(self.config.LACE_BIKINI_STYLES),
149
- random.choice(self.config.HOSIERY_STYLES),
150
- random.choice(self.config.HEEL_STYLES),
151
- random.choice(self.config.HAIRSTYLES),
152
- random.choice(self.config.MAKEUP_STYLES),
153
- random.choice(self.config.LIGHTING_DETAILS),
154
- random.choice(self.config.PHOTOGRAPHY_STYLES),
155
- random.choice(self.config.CAMERAS),
156
- random.choice(self.config.LENSES)
157
- )
158
-
159
- def generate_prompt(self, role_name: str, nsfw_mode: bool = False) -> str:
160
  role = next((r for r in self.config.PROFESSIONAL_ROLES if r["role"] == role_name), None)
161
  if not role:
162
- return "Error: Rol no encontrado."
163
- body, skin, lace, hosiery, heels, hairstyle, makeup, lighting, photo_style, camera, lens = self._random_style()
164
-
165
- underwear_desc = f"wearing delicate {lace} under {role['uniform']}" if not nsfw_mode else f"wearing {lace} under {role['uniform']}"
166
- sensuality = "professional elegance with natural feminine grace" if not nsfw_mode else "artistic intimate moment with effortless natural beauty"
167
-
168
  prompt = (
169
- f"Hyper-realistic 4K photograph, 9:16 vertical full-body composition, dynamic low-angle view, "
170
- f"of a stunning {role['role'].lower()} with {body} figure {skin}, "
171
- f"{underwear_desc}, {hosiery}, {heels}, styled with {hairstyle}, and {makeup}. "
172
- f"In {role['environment']}, captured while {role['pose']}, {role['accidental_hint']}. "
173
- f"{lighting}, {photo_style}, Camera: {camera} with {lens} lens, ultra-high resolution 16K, "
174
- f"extreme detail showing skin texture with visible pores, realistic fabric wrinkles, "
175
- f"subsurface scattering effect, cinematic depth of field. Professional atmosphere, elegant composition, {sensuality}. "
176
- f"Include {role['accessories']} in scene. --no explicit_nudity --style raw --stylize 150"
177
  )
178
 
179
  self.history.append({
180
- "prompt": prompt, "role": role_name, "nsfw": nsfw_mode,
 
 
181
  "timestamp": datetime.datetime.now().isoformat(),
182
- "votes": 0, "notes": ""
183
  })
 
 
 
 
184
  return prompt
185
 
186
- def suggest_prompts(self, count=3):
187
- if not self.history:
188
- roles = [r["role"] for r in self.config.PROFESSIONAL_ROLES]
189
- return [self.generate_prompt(random.choice(roles)) for _ in range(count)]
190
- top_prompts = sorted(self.history, key=lambda x: x["votes"], reverse=True)[:count]
191
- suggestions = []
192
- for entry in top_prompts:
193
- base_role = entry["role"]
194
- suggestion = self.generate_prompt(base_role)
195
- suggestions.append(suggestion)
196
- return suggestions
197
-
198
- def vote_prompt(self, index, vote_change=1):
199
- if 0 <= index < len(self.history):
200
- self.history[index]["votes"] += vote_change
201
-
202
- def annotate_prompt(self, index, note_text):
203
- if 0 <= index < len(self.history):
204
- self.history[index]["notes"] = note_text
205
 
206
  def clear_history(self):
207
  self.history = []
208
 
209
  def get_history(self):
210
- return self.history.copy()
 
 
 
 
211
 
212
- # -------------------------------
213
- # INTEGRACION API REVE CREATE (IMÁGENES)
214
- # -------------------------------
215
- API_URL_REVE = "https://api.aimlapi.com/v1/images/generations"
216
- IMAGES_FOLDER = "generated_images"
217
- if not os.path.exists(IMAGES_FOLDER):
218
- os.makedirs(IMAGES_FOLDER)
219
 
220
- def save_image(img, index):
221
- timestamp = int(time.time())
222
- filename = f"image_{timestamp}_{index}.png"
223
- full_path = os.path.join(IMAGES_FOLDER, filename)
224
- img.save(full_path)
225
- return full_path
 
 
 
 
226
 
227
- def call_image_api(prompt, api_key, index):
228
  payload = {
229
- "model": "reve/create-image",
230
  "prompt": prompt,
231
- "aspect_ratio": "9:16"
 
232
  }
233
  headers = {
234
  "Authorization": f"Bearer {api_key}",
@@ -236,83 +310,288 @@ def call_image_api(prompt, api_key, index):
236
  "Content-Type": "application/json"
237
  }
238
  try:
239
- response = requests.post(API_URL_REVE, headers=headers, json=payload, timeout=60)
240
  if response.status_code == 200:
241
  data = response.json()
242
  if "image" in data:
243
  img_bytes = base64.b64decode(data["image"])
244
  img = Image.open(BytesIO(img_bytes))
245
- save_image(img, index)
246
- return img, None
247
- return None, f"Error {response.status_code}: {response.text}"
248
  except Exception as e:
249
- return None, str(e)
250
 
251
- def generate_images_batch(prompt, api_key, num_images):
252
- images = []
253
- errors = []
254
- for i in range(num_images):
255
- img, err = call_image_api(prompt, api_key, i)
256
- if img:
257
- images.append(img)
258
- elif err:
259
- errors.append(err)
260
- return images, errors
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
261
 
262
- # ------------------------------
263
- # INTERFAZ GRADIO COMPLETA
264
- # ------------------------------
265
  generator = HyperRealisticPromptGenerator()
266
 
267
- def generate_prompt_ui(role, nsfw):
268
- return generator.generate_prompt(role, nsfw)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
269
 
270
- def suggest_prompt_ui(user_input):
271
- return smart_prompt_suggestions(user_input)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
 
273
- def generate_images_ui(prompt, api_key, num_images):
274
- if not api_key:
275
- return [], "Por favor, ingresa tu API Key."
276
- imgs, errors = generate_images_batch(prompt, api_key, num_images)
277
- msg = "Imágenes generadas con éxito." if imgs else "Error generando imágenes: " + "; ".join(errors)
278
- return imgs, msg
 
279
 
280
  def clear_history_ui():
281
  generator.clear_history()
282
- return json.dumps(generator.get_history(), indent=2)
283
 
284
- with gr.Blocks() as demo:
285
- gr.Markdown("# HyperRealistic Roles AI - Generador + REVE CREATE + Maverick IA")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
286
 
287
- with gr.Row():
288
- with gr.Column(scale=1):
289
- role_dropdown = gr.Dropdown(
290
- choices=[r["role"] for r in generator.config.PROFESSIONAL_ROLES],
291
- label="Seleccione Rol Profesional",
292
- value=generator.config.PROFESSIONAL_ROLES[0]["role"]
293
- )
294
- nsfw_checkbox = gr.Checkbox(label="Modo NSFW", value=False)
295
- gen_prompt_btn = gr.Button("Generar Prompt")
296
- user_input_text = gr.Textbox(label="Texto para sugerencia inteligente")
297
- suggest_btn = gr.Button("Sugerir Prompt Inteligente")
298
-
299
- api_key_input = gr.Textbox(label="API Key REVE CREATE", placeholder="Tu API Key REVE CREATE", type="password")
300
- num_images = gr.Slider(1, 5, value=1, step=1, label="Cantidad de Imágenes")
301
- gen_images_btn = gr.Button("Generar Imágenes")
302
- clear_hist_btn = gr.Button("Limpiar Historial")
303
-
304
- with gr.Column(scale=2):
305
- prompt_out = gr.Textbox(label="Prompt Generado", lines=10)
306
- suggestion_out = gr.Textbox(label="Sugerencias Maverick IA", lines=15)
307
- images_gallery = gr.Gallery(label="Imágenes Generadas", columns=2)
308
-
309
- history_out = gr.JSON(label="Historial")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
310
 
311
- gen_prompt_btn.click(generate_prompt_ui, inputs=[role_dropdown, nsfw_checkbox], outputs=prompt_out)
312
- suggest_btn.click(suggest_prompt_ui, inputs=[user_input_text], outputs=suggestion_out)
313
- gen_images_btn.click(generate_images_ui, inputs=[prompt_out, api_key_input, num_images], outputs=[images_gallery, prompt_out])
314
- clear_hist_btn.click(clear_history_ui, inputs=[], outputs=history_out)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
315
 
316
  if __name__ == "__main__":
317
- demo.launch(server_name="0.0.0.0", server_port=7860, share=True)
318
-
 
 
 
 
1
  import os
2
  import base64
3
  import requests
4
  import time
5
+ import concurrent.futures
6
+ import random
7
+ import datetime
8
+ import json
9
  from io import BytesIO
10
  from PIL import Image
11
  import gradio as gr
12
+
13
+ # Configuración para Hugging Face
14
+ HF_SPACE = os.getenv('SPACE_ID') is not None
15
 
16
  # --------------------------
17
+ # CONFIGURACIÓN SAMBANOVA - MODELO ÚNICO
18
  # --------------------------
19
+ try:
20
+ from openai import OpenAI
21
+ SAMBANOVA_AVAILABLE = True
22
+ except ImportError:
23
+ SAMBANOVA_AVAILABLE = False
24
 
25
+ SAMBANOVA_API_KEY = os.getenv("SAMBANOVA_API_KEY")
26
+ if SAMBANOVA_AVAILABLE and SAMBANOVA_API_KEY:
27
+ client_sambanova = OpenAI(api_key=SAMBANOVA_API_KEY, base_url="https://api.sambanova.ai/v1")
28
+ SAMBANOVA_ENABLED = True
29
+ else:
30
+ client_sambanova = None
31
+ SAMBANOVA_ENABLED = False
 
 
 
 
 
32
 
33
+ # MODELO ÚNICO PRINCIPAL - Llama 4 Maverick para todo
34
+ PRIMARY_MODEL = "Llama-4-Maverick-17B-128E-Instruct"
35
+
36
+ def enhance_prompt_with_ai(base_prompt, enhancement_type="creative"):
37
+ """
38
+ Mejora el prompt usando Llama 4 Maverick según el tipo de mejora
39
+ """
40
+ if not SAMBANOVA_ENABLED:
41
+ return base_prompt
42
+
43
+ enhancement_instructions = {
44
+ "creative": """
45
+ Como experto en creación de prompts para generación de imágenes, mejora este prompt
46
+ para hacerlo más visualmente impactante, detallado y efectivo.
47
+
48
+ INSTRUCCIONES:
49
+ 1. Añade detalles específicos de iluminación, texturas, colores y composición
50
+ 2. Incluye terminología fotográfica profesional (depth of field, bokeh, lighting ratios, etc.)
51
+ 3. Mantén el aspecto ratio 9:16 y formato vertical
52
+ 4. Enriquece la descripción de personajes, ambiente y emociones
53
+ 5. Asegura realismo fotográfico con detalles técnicos de cámara
54
+ 6. Optimiza para modelos de generación de imágenes como REVE CREATE
55
+
56
+ Responde SOLO con el prompt mejorado, sin explicaciones.
57
+ """,
58
+
59
+ "technical": """
60
+ Como técnico especializado en prompts para AI, optimiza este prompt
61
+ enfocándote en aspectos técnicos y de realismo.
62
+
63
+ INSTRUCCIONES:
64
+ 1. Especifica detalles técnicos de cámara, lentes y configuración
65
+ 2. Añade parámetros de iluminación profesional
66
+ 3. Describe texturas, materiales y superficies con precisión
67
+ 4. Incluye efectos visuales y post-procesado realista
68
+ 5. Mantén coherencia técnica y física
69
+
70
+ Responde SOLO con el prompt mejorado.
71
+ """,
72
+
73
+ "artistic": """
74
+ Como artista conceptual, transforma este prompt en una descripción
75
+ artística y cinematográfica.
76
+
77
+ INSTRUCCIONES:
78
+ 1. Enfócate en atmósfera, mood y emociones
79
+ 2. Usa lenguaje cinematográfico y composición artística
80
+ 3. Añade elementos de narrativa visual
81
+ 4. Describe colores, luces y sombras de forma poética pero precisa
82
+ 5. Crea una escena con impacto visual fuerte
83
+
84
+ Responde SOLO con el prompt mejorado.
85
+ """
86
+ }
87
+
88
+ instruction = enhancement_instructions.get(enhancement_type, enhancement_instructions["creative"])
89
+
90
  try:
91
  response = client_sambanova.chat.completions.create(
92
+ model=PRIMARY_MODEL,
93
  messages=[
94
+ {"role": "system", "content": "Eres un especialista en creación y optimización de prompts para generación de imágenes AI."},
95
+ {"role": "user", "content": f"{instruction}\n\nPROMPT ORIGINAL:\n{base_prompt}"}
96
  ],
97
+ temperature=0.4,
98
+ max_tokens=800,
99
+ top_p=0.9
100
  )
101
+ enhanced = response.choices[0].message.content.strip()
102
+ return enhanced if enhanced and len(enhanced) > 50 else base_prompt
 
 
103
  except Exception as e:
104
+ print(f"Error mejorando prompt: {e}")
105
+ return base_prompt
106
 
107
+ def describe_image_with_ai(image_path, description_style="detailed"):
108
+ """
109
+ Genera una descripción de imagen usando Llama 4 Maverick
110
+ """
111
+ if not SAMBANOVA_ENABLED:
112
+ return "⚠️ Servicio de descripción no disponible. Configura SAMBANOVA_API_KEY."
113
+
114
+ if not image_path or not os.path.exists(image_path):
115
+ return "❌ Imagen no encontrada para describir."
116
+
117
+ style_instructions = {
118
+ "detailed": "Describe la imagen en detalle incluyendo composición, colores, iluminación, personajes y ambiente.",
119
+ "technical": "Analiza la imagen desde perspectiva técnica: composición, iluminación, estilo fotográfico y elementos visuales.",
120
+ "prompt_style": "Crea un prompt de generación de imágenes basado en esta imagen, en estilo detallado y técnico."
121
+ }
122
+
123
+ instruction = style_instructions.get(description_style, style_instructions["detailed"])
124
+
125
+ try:
126
+ # Simulamos una descripción basada en el nombre del archivo
127
+ description_prompt = f"""
128
+ {instruction}
129
+
130
+ Información de la imagen: {os.path.basename(image_path)}
131
+
132
+ Genera una descripción detallada y útil.
133
+ """
134
+
135
+ response = client_sambanova.chat.completions.create(
136
+ model=PRIMARY_MODEL,
137
+ messages=[
138
+ {"role": "system", "content": "Eres un experto en análisis y descripción de imágenes."},
139
+ {"role": "user", "content": description_prompt}
140
+ ],
141
+ temperature=0.3,
142
+ max_tokens=500
143
+ )
144
+
145
+ description = response.choices[0].message.content.strip()
146
+ return description
147
+
148
+ except Exception as e:
149
+ return f"❌ Error en descripción de imagen: {str(e)}"
150
+
151
+ def generate_prompt_from_description(user_description, style="realistic"):
152
+ """
153
+ Genera un prompt completo a partir de una descripción del usuario
154
+ """
155
+ if not SAMBANOVA_ENABLED:
156
+ return "⚠️ Servicio de generación no disponible. Configura SAMBANOVA_API_KEY."
157
+
158
+ style_prompts = {
159
+ "realistic": "Genera un prompt detallado para creación de imágenes realistas y fotográficas",
160
+ "cinematic": "Crea un prompt con estilo cinematográfico y dramático",
161
+ "artistic": "Diseña un prompt artístico y creativo para generación de imágenes",
162
+ "professional": "Elabora un prompt profesional para fotografía de alta calidad"
163
+ }
164
+
165
+ base_instruction = style_prompts.get(style, style_prompts["realistic"])
166
+
167
  try:
168
+ system_prompt = """
169
+ Eres un creador de prompts experto para generación de imágenes AI.
170
+ Crea prompts detallados, técnicos y visualmente ricos que incluyan:
171
+ - Composición y encuadre
172
+ - Iluminación y atmosfera
173
+ - Detalles técnicos de cámara
174
+ - Descripción de personajes y ambiente
175
+ - Estilo y mood
176
+ - Formato 9:16 vertical
177
+ """
178
+
179
+ response = client_sambanova.chat.completions.create(
180
+ model=PRIMARY_MODEL,
181
+ messages=[
182
+ {"role": "system", "content": system_prompt},
183
+ {"role": "user", "content": f"{base_instruction} basado en esta descripción: {user_description}"}
184
+ ],
185
+ temperature=0.5,
186
+ max_tokens=700,
187
+ top_p=0.85
188
  )
189
+
190
+ generated_prompt = response.choices[0].message.content.strip()
191
+ return generated_prompt
192
+
 
 
193
  except Exception as e:
194
+ return f"❌ Error generando prompt: {str(e)}"
195
 
196
  # --------------------------
197
+ # GENERADOR PRINCIPAL DE PROMPTS
198
  # --------------------------
199
  class HyperRealisticConfig:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  PROFESSIONAL_ROLES = [
201
+ {
202
+ "role": "Executive Secretary",
203
+ "uniform": "form-fitting tailored black dress with silk blouse",
204
+ "environment": "luxurious corporate office with marble floors",
205
+ "accessories": "slim tablet and leather portfolio",
206
+ "pose": "bending over conference table arranging documents",
207
+ "accidental_hint": "causing the hem to naturally ride up just enough to reveal a delicate lace edge"
208
+ },
209
+ {
210
+ "role": "Luxury Hotel Manager",
211
+ "uniform": "elegant navy blue blazer and pencil skirt",
212
+ "environment": "five-star hotel lobby with golden lighting",
213
+ "accessories": "gold name tag and master key cards",
214
+ "pose": "leaning forward to assist guest at reception",
215
+ "accidental_hint": "causing the skirt to hug the hips and subtly outline lace beneath"
216
+ },
217
+ {
218
+ "role": "Fashion Boutique Manager",
219
+ "uniform": "chic black designer dress with elegant draping",
220
+ "environment": "high-end boutique with minimalist decor",
221
+ "accessories": "designer handbag and inventory clipboard",
222
+ "pose": "kneeling to adjust mannequin display",
223
+ "accidental_hint": "causing the fabric to stretch gently across the hips, revealing faint lace texture"
224
+ }
225
  ]
226
 
227
  class HyperRealisticPromptGenerator:
 
229
  self.config = HyperRealisticConfig()
230
  self.history = []
231
 
232
+ def generate_base_prompt(self, role_name: str, nsfw_mode: bool = False) -> str:
233
+ """Genera el prompt base sin mejoras de IA"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
234
  role = next((r for r in self.config.PROFESSIONAL_ROLES if r["role"] == role_name), None)
235
  if not role:
236
+ return "❌ Error: Rol no encontrado."
237
+
 
 
 
 
238
  prompt = (
239
+ f"Hyper-realistic photograph, 9:16 vertical composition, "
240
+ f"professional {role['role'].lower()} in {role['environment']}, "
241
+ f"wearing {role['uniform']}, {role['pose']}, {role['accidental_hint']}. "
242
+ f"Professional atmosphere, elegant composition, cinematic lighting, "
243
+ f"ultra-high detail, realistic textures. Include {role['accessories']}. "
244
+ f"--style raw --stylize 150"
 
 
245
  )
246
 
247
  self.history.append({
248
+ "prompt": prompt,
249
+ "role": role_name,
250
+ "nsfw": nsfw_mode,
251
  "timestamp": datetime.datetime.now().isoformat(),
252
+ "enhanced": False
253
  })
254
+
255
+ if len(self.history) > 30:
256
+ self.history = self.history[-30:]
257
+
258
  return prompt
259
 
260
+ def generate_enhanced_prompt(self, role_name: str, nsfw_mode: bool = False, enhancement_type: str = "creative") -> str:
261
+ """Genera prompt base y luego lo mejora con IA"""
262
+ base_prompt = self.generate_base_prompt(role_name, nsfw_mode)
263
+
264
+ if not SAMBANOVA_ENABLED:
265
+ return base_prompt
266
+
267
+ enhanced_prompt = enhance_prompt_with_ai(base_prompt, enhancement_type)
268
+
269
+ # Actualizar el historial con el prompt mejorado
270
+ if self.history:
271
+ self.history[-1]["prompt"] = enhanced_prompt
272
+ self.history[-1]["enhanced"] = True
273
+ self.history[-1]["enhancement_type"] = enhancement_type
274
+
275
+ return enhanced_prompt
 
 
 
276
 
277
  def clear_history(self):
278
  self.history = []
279
 
280
  def get_history(self):
281
+ return self.history.copy()# --------------------------
282
+ # CONFIGURACIÓN REVE CREATE
283
+ # --------------------------
284
+ API_URL = "https://api.reve.com/v1/image/create"
285
+ CARPETA_SALIDA = "generated_images"
286
 
287
+ if not os.path.exists(CARPETA_SALIDA):
288
+ os.makedirs(CARPETA_SALIDA)
 
 
 
 
 
289
 
290
+ def guardar_imagen_local(img, index):
291
+ try:
292
+ timestamp = int(time.time())
293
+ nombre_archivo = f"reve_{timestamp}_{index}.png"
294
+ ruta_completa = os.path.join(CARPETA_SALIDA, nombre_archivo)
295
+ img.save(ruta_completa)
296
+ return ruta_completa
297
+ except Exception as e:
298
+ print(f"⚠️ Error guardando imagen: {e}")
299
+ return None
300
 
301
+ def llamar_api(prompt, ratio, version, api_key, index):
302
  payload = {
 
303
  "prompt": prompt,
304
+ "aspect_ratio": ratio,
305
+ "version": version
306
  }
307
  headers = {
308
  "Authorization": f"Bearer {api_key}",
 
310
  "Content-Type": "application/json"
311
  }
312
  try:
313
+ response = requests.post(API_URL, headers=headers, json=payload, timeout=120)
314
  if response.status_code == 200:
315
  data = response.json()
316
  if "image" in data:
317
  img_bytes = base64.b64decode(data["image"])
318
  img = Image.open(BytesIO(img_bytes))
319
+ saved_path = guardar_imagen_local(img, index)
320
+ return img, data.get('credits_used', 0), None, saved_path
321
+ return None, 0, f"Error {response.status_code}: {response.text}", None
322
  except Exception as e:
323
+ return None, 0, f"Excepción: {str(e)}", None
324
 
325
+ def generar_imagenes_batch(prompt, api_key_ui, ratio, version, num_imagenes):
326
+ api_key = api_key_ui.strip() if api_key_ui else os.getenv("REVE_API_KEY")
327
+
328
+ if not api_key:
329
+ return [], "❌ ¡Falta la API Key de REVE CREATE!", []
330
+
331
+ if not prompt or prompt.strip() == "":
332
+ return [], "❌ ¡El prompt está vacío!", []
333
+
334
+ if HF_SPACE:
335
+ num_imagenes = min(num_imagenes, 4)
336
+
337
+ imagenes_nuevas = []
338
+ errores = []
339
+ creditos_totales = 0
340
+ image_paths = []
341
+
342
+ with concurrent.futures.ThreadPoolExecutor(max_workers=min(num_imagenes, 4)) as executor:
343
+ futuros = [
344
+ executor.submit(llamar_api, prompt, ratio, version, api_key, i)
345
+ for i in range(num_imagenes)
346
+ ]
347
+ for i, futuro in enumerate(concurrent.futures.as_completed(futuros)):
348
+ img, creditos, error, img_path = futuro.result()
349
+ if img:
350
+ imagenes_nuevas.append(img)
351
+ creditos_totales += creditos
352
+ if img_path:
353
+ image_paths.append(img_path)
354
+ if error:
355
+ errores.append(f"Imagen {i+1}: {error}")
356
+
357
+ if imagenes_nuevas:
358
+ mensaje = f"✅ {len(imagenes_nuevas)} imagen(es) generada(s) | Créditos: {creditos_totales}"
359
+ if errores:
360
+ mensaje += f" | Errores: {len(errores)}"
361
+ return imagenes_nuevas, mensaje, image_paths
362
+ else:
363
+ error_msg = "❌ Error: " + "; ".join(errores[:3])
364
+ return [], error_msg, []
365
 
366
+ # --------------------------
367
+ # INTERFAZ GRADIO OPTIMIZADA
368
+ # --------------------------
369
  generator = HyperRealisticPromptGenerator()
370
 
371
+ def generar_todo(role, nsfw, api_key, ratio, version, cantidad, use_ai_enhancement, enhancement_type):
372
+ """Función principal que integra todo el flujo"""
373
+ if use_ai_enhancement and SAMBANOVA_ENABLED:
374
+ prompt = generator.generate_enhanced_prompt(role, nsfw, enhancement_type)
375
+ enhancement_status = f"🚀 Prompt MEJORADO ({enhancement_type})"
376
+ else:
377
+ prompt = generator.generate_base_prompt(role, nsfw)
378
+ enhancement_status = "📝 Prompt BÁSICO"
379
+
380
+ imagenes, mensaje, image_paths = generar_imagenes_batch(prompt, api_key, ratio, version, cantidad)
381
+
382
+ # Añadir información del enhancement al mensaje
383
+ final_message = f"{enhancement_status} | {mensaje}"
384
+ if not SAMBANOVA_ENABLED and use_ai_enhancement:
385
+ final_message += " | ⚠️ SAMBANOVA_API_KEY no configurada"
386
+
387
+ return prompt, imagenes, final_message, image_paths
388
 
389
+ def generate_from_description_ui(user_description, prompt_style):
390
+ """Genera prompt desde descripción del usuario"""
391
+ if not user_description or user_description.strip() == "":
392
+ return "❌ Por favor, describe lo que quieres generar"
393
+
394
+ generated_prompt = generate_prompt_from_description(user_description, prompt_style)
395
+
396
+ # Añadir al historial
397
+ generator.history.append({
398
+ "prompt": generated_prompt,
399
+ "role": "custom_description",
400
+ "timestamp": datetime.datetime.now().isoformat(),
401
+ "enhanced": True,
402
+ "source": "description_generation"
403
+ })
404
+
405
+ return generated_prompt
406
 
407
+ def describe_image_ui(image_path, description_style):
408
+ """Describe una imagen generada"""
409
+ if not image_path:
410
+ return "❌ Selecciona una imagen primero"
411
+
412
+ description = describe_image_with_ai(image_path, description_style)
413
+ return description
414
 
415
  def clear_history_ui():
416
  generator.clear_history()
417
+ return gr.update(value=json.dumps(generator.get_history(), indent=2))
418
 
419
+ # Interfaz Gradio optimizada
420
+ with gr.Blocks(
421
+ theme=gr.themes.Soft(primary_hue="blue"),
422
+ title="AI Image Generator - Llama 4 Maverick",
423
+ css="""
424
+ .success { color: #22c55e; font-weight: bold; }
425
+ .warning { color: #f59e0b; font-weight: bold; }
426
+ .error { color: #ef4444; font-weight: bold; }
427
+ """
428
+ ) as demo:
429
+
430
+ gr.Markdown(f"""
431
+ # 🚀 AI Image Generator + Llama 4 Maverick
432
+
433
+ **Modelo único: {PRIMARY_MODEL}** - Generación, mejora y descripción de imágenes
434
+ """)
435
+
436
+ with gr.Tab("🎨 Generar Imágenes"):
437
+ with gr.Row():
438
+ with gr.Column(scale=1):
439
+ gr.Markdown("### Configuración Principal")
440
+
441
+ role_dropdown = gr.Dropdown(
442
+ choices=[r["role"] for r in generator.config.PROFESSIONAL_ROLES],
443
+ label="Rol Profesional",
444
+ value=generator.config.PROFESSIONAL_ROLES[0]["role"]
445
+ )
446
+
447
+ nsfw_checkbox = gr.Checkbox(label="Modo NSFW", value=False)
448
+
449
+ use_ai_enhancement = gr.Checkbox(
450
+ label="Usar Mejora con Llama 4 Maverick",
451
+ value=SAMBANOVA_ENABLED,
452
+ interactive=SAMBANOVA_ENABLED
453
+ )
454
+
455
+ enhancement_type = gr.Radio(
456
+ choices=["creative", "technical", "artistic"],
457
+ label="Tipo de Mejora",
458
+ value="creative",
459
+ interactive=SAMBANOVA_ENABLED
460
+ )
461
+
462
+ with gr.Row():
463
+ gen_prompt_btn = gr.Button("✨ Generar Prompt", variant="primary")
464
+ clear_hist_btn = gr.Button("🗑️ Limpiar", variant="secondary")
465
+
466
+ gr.Markdown("### Configuración REVE CREATE")
467
+
468
+ api_key_input = gr.Textbox(
469
+ label="API Key REVE CREATE",
470
+ type="password",
471
+ placeholder="Ingresa tu API Key..."
472
+ )
473
+
474
+ with gr.Row():
475
+ ratio = gr.Dropdown(
476
+ ["16:9", "9:16", "1:1", "4:3", "3:2"],
477
+ label="Aspect Ratio",
478
+ value="9:16"
479
+ )
480
+ version = gr.Dropdown(
481
+ ["latest", "reve-create@20250915"],
482
+ label="Versión",
483
+ value="latest"
484
+ )
485
+
486
+ cantidad = gr.Slider(1, 4, step=1, value=1, label="Cantidad de Imágenes")
487
+
488
+ gen_images_btn = gr.Button("🎨 Generar Imágenes", variant="primary", size="lg")
489
 
490
+ with gr.Column(scale=2):
491
+ prompt_out = gr.Textbox(
492
+ label="Prompt Generado",
493
+ lines=6,
494
+ show_copy_button=True
495
+ )
496
+
497
+ gallery_out = gr.Gallery(
498
+ label="Imágenes Generadas",
499
+ columns=2,
500
+ height="auto",
501
+ show_download_button=True
502
+ )
503
+
504
+ msg_out = gr.HTML()
505
+
506
+ # Descripción de imágenes
507
+ with gr.Accordion("🔍 Describir Imágenes (Llama 4 Maverick)", open=False):
508
+ with gr.Row():
509
+ image_to_describe = gr.Dropdown(
510
+ label="Seleccionar Imagen para Describir",
511
+ choices=[],
512
+ interactive=True
513
+ )
514
+ desc_style = gr.Radio(
515
+ choices=["detailed", "technical", "prompt_style"],
516
+ label="Estilo de Descripción",
517
+ value="detailed"
518
+ )
519
+ describe_btn = gr.Button("📝 Describir Imagen", variant="secondary")
520
+ image_description = gr.Textbox(
521
+ label="Descripción Generada",
522
+ lines=4,
523
+ show_copy_button=True
524
+ )
525
+
526
+ with gr.Tab("📝 Generar desde Descripción"):
527
+ gr.Markdown("### Generar Prompt desde tu Descripción")
528
+
529
+ user_description = gr.Textbox(
530
+ label="Describe la imagen que quieres generar",
531
+ placeholder="Ej: Una mujer ejecutiva en una oficina moderna con iluminación dramática al atardecer...",
532
+ lines=4
533
+ )
534
+
535
+ prompt_style = gr.Radio(
536
+ choices=["realistic", "cinematic", "artistic", "professional"],
537
+ label="Estilo del Prompt",
538
+ value="realistic"
539
+ )
540
+
541
+ generate_from_desc_btn = gr.Button("🚀 Generar Prompt desde Descripción", variant="primary")
542
+
543
+ generated_prompt_out = gr.Textbox(
544
+ label="Prompt Generado",
545
+ lines=6,
546
+ show_copy_button=True
547
+ )
548
+
549
+ with gr.Tab("📊 Historial"):
550
+ gr.Markdown("### Historial de Generaciones")
551
+ history_out = gr.JSON(label="Historial", show_label=False)
552
 
553
+ # Event handlers
554
+ gen_prompt_btn.click(
555
+ fn=lambda role, nsfw, enhancement, enh_type: generator.generate_enhanced_prompt(role, nsfw, enh_type)
556
+ if enhancement and SAMBANOVA_ENABLED else generator.generate_base_prompt(role, nsfw),
557
+ inputs=[role_dropdown, nsfw_checkbox, use_ai_enhancement, enhancement_type],
558
+ outputs=prompt_out
559
+ ).then(
560
+ fn=lambda: json.dumps(generator.get_history(), indent=2),
561
+ outputs=history_out
562
+ )
563
+
564
+ gen_images_btn.click(
565
+ fn=generar_todo,
566
+ inputs=[role_dropdown, nsfw_checkbox, api_key_input, ratio, version, cantidad, use_ai_enhancement, enhancement_type],
567
+ outputs=[prompt_out, gallery_out, msg_out, image_to_describe]
568
+ ).then(
569
+ fn=lambda: json.dumps(generator.get_history(), indent=2),
570
+ outputs=history_out
571
+ ).then(
572
+ fn=lambda: gr.update(choices=os.listdir(CARPETA_SALIDA) if os.path.exists(CARPETA_SALIDA) else []),
573
+ outputs=image_to_describe
574
+ )
575
+
576
+ generate_from_desc_btn.click(
577
+ fn=generate_from_description_ui,
578
+ inputs=[user_description, prompt_style],
579
+ outputs=generated_prompt_out
580
+ ).then(
581
+ fn=lambda: json.dumps(generator.get_history(), indent=2),
582
+ outputs=history_out
583
+ )
584
+
585
+ describe_btn.click(
586
+ fn=describe_image_ui,
587
+ inputs=[image_to_describe, desc_style],
588
+ outputs=image_description
589
+ )
590
+
591
+ clear_hist_btn.click(
592
+ fn=clear_history_ui,
593
+ outputs=history_out
594
+ )
595
 
596
  if __name__ == "__main__":
597
+ demo.launch(server_name="0.0.0.0", server_port=7860, share=False)