BATUTO-ART commited on
Commit
a5b30d9
·
verified ·
1 Parent(s): d445c17

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +203 -98
app.py CHANGED
@@ -1,11 +1,18 @@
1
- # app.py
 
 
 
2
  import os
3
- import gradio as gr
 
4
  import requests
 
5
  from dotenv import load_dotenv
6
- from assistants import AssistantManager
7
 
8
- # --- CONFIG ---
 
 
9
  load_dotenv()
10
  SAMBANOVA_API_KEY = os.getenv("SAMBANOVA_API_KEY")
11
  REVE_API_KEY = os.getenv("REVE_API_KEY")
@@ -13,112 +20,210 @@ REVE_API_KEY = os.getenv("REVE_API_KEY")
13
  SAMBANOVA_URL = "https://api.sambanova.ai/v1/chat/completions"
14
  REVE_URL = "https://api.reve.com/v1/image/create"
15
 
16
- # --- INICIALIZAR GESTOR ---
17
- manager = AssistantManager()
18
-
19
- # --- FUNCIONES CORE ---
20
- def llm_chat(assistant_id, user_msg, history):
21
- if not SAMBANOVA_API_KEY:
22
- return "⚠️ Error: Falta SAMBANOVA_API_KEY"
23
-
24
- # Obtenemos los mensajes con la personalidad correcta
25
- messages = manager.get_chat_response(assistant_id, user_msg, history)
26
-
27
- # Añadimos historia reciente si existe
28
- # (Simplificado para este ejemplo)
29
-
30
- payload = {
31
- "model": "Llama-4-Maverick-17B-128E-Instruct", # O el modelo que estés usando
32
- "messages": messages,
33
- "temperature": 0.7,
34
- "max_tokens": 1024
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  }
36
-
37
- try:
38
- headers = {"Authorization": f"Bearer {SAMBANOVA_API_KEY}", "Content-Type": "application/json"}
39
- r = requests.post(SAMBANOVA_URL, json=payload, headers=headers, timeout=60)
40
- r.raise_for_status()
41
- return r.json()["choices"][0]["message"]["content"]
42
- except Exception as e:
43
- return f"Error con SambaNova: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
  def generate_image(prompt):
46
  if not REVE_API_KEY:
47
  return None
48
-
49
  payload = {
50
  "prompt": prompt,
51
  "aspect_ratio": "9:16",
52
- "style": "raw", # Ojo: ReVe debe soportar raw
53
  "steps": 30,
54
- "cfg_scale": 7.0
55
  }
56
-
57
- try:
58
- headers = {"Authorization": f"Bearer {REVE_API_KEY}", "Content-Type": "application/json"}
59
- r = requests.post(REVE_URL, json=payload, headers=headers, timeout=120)
60
- r.raise_for_status()
61
- return r.json().get("image_url")
62
- except Exception as e:
63
- print(f"Error ReVe: {e}")
64
- return None
65
 
66
- # --- INTERFAZ UI ---
67
- def ui_interact(assistant_choice, user_input, chat_history):
68
- # 1. Chat con la asistente
69
- response_text = llm_chat(assistant_choice, user_input, chat_history)
70
- chat_history.append((user_input, response_text))
71
-
72
- # 2. Si el usuario pide generar, creamos prompt e imagen
73
- generated_prompt = ""
74
- generated_img = None
75
-
76
- trigger_words = ["genera", "crea", "haz", "generate", "make", "create", "imagen", "foto"]
77
- if any(w in user_input.lower() for w in trigger_words):
78
- # Usamos el input del usuario como descripción base
79
- generated_prompt = manager.generate_prompt(assistant_choice, user_input)
80
- # Llamamos a ReVe
81
- generated_img = generate_image(generated_prompt)
82
-
83
- # Añadimos nota al chat
84
- chat_history.append((None, "📸 ¡He creado esta obra maestra para ti, BATUTO!"))
85
-
86
- return chat_history, "", generated_prompt, generated_img
87
-
88
- def change_assistant(new_id):
89
- profile = manager.get_assistant(new_id)
90
- return f"✨ {profile.greeting}", [] # Limpia chat y pone saludo
91
-
92
- # --- LAYOUT GRADIO ---
93
- with gr.Blocks(theme=gr.themes.Soft(primary_hue="amber"), title="BATUTO-ART ULTIMATE") as app:
94
- gr.Markdown("# 👑 BATUTO-ART STUDIO vUltimate")
95
-
96
  with gr.Row():
97
- with gr.Column(scale=1):
98
- # Selector de Asistente
99
- assistant_selector = gr.Dropdown(
100
- choices=[("Sara (Sensual)", "sara"),
101
- ("Vera (Editorial)", "vera"),
102
- ("Nadia (Corporativa)", "nadia"),
103
- ("Luna (Artística)", "luna"),
104
- ("Iris (Técnica)", "iris")],
105
- value="sara",
106
- label="Selecciona tu Musa"
107
- )
108
- status_box = gr.Markdown("✨ Hola BATUTO, soy Sara.")
109
-
110
- with gr.Column(scale=4):
111
- chatbot = gr.Chatbot(height=400, label="Sala de Chat")
112
- msg_input = gr.Textbox(placeholder="Dime qué quieres crear hoy, rey...", label="Tus deseos")
113
-
114
  with gr.Row():
