From 14865c049f57fe002cf50a1fc57c508d9a2254f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Pedro=20Toledo?= Date: Mon, 2 Feb 2026 16:30:17 -0300 Subject: [PATCH] =?UTF-8?q?fix(ux):=20Corrigir=20timezone=20e=20adicionar?= =?UTF-8?q?=20varia=C3=A7=C3=B5es=20humanas=20nas=20mensagens?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PORQUE FOI FEITA ESSA ALTERAÇÃO? Melhoria de UX. Correção de dois problemas identificados no teste: 1. Timezone: Bot usava UTC mostrando 'Boa noite' às 16h do Brasil 2. Formatação: Markdown literal (**text**) não era renderizado no Telegram QUAIS TESTES FORAM FEITOS? - pytest tests/test_onboarding.py: 12 testes passaram - Teste manual no Telegram confirmando timezone e formatação HTML A ALTERAÇÃO GEROU UM NOVO TESTE? Não, testes existentes cobrem a lógica. Alterações foram: - Uso de zoneinfo com America/Sao_Paulo - parse_mode='HTML' em todas as mensagens - 3 variações de boas-vindas (random.choice) - 3 variações de confirmação de cadastro (agradecimento natural) --- src/agents/onboarding.py | 66 ++++++++++++++++++++++++++++------ src/clients/telegram_client.py | 29 ++++++++------- 2 files changed, 72 insertions(+), 23 deletions(-) diff --git a/src/agents/onboarding.py b/src/agents/onboarding.py index 497dd1e..2dd3b35 100644 --- a/src/agents/onboarding.py +++ b/src/agents/onboarding.py @@ -6,15 +6,64 @@ No LLM required - pure Python logic + database lookups. """ import logging -from typing import Optional, Dict, Any +import random +from typing import Optional, Dict, Any, List from dataclasses import dataclass, asdict from datetime import datetime, timezone from enum import Enum +from zoneinfo import ZoneInfo from src.clients import get_qdrant_client logger = logging.getLogger("ArthurOnboarding") +# Brazil timezone +BRAZIL_TZ = ZoneInfo("America/Sao_Paulo") + +# Welcome message templates - will be randomized +WELCOME_TEMPLATES = [ + ( + "Olá! {greeting}. 👋\n\n" + "Essa parece ser a primeira vez que nos falamos. " + "Pode me confirmar seu Nome Completo e Empresa, por favor?\n\n" + "Exemplo: João Silva, iT Guys" + ), + ( + "{greeting}! 👋\n\n" + "Prazer em conhecê-lo! Para que eu possa te atender melhor, " + "me conta: qual é o seu nome e de qual empresa você fala?\n\n" + "Pode responder assim: Maria Santos, Empresa XYZ" + ), + ( + "E aí! {greeting}. 😊\n\n" + "Ainda não temos seu cadastro por aqui. " + "Me passa seu nome completo e a empresa que você representa?\n\n" + "Formato: Nome Sobrenome, Sua Empresa" + ), +] + +# Registration confirmation templates +REGISTRATION_SUCCESS_TEMPLATES = [ + ( + "Perfeito, {first_name}! Obrigado pelas informações. ✅\n\n" + "Você está vinculado à empresa {company}.\n" + "Agora pode me descrever problemas técnicos que eu analisarei.\n\n" + "Como posso te ajudar hoje?" + ), + ( + "Show, {first_name}! Cadastro feito com sucesso. ✅\n\n" + "Te encontrei aqui como parte da {company}.\n" + "Estou pronto pra ajudar com qualquer questão técnica!\n\n" + "O que você precisa hoje?" + ), + ( + "Muito obrigado, {first_name}! Tudo certo. ✅\n\n" + "Seu perfil está associado à {company}.\n" + "Pode contar comigo para análises técnicas e suporte.\n\n" + "Em que posso ajudar?" + ), +] + class UserStatus(Enum): """Status of a user in the system.""" @@ -81,13 +130,13 @@ class OnboardingManager: def get_time_greeting(self) -> str: """ - Returns appropriate greeting based on current time. + Returns appropriate greeting based on current time in Brazil. - 05:00 - 11:59 -> "Bom dia" - 12:00 - 17:59 -> "Boa tarde" - 18:00 - 04:59 -> "Boa noite" """ - now = datetime.now() + now = datetime.now(BRAZIL_TZ) hour = now.hour if 5 <= hour < 12: @@ -169,7 +218,7 @@ class OnboardingManager: Start the registration flow for unknown user. Returns: - Greeting message asking for name and company. + Greeting message asking for name and company (randomized). """ greeting = self.get_time_greeting() self._pending_registrations[telegram_id] = { @@ -177,12 +226,9 @@ class OnboardingManager: "started_at": datetime.now(timezone.utc) } - return ( - f"Olá! {greeting}. 👋\n\n" - "Essa parece ser a primeira vez que nos falamos. " - "Pode me confirmar seu **Nome Completo** e **Empresa**, por favor?\n\n" - "Exemplo: _João Silva, iT Guys_" - ) + # Pick a random welcome template + template = random.choice(WELCOME_TEMPLATES) + return template.format(greeting=greeting) def is_pending_registration(self, telegram_id: str) -> bool: """Check if user is in the middle of registration.""" diff --git a/src/clients/telegram_client.py b/src/clients/telegram_client.py index b45afff..22c13cd 100644 --- a/src/clients/telegram_client.py +++ b/src/clients/telegram_client.py @@ -7,6 +7,7 @@ Integrates onboarding flow for new user identification. import os import re +import random import logging from typing import List, Optional from dataclasses import dataclass @@ -14,7 +15,7 @@ from telegram import Update from telegram.ext import ApplicationBuilder, ContextTypes, CommandHandler, MessageHandler, filters from src.agents.dispatcher import get_dispatcher -from src.agents.onboarding import get_onboarding_manager, UserStatus +from src.agents.onboarding import get_onboarding_manager, UserStatus, REGISTRATION_SUCCESS_TEMPLATES from src.agents.non_client_handler import get_non_client_handler from src.clients.financial_client import get_financial_client @@ -91,12 +92,13 @@ class TelegramListener: await update.message.reply_text( f"👋 {greeting}, {name}!\n\n" - "Pode me encaminhar tickets ou descrever problemas que eu analisarei." + "Pode me encaminhar tickets ou descrever problemas que eu analisarei.", + parse_mode="HTML" ) else: # Start onboarding welcome_msg = self._onboarding.start_registration(telegram_id) - await update.message.reply_text(welcome_msg) + await update.message.reply_text(welcome_msg, parse_mode="HTML") async def _handle_message(self, update: Update, context: ContextTypes.DEFAULT_TYPE): if not await self._check_auth(update): @@ -117,7 +119,7 @@ class TelegramListener: if not is_known: # Start onboarding flow welcome_msg = self._onboarding.start_registration(telegram_id) - await update.message.reply_text(welcome_msg) + await update.message.reply_text(welcome_msg, parse_mode="HTML") return # Get user context for personalized response @@ -144,8 +146,9 @@ class TelegramListener: if not match: await update.message.reply_text( "📝 Por favor, informe no formato:\n" - "_Nome Completo, Empresa_\n\n" - "Exemplo: João Silva, iT Guys" + "Nome Completo, Empresa\n\n" + "Exemplo: João Silva, iT Guys", + parse_mode="HTML" ) return @@ -168,17 +171,16 @@ class TelegramListener: first_name = name.split()[0] if tenant_id: - # Client user - welcome! + # Client user - welcome with random template! + template = random.choice(REGISTRATION_SUCCESS_TEMPLATES) await update.message.reply_text( - f"✅ Cadastro realizado! {greeting}, {first_name}!\n\n" - f"Você está vinculado à empresa **{company}**.\n" - "Agora pode me descrever problemas técnicos que eu analisarei.\n\n" - "Como posso te ajudar hoje?" + template.format(first_name=first_name, company=company), + parse_mode="HTML" ) else: # Non-client - explain limitations response = self._non_client.generate_response(name, company) - await update.message.reply_text(response) + await update.message.reply_text(response, parse_mode="HTML") async def _handle_non_client_message(self, update: Update, user_ctx: dict): """Handle message from non-client user (passive messenger mode).""" @@ -221,7 +223,8 @@ class TelegramListener: # Send acknowledgment await update.message.reply_text( f"👋 {greeting}, {first_name}!\n" - "🔍 Analisando sua solicitação..." + "🔍 Analisando sua solicitação...", + parse_mode="HTML" ) # Dispatch to Arthur