fix(ux): Corrigir timezone e adicionar variações humanas nas mensagens
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)
This commit is contained in:
parent
8005c0c6a3
commit
14865c049f
|
|
@ -6,15 +6,64 @@ No LLM required - pure Python logic + database lookups.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from typing import Optional, Dict, Any
|
import random
|
||||||
|
from typing import Optional, Dict, Any, List
|
||||||
from dataclasses import dataclass, asdict
|
from dataclasses import dataclass, asdict
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
from src.clients import get_qdrant_client
|
from src.clients import get_qdrant_client
|
||||||
|
|
||||||
logger = logging.getLogger("ArthurOnboarding")
|
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 <b>Nome Completo</b> e <b>Empresa</b>, por favor?\n\n"
|
||||||
|
"Exemplo: <i>João Silva, iT Guys</i>"
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"{greeting}! 👋\n\n"
|
||||||
|
"Prazer em conhecê-lo! Para que eu possa te atender melhor, "
|
||||||
|
"me conta: qual é o seu <b>nome</b> e de qual <b>empresa</b> você fala?\n\n"
|
||||||
|
"Pode responder assim: <i>Maria Santos, Empresa XYZ</i>"
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"E aí! {greeting}. 😊\n\n"
|
||||||
|
"Ainda não temos seu cadastro por aqui. "
|
||||||
|
"Me passa seu <b>nome completo</b> e a <b>empresa</b> que você representa?\n\n"
|
||||||
|
"Formato: <i>Nome Sobrenome, Sua Empresa</i>"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Registration confirmation templates
|
||||||
|
REGISTRATION_SUCCESS_TEMPLATES = [
|
||||||
|
(
|
||||||
|
"Perfeito, <b>{first_name}</b>! Obrigado pelas informações. ✅\n\n"
|
||||||
|
"Você está vinculado à empresa <b>{company}</b>.\n"
|
||||||
|
"Agora pode me descrever problemas técnicos que eu analisarei.\n\n"
|
||||||
|
"Como posso te ajudar hoje?"
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Show, <b>{first_name}</b>! Cadastro feito com sucesso. ✅\n\n"
|
||||||
|
"Te encontrei aqui como parte da <b>{company}</b>.\n"
|
||||||
|
"Estou pronto pra ajudar com qualquer questão técnica!\n\n"
|
||||||
|
"O que você precisa hoje?"
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Muito obrigado, <b>{first_name}</b>! Tudo certo. ✅\n\n"
|
||||||
|
"Seu perfil está associado à <b>{company}</b>.\n"
|
||||||
|
"Pode contar comigo para análises técnicas e suporte.\n\n"
|
||||||
|
"Em que posso ajudar?"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class UserStatus(Enum):
|
class UserStatus(Enum):
|
||||||
"""Status of a user in the system."""
|
"""Status of a user in the system."""
|
||||||
|
|
@ -81,13 +130,13 @@ class OnboardingManager:
|
||||||
|
|
||||||
def get_time_greeting(self) -> str:
|
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"
|
- 05:00 - 11:59 -> "Bom dia"
|
||||||
- 12:00 - 17:59 -> "Boa tarde"
|
- 12:00 - 17:59 -> "Boa tarde"
|
||||||
- 18:00 - 04:59 -> "Boa noite"
|
- 18:00 - 04:59 -> "Boa noite"
|
||||||
"""
|
"""
|
||||||
now = datetime.now()
|
now = datetime.now(BRAZIL_TZ)
|
||||||
hour = now.hour
|
hour = now.hour
|
||||||
|
|
||||||
if 5 <= hour < 12:
|
if 5 <= hour < 12:
|
||||||
|
|
@ -169,7 +218,7 @@ class OnboardingManager:
|
||||||
Start the registration flow for unknown user.
|
Start the registration flow for unknown user.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Greeting message asking for name and company.
|
Greeting message asking for name and company (randomized).
|
||||||
"""
|
"""
|
||||||
greeting = self.get_time_greeting()
|
greeting = self.get_time_greeting()
|
||||||
self._pending_registrations[telegram_id] = {
|
self._pending_registrations[telegram_id] = {
|
||||||
|
|
@ -177,12 +226,9 @@ class OnboardingManager:
|
||||||
"started_at": datetime.now(timezone.utc)
|
"started_at": datetime.now(timezone.utc)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
# Pick a random welcome template
|
||||||
f"Olá! {greeting}. 👋\n\n"
|
template = random.choice(WELCOME_TEMPLATES)
|
||||||
"Essa parece ser a primeira vez que nos falamos. "
|
return template.format(greeting=greeting)
|
||||||
"Pode me confirmar seu **Nome Completo** e **Empresa**, por favor?\n\n"
|
|
||||||
"Exemplo: _João Silva, iT Guys_"
|
|
||||||
)
|
|
||||||
|
|
||||||
def is_pending_registration(self, telegram_id: str) -> bool:
|
def is_pending_registration(self, telegram_id: str) -> bool:
|
||||||
"""Check if user is in the middle of registration."""
|
"""Check if user is in the middle of registration."""
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ Integrates onboarding flow for new user identification.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import random
|
||||||
import logging
|
import logging
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
@ -14,7 +15,7 @@ from telegram import Update
|
||||||
from telegram.ext import ApplicationBuilder, ContextTypes, CommandHandler, MessageHandler, filters
|
from telegram.ext import ApplicationBuilder, ContextTypes, CommandHandler, MessageHandler, filters
|
||||||
|
|
||||||
from src.agents.dispatcher import get_dispatcher
|
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.agents.non_client_handler import get_non_client_handler
|
||||||
from src.clients.financial_client import get_financial_client
|
from src.clients.financial_client import get_financial_client
|
||||||
|
|
||||||
|
|
@ -91,12 +92,13 @@ class TelegramListener:
|
||||||
|
|
||||||
await update.message.reply_text(
|
await update.message.reply_text(
|
||||||
f"👋 {greeting}, {name}!\n\n"
|
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:
|
else:
|
||||||
# Start onboarding
|
# Start onboarding
|
||||||
welcome_msg = self._onboarding.start_registration(telegram_id)
|
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):
|
async def _handle_message(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
if not await self._check_auth(update):
|
if not await self._check_auth(update):
|
||||||
|
|
@ -117,7 +119,7 @@ class TelegramListener:
|
||||||
if not is_known:
|
if not is_known:
|
||||||
# Start onboarding flow
|
# Start onboarding flow
|
||||||
welcome_msg = self._onboarding.start_registration(telegram_id)
|
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
|
return
|
||||||
|
|
||||||
# Get user context for personalized response
|
# Get user context for personalized response
|
||||||
|
|
@ -144,8 +146,9 @@ class TelegramListener:
|
||||||
if not match:
|
if not match:
|
||||||
await update.message.reply_text(
|
await update.message.reply_text(
|
||||||
"📝 Por favor, informe no formato:\n"
|
"📝 Por favor, informe no formato:\n"
|
||||||
"_Nome Completo, Empresa_\n\n"
|
"<i>Nome Completo, Empresa</i>\n\n"
|
||||||
"Exemplo: João Silva, iT Guys"
|
"Exemplo: João Silva, iT Guys",
|
||||||
|
parse_mode="HTML"
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -168,17 +171,16 @@ class TelegramListener:
|
||||||
first_name = name.split()[0]
|
first_name = name.split()[0]
|
||||||
|
|
||||||
if tenant_id:
|
if tenant_id:
|
||||||
# Client user - welcome!
|
# Client user - welcome with random template!
|
||||||
|
template = random.choice(REGISTRATION_SUCCESS_TEMPLATES)
|
||||||
await update.message.reply_text(
|
await update.message.reply_text(
|
||||||
f"✅ Cadastro realizado! {greeting}, {first_name}!\n\n"
|
template.format(first_name=first_name, company=company),
|
||||||
f"Você está vinculado à empresa **{company}**.\n"
|
parse_mode="HTML"
|
||||||
"Agora pode me descrever problemas técnicos que eu analisarei.\n\n"
|
|
||||||
"Como posso te ajudar hoje?"
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# Non-client - explain limitations
|
# Non-client - explain limitations
|
||||||
response = self._non_client.generate_response(name, company)
|
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):
|
async def _handle_non_client_message(self, update: Update, user_ctx: dict):
|
||||||
"""Handle message from non-client user (passive messenger mode)."""
|
"""Handle message from non-client user (passive messenger mode)."""
|
||||||
|
|
@ -221,7 +223,8 @@ class TelegramListener:
|
||||||
# Send acknowledgment
|
# Send acknowledgment
|
||||||
await update.message.reply_text(
|
await update.message.reply_text(
|
||||||
f"👋 {greeting}, {first_name}!\n"
|
f"👋 {greeting}, {first_name}!\n"
|
||||||
"🔍 Analisando sua solicitação..."
|
"🔍 Analisando sua solicitação...",
|
||||||
|
parse_mode="HTML"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Dispatch to Arthur
|
# Dispatch to Arthur
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue