Lukeetah commited on
Commit
cc5cb68
·
verified ·
1 Parent(s): a5488de

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +173 -242
app.py CHANGED
@@ -825,7 +825,7 @@ with demo: # Ahora el bloque 'with' utiliza el objeto demo ya creado
825
  voiceStatus.textContent = 'No se detectó voz. Intenta hablar más claro o más fuerte. 🎤';
826
  voiceStatus.style.color = '#fbbf24'; // Amber
827
  } else if (event.error === 'aborted') {
828
- voiceStatus.textContent = 'Reconocimiento de voz cancelado. ';
829
  voiceStatus.style.color = '#4b5563';
830
  }
831
  };
@@ -1103,7 +1103,7 @@ with demo: # Ahora el bloque 'with' utiliza el objeto demo ya creado
1103
  with nudges_section: # Nudges visible por defecto
1104
  gr.Markdown("<h2 style='color: #10b981;'>¡Che, acá estoy para cebarte un susurro!</h2><p>Contame un poco de tu día y te tiro la posta. Para empezar, podés decir: <b>'Quiero un susurro'</b>.</p>")
1105
  chat_history = gr.State([]) # Para mantener el historial del chat
1106
- chatbot = gr.Chatbot(label="Conversación con MateAI", height=300, type='messages') # Added type='messages'
1107
  msg_input = gr.Textbox(label="Contale a MateAI...", placeholder="Ej: 'Estoy en casa, laburando y medio cansado.' o 'Quiero un susurro de bienestar.'")
1108
 
1109
  # Botón para enviar el mensaje de texto (además de la entrada de voz)
@@ -1179,7 +1179,7 @@ with demo: # Ahora el bloque 'with' utiliza el objeto demo ya creado
1179
  """
1180
  <div class="browser-frame">
1181
  <div class="browser-header">
1182
- <span style="color: #666;">&#9679; &#9679; &#9679;</span>
1183
  <div class="browser-address-bar" id="simulated_browser_address">https://www.google.com.ar</div>
1184
  </div>
1185
  <div class="browser-content" id="simulated_browser_content">
@@ -1201,29 +1201,6 @@ with demo: # Ahora el bloque 'with' utiliza el objeto demo ya creado
1201
  </p>
1202
  """
1203
  )
1204
-
1205
- # Funciones simuladas para el asistente visual
1206
- def simulate_browser_action(action_description, new_url=None, new_content=None):
1207
- if new_url:
1208
- js_code = f"""
1209
- document.getElementById('simulated_browser_address').innerText = '{new_url}';
1210
- document.getElementById('simulated_browser_content').innerHTML = '<p>Cargando: {new_url}...</p>';
1211
- """
1212
- if "google.com" in new_url:
1213
- js_code += """
1214
- document.getElementById('simulated_browser_content').innerHTML = '<p>¡Estás en Google! ¿Qué querés buscar?</p><img src="https://placehold.co/200x100/ffffff/000000?text=Google" alt="Google Logo">';
1215
- """
1216
- elif "wikipedia.org" in new_url:
1217
- js_code += """
1218
- document.getElementById('simulated_browser_content').innerHTML = '<p>¡Estás en Wikipedia! Buscando información...</p><img src="https://placehold.co/200x100/ffffff/000000?text=Wikipedia" alt="Wikipedia Logo">';
1219
- """
1220
- else:
1221
- js_code += f"""
1222
- document.getElementById('simulated_browser_content').innerHTML = '<p>Contenido simulado de: {new_url}</p>';
1223
- """
1224
- return action_description, new_url, gr.HTML.update(value=js_code)
1225
-
1226
- return action_description, gr.skip(), gr.skip() # No cambia URL ni contenido si no se especifica
1227
 
1228
  # --- Funciones de Interacción para Gradio ---
1229
 
@@ -1300,7 +1277,7 @@ with demo: # Ahora el bloque 'with' utiliza el objeto demo ya creado
1300
  tareas_str = "\n".join([f"- {t['task']} (Agregada el: {datetime.strptime(t['added_at'], '%Y-%m-%d %H:%M:%S.%f').strftime('%d/%m')})" for t in user.tasks])
1301
 
1302
  # Retorna todos los outputs en el orden correcto para los componentes de Gradio
1303
- return (user, user.user_id, msg, user.name, str(current_points), current_insignia, next_insignia_goal,
1304
  historial, user.preferences.get('tipo_susurro'), user.preferences.get('frecuencia'),
1305
  user.preferences.get('modo_che_tranqui'), tareas_str)
1306
  # If user loading failed, return default values and the error message
@@ -1333,244 +1310,187 @@ with demo: # Ahora el bloque 'with' utiliza el objeto demo ya creado
1333
  challenge_text = await nudge_generator.get_mateai_challenge(user_obj.user_id)
1334
  return challenge_text, challenge_text # Return the text for vocalization
1335
 
 
1336
  async def _add_task_gradio(user_obj, task_name):
1337
  user_id = user_obj.user_id if user_obj else None
