BATUTO-ART commited on
Commit
000b7bb
·
verified ·
1 Parent(s): 24658e0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +174 -185
app.py CHANGED
@@ -1,199 +1,188 @@
1
- import os
2
- import json
3
- import base64
4
- import random
5
- import requests
6
- import io
7
-
8
  import gradio as gr
 
 
 
 
9
  from PIL import Image
 
10
 
11
- # ===========================
12
- # CLAVES PARA SAMBANOVA
13
- # ===========================
14
- API_KEY = os.getenv("REVE_API_KEY")
15
- BASE_URL = "https://api.sambanova.ai/v1"
16
-
17
- if not API_KEY:
18
- raise ValueError("⚠️ ERROR: No se encontró la variable REVE_API_KEY en HuggingFace Spaces.")
19
-
20
- # ===========================
21
- # FUNCIÓN SELECT MODEL
22
- # ===========================
23
- def select_model(preference):
24
- if preference == "Lento 🧠 (mejor calidad)":
25
- return {
26
- "name": "Qwen2.5-72B-Instruct",
27
- "description": "Máxima calidad de razonamiento"
28
- }
29
- else:
30
- return {
31
- "name": "Meta-Llama-3.1-8B-Instruct",
32
- "description": "Rápido y eficiente"
33
- }
34
-
35
- # ===========================
36
- # DICCIONARIO DE MODELOS
37
- # ===========================
38
- MODELS = {
39
- "general_fast": {
40
- "name": "Meta-Llama-3.1-8B-Instruct",
41
- "role": "🔄 Respuestas rápidas y generales",
42
- "description": "Conversación ligera y eficiente."
43
- },
44
- "general_smart": {
45
- "name": "Meta-Llama-3.3-70B-Instruct",
46
- "role": "🧠 Razonamiento profundo",
47
- "description": "Análisis detallado y avanzado."
48
- },
49
- "coding_expert": {
50
- "name": "DeepSeek-V3.1",
51
- "role": "💻 Programación y debugging",
52
- "description": "Ideal para desarrollo."
53
- },
54
- "coding_alt": {
55
- "name": "DeepSeek-V3-0324",
56
- "role": "⚡ Código rápido",
57
- "description": "Alternativa veloz."
58
- },
59
- "massive_brain": {
60
- "name": "gpt-oss-120b",
61
- "role": "🏛️ Sabiduría masiva",
62
- "description": "Problemas pesados y complejos."
63
- },
64
- "specialized_1": {
65
- "name": "DeepSeek-V3.1-Terminus",
66
- "role": "🎯 Especialista técnico",
67
- "description": "Tareas científicas y avanzadas."
68
- },
69
- "specialized_2": {
70
- "name": "Llama-3.3-Swallow-70B-Instruct-v0.4",
71
- "role": "🔥 Sin censura",
72
- "description": "Modelo sin restricciones."
73
- },
74
- "multilingual": {
75
- "name": "Qwen3-32B",
76
- "role": "🌍 Multilingüe",
77
- "description": "Múltiples idiomas."
78
- },
79
- "arabic_special": {
80
- "name": "ALLaM-7B-Instruct-preview",
81
- "role": "🕌 Estilo árabe y moda íntima",
82
- "description": "Experto en estilos del Medio Oriente."
83
- },
84
- "vision_expert": {
85
- "name": "Llama-4-Maverick-17B-128E-Instruct",
86
- "role": "👁️ Visión avanzada",
87
- "description": "Análisis de imágenes."
88
- }
89
- }
90
-
91
- # ===========================
92
- # CSS PERSONALIZADO
93
- # ===========================
94
- custom_css = """
95
- .gradio-container {max-width: 900px !important; margin: auto;}
96
- .model-box {padding: 10px; border-radius: 10px; background: #1d1d1d; margin-bottom: 6px;}
97
- """# ===========================
98
- # CODIFICAR IMAGEN EN BASE64
99
- # ===========================
100
- def encode_image(img):
101
- if img is None:
102
- return None
103
- buffer = io.BytesIO()
104
- img.save(buffer, format="PNG")
105
- return base64.b64encode(buffer.getvalue()).decode()
106
-
107
- # ===========================
108
- # API CALL SAMBANOVA
109
- # ===========================
110
- def call_sambanova(model, messages, images=None):
111
- url = f"{BASE_URL}/chat/completions"
112
-
113
- payload = {
114
- "model": model,
115
- "messages": messages,
116
- "stream": False
117
  }
