caissaa23 commited on
Commit
65c10eb
·
verified ·
1 Parent(s): 26b63da

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +97 -417
app.py CHANGED
@@ -1,435 +1,115 @@
1
- # app.py (archivo completo — pégalo tal cual)
2
  import gradio as gr
3
- import datetime
4
- import random
5
  import json
6
  import os
7
- from hashlib import md5
8
- from PIL import Image
9
- import io
 
10
 
11
- # -------------------- ARCHIVOS / CONSTANTES --------------------
12
- USUARIOS_FILE = "usuarios.json"
13
  SESION_FILE = "sesion.json"
14
- MEMORIA_NUTI = "memoria_nuti.json"
15
- MEMORIA_COACH = "memoria_coach.json"
16
- CACHE_CLASS = {} # cache en memoria para clasificador
17
 
18
- # -------------------- UTILIDADES: USUARIOS / SESIÓN --------------------
19
- def cargar_usuarios():
20
- if os.path.exists(USUARIOS_FILE):
21
- with open(USUARIOS_FILE, "r", encoding="utf-8") as f:
22
- return json.load(f)
23
- return {}
24
-
25
- def guardar_usuarios(u):
26
- with open(USUARIOS_FILE, "w", encoding="utf-8") as f:
27
- json.dump(u, f, indent=2, ensure_ascii=False)
28
-
29
- def registrar_usuario(nombre, email, password):
30
- usuarios = cargar_usuarios()
31
- if not email or not password or not nombre:
32
- return "⚠️ Completa todos los campos."
33
- if email in usuarios:
34
- return "⚠️ Ya existe una cuenta con ese correo."
35
- usuarios[email] = {"nombre": nombre, "password": password, "created": str(datetime.datetime.now())}
36
- guardar_usuarios(usuarios)
37
- # crear sesión al registrarse
38
- with open(SESION_FILE, "w", encoding="utf-8") as f:
39
- json.dump({"usuario": email}, f)
40
- return "✅ Registro exitoso. Sesión iniciada."
41
-
42
- def iniciar_sesion(email, password):
43
- usuarios = cargar_usuarios()
44
- if email not in usuarios:
45
- return "❌ Usuario no encontrado."
46
- if usuarios[email]["password"] != password:
47
- return "🔐 Contraseña incorrecta."
48
- with open(SESION_FILE, "w", encoding="utf-8") as f:
49
  json.dump({"usuario": email}, f)
50
- return f"✅ Bienvenido de nuevo, {usuarios[email]['nombre']}!"
51
 
52
- def obtener_usuario_sesion():
53
  if os.path.exists(SESION_FILE):
54
- with open(SESION_FILE, "r", encoding="utf-8") as f:
55
- data = json.load(f)
56
- return data.get("usuario")
57
  return None
58
 