115
- prompt_display = gr.Textbox(label="Prompt Generado (Con Firma BATUTO-ART)", lines=6, interactive=False)
116
- img_display = gr.Image(label="Resultado Final", height=600)
 
 
 
 
 
 
 
 
117
 
118
- # Eventos
119
- assistant_selector.change(change_assistant, assistant_selector, [status_box, chatbot])
120
- msg_input.submit(ui_interact, [assistant_selector, msg_input, chatbot], [chatbot, msg_input, prompt_display, img_display])
 
 
 
 
 
 
 
 
 
121
 
122
- if __name__ == "__main__":
123
- app.launch()
124
-
 
1
+ # ===============================
2
+ # BATUTO-ART STUDIO | app.py
3
+ # ===============================
4
+
5
  import os
6
+ import random
7
+ import textwrap
8
  import requests
9
+ from datetime import datetime
10
  from dotenv import load_dotenv
11
+ import gradio as gr
12
 
13
+ # ===============================
14
+ # CONFIG
15
+ # ===============================
16
  load_dotenv()
17
  SAMBANOVA_API_KEY = os.getenv("SAMBANOVA_API_KEY")
18
  REVE_API_KEY = os.getenv("REVE_API_KEY")
 
20
  SAMBANOVA_URL = "https://api.sambanova.ai/v1/chat/completions"
21
  REVE_URL = "https://api.reve.com/v1/image/create"
22
 
23
+ # ===============================
24
+ # DATABASE (INLINE)
25
+ # ===============================
26
+ HAIRSTYLES = {
27
+ "sensual": [
28
+ "long chestnut waves with natural shine",
29
+ "wet-look hair slicked back",
30
+ "messy bed-hair with soft volume"
31
+ ],
32
+ "editorial": [
33
+ "geometric platinum bob",
34
+ "tight high ponytail",
35
+ "sharp straight fringe"
36
+ ],
37
+ "professional": [
38
+ "polished low bun",
39
+ "sleek shoulder-length hair",
40
+ "impeccable executive styling"
41
+ ],
42
+ "artistic": [
43
+ "wind-textured hair",
44
+ "complex tribal braids",
45
+ "washed pastel tones"
46
+ ]
47
+ }
48
+
49
+ LIGHTING = {
50
+ "sensual": "warm sunset light filtering through curtains, soft shadows",
51
+ "editorial": "high-key studio lighting, strong contrast",
52
+ "professional": "balanced office lighting, neutral tones",
53
+ "artistic": "cyan and magenta neon lights, dramatic chiaroscuro"
54
+ }
55
+
56
+ BACKGROUNDS = {
57
+ "sensual": "luxury boutique hotel room with silk sheets",
58
+ "editorial": "minimalist photo studio with concrete backdrop",
59
+ "professional": "glass skyscraper boardroom",
60
+ "artistic": "urban alley with textured walls, contemporary art mood"
61
+ }
62
+
63
+ ROLES = {
64
+ "sensual": [
65
+ ("Intimate muse", "black haute couture lace lingerie"),
66
+ ("Vanity model", "champagne silk robe slightly open")
67
+ ],
68
+ "editorial": [
69
+ ("Vogue icon", "avant-garde asymmetrical designer dress"),
70
+ ("Runway supermodel", "oversized faux fur coat and dark glasses")
71
+ ],
72
+ "professional": [
73
+ ("Tech CEO", "immaculate white tailored suit"),
74
+ ("Corporate lawyer", "navy silk blouse and strict pencil skirt")
75
+ ],
76
+ "artistic": [
77
+ ("Free spirit", "flowing translucent fabrics"),
78
+ ("Cyber-art entity", "transparent vinyl jacket with chrome accessories")
79
+ ]
80
+ }
81
+
82
+ # ===============================
83
+ # ASSISTANTS
84
+ # ===============================
85
+ ASSISTANTS = {
86
+ "sara": {
87
+ "name": "Sara",
88
+ "style": "sensual",
89
+ "greeting": "Hola Batuto… estoy lista para inspirarte despacio y con intención.",
90
+ "system": "You are Sara, a sensual, elegant muse. Your tone is warm, intimate and refined."
91
+ },
92
+ "vera": {
93
+ "name": "Vera",
94
+ "style": "editorial",
95
+ "greeting": "Batuto. Vamos a crear imágenes de portada. Precisión absoluta.",
96
+ "system": "You are Vera, a high-fashion editorial director. Commanding, sharp, demanding perfection."
97
+ },
98
+ "nadia": {
99
+ "name": "Nadia",
100
+ "style": "professional",
101
+ "greeting": "Buenos días Batuto. Control, poder y presencia.",
102
+ "system": "You are Nadia, a dominant corporate executive. Cold, authoritative, subtly seductive."
103
+ },
104
+ "luna": {
105
+ "name": "Luna",
106
+ "style": "artistic",
107
+ "greeting": "Creador… dejemos que la imagen respire.",
108
+ "system": "You are Luna, an artistic soul. Poetic, visual, emotional."
109
+ },
110
+ "iris": {
111
+ "name": "Iris",
112
+ "style": "editorial",
113
+ "greeting": "Sistema Iris activo. Optimicemos tu prompt.",
114
+ "system": "You are Iris, a technical AI. Precise, analytical, efficient."
115
  }
116
+ }
117
+
118
+ SIGNATURE = (
119
+ "Integrate a small elongated graffiti tag reading 'BATUTO-ART' "
120
+ "in liquid gold marker, placed subtly in the top-left corner."
121
+ )
122
+
123
+ # ===============================
124
+ # CORE LOGIC
125
+ # ===============================
126
+ def generate_prompt(assistant_id, subject):
127
+ a = ASSISTANTS[assistant_id]
128
+ style = a["style"]
129
+
130
+ role, outfit = random.choice(ROLES[style])
131
+ hair = random.choice(HAIRSTYLES[style])
132
+ bg = random.choice(BACKGROUNDS[style])
133
+ light = LIGHTING[style]
134
+
135
+ prompt = f"""
136
+ BATUTO-ART PROMPT | {a['name'].upper()}
137
+ Date: {datetime.now().strftime('%Y-%m-%d')}
138
+
139
+ Subject: Adult female model, {subject}
140
+ Role: {role}, wearing {outfit}
141
+ Hair: {hair}
142
+ Environment: {bg}
143
+ Lighting: {light}
144
+
145
+ Camera: Canon EOS R5, 85mm lens, f/1.8
146
+ Quality: 8K, hyper-realistic, RAW photo, natural skin texture
147
+
148
+ Signature: {SIGNATURE}
149
+
150
+ --ar 9:16 --style raw
151
+ """
152
+ return textwrap.dedent(prompt).strip()
153
+
154
 