118
 
119
- if images:
120
- payload["images"] = images
121
-
122
- headers = {
123
- "Authorization": f"Bearer {API_KEY}",
124
- "Content-Type": "application/json"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
  }
126
 
127
- response = requests.post(url, json=payload, headers=headers)
128
-
129
- if response.status_code != 200:
130
- return f"⚠️ Error en API: {response.status_code}\n{response.text}"
131
-
132
- data = response.json()
133
- return data["choices"][0]["message"]["content"]
134
 
135
- # ===========================
136
- # CHAT PRINCIPAL
137
- # ===========================
138
- def chat_logic(user_text, user_image, model_selection, history):
139
- selected = MODELS[model_selection]
140
- model_name = selected["name"]
141
 
142
- msg = []
143
- images_encoded = None
144
 
145
- msg.append({"role": "system", "content": selected["role"]})
146
-
147
- if user_image:
148
- images_encoded = [encode_image(user_image)]
149
- msg.append({
150
- "role": "user",
151
- "content": [
152
- {"type": "text", "text": user_text or "Describe esta imagen."},
153
- {"type": "image", "image": images_encoded[0]}
154
- ]
155
- })
156
- else:
157
- msg.append({"role": "user", "content": user_text})
158
-
159
- reply = call_sambanova(model_name, msg, images_encoded)
160
-
161
- history.append(("🧍 Usuario: " + (user_text or "[Imagen]"), "🤖 Modelo: " + reply))
162
- return history, reply
163
-
164
- # ===========================
165
- # INTERFAZ
166
- # ===========================
167
- def create_ui():
168
- with gr.Blocks(css=custom_css) as demo:
169
-
170
- gr.Markdown("# 🤖 Chat avanzado con modelos SambaNova")
 
 
 
 
 
 
171
 
172
  with gr.Row():
173
- model_selection = gr.Dropdown(
174
- choices=list(MODELS.keys()),
175
- value="general_fast",
176
- label="Modelo"
 
 
 
 
 
 
 
177
  )
178
 
179
- user_text = gr.Textbox(label="Escribe tu mensaje")
180
- user_image = gr.Image(label="Sube una imagen (opcional)")
181
-
182
- chatbox = gr.Chatbot(label="Conversación")
183
- output_text = gr.Textbox(label="Respuesta del modelo")
184
-
185
- send_btn = gr.Button("Enviar")
186
-
187
- send_btn.click(
188
- chat_logic,
189
- inputs=[user_text, user_image, model_selection, chatbox],
190
- outputs=[chatbox, output_text]
191
- )
192
-
193
- return demo# ===========================
194
- # LANZAR INTERFAZ
195
- # ===========================
196
- demo = create_ui()
197
-
198
- if __name__ == "__main__":
199
- demo.launch()
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
+ import torch
3
+ from diffusers import FluxPipeline
4
+ import random
5
+ import json
6
  from PIL import Image
7
+ import os
8
 