1338
- if not user_id:
1339
- return "Error: Por favor, crea o carga un usuario primero.", ""
1340
- user = await self.user_manager.get_user(user_id)
1341
- if not user:
1342
- return "Error: Usuario no logueado. Por favor, crea o carga un usuario.", ""
1343
-
1344
- new_task = {"task": task_name, "added_at": datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f'), "last_nudged": None}
1345
- user.tasks.append(new_task)
1346
- await self.user_manager.update_user_data(user)
1347
- tareas_str = "\n".join([f"- {t['task']} (Agregada el: {datetime.strptime(t['added_at'], '%Y-%m-%d %H:%M:%S.%f').strftime('%d/%m')})" for t in user.tasks])
1348
- return f"¡Tarea '{task_name}' agregada a tu lista, {user.name}!", tareas_str
1349
 
1350
  async def _complete_task_gradio(user_obj, task_name):
1351
  user_id = user_obj.user_id if user_obj else None
1352
- if not user_id:
1353
- return "Error: Por favor, crea o carga un usuario primero.", ""
1354
- user = await self.user_manager.get_user(user_id)
1355
- if not user:
1356
- return "Error: Usuario no logueado. Por favor, crea o carga un usuario.", ""
1357
-
1358
- initial_task_count = len(user.tasks)
1359
- user.tasks = [task for task in user.tasks if task['task'].lower() != task_name.lower()]
1360
-
1361
- if len(user.tasks) < initial_task_count:
1362
- await self.user_manager.update_user_data(user)
1363
- tareas_str = "\n".join([f"- {t['task']} (Agregada el: {datetime.strptime(t['added_at'], '%Y-%m-%d %H:%M:%S.%f').strftime('%d/%m')})" for t in user.tasks])
1364
- return f"¡Tarea '{task_name}' marcada como completada, {user.name}! ¡Bien ahí!", tareas_str
1365
- tareas_str = "\n".join([f"- {t['task']} (Agregada el: {datetime.strptime(t['added_at'], '%Y-%m-%d %H:%M:%S.%f').strftime('%d/%m')})" for t in user.tasks])
1366
- return f"No encontré la tarea '{task_name}' en tu lista, {user.name}.", tareas_str
1367
 
1368
  def _download_diary_gradio(diary_text):
1369
- return gr.File(value=diary_text.encode('utf-8'), filename="diario_mateai.txt", type="bytes")
1370
-
1371
- # --- Funciones para el chat conversacional ---
 
 
 
 
 
1372
  async def _process_conversational_input(user_message, chat_history, current_user_state, conversation_context_state):
 
 
 
1373
  user_message_lower = user_message.lower()
1374
- response = ""
1375
  user_obj = current_user_state
1376
 
1377
  # Append user message to chat history immediately
1378
- chat_history.append({"role": "user", "content": user_message})
1379
 
1380
  # Check if user is logged in
1381
  if not user_obj:
1382
  mateai_response = "¡Che, para arrancar, necesito que crees o cargues tu perfil en la sección 'Inicio & Perfil'! Después volvé acá y seguimos charlando."
1383
- chat_history.append({"role": "MateAI", "content": mateai_response})
1384
- return chat_history, "", conversation_context_state, mateai_response, gr.skip(), gr.skip(), gr.skip()
1385
 
1386
- # Command handling for other sections (simulates voice controlling the menu)
1387
- if "oráculo" in user_message_lower or "revelación" in user_message_lower:
1388
- revelation_text = await nudge_generator.get_daily_oracle_revelation(user_obj.user_id)
1389
- chat_history.append({"role": "MateAI", "content": revelation_text})
1390
- return chat_history, "", conversation_context_state, revelation_text, gr.skip(), gr.skip(), gr.skip()
 
 
 
1391
 
1392
- if "desafío" in user_message_lower or "reto" in user_message_lower:
1393
- challenge_text = await nudge_generator.get_mateai_challenge(user_obj.user_id)
1394
- chat_history.append({"role": "MateAI", "content": challenge_text})
1395
- return chat_history, "", conversation_context_state, challenge_text, gr.skip(), gr.skip(), gr.skip()
 
1396
 
1397
- if "agregar tarea" in user_message_lower or "nueva tarea" in user_message_lower:
1398
- task_name = user_message_lower.replace("agregar tarea", "").replace("nueva tarea", "").strip()
 
 
 
 
 
1399
  if task_name:
1400
- msg, _ = await nudge_generator.add_task(user_obj.user_id, task_name)
1401
- chat_history.append({"role": "MateAI", "content": msg})
1402
- return chat_history, "", conversation_context_state, msg, gr.skip(), gr.skip(), gr.skip()
1403
  else:
1404
  response = "¡Dale, che! ¿Qué tarea querés que agregue? Decime, por ejemplo: 'agregar tarea comprar yerba'."
1405
- chat_history.append({"role": "MateAI", "content": response})
1406
- return chat_history, "", conversation_context_state, response, gr.skip(), gr.skip(), gr.skip()
1407
 
1408
- if "completar tarea" in user_message_lower or "tarea lista" in user_message_lower:
1409
- task_name = user_message_lower.replace("completar tarea", "").replace("tarea lista", "").strip()
1410
  if task_name:
1411
- msg, _ = await nudge_generator.complete_task(user_obj.user_id, task_name)
1412
- chat_history.append({"role": "MateAI", "content": msg})
1413
- return chat_history, "", conversation_context_state, msg, gr.skip(), gr.skip(), gr.skip()
1414
  else:
1415
  response = "¡Decime qué tarea completaste, así la saco de la lista! Por ejemplo: 'completar tarea ir al súper'."
1416
- chat_history.append({"role": "MateAI", "content": response})
1417
- return chat_history, "", conversation_context_state, response, gr.skip(), gr.skip(), gr.skip()
1418
-
1419
- # --- Conversational Browser Agent (Simulated) ---
1420
- if "abrir" in user_message_lower or "ir a" in user_message_lower or "navegar" in user_message_lower:
1421
- if "google" in user_message_lower:
1422
- action_desc = "¡Dale, abriendo Google en el navegador simulado!"
1423
- new_url = "https://www.google.com.ar"
1424
- chat_history.append({"role": "MateAI", "content": action_desc})
1425
- action_output, browser_url, browser_content = simulate_browser_action(action_desc, new_url)
1426
- return chat_history, "", conversation_context_state, action_output, browser_url, browser_content
1427
- elif "wikipedia" in user_message_lower:
1428
- action_desc = "¡Perfecto! Abriendo Wikipedia en el navegador simulado."
1429
- new_url = "https://es.wikipedia.org"
1430
- chat_history.append({"role": "MateAI", "content": action_desc})
1431
- action_output, browser_url, browser_content = simulate_browser_action(action_desc, new_url)
1432
- return chat_history, "", conversation_context_state, action_output, browser_url, browser_content
1433
- elif "pagina de inicio" in user_message_lower or "inicio" in user_message_lower:
1434
- action_desc = "Volviendo a la página de inicio del navegador simulado."
1435
- new_url = "https://www.google.com.ar" # Or your default URL
1436
- chat_history.append({"role": "MateAI", "content": action_desc})
1437
- action_output, browser_url, browser_content = simulate_browser_action(action_desc, new_url)
1438
- return chat_history, "", conversation_context_state, action_output, browser_url, browser_content
1439
- else:
1440
- response = "¡Che, a qué página querés ir? Decime, por ejemplo: 'abrir Google' o 'ir a Wikipedia'."
1441
- chat_history.append({"role": "MateAI", "content": response})
1442
- return chat_history, "", conversation_context_state, response, gr.skip(), gr.skip(), gr.skip()
1443
-
1444
- if "buscar" in user_message_lower and "en google" in user_message_lower:
1445
- query = user_message_lower.replace("buscar", "").replace("en google", "").strip()
1446
- if query:
1447
- action_desc = f"¡Buscando '{query}' en Google!"
1448
- new_url = f"https://www.google.com.ar/search?q={query.replace(' ', '+')}"
1449
- chat_history.append({"role": "MateAI", "content": action_desc})
1450
- action_output, browser_url, browser_content = simulate_browser_action(action_desc, new_url)
1451
- return chat_history, "", conversation_context_state, action_output, browser_url, browser_content
1452
- else:
1453
- response = "¡Decime qué querés buscar, che! Por ejemplo: 'buscar el clima en Google'."
1454
- chat_history.append({"role": "MateAI", "content": response})
1455
- return chat_history, "", conversation_context_state, response, gr.skip(), gr.skip(), gr.skip()
1456
-
1457
- if "cerrar esta pagina" in user_message_lower or "cerrar pagina" in user_message_lower:
1458
- action_desc = "¡Listo, cerrando la página actual en el navegador simulado!"
1459
- new_url = "about:blank" # Simulate a blank or closed page
1460
- chat_history.append({"role": "MateAI", "content": action_desc})
1461
- action_output, browser_url, browser_content = simulate_browser_action(action_desc, new_url)
1462
- return chat_history, "", conversation_context_state, action_output, browser_url, browser_content
1463
-
1464
- # Logic to request a contextual nudge
1465
- current_step = conversation_context_state["step"]
1466
- location = conversation_context_state["location"]
1467
- activity = conversation_context_state["activity"]
1468
- sentiment = conversation_context_state["sentiment"]
1469
- pending_nudge_request = conversation_context_state["pending_nudge_request"]
1470
-
1471
- if "susurro" in user_message_lower or "decime algo" in user_message_lower or "onda" in user_message_lower or "che" in user_message_lower or pending_nudge_request:
1472
- pending_nudge_request = True
1473
- conversation_context_state["pending_nudge_request"] = True
1474
- if not location:
1475
- response = "¡Dale! Para cebarte un susurro a medida, contame, ¿dónde estás ahora? ¿En casa, en la oficina, en la calle? (Ej: 'Estoy en casa')"
1476
- conversation_context_state["step"] = "ask_location"
1477
- elif not activity:
1478
- response = f"Ah, estás en {location}. ¿Y en qué andás ahora? ¿Laburando, haciendo ejercicio, relajado, cocinando, viendo un partido? (Ej: 'Estoy laburando')"
1479
- conversation_context_state["step"] = "ask_activity"
1480
- elif not sentiment:
1481
- response = f"Entendido, en {location} y {activity}. ¿Y cómo te sentís? ¿Bien, cansado, bajoneado, motivado? (Ej: 'Me siento bien')"
1482
- conversation_context_state["step"] = "ask_sentiment"
1483
- else:
1484
- # We have everything, generate the nudge
1485
- nudge_text, current_points, current_insignia, next_insignia_goal, historial = await nudge_generator.generate_nudge(user_obj.user_id, location, activity, sentiment)
1486
- response = nudge_text
1487
- chat_history.append({"role": "MateAI", "content": response})
1488
- # Reset context after generating the nudge
1489
- conversation_context_state = {"step": "initial", "pending_nudge_request": False, "location": None, "activity": None, "sentiment": None}
1490
- return chat_history, "", conversation_context_state, response, gr.skip(), gr.skip(), gr.skip()
1491
-
1492
- elif current_step == "ask_location":
1493
- if any(k in user_message_lower for k in ["casa", "hogar"]):
1494
- location = "Casa"
1495
- elif any(k in user_message_lower for k in ["oficina", "laburo", "estudio", "trabajando"]):
1496
- location = "Oficina/Estudio"
1497
- elif any(k in user_message_lower for k in ["calle", "aire libre", "plaza", "parque", "caminando"]):
1498
- location = "Aire Libre/Calle"
1499
- else:
1500
- response = "No te entendí bien, che. ¿Estás en casa, en la oficina o en la calle? (Ej: 'Estoy en casa')"
1501
- chat_history.append({"role": "MateAI", "content": response})
1502
- return chat_history, "", conversation_context_state, response, gr.skip(), gr.skip(), gr.skip()
1503
 
1504
- conversation_context_state["location"] = location
1505
- if not activity:
1506
- response = f"Ah, estás en {location}. ¿Y en qué andás ahora? ¿Laburando, haciendo ejercicio, relajado, cocinando, viendo un partido? (Ej: 'Estoy laburando')"
1507
- conversation_context_state["step"] = "ask_activity"
1508
- elif not sentiment:
1509
- response = f"Entendido, en {location} y {activity}. ¿Y cómo te sentís? ¿Bien, cansado, bajoneado, motivado? (Ej: 'Me siento bien')"
1510
- conversation_context_state["step"] = "ask_sentiment"
1511
- else: # Should not happen if flow is sequential, but as fallback
1512
- nudge_text, current_points, current_insignia, next_insignia_goal, historial = await nudge_generator.generate_nudge(user_obj.user_id, location, activity, sentiment)
1513
- response = nudge_text
1514
- chat_history.append({"role": "MateAI", "content": response})
1515
- conversation_context_state = {"step": "initial", "pending_nudge_request": False, "location": None, "activity": None, "sentiment": None}
1516
- return chat_history, "", conversation_context_state, response, gr.skip(), gr.skip(), gr.skip()
1517
-
1518
- elif current_step == "ask_activity":
1519
- if any(k in user_message_lower for k in ["relajado", "tranqui", "descansando"]):
1520
- activity = "Relajado"
1521
- elif any(k in user_message_lower for k in ["laburando", "trabajando", "estudiando"]):
1522
- activity = "Trabajando"
1523
- elif any(k in user_message_lower for k in ["ejercicio", "entrenando", "corriendo", "caminando"]):
1524
- activity = "Ejercicio"
1525
- elif any(k in user_message_lower for k in ["leyendo", "libro"]):
1526
- activity = "Leyendo"
1527
- elif any(k in user_message_lower for k in ["cocinando", "comida"]):
1528
- activity = "Cocinando"
1529
- elif any(k in user_message_lower for k in ["partido", "fútbol", "viendo tele"]):
1530
- activity = "Viendo un partido"
1531
- else:
1532
- response = "No te pesqué esa, che. ¿Estás laburando, haciendo ejercicio, relajado, cocinando, o viendo un partido? (Ej: 'Estoy relajado')"
1533
- chat_history.append({"role": "MateAI", "content": response})
1534
- return chat_history, "", conversation_context_state, response, gr.skip(), gr.skip(), gr.skip()
1535
 
1536
- conversation_context_state["activity"] = activity
1537
- if not sentiment:
1538
- response = f"Entendido, en {location} y {activity}. ¿Y cómo te sentís? ¿Bien, cansado, bajoneado, motivado? (Ej: 'Me siento bien')"
1539
- conversation_context_state["step"] = "ask_sentiment"
1540
- else: # Should not happen if flow is sequential, but as fallback
1541
- nudge_text, current_points, current_insignia, next_insignia_goal, historial = await nudge_generator.generate_nudge(user_obj.user_id, location, activity, sentiment)
1542
- response = nudge_text
1543
- chat_history.append({"role": "MateAI", "content": response})
1544
- conversation_context_state = {"step": "initial", "pending_nudge_request": False, "location": None, "activity": None, "sentiment": None}
1545
- return chat_history, "", conversation_context_state, response, gr.skip(), gr.skip(), gr.skip()
1546
-
1547
- elif current_step == "ask_sentiment":
1548
- if any(k in user_message_lower for k in ["bien", "joya", "diez puntos", "contento"]):
1549
- sentiment = "Bien"
1550
- elif any(k in user_message_lower for k in ["cansado", "agotado", "fundido"]):
1551
- sentiment = "Cansado"
1552
- elif any(k in user_message_lower for k in ["bajoneado", "triste", "mal", "depre"]):
1553
- sentiment = "Bajoneado"
1554
- elif any(k in user_message_lower for k in ["motivado", "con pilas", "enchufado"]):
1555
- sentiment = "Motivado"
1556
- else:
1557
- response = "No te capto el sentimiento, che. ¿Estás bien, cansado, bajoneado o motivado? (Ej: 'Estoy cansado')"
1558
- chat_history.append({"role": "MateAI", "content": response})
1559
- return chat_history, "", conversation_context_state, response, gr.skip(), gr.skip(), gr.skip()
1560
 
1561
- conversation_context_state["sentiment"] = sentiment
1562
- # Now that we have everything, generate the nudge
1563
- nudge_text, current_points, current_insignia, next_insignia_goal, historial = await nudge_generator.generate_nudge(user_obj.user_id, location, activity, sentiment)
1564
- response = nudge_text
1565
- chat_history.append({"role": "MateAI", "content": response})
1566
- # Reset context after generating the nudge
1567
- conversation_context_state = {"step": "initial", "pending_nudge_request": False, "location": None, "activity": None, "sentiment": None}
1568
- return chat_history, "", conversation_context_state, response, gr.skip(), gr.skip(), gr.skip()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1569
 
1570
- else: # Default response if no specific command or context step
1571
- response = "¡No te entendí bien, che! Soy MateAI, tu compañero. Si querés un susurro, decime <b>'quiero un susurro'</b> y te voy a preguntar unas cositas. Si no, decime qué andás necesitando."
1572
- chat_history.append({"role": "MateAI", "content": response})
1573
- return chat_history, "", conversation_context_state, response, gr.skip(), gr.skip(), gr.skip()
1574
 
1575
  # --- Conexión de Eventos ---
1576
  btn_crear_usuario.click(
@@ -1620,26 +1540,37 @@ with demo: # Ahora el bloque 'with' utiliza el objeto demo ya creado
1620
  inputs=[diario_reflexion],
1621
  outputs=gr.File(label="Descargar tu Diario")
1622
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
1623
 
1624
  # --- Manejo de la entrada de voz y texto conversacional ---
1625
- # El input de texto (msg_input) y el botón de enviar (btn_send_msg)
1626
- # ahora se conectan a la función _process_conversational_input
1627
  msg_input.submit(
1628
  fn=_process_conversational_input,
1629
  inputs=[msg_input, chat_history, current_user_state, conversation_context_state],
1630
- outputs=[chatbot, msg_input, conversation_context_state, voice_output_text, simulated_action_output, simulated_browser_url, simulated_browser_content]
1631
  )
1632
  btn_send_msg.click(
1633
  fn=_process_conversational_input,
1634
  inputs=[msg_input, chat_history, current_user_state, conversation_context_state],
1635
- outputs=[chatbot, msg_input, conversation_context_state, voice_output_text, simulated_action_output, simulated_browser_url, simulated_browser_content]
1636
  )
1637
 
1638
- # El botón oculto para la entrada de voz también se conecta a la función conversacional
1639
  hidden_voice_submit_button.click(
1640
  fn=_process_conversational_input,
1641
  inputs=[voice_input_textbox, chat_history, current_user_state, conversation_context_state],
1642
- outputs=[chatbot, voice_input_textbox, conversation_context_state, voice_output_text, simulated_action_output, simulated_browser_url, simulated_browser_content]
1643
  )
1644
 
1645
  # When the backend generates text for voice, it sends it to voice_output_text,
@@ -1652,4 +1583,4 @@ with demo: # Ahora el bloque 'with' utiliza el objeto demo ya creado
1652
  )
1653
 
1654
  # Lanza la interfaz de Gradio
1655
- demo.launch()
 
825
  voiceStatus.textContent = 'No se detectó voz. Intenta hablar más claro o más fuerte. 🎤';
826
  voiceStatus.style.color = '#fbbf24'; // Amber
827
  } else if (event.error === 'aborted') {
828
+ voiceStatus.textContent = 'Reconocimiento de voz cancelado. 👍';
829
  voiceStatus.style.color = '#4b5563';
830
  }
