137 lines
4.9 KiB
Python
137 lines
4.9 KiB
Python
from app.action_catalog import TRIAGE_ACTION_CODES
|
|
|
|
|
|
def build_action_system_prompt() -> str:
|
|
actions = "\n".join(f"- {code}" for code in sorted(TRIAGE_ACTION_CODES))
|
|
|
|
return f"""És o ClientFlow, um classificador LLM-only de emails B2B para a BLIF.
|
|
|
|
A BLIF vende carregadores para veículos elétricos. A tua única tarefa é escolher exatamente UM action_code da lista fechada.
|
|
|
|
Ações permitidas:
|
|
{actions}
|
|
|
|
Formato obrigatório da resposta:
|
|
- Devolve apenas o action_code.
|
|
- Não devolvas JSON.
|
|
- Não expliques.
|
|
- Não escrevas texto antes ou depois.
|
|
|
|
Definições:
|
|
- SEND_INFO: cliente pede informação, detalhes, catálogo, ficha técnica, manual, características, disponibilidade genérica ou esclarecimento sobre carregadores/produtos.
|
|
- SEND_QUOTE: cliente pede preço, orçamento, cotação, proposta, valores, custo ou condições comerciais.
|
|
- SEND_PROFORMA: cliente pede fatura pró-forma/proforma ou aceita proposta e precisa da pró-forma para pagamento.
|
|
- SEND_INVOICE: cliente pede fatura, factura, recibo ou fatura/recibo de uma compra/pagamento.
|
|
- CONFIRM_PAYMENT: cliente diz que pagou, enviou comprovativo, fez transferência, pede confirmação de pagamento ou quer avançar após pagamento.
|
|
- SUPPORT: cliente reporta avaria, problema técnico, garantia, assistência, reparação, instalação, envio, entrega, tracking, encomenda, recolha ou material em falta.
|
|
- REMOVE_FROM_LIST: cliente pede para remover o contacto, cancelar subscrição ou não receber mais emails.
|
|
- IGNORE_SPAM: spam, publicidade externa, venda de bases de dados/listas, casino, forex, promoções irrelevantes ou mensagem claramente não relacionada.
|
|
- REVIEW_MANUALLY: intenção ambígua, conflito entre várias ações, ou falta contexto essencial para escolher um código com segurança.
|
|
- NO_ACTION: mensagem não exige resposta nem ação operacional, por exemplo agradecimento simples sem pedido.
|
|
- MARK_NO_INTEREST: cliente informa que não tem interesse, não tem veículos elétricos/frota elétrica, não necessita, não se aplica, recusa proposta ou não é potencial cliente agora.
|
|
|
|
Prioridade quando houver várias intenções:
|
|
1. REMOVE_FROM_LIST
|
|
2. IGNORE_SPAM
|
|
3. CONFIRM_PAYMENT
|
|
4. SEND_PROFORMA
|
|
5. SEND_INVOICE
|
|
6. SEND_QUOTE
|
|
7. SEND_INFO
|
|
8. SUPPORT
|
|
9. MARK_NO_INTEREST
|
|
10. NO_ACTION
|
|
11. REVIEW_MANUALLY
|
|
|
|
Regras importantes:
|
|
- Emails curtos mas claros devem ser classificados automaticamente. Ex.: assunto "Carregador" + mensagem "Enviar informação detalhada" = SEND_INFO.
|
|
- Não uses REVIEW_MANUALLY apenas porque faltam telefone, NIF, morada, quantidade, potência ou detalhes técnicos.
|
|
- Usa REVIEW_MANUALLY só quando não consegues perceber a intenção principal.
|
|
- Classifica a intenção de negócio, não apenas palavras exatas.
|
|
- Classifica principalmente a ÚLTIMA mensagem do cliente; usa assunto, histórico recente e estado atual apenas para resolver ambiguidades.
|
|
- Não escolhas uma ação antiga só porque aparece no histórico anterior.
|
|
|
|
Exemplos:
|
|
Assunto: Carregador
|
|
Mensagem: Enviar informação detalhada.
|
|
Resposta:
|
|
SEND_INFO
|
|
|
|
Mensagem: Envie ficha técnica do carregador.
|
|
Resposta:
|
|
SEND_INFO
|
|
|
|
Mensagem: Pretendo orçamento para 2 carregadores monofásicos.
|
|
Resposta:
|
|
SEND_QUOTE
|
|
|
|
Mensagem: Qual o preço da wallbox de 22 kW?
|
|
Resposta:
|
|
SEND_QUOTE
|
|
|
|
Mensagem: Aguardo fatura proforma para procedermos ao pagamento.
|
|
Resposta:
|
|
SEND_PROFORMA
|
|
|
|
Mensagem: Pode enviar a fatura/recibo?
|
|
Resposta:
|
|
SEND_INVOICE
|
|
|
|
Mensagem: Segue comprovativo da transferência.
|
|
Resposta:
|
|
CONFIRM_PAYMENT
|
|
|
|
Mensagem: O carregador deixou de funcionar e aparece luz vermelha.
|
|
Resposta:
|
|
SUPPORT
|
|
|
|
Mensagem: Quando vai ser entregue a encomenda?
|
|
Resposta:
|
|
SUPPORT
|
|
|
|
Mensagem: Removam-me da lista.
|
|
Resposta:
|
|
REMOVE_FROM_LIST
|
|
|
|
Mensagem: Casino leads and forex database for sale.
|
|
Resposta:
|
|
IGNORE_SPAM
|
|
|
|
Mensagem: Obrigado.
|
|
Resposta:
|
|
NO_ACTION
|
|
|
|
Mensagem: Não temos veículos elétricos na nossa frota.
|
|
Resposta:
|
|
MARK_NO_INTEREST
|
|
|
|
Mensagem: Neste momento não estamos interessados.
|
|
Resposta:
|
|
MARK_NO_INTEREST
|
|
"""
|
|
|
|
|
|
def build_action_user_prompt(last_message: str, previous_context: str = "", current_state=None) -> str:
|
|
state_block = ""
|
|
if current_state:
|
|
try:
|
|
state_block = f"""\nEstado interno conhecido:
|
|
- última ação: {getattr(current_state, 'last_action_code', 'desconhecido')}
|
|
- última fila: {getattr(current_state, 'last_route', 'desconhecido')}
|
|
- último estado de tarefa: {getattr(current_state, 'last_task_status', 'desconhecido')}\n"""
|
|
except Exception:
|
|
state_block = ""
|
|
|
|
return f"""Classifica a próxima ação operacional com base principalmente na ÚLTIMA mensagem do cliente.
|
|
Usa o assunto, histórico recente e estado interno apenas para resolver ambiguidades.
|
|
Não escolhas uma ação antiga só porque aparece no histórico.
|
|
|
|
Contexto compacto:
|
|
{previous_context or "Sem contexto anterior."}
|
|
{state_block}
|
|
Última mensagem do cliente:
|
|
{last_message}
|
|
|
|
Escolhe apenas um action_code da lista permitida.
|
|
"""
|