59
- # -------------------- MEMORIA (Nuti y Coach) --------------------
60
- def cargar_json(path):
61
- if os.path.exists(path):
62
- with open(path, "r", encoding="utf-8") as f:
63
- return json.load(f)
64
- return {}
65
-
66
- def guardar_json(path, data):
67
- with open(path, "w", encoding="utf-8") as f:
68
- json.dump(data, f, indent=2, ensure_ascii=False)
69
-
70
- def cargar_memoria_nuti(usuario):
71
- data = cargar_json(MEMORIA_NUTI)
72
- return data.get(usuario, {"historial": []})
73
-
74
- def actualizar_memoria_nuti(usuario, pregunta, respuesta):
75
- data = cargar_json(MEMORIA_NUTI)
76
- if usuario not in data:
77
- data[usuario] = {"historial": []}
78
- data[usuario]["historial"].append({
79
- "pregunta": pregunta,
80
- "respuesta": respuesta,
81
- "fecha": str(datetime.datetime.now())
82
- })
83
- # limitar historial a últimos 50
84
- data[usuario]["historial"] = data[usuario]["historial"][-50:]
85
- guardar_json(MEMORIA_NUTI, data)
86
-
87
- def cargar_memoria_coach(usuario):
88
- data = cargar_json(MEMORIA_COACH)
89
- return data.get(usuario, {"historial": []})
90
-
91
- def actualizar_memoria_coach(usuario, entrada, respuesta, estado_emocional=None):
92
- data = cargar_json(MEMORIA_COACH)
93
- if usuario not in data:
94
- data[usuario] = {"historial": []}
95
- registro = {"entrada": entrada, "respuesta": respuesta, "fecha": str(datetime.datetime.now())}
96
- if estado_emocional:
97
- registro["estado_emocional"] = estado_emocional
98
- data[usuario]["historial"].append(registro)
99
- data[usuario]["historial"] = data[usuario]["historial"][-50:]
100
- guardar_json(MEMORIA_COACH, data)
101
-
102
- # -------------------- CLASIFICADOR DE IMÁGENES (intenta transformers, si no fallback) --------------------
103
- def cargar_modelo_transformers():
104
- try:
105
- # Import dentro de la función para fallar suavemente si no está instalado
106
- from transformers import pipeline
107
- model = pipeline("image-classification", model="nateraw/food")
108
- return model
109
- except Exception:
110
- return None
111
-
112
- MODEL_PIPELINE = cargarmodelo := None
113
- try:
114
- MODEL_PIPELINE = cargar_modelo_transformers()
115
- except Exception:
116
- MODEL_PIPELINE = None
117
-
118
- def resize_imagen_pil(img, size=(224,224)):
119
- if isinstance(img, Image.Image):
120
- return img.convert("RGB").resize(size)
121
- # si es bytes
122
- try:
123
- im = Image.open(io.BytesIO(img))
124
- return im.convert("RGB").resize(size)
125
- except Exception:
126
- return None
127
-
128
- def clasificar_imagen(img):
129
- """
130
- Intenta usar transformers pipeline; si no está disponible usa fallback simple.
131
- Devuelve una lista tipo [{'label':'pizza', 'score':0.9}] para compatibilidad.
132
- """
133
- # cache by bytes hash
134
- try:
135
- buf = io.BytesIO()
136
- if isinstance(img, Image.Image):
137
- img.save(buf, format="JPEG")
138
- k = md5(buf.getvalue()).hexdigest()
139
- else:
140
- # if it's a path or raw bytes
141
- raw = img if isinstance(img, (bytes, bytearray)) else str(img).encode("utf-8")
142
- k = md5(raw).hexdigest()
143
- if k in CACHE_CLASS:
144
- return CACHE_CLASS[k]
145
- except Exception:
146
- k = None
147
-
148
- # try transformers model
149
- if MODEL_PIPELINE:
150
- try:
151
- res = MODEL_PIPELINE(img)
152
- CACHE_CLASS[k] = res
153
- return res
154
- except Exception:
155
- pass
156
-
157
- # fallback classifier (heurístico basado en tamaño/colors)
158
- try:
159
- im = img if isinstance(img, Image.Image) else Image.open(io.BytesIO(img))
160
- im_small = im.resize((64,64)).convert("RGB")
161
- pixels = list(im_small.getdata())
162
- # average R,G,B
163
- r = sum(p[0] for p in pixels)/len(pixels)
164
- g = sum(p[1] for p in pixels)/len(pixels)
165
- b = sum(p[2] for p in pixels)/len(pixels)
166
- # heurística simple
167
- if r > 150 and g < 120:
168
- label = "pizza"
169
- elif g > r and g > b:
170
- label = "salad"
171
- elif b > r and b > g:
172
- label = "fish"
173
- else:
174
- label = "pasta"
175
- res = [{"label": label, "score": 0.6}]
176
- if k:
177
- CACHE_CLASS[k] = res
178
- return res
179
- except Exception:
180
- return [{"label":"unknown","score":0.0}]
181
-
182
- # -------------------- BASES DE CONOCIMIENTO (Nuti y Coach) --------------------
183
- TEMAS_NUTRICION = {
184
- "desayuno": [
185
- "Un desayuno equilibrado (proteína + carbohidratos complejos + fruta) mejora concentración y saciedad.",
186
- "Evita azúcares simples por la mañana; prueba avena o yogurt natural con fruta."
187
- ],
188
- "almuerzo": [
189
- "Incluye proteína, verduras y un carbohidrato integral para energía sostenida.",
190
- "No olvides una porción de verduras para vitaminas y fibra."
191
- ],
192
- "cena": [
193
- "Cena ligera 2 horas antes de dormir para una mejor calidad de sueño.",
194
- "Sopa de verduras con proteína magra es una excelente opción nocturna."
195
- ]
196
- }
197
-
198
- PALABRAS_CLAVE = {
199
- "ansiedad": "Cuando sientas ansiedad, prueba respirar 4-4-4 (inhala 4s, mantén 4s, exhala 4s). Bebe agua y espera 5-10 min antes de decidir comer.",
200
- "estrés": "El estrés puede aumentar los antojos. Pausas cortas, hidratarte y caminar 10 min ayudan mucho.",
201
- "peso": "El peso es un indicador, no la definición. Enfócate en hábitos sostenibles y salud, no solo en la balanza.",
202
- "agua": "Beber suficiente agua ayuda al hambre real vs. hambre emocional. Intenta un vaso antes de cada comida."
203
- }
204
-
205
- # -------------------- FUNCIONES INTELIGENTES (sin API externa) --------------------
206
- def buscar_respuesta(usuario, mensaje, historial=None):
207
- """
208
- Nuti local: usa historial y reglas para generar respuesta contextual.
209
- historial: lista de dicts opcional
210
- """
211
- texto = (mensaje or "").lower().strip()
212
- historial = historial or cargar_memoria_nuti(usuario)["historial"] if usuario else []
213
-
214
- # detección rápida de temas por palabra
215
- for clave, frases in TEMAS_NUTRICION.items():
216
- if clave in texto:
217
- resp = random.choice(frases)
218
- actualizar_memoria_nuti(usuario, mensaje, resp)
219
- return resp
220
-
221
- for palabra, resp in PALABRAS_CLAVE.items():
222
- if palabra in texto:
223
- actualizar_memoria_nuti(usuario, mensaje, resp)
224
- return resp
225
-
226
- # si hay historial, intentar continuidad
227
- if historial:
228
- # mira últimas interacciones y responde con continuidad
229
- last = historial[-1]
230
- resp = f"Veo que antes hablaste de \"{last.get('pregunta','...')[:60]}\". {random.choice(['¿Quieres que profundicemos?','Puedo sugerirte un plan corto para esto.'])}"
231
- actualizar_memoria_nuti(usuario, mensaje, resp)
232
- return resp
233
-
234
- # fallback más elaborado
235
- respuestas_generales = [
236
- "Cuéntame más: ¿qué buscas — perder peso, ganar músculo, mejorar energía o algo más?",
237
- "Puedo darte un ejemplo de menú, una receta o un plan de ejercicio breve. ¿Cuál prefieres?",
238
- "Pequeños cambios diarios hacen gran diferencia. ¿Qué hábito te gustaría mejorar primero?"
239
- ]
240
- resp = random.choice(respuestas_generales)
241
- actualizar_memoria_nuti(usuario, mensaje, resp)
242
- return resp
243
-
244
- def coach_emocional_inteligente(usuario, mensaje, historial=None):
245
- """
246
- Coach emocional local: empatía + recomendaciones prácticas, usando historial.
247
- historial: lista opcional de entradas previas (de app)
248
- """
249
- texto = (mensaje or "").lower().strip()
250
- historial = historial or cargar_memoria_coach(usuario)["historial"] if usuario else []
251
-
252
- # detectar emoción en texto
253
- if any(x in texto for x in ["ansiedad", "ansioso", "nervioso"]):
254
- resp = ("Siento que estás ansioso/a. Prueba respiraciones lentas (inhala 4s, exhala 6s), bebe agua y "
255
- "si puedes, camina 5-10 minutos. Para picar, una fruta o un puñado de nueces ayuda.")
256
- estado = "ansioso"
257
- elif any(x in texto for x in ["triste", "deprim", "mal", "melanc"]):
258
- resp = ("Lamento que te sientas así. Hablar con alguien de confianza o escribir cómo te sientes ayuda. "
259
- "Una merienda ligera, descansar y movimiento suave (una caminata) pueden mejorar el ánimo.")
260
- estado = "triste"
261
- elif any(x in texto for x in ["feliz", "contento", "genial"]):
262
- resp = ("¡Qué bien que te sientes así! Mantén esos hábitos: come variado, hidrátate y celebra los logros.")
263
- estado = "positivo"
264
- else:
265
- # si no hay emoción clara, usar historial para seguimiento
266
- if historial:
267
- last = historial[-1]
268
- resp = (f"Recuerdo que antes comentaste: '{last.get('entrada','...')[:80]}'. "
269
- "¿Quieres seguir con eso o prefieres cambiar de tema? Puedo sugerir técnicas prácticas.")
270
- else:
271
- resp = ("Cuéntame más sobre cómo te sientes hoy: ¿ansioso, estresado, triste, con hambre emocional? "
272
- "Así te doy una recomendación práctica.")
273
- estado = "neutral"
274
-
275
- actualizar_memoria_coach(usuario, mensaje, resp, estado_emocional=estado)
276
- return resp
277
-
278
- # -------------------- APP: ESTADO GLOBAL (comida, metas) --------------------
279
- # Mantendremos un registro simple en memoria/archivo llamado registro.json
280
- REGISTRO_FILE = "registro.json"
281
- def cargar_registro():
282
- if os.path.exists(REGISTRO_FILE):
283
- with open(REGISTRO_FILE, "r", encoding="utf-8") as f:
284
- return json.load(f)
285
- # estructura inicial
286
- base = {"meta_diaria": 0, "restantes": 0, "quemas": 0, "puntos": 0, "registro": [], "badges": [], "emocion": "", "nivel": 1, "historial_nuti": {}, "historial_emocional": {}}
287
- guardar_registro(base)
288
- return base
289
-
290
- def guardar_registro(data):
291
- with open(REGISTRO_FILE, "w", encoding="utf-8") as f:
292
- json.dump(data, f, indent=2, ensure_ascii=False)
293
-
294
- estado = cargar_registro() # carga inicial
295
-
296
- # -------------------- DATOS AUXILIARES --------------------
297
- calorias_promedio = {
298
- "pizza": 285, "hamburger": 354, "apple": 95, "banana": 105,
299
- "salad": 150, "pasta": 350, "rice": 200, "ice cream": 210,
300
- "donut": 195, "fish": 206, "chicken": 239, "broccoli": 55
301
- }
302
-
303
- actividades = {
304
- "Correr": 700, "Caminar": 250, "Fútbol": 600,
305
- "Natación": 550, "Básquetbol": 500, "Voleibol": 400, "Yoga": 200,
306
- }
307
-
308
- nutriologos = [
309
- {"nombre": "Dra. Ana López", "pais": "México", "estado": "Sonora", "ciudad": "Hermosillo",
310
- "especialidad": "Nutrición deportiva", "direccion": "Av. Universidad 200", "contacto": "Instagram: @dra.analpz"},
311
- {"nombre": "Lic. Jorge Ramírez", "pais": "México", "estado": "CDMX", "ciudad": "Coyoacán",
312
- "especialidad": "Control de peso", "direccion": "Centro NutriVida, Av. Pacífico 300", "contacto": "Tel: +52 55 1234 5678"},
313
- {"nombre": "Dra. Camila Torres", "pais": "Colombia", "estado": "Antioquia", "ciudad": "Medellín",
314
- "especialidad": "Nutrición infantil", "direccion": "Cra 40 #23", "contacto": "Email: camilatorresnutri@gmail.com"},
315
- ]
316
 