9
+ HF_TOKEN = os.getenv("HF_TOKEN") # Toma tu token automáticamente
10
+
11
+ # -------------------------------------------------------
12
+ # Cargar modelo FLUX.2 (optimizado para CPU)
13
+ # -------------------------------------------------------
14
+ def load_flux_model():
15
+ # Usar torch.float32 para CPU, ya que float16 puede no ser óptimo
16
+ dtype = torch.float32
17
+ pipe = FluxPipeline.from_pretrained(
18
+ "black-forest-labs/FLUX.2-dev",
19
+ torch_dtype=dtype,
20
+ token=HF_TOKEN
21
+ )
22
+
23
+ # Forzar a CPU
24
+ pipe.to("cpu")
25
+ # Optimizar para CPU: habilitar offload secuencial para ahorrar memoria
26
+ pipe.enable_sequential_cpu_offload()
27
+ # Habilitar attention slicing para reducir uso de memoria
28
+ pipe.enable_attention_slicing()
29
+
30
+ return pipe
31
+
32
+ pipe = load_flux_model()
33
+
34
+ # -------------------------------------------------------
35
+ # GENERACIÓN SIMPLE
36
+ # -------------------------------------------------------
37
+ def generate_flux_image(prompt, negative_prompt="", steps=28, guidance=7.0,
38
+ width=576, height=1024, seed=None):
39
+
40
+ if seed is None or seed == -1:
41
+ seed = random.randint(0, 2**32 - 1)
42
+
43
+ generator = torch.Generator("cpu").manual_seed(seed)
44
+
45
+ try:
46
+ image = pipe(
47
+ prompt,
48
+ num_inference_steps=steps,
49
+ guidance_scale=guidance,
50
+ height=height,
51
+ width=width,
52
+ generator=generator
53
+ ).images[0]
54
+
55
+ return image, seed
56
+
57
+ except Exception as e:
58
+ return None, f"Error: {str(e)}"
59
+
60
+ # -------------------------------------------------------
61
+ # GENERACIÓN JSON
62
+ # -------------------------------------------------------
63
+ def generate_json_image(scene, subjects, style, colors, lighting, mood,
64
+ background, camera_angle, seed=None):
65
+
66
+ json_prompt = {
67
+ "scene": scene,
68
+ "subjects": [{"description": subjects}],
69
+ "style": style,
70
+ "color_palette": [c.strip() for c in colors.split(",")] if colors else [],
71
+ "lighting": lighting,
72
+ "mood": mood,
73
+ "background": background,
74
+ "camera": {"angle": camera_angle}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  }
76
 
77
+ prompt_text = json.dumps(json_prompt, ensure_ascii=False)
78
+
79
+ return generate_flux_image(prompt_text, steps=25, seed=seed)
80
+
81
+ def load_example(example_id):
82
+ examples = {
83
+ "producto": {
84
+ "scene": "Fotografía profesional de producto en estudio",
85
+ "subjects": "Taza de café minimalista con vapor ascendiendo",
86
+ "style": "Fotografía de producto ultra realista",
87
+ "colors": "#2C2C2C, #E8E8E8, #FF6B35",
88
+ "lighting": "Iluminación suave de 3 puntos",
89
+ "mood": "Limpio y profesional",
90
+ "background": "Superficie de concreto pulido",
91
+ "camera_angle": "ángulo alto"
92
+ },
93
+ "paisaje": {
94
+ "scene": "Paisaje de montaña al atardecer",
95
+ "subjects": "Lobo solitario en la cima de la montaña",
96
+ "style": "Pintura digital épica",
97
+ "colors": "#FF6B35, #1A535C, #4ECDC4",
98
+ "lighting": "Luz dorada del atardecer",
99
+ "mood": "Épico y sereno",
100
+ "background": "Montañas y cielo naranja",
101
+ "camera_angle": "vista panorámica"
102
+ },
103
+ "retrato": {
104
+ "scene": "Estudio de retrato profesional",
105
+ "subjects": "Persona con sonrisa genuina, iluminación dramática",
106
+ "style": "Retrato fotográfico profesional",
107
+ "colors": "#2C2C2C, #F5F5F5, #8B4513",
108
+ "lighting": "Iluminación Rembrandt",
109
+ "mood": "Elegante y confiado",
110
+ "background": "Fondo negro mate",
111
+ "camera_angle": "primer plano"
112
+ }
113
  }