831
  };
 
1103
  with nudges_section: # Nudges visible por defecto
1104
  gr.Markdown("<h2 style='color: #10b981;'>¡Che, acá estoy para cebarte un susurro!</h2><p>Contame un poco de tu día y te tiro la posta. Para empezar, podés decir: <b>'Quiero un susurro'</b>.</p>")
1105
  chat_history = gr.State([]) # Para mantener el historial del chat
1106
+ chatbot = gr.Chatbot(label="Conversación con MateAI", height=300, bubble_full_width=False)
1107
  msg_input = gr.Textbox(label="Contale a MateAI...", placeholder="Ej: 'Estoy en casa, laburando y medio cansado.' o 'Quiero un susurro de bienestar.'")
1108
 
1109
  # Botón para enviar el mensaje de texto (además de la entrada de voz)
 
1179
  """
1180
  <div class="browser-frame">
1181
  <div class="browser-header">
1182
+ <span style="color: #666;">● ●</span>
1183
  <div class="browser-address-bar" id="simulated_browser_address">https://www.google.com.ar</div>
1184
  </div>
1185
  <div class="browser-content" id="simulated_browser_content">
 
1201
  </p>
1202
  """
1203
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1204
 
1205
  # --- Funciones de Interacción para Gradio ---
1206
 
 
1277
  tareas_str = "\n".join([f"- {t['task']} (Agregada el: {datetime.strptime(t['added_at'], '%Y-%m-%d %H:%M:%S.%f').strftime('%d/%m')})" for t in user.tasks])