155
  def generate_image(prompt):
156
  if not REVE_API_KEY:
157
  return None
158
+
159
  payload = {
160
  "prompt": prompt,
161
  "aspect_ratio": "9:16",
 
162
  "steps": 30,
163
+ "cfg_scale": 7
164
  }
 
 
 
 
 
 
 
 
 
165
 
166
+ headers = {
167
+ "Authorization": f"Bearer {REVE_API_KEY}",
168
+ "Content-Type": "application/json"
169
+ }
170
+
171
+ r = requests.post(REVE_URL, json=payload, headers=headers, timeout=120)
172
+ r.raise_for_status()
173
+ return r.json().get("image_url")
174
+
175
+ # ===============================
176
+ # UI LOGIC
177
+ # ===============================
178
+ def interact(assistant_id, user_text, history):
179
+ prompt = generate_prompt(assistant_id, user_text)
180
+ image = generate_image(prompt)
181
+ history.append((user_text, "Hecho. Observa el resultado."))
182
+ return history, "", prompt, image
183
+
184
+ def change_assistant(aid):
185
+ return ASSISTANTS[aid]["greeting"], []
186
+
187
+ # ===============================
188
+ # UI
189
+ # ===============================
190
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue="amber")) as app:
191
+ gr.Markdown("# 👑 BATUTO-ART STUDIO")
192
+
 
 
 
193
  with gr.Row():
194
+ assistant = gr.Dropdown(
195
+ choices=[(v["name"], k) for k, v in ASSISTANTS.items()],
196
+ value="sara",
197
+ label="Asistente"
198
+ )
199
+ status = gr.Markdown(ASSISTANTS["sara"]["greeting"])
200
+
201
+ chatbot = gr.Chatbot(height=300)
202
+ user_input = gr.Textbox(label="Describe la escena")
203
+
 
 
 
 
 
 
 
204
  with gr.Row():
205
+ prompt_box = gr.Textbox(label="Prompt Final", lines=8)
206
+ image_box = gr.Image(label="Imagen", height=550)
207
+
208
+ with gr.Row():
209
+ copy_btn = gr.Button("📋 Copiar Prompt")
210
+ clear_btn = gr.Button("🧹 Limpiar")
211
+ download_btn = gr.Button("⬇️ Descargar Imagen")
212
+
213
+ assistant.change(change_assistant, assistant, [status, chatbot])
214
+ user_input.submit(interact, [assistant, user_input, chatbot], [chatbot, user_input, prompt_box, image_box])
215
 
216
+ copy_btn.click(None, None, None, js="() => navigator.clipboard.writeText(document.querySelector('textarea').value)")
217
+ clear_btn.click(lambda: ("", None), None, [prompt_box, image_box])
218
+ download_btn.click(None, None, None, js="""
219
+ () => {
220
+ const img = document.querySelector('img');
221
+ if (!img) return;
222
+ const a = document.createElement('a');
223
+ a.href = img.src;
224
+ a.download = 'BATUTO-ART.png';
225
+ a.click();
226
+ }
227
+ """)
228
 
229
+ app.launch()