317
- misiones = [
318
- "🥤 Bebe 8 vasos de agua.",
319
- "🍎 Come 3 frutas distintas.",
320
- "🚶 Camina 20 minutos.",
321
- "🌈 Come 4 colores de comida diferentes.",
322
- "🧘 Haz 10 minutos de respiración o yoga."
323
- ]
324
 
325
- # -------------------- FUNCIONES EXPUESTAS A LA UI --------------------
326
- def calcular_calorias_ui(edad, peso, altura, sexo, actividad_str):
327
- if not all([edad, peso, altura, sexo]):
328
- return "⚠️ Completa tus datos para calcular."
329
- try:
330
- edad = float(edad); peso = float(peso); altura = float(altura)
331
- except Exception:
332
- return "⚠️ Datos inválidos. Revisa números."
333
- if sexo.lower() == "hombre":
334
- bmr = 88.36 + (13.4 * peso) + (4.8 * altura) - (5.7 * edad)
335
  else:
336
- bmr = 447.6 + (9.2 * peso) + (3.1 * altura) - (4.3 * edad)
337
- niveles = {"Sedentario": 1.2, "Ligero": 1.375, "Moderado": 1.55, "Activo": 1.725, "Muy activo": 1.9}
338
- tdee = bmr * niveles.get(actividad_str, 1.2)
339
- estado["meta_diaria"] = round(tdee)
340
- estado["restantes"] = round(tdee)
341
- guardar_registro(estado)
342
- return f"🔥 Tu meta calórica diaria es de {round(tdee)} cal."
343
-
344
- def analizar_foto_ui(img, usuario):
345
- if estado.get("meta_diaria", 0) == 0:
346
- return "⚠️ Primero calcula tu meta diaria."
347
- if img is None:
348
- return "⚠️ Sube una foto."
349
- img_opt = resize_imagen_pil(img)
350
- result = clasificar_imagen(img_opt)
351
- nombre = result[0]["label"].lower() if result else "comida"
352
- calorias = calorias_promedio.get(nombre, 250)
353
- estado["restantes"] = max(0, estado["restantes"] - calorias)
354
- estado["registro"].append({"fecha": str(datetime.datetime.now()), "tipo": "comida", "nombre": nombre, "calorias": calorias, "usuario": usuario})
355
- estado["puntos"] += 10
356
- guardar_registro(estado)
357
- return f"🍽️ {nombre.title()} {calorias} cal. Restan {estado['restantes']} / {estado['meta_diaria']} cal."
358
-
359
- def registrar_actividad_ui(tipo, duracion, usuario):
360
- try:
361
- dur = float(duracion)
362
- except Exception:
363
- return "⚠️ Duración inválida."
364
- if tipo not in actividades:
365
- return "Selecciona una actividad válida."
366
- quemadas = int(actividades[tipo] * (dur / 60))
367
- estado["restantes"] += quemadas
368
- estado["quemas"] += quemadas
369
- estado["registro"].append({"fecha": str(datetime.datetime.now()), "tipo":"actividad", "nombre":tipo, "calorias":quemadas, "usuario": usuario})
370
- estado["puntos"] += 15
371
- guardar_registro(estado)
372
- return f"🏃‍♂️ {tipo} durante {dur} min ≈ {quemadas} cal quemadas. Restantes: {estado['restantes']}."
373
-
374
- def coach_emocional_ui(texto, usuario):
375
- if not usuario:
376
- usuario = "usuario_desconocido"
377
- memoria = cargar_memoria_coach(usuario)["historial"]
378
- resp = coach_emocional_inteligente(usuario, texto, memoria)
379
- return resp
380
-
381
- def chat_nuti_ui(pregunta, usuario):
382
- if not usuario:
383
- usuario = "usuario_desconocido"
384
- memoria = cargar_memoria_nuti(usuario)["historial"]
385
- resp = buscar_respuesta(usuario, pregunta, memoria)
386
- return resp
387
-
388
- def buscar_nutriologo_ui(pais, estado_, ciudad):
389
- if not pais or not estado_ or not ciudad:
390
- return "Introduce país, estado y ciudad."
391
- resultados = [n for n in nutriologos if n["pais"].lower()==pais.lower() and n["estado"].lower()==estado_.lower() and n["ciudad"].lower()==ciudad.lower()]
392
- if not resultados:
393
- return "😔 No se encontraron nutriólogos en esa zona aún."
394
- salida = "👩‍⚕️ Nutriólogos disponibles:\n"
395
- for n in resultados:
396
- salida += f"\n• {n['nombre']} — {n['especialidad']}\n 📍 {n['direccion']}\n 📞 {n['contacto']}\n"
397
- return salida
398
-
399
- def generar_mision_ui():
400
- mision = random.choice(misiones)
401
- return f"🎯 Tu misión de hoy: {mision}"
402
-
403
- # -------------------- INTERFAZ GRADIO --------------------
404
- with gr.Blocks() as demo:
405
- gr.Markdown("# 🥦 NutriBot Ultra — Demo local")
406
- # Estado de login en gradio
407
- usuario_state = gr.State(value=None)
408
- saludo = gr.Markdown("")
409
-
410
- # Columnas: login visible inicialmente
411
- with gr.Column():
412
- with gr.Box(visible=True) as login_box:
413
- gr.Markdown("## 🔐 Iniciar sesión / Registrarse")
414
- email_login = gr.Textbox(label="Correo electrónico")
415
- pass_login = gr.Textbox(label="Contraseña", type="password")
416
- salida_login = gr.Textbox(label="Mensaje")
417
-
418
- nombre_reg = gr.Textbox(label="Nombre completo")
419
- email_reg = gr.Textbox(label="Correo electrónico (registro)")
420
- pass_reg = gr.Textbox(label="Contraseña (registro)", type="password")
421
  salida_reg = gr.Textbox(label="Resultado del registro")
 