1278
 
1279
  # Retorna todos los outputs en el orden correcto para los componentes de Gradio
1280
+ return (user, user.id, msg, user.name, str(current_points), current_insignia, next_insignia_goal,
1281
  historial, user.preferences.get('tipo_susurro'), user.preferences.get('frecuencia'),
1282
  user.preferences.get('modo_che_tranqui'), tareas_str)
1283
  # If user loading failed, return default values and the error message
 
1310
  challenge_text = await nudge_generator.get_mateai_challenge(user_obj.user_id)
1311
  return challenge_text, challenge_text # Return the text for vocalization
1312
 
1313
+ # --- Refactored Task Functions to use the central nudge_generator methods ---
1314
  async def _add_task_gradio(user_obj, task_name):
1315
  user_id = user_obj.user_id if user_obj else None
1316
+ msg, tareas_str = await nudge_generator.add_task(user_id, task_name)
1317
+ return msg, tareas_str
 
 
 
 
 
 
 
 
 
1318
 
1319
  async def _complete_task_gradio(user_obj, task_name):
1320
  user_id = user_obj.user_id if user_obj else None
1321
+ msg, tareas_str = await nudge_generator.complete_task(user_id, task_name)
1322
+ return msg, tareas_str
 
 
 
 
 
 
 
 
 
 
 
 
 
