Update app.py
Browse files
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,
|
| 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;"
|
| 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.
|
| 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 |
-
|
| 1339 |
-
|
| 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 |
-
|
| 1353 |
-
|
| 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 |
-
|
| 1370 |
-
|
| 1371 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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(
|
| 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
|
| 1384 |
-
return chat_history, "", conversation_context_state, mateai_response, gr.skip(), gr.skip(), gr.skip()
|
| 1385 |
|
| 1386 |
-
#
|
| 1387 |
-
|
| 1388 |
-
|
| 1389 |
-
|
| 1390 |
-
|
|
|
|
|
|
|
|
|
|
| 1391 |
|
| 1392 |
-
|
| 1393 |
-
|
| 1394 |
-
|
| 1395 |
-
|
|
|
|
| 1396 |
|
| 1397 |
-
|
| 1398 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1399 |
if task_name:
|
| 1400 |
-
|
| 1401 |
-
|
| 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 |
-
|
| 1406 |
-
return chat_history, "", conversation_context_state, response, gr.skip(), gr.skip(), gr.skip()
|
| 1407 |
|
| 1408 |
-
|
| 1409 |
-
task_name =
|
| 1410 |
if task_name:
|
| 1411 |
-
|
| 1412 |
-
|
| 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 |
-
|
| 1417 |
-
|
| 1418 |
-
|
| 1419 |
-
|
| 1420 |
-
|
| 1421 |
-
|
| 1422 |
-
|
| 1423 |
-
|
| 1424 |
-
|
| 1425 |
-
|
| 1426 |
-
|
| 1427 |
-
|
| 1428 |
-
|
| 1429 |
-
|
| 1430 |
-
|
| 1431 |
-
|
| 1432 |
-
|
| 1433 |
-
|
| 1434 |
-
|
| 1435 |
-
|
| 1436 |
-
|
| 1437 |
-
|
| 1438 |
-
|
| 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 |
-
|
| 1505 |
-
|
| 1506 |
-
|
| 1507 |
-
|
| 1508 |
-
|
| 1509 |
-
|
| 1510 |
-
|
| 1511 |
-
|
| 1512 |
-
|
| 1513 |
-
|
| 1514 |
-
|
| 1515 |
-
|
| 1516 |
-
|
| 1517 |
-
|
| 1518 |
-
|
| 1519 |
-
|
| 1520 |
-
|
| 1521 |
-
|
| 1522 |
-
|
| 1523 |
-
|
| 1524 |
-
|
| 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 |
-
|
| 1537 |
-
|
| 1538 |
-
|
| 1539 |
-
|
| 1540 |
-
|
| 1541 |
-
|
| 1542 |
-
|
| 1543 |
-
|
| 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["
|
| 1562 |
-
|
| 1563 |
-
|
| 1564 |
-
|
| 1565 |
-
|
| 1566 |
-
|
| 1567 |
-
|
| 1568 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1569 |
|
| 1570 |
-
|
| 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=
|
| 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=
|
| 1636 |
)
|
| 1637 |
|
| 1638 |
-
#
|
| 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)
|