422
 
423
- btn_login = gr.Button("Entrar")
424
- btn_reg = gr.Button("Registrarse")
425
 
426
- with gr.Box(visible=False) as app_box:
427
- # Saludo dinámico
428
- saludo_md = gr.Markdown("")
 
 
 
 
 
429
 
430
- # TABS de la app
431
- with gr.Tabs():
432
- with gr.TabItem("🧍 Tu perfil"):
433
- edad = gr.Number(label="Edad (años)")
434
- peso = gr.Number(label="Peso (kg)")
435
- altura = gr.Number
 
 
1
  import gradio as gr
 
 
2
  import json
3
  import os
4
+ from datetime import datetime
5
+ from chatbot_nuti import buscar_respuesta
6
+ from coach_emocional import coach_emocional_inteligente
7
+ from login import cargar_usuarios, registrar_usuario, iniciar_sesion
8
 
 
 
9
  SESION_FILE = "sesion.json"
 
 
 
10
 
11
+ # ---------- FUNCIONES DE SESIÓN ---------- #
12
+ def guardar_sesion(email):
13
+ with open(SESION_FILE, "w") as f:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  json.dump({"usuario": email}, f)
 
15
 
16
+ def cargar_sesion():
17
  if os.path.exists(SESION_FILE):
18
+ with open(SESION_FILE, "r") as f:
19
+ return json.load(f).get("usuario")
 