1323
 
1324
  def _download_diary_gradio(diary_text):
1325
+ if not diary_text:
1326
+ return None # Avoid error on empty download
1327
+ # Create a temporary file to be returned by Gradio
1328
+ with open("diario_mateai.txt", "w", encoding="utf-8") as f:
1329
+ f.write(diary_text)
1330
+ return "diario_mateai.txt"
1331
+
1332
+ # --- THE NEW UNIFIED CONVERSATIONAL ENGINE ---
1333
  async def _process_conversational_input(user_message, chat_history, current_user_state, conversation_context_state):
1334
+ if not user_message.strip():
1335
+ return chat_history, "", conversation_context_state, "", gr.skip(), gr.skip(), gr.skip(), gr.skip(), gr.skip()
1336
+
1337
  user_message_lower = user_message.lower()
 
1338
  user_obj = current_user_state
1339
 
1340
  # Append user message to chat history immediately
1341
+ chat_history.append((user_message, None))
1342
 
1343
  # Check if user is logged in
1344
  if not user_obj:
1345
  mateai_response = "¡Che, para arrancar, necesito que crees o cargues tu perfil en la sección 'Inicio & Perfil'! Después volvé acá y seguimos charlando."
1346
+ chat_history[-1] = (user_message, mateai_response)
1347
+ return chat_history, "", conversation_context_state, mateai_response, gr.skip(), gr.skip(), gr.skip(), gr.skip(), gr.skip()
1348
 