114
 
115
+ return [examples[example_id][field] for field in [
116
+ "scene", "subjects", "style", "colors", "lighting",
117
+ "mood", "background", "camera_angle"
118
+ ]]
 
 
 
119
 
120
+ # -------------------------------------------------------
121
+ # INTERFAZ GRADIO
122
+ # -------------------------------------------------------
123
+ with gr.Blocks(title="FLUX.2 - Generador de Imágenes") as demo:
 
 
124
 
125
+ gr.Markdown("# 🎨 FLUX.2 - Generador de Imágenes (Optimizado para CPU, Formato 9:16)")
 
126
 
127
+ # ----------------- TAB SIMPLE -----------------
128
+ with gr.Tab("🎯 Prompt Simple"):
129
+ with gr.Row():
130
+ with gr.Column():
131
+ prompt_simple = gr.Textbox(label="Prompt")
132
+ negative_prompt = gr.Textbox(label="Negative Prompt (FLUX no lo usa)")
133
+ steps = gr.Slider(10, 50, value=28, step=1, label="Steps")
134
+ guidance = gr.Slider(1, 20, value=7, step=0.5, label="Guidance")
135
+ width = gr.Slider(256, 1024, value=576, step=64, label="Ancho (9:16 por defecto)")
136
+ height = gr.Slider(256, 1024, value=1024, step=64, label="Alto (9:16 por defecto)")
137
+ seed = gr.Number(value=-1, label="Semilla")
138
+ btn_simple = gr.Button("Generar Imagen")
139
+
140
+ with gr.Column():
141
+ out_img_simple = gr.Image(label="Imagen Generada")
142
+ out_seed_simple = gr.Number(label="Semilla Usada")
143
+
144
+ # ----------------- TAB JSON -----------------
145
+ with gr.Tab("📝 JSON Prompt"):
146
+ scene = gr.Textbox(label="Escena")
147
+ subjects = gr.Textbox(label="Sujetos")
148
+ style = gr.Textbox(label="Estilo")
149
+ colors = gr.Textbox(label="Colores (coma)")
150
+ lighting = gr.Textbox(label="Iluminación")
151
+ mood = gr.Textbox(label="Estado de Ánimo")
152
+ background = gr.Textbox(label="Fondo")
153
+ camera_angle = gr.Textbox(label="Ángulo de cámara")
154
+ json_seed = gr.Number(value=-1, label="Semilla")
155
+ btn_json = gr.Button("Generar con JSON")
156
+
157
+ out_img_json = gr.Image()
158
+ out_seed_json = gr.Number()
159
 
160
  with gr.Row():
161
+ gr.Button("Ej Producto").click(
162
+ fn=lambda: load_example("producto"),
163
+ outputs=[scene, subjects, style, colors, lighting, mood, background, camera_angle]
164
+ )
165
+ gr.Button("Ej Paisaje").click(
166
+ fn=lambda: load_example("paisaje"),
167
+ outputs=[scene, subjects, style, colors, lighting, mood, background, camera_angle]
168
+ )
169
+ gr.Button("Ej Retrato").click(
170
+ fn=lambda: load_example("retrato"),
171
+ outputs=[scene, subjects, style, colors, lighting, mood, background, camera_angle]
172
  )
173
 
174
+ # Eventos
175
+ btn_simple.click(
176
+ fn=generate_flux_image,
177
+ inputs=[prompt_simple, negative_prompt, steps, guidance, width, height, seed],
178
+ outputs=[out_img_simple, out_seed_simple]
179
+ )
180
+
181
+ btn_json.click(
182
+ fn=generate_json_image,
183
+ inputs=[scene, subjects, style, colors, lighting, mood, background, camera_angle, json_seed],
184
+ outputs=[out_img_json, out_seed_json]
185
+ )
186
+
187
+ # Lanzar la demo (para ejecución local o en CPU)
188
+ demo.launch()