20
  return None
21
 
22
+ def cerrar_sesion():
23
+ if os.path.exists(SESION_FILE):
24
+ os.remove(SESION_FILE)
25
+ return "Sesión cerrada. 👋"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
+ # ---------- MEMORIA DE CONVERSACIÓN ---------- #
28
+ MEMORIA_NUTI = {}
29
+ MEMORIA_COACH = {}
 
 
 
 
30
 
31
+ def obtener_memoria(usuario, tipo="nuti"):
32
+ if tipo == "nuti":
33
+ return MEMORIA_NUTI.setdefault(usuario, [])
 
 
 
 
 
 
 
34
  else:
35
+ return MEMORIA_COACH.setdefault(usuario, [])
36
+
37
+ # ---------- CHATBOT NUTI ---------- #
38
+ def conversar_nuti(mensaje, email):
39
+ memoria = obtener_memoria(email, "nuti")
40
+ memoria.append({"user": mensaje})
41
+ respuesta = buscar_respuesta(mensaje, memoria)
42
+ memoria.append({"nuti": respuesta})
43
+ return respuesta
44
+
45
+ # ---------- COACH EMOCIONAL ---------- #
46
+ def conversar_coach(mensaje, email):
47
+ memoria = obtener_memoria(email, "coach")
48
+ memoria.append({"user": mensaje})
49
+ respuesta = coach_emocional_inteligente(mensaje, memoria)
50
+ memoria.append({"coach": respuesta})
51
+ return respuesta
52
+
53
+ # ---------- INTERFAZ PRINCIPAL (NutriBot) ---------- #
54
+ def crear_interfaz_nutribot(email):
55
+ with gr.Blocks(title="NutriBot Ultra 🥗") as app:
56
+ gr.Markdown(f"## 🌈 ¡Bienvenido, {email}! Tu asistente inteligente de salud y bienestar 🧠💪")
57
+ gr.Markdown("Habla con Nuti o con tu Coach Emocional, según cómo te sientas hoy 💚")
58
+
59
+ with gr.Tab("🤖 Chat con Nuti"):
60
+ chat_nuti = gr.Chatbot(label="Nuti - Tu guía nutricional")
61
+ entrada_nuti = gr.Textbox(label="Escribe algo para Nuti")
62
+ boton_nuti = gr.Button("Enviar")
63
+ boton_nuti.click(conversar_nuti, inputs=[entrada_nuti, gr.State(email)], outputs=chat_nuti)
64
+
65
+ with gr.Tab("🧘 Coach Emocional"):
66
+ chat_coach = gr.Chatbot(label="Coach Emocional - Bienestar Mental")
67
+ entrada_coach = gr.Textbox(label="Cuéntame cómo te sientes hoy...")
68
+ boton_coach = gr.Button("Enviar")
69
+ boton_coach.click(conversar_coach, inputs=[entrada_coach, gr.State(email)], outputs=chat_coach)
70
+
71
+ gr.Button("Cerrar sesión 🚪").click(cerrar_sesion, outputs=None)
72
+
73
+ return app
74
+
75
+ # ---------- LOGIN Y REGISTRO ---------- #
76
+ def interfaz_login():
77
+ with gr.Blocks(title="Inicio de Sesión - NutriBot Ultra") as login_ui:
78
+ gr.Markdown("# 🥗 Bienvenido a NutriBot Ultra 🌟\nTu IA de nutrición y bienestar emocional.")
79
+
80
+ with gr.Tab("🔑 Iniciar sesión"):
81
+ email = gr.Textbox(label="Correo electrónico")
82
+ password = gr.Textbox(label="Contraseña", type="password")
83
+ boton_login = gr.Button("Entrar")
84
+ mensaje_login = gr.Textbox(label="Estado")
85
+
86
+ def login_action(email, password):
87
+ res = iniciar_sesion(email, password)
88
+ if res.startswith("✅"):
89
+ guardar_sesion(email)
90
+ return gr.update(visible=False), gr.update(visible=True)
91
+ return res
92
+
93
+ boton_login.click(login_action, inputs=[email, password], outputs=[login_ui, mensaje_login])
94
+
95
+ with gr.Tab("📝 Registrarse"):
96
+ nombre = gr.Textbox(label="Nombre completo")
97
+ correo = gr.Textbox(label="Correo electrónico")
98
+ contra = gr.Textbox(label="Contraseña", type="password")
99
+ boton_reg = gr.Button("Crear cuenta")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  salida_reg = gr.Textbox(label="Resultado del registro")
101
+ boton_reg.click(registrar_usuario, inputs=[nombre, correo, contra], outputs=salida_reg)
102
 
103
+ return login_ui
 
104
 
105
+ # ---------- FLUJO PRINCIPAL ---------- #
106
+ def main():
107
+ usuario_actual = cargar_sesion()
108
+ if usuario_actual:
109
+ app = crear_interfaz_nutribot(usuario_actual)
110
+ else:
111
+ app = interfaz_login()
112
+ app.launch()
113
 
114
+ if __name__ == "__main__":
115
+ main()