1349
+ # --- Intent Router ---
1350
+ response = ""
1351
+ voice_response = ""
1352
+ action_output = gr.skip()
1353
+ browser_url = gr.skip()
1354
+ browser_content = gr.skip()
1355
+ task_list_update = gr.skip()
1356
+ oracle_update = gr.skip()
1357
 
1358
+ # --- Intent: Oracle/Challenge ---
1359
+ if "oráculo" in user_message_lower or "revelación" in user_message_lower:
1360
+ response = await nudge_generator.get_daily_oracle_revelation(user_obj.user_id)
1361
+ voice_response = response
1362
+ oracle_update = response
1363
 
1364
+ elif "desafío" in user_message_lower or "reto" in user_message_lower:
1365
+ response = await nudge_generator.get_mateai_challenge(user_obj.user_id)
1366
+ voice_response = response
1367
+
1368
+ # --- Intent: Task Management ---
1369
+ elif "agregar tarea" in user_message_lower or "nueva tarea" in user_message_lower:
1370
+ task_name = user_message.replace("agregar tarea", "").replace("nueva tarea", "", 1).strip()
1371
  if task_name:
1372
+ response, task_list_update = await nudge_generator.add_task(user_obj.user_id, task_name)
1373
+ voice_response = response
 
1374
  else:
1375
  response = "¡Dale, che! ¿Qué tarea querés que agregue? Decime, por ejemplo: 'agregar tarea comprar yerba'."
1376
+ voice_response = response
 
1377
 
1378
+ elif "completar tarea" in user_message_lower or "tarea lista" in user_message_lower:
1379
+ task_name = user_message.replace("completar tarea", "").replace("tarea lista", "", 1).strip()
1380
  if task_name:
1381
+ response, task_list_update = await nudge_generator.complete_task(user_obj.user_id, task_name)
1382
+ voice_response = response
 
1383
  else:
1384
  response = "¡Decime qué tarea completaste, así la saco de la lista! Por ejemplo: 'completar tarea ir al súper'."
1385
+ voice_response = response
1386
+
1387
+ # --- Intent: Simulated Browser Agent ---
1388
+ elif any(keyword in user_message_lower for keyword in ["abrir", "ir a", "navegar a", "buscar", "cerrar"]):
1389
+ if any(keyword in user_message_lower for keyword in ["abrir", "ir a", "navegar a"]):
1390
+ if "google" in user_message_lower:
1391
+ response = "¡Dale, abriendo Google en el navegador simulado!"
1392
+ new_url = "https://www.google.com.ar"
1393
+ js_code = f"""
1394
+ document.getElementById('simulated_browser_address').innerText = '{new_url}';
1395
+ document.getElementById('simulated_browser_content').innerHTML = '<p>¡Estás en Google! ¿Qué querés buscar?</p><img src="https://www.gstatic.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png" alt="Google Logo" style="height: 92px;">';
1396
+ """
1397
+ action_output, browser_url, browser_content = response, new_url, gr.HTML(js_code)
1398
+ elif "wikipedia" in user_message_lower:
1399
+ response = "¡Perfecto! Abriendo Wikipedia en el navegador simulado."
1400
+ new_url = "https://es.wikipedia.org"
1401
+ js_code = f"""
1402
+ document.getElementById('simulated_browser_address').innerText = '{new_url}';
1403
+ document.getElementById('simulated_browser_content').innerHTML = '<p>¡Estás en Wikipedia! ¿Qué querés buscar?</p><img src="https://upload.wikimedia.org/wikipedia/commons/8/80/Wikipedia-logo-v2.svg" alt="Wikipedia Logo" style="height: 100px;">';
1404
+ """
1405
+ action_output, browser_url, browser_content = response, new_url, gr.HTML(js_code)
1406
+ else:
1407
+ response = "¡Che, a qué página querés ir? Decime un sitio conocido como 'Google' o 'Wikipedia'."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1408
 
1409
+ elif "buscar" in user_message_lower:
1410
+ query = user_message_lower.split("buscar", 1)[1].strip()
1411
+ if query:
1412
+ response = f"¡Buscando '{query}' en el navegador simulado!"
1413
+ new_url = f"https://www.google.com.ar/search?q={query.replace(' ', '+')}"
1414
+ js_code = f"""
1415
+ document.getElementById('simulated_browser_address').innerText = '{new_url}';
1416
+ document.getElementById('simulated_browser_content').innerHTML = '<h3>Resultados de búsqueda para: {query}</h3><p><i>(Simulación de resultados)</i></p><ul><li>{query} - Wikipedia</li><li>Noticias sobre {query}</li><li>Imágenes de {query}</li></ul>';
1417
+ """
1418
+ action_output, browser_url, browser_content = response, new_url, gr.HTML(js_code)
1419
+ else:
1420
+ response = "¡Decime qué querés buscar, che! Por ejemplo: 'buscar el clima en Google'."
1421
+
1422
+ elif "cerrar" in user_message_lower:
1423
+ response = "¡Listo, cerrando la página actual en el navegador simulado!"
1424
+ new_url = "about:blank"
1425
+ js_code = """
1426
+ document.getElementById('simulated_browser_address').innerText = 'Ninguna página abierta';
1427
+ document.getElementById('simulated_browser_content').innerHTML = '<p>Navegador listo para tu próxima instrucción.</p>';
1428
+ """
1429
+ action_output, browser_url, browser_content = response, new_url, gr.HTML(js_code)
 
 
 
 
 
 
 
 
 
 
1430
 
1431
+ voice_response = response
1432
+
1433
+ # --- Intent: Nudge Request (Multi-step) ---
1434
+ else:
1435
+ current_step = conversation_context_state["step"]
1436
+ location = conversation_context_state["location"]
1437
+ activity = conversation_context_state["activity"]
1438
+ sentiment = conversation_context_state["sentiment"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1439
 
1440
+ if "susurro" in user_message_lower or "decime algo" in user_message_lower or conversation_context_state["pending_nudge_request"]:
1441
+ conversation_context_state["pending_nudge_request"] = True
1442
+
1443
+ if current_step == "initial":
1444
+ response = "¡Dale! Para cebarte un susurro a medida, contame, ¿dónde estás ahora? ¿En casa, en la oficina, en la calle?"
1445
+ conversation_context_state["step"] = "ask_location"
1446
+
1447
+ elif current_step == "ask_location":
1448
+ if any(k in user_message_lower for k in ["casa", "hogar"]): location = "Casa"
1449
+ elif any(k in user_message_lower for k in ["oficina", "laburo", "estudio"]): location = "Oficina/Estudio"
1450
+ elif any(k in user_message_lower for k in ["calle", "aire libre", "plaza"]): location = "Aire Libre/Calle"
1451
+ else:
1452
+ response = "No te entendí bien, che. ¿Estás en casa, en la oficina o en la calle?"
1453
+ if location:
1454
+ conversation_context_state["location"] = location
1455
+ response = f"Ah, estás en {location}. ¿Y en qué andás ahora? ¿Laburando, haciendo ejercicio, relajado, cocinando...?"
1456
+ conversation_context_state["step"] = "ask_activity"
1457
+
1458
+ elif current_step == "ask_activity":
1459
+ if any(k in user_message_lower for k in ["relajado", "tranqui"]): activity = "Relajado"
1460
+ elif any(k in user_message_lower for k in ["laburando", "trabajando"]): activity = "Trabajando"
1461
+ elif any(k in user_message_lower for k in ["ejercicio", "entrenando"]): activity = "Ejercicio"
1462
+ elif any(k in user_message_lower for k in ["cocinando", "comida"]): activity = "Cocinando"
1463
+ elif any(k in user_message_lower for k in ["partido", "fútbol", "tele"]): activity = "Viendo un partido"
1464
+ else:
1465
+ response = "No te pesqué esa, che. ¿Estás laburando, haciendo ejercicio, relajado, cocinando...?"
1466
+ if activity:
1467
+ conversation_context_state["activity"] = activity
1468
+ response = f"Entendido, en {location} y {activity}. ¿Y cómo te sentís? ¿Bien, cansado, bajoneado, motivado?"
1469
+ conversation_context_state["step"] = "ask_sentiment"
1470
+
1471
+ elif current_step == "ask_sentiment":
1472
+ if any(k in user_message_lower for k in ["bien", "joya"]): sentiment = "Bien"
1473
+ elif any(k in user_message_lower for k in ["cansado", "agotado"]): sentiment = "Cansado"
1474
+ elif any(k in user_message_lower for k in ["bajoneado", "triste"]): sentiment = "Bajoneado"
1475
+ elif any(k in user_message_lower for k in ["motivado", "con pilas"]): sentiment = "Motivado"
1476
+ else:
1477
+ response = "No te capto el sentimiento, che. ¿Estás bien, cansado, bajoneado o motivado?"
1478
+ if sentiment:
1479
+ conversation_context_state["sentiment"] = sentiment
1480
+ # We have everything, generate the nudge
1481
+ response, _, _, _, _ = await nudge_generator.generate_nudge(user_obj.user_id, location, activity, sentiment)
1482
+ # Reset context
1483
+ conversation_context_state = {"step": "initial", "pending_nudge_request": False, "location": None, "activity": None, "sentiment": None}
1484
+
1485
+ else:
1486
+ response = "¡No te entendí bien, che! Soy MateAI. Podés pedirme un 'susurro', un 'desafío', el 'oráculo', o manejar tus tareas y el navegador."
1487
+
1488
+ voice_response = response
1489
+
1490
+ # Update chat history with MateAI's response
1491
+ chat_history[-1] = (user_message, response)
1492
 
1493
+ return chat_history, "", conversation_context_state, voice_response, action_output, browser_url, browser_content, task_list_update, oracle_update
 
 
 
1494
 
1495
  # --- Conexión de Eventos ---
1496
  btn_crear_usuario.click(
 
1540
  inputs=[diario_reflexion],
1541
  outputs=gr.File(label="Descargar tu Diario")
1542
  )
1543
+
1544
+ # Define outputs for the unified conversational engine
1545
+ CONVERSATIONAL_OUTPUTS = [
1546
+ chatbot,
1547
+ msg_input,
1548
+ conversation_context_state,
1549
+ voice_output_text,
1550
+ simulated_action_output,
1551
+ simulated_browser_url,
1552
+ simulated_browser_content,
1553
+ tareas_pendientes_output,
1554
+ oraculo_output
1555
+ ]
1556
 
1557
  # --- Manejo de la entrada de voz y texto conversacional ---
 
 
1558
  msg_input.submit(
1559
  fn=_process_conversational_input,
1560
  inputs=[msg_input, chat_history, current_user_state, conversation_context_state],
1561
+ outputs=CONVERSATIONAL_OUTPUTS
1562
  )
1563
  btn_send_msg.click(
1564
  fn=_process_conversational_input,
1565
  inputs=[msg_input, chat_history, current_user_state, conversation_context_state],
1566
+ outputs=CONVERSATIONAL_OUTPUTS
1567
  )
1568
 
1569
+ # The hidden voice input button also connects to the unified engine
1570
  hidden_voice_submit_button.click(
1571
  fn=_process_conversational_input,
1572
  inputs=[voice_input_textbox, chat_history, current_user_state, conversation_context_state],
1573
+ outputs=[chatbot, voice_input_textbox, conversation_context_state, voice_output_text, simulated_action_output, simulated_browser_url, simulated_browser_content, tareas_pendientes_output, oraculo_output]
1574
  )
1575
 
1576
  # When the backend generates text for voice, it sends it to voice_output_text,
 
1583
  )
1584
 
1585
  # Lanza la interfaz de Gradio
1586
+ demo.launch(debug=True)