Skip to content
mobius1qwe edited this page Nov 13, 2026 · 2 revisions

Home > Chatbot

Chatbot

Important

Em desenvolvimento (2.0). Ainda não está numa versão lançada e pode mudar.

Nível: intermediário

Em uma frase: o módulo de chat do RAL liga a sua aplicação a aplicativos de mensagem (Telegram, Discord, Slack, Teams e gateways de WhatsApp) com um robô só: as mensagens de todos os canais chegam no mesmo formato, os comandos e as respostas são escritos uma vez, e o que um canal não sabe mostrar vira texto.

Você vai precisar: RAL 2.0 com o pacote RALModuleChatPackage (e o RALModuleChatDsgn para a IDE) e o pacote de cada canal, como o RALModuleChatTelegramPackage (Telegram). Para receber por webhook, um servidor RAL acessível pela internet com HTTPS (HTTPS).

Os componentes

componente paleta para
TRALChatBot RAL - Modules o robô: canais, comandos, eventos, sessões
TRALChatWebhookModule RAL - Modules recebe os webhooks dos canais em qualquer servidor RAL
TRALChatStore RAL - Modules guarda as sessões das conversas num arquivo que sobrevive a queda de energia
TRALChatTelegram RAL - Modules o canal do Telegram (Telegram)
TRALChatGateway RAL - Modules gateways REST: Evolution API, WPPConnect, Z-API ou outro (gateways)
TRALChatDiscord RAL - Modules o canal do Discord (Discord)
TRALChatSlack RAL - Modules o canal do Slack (Slack)
TRALChatTeams RAL - Modules o canal do Microsoft Teams (Teams)
TRALChatFlow RAL - Modules conversa em etapas montada no Object Inspector (conversa em etapas)
TRALChatDBStore RAL - Modules as sessões num banco, para várias instâncias (conversa em etapas)

Montando

uses RALChatMessage, RALChatChannel, RALChatBot, RALChatWebhook, RALChatTelegram;

  FBot := TRALChatBot.Create(Self);
  FBot.OnMessage := ChegouMensagem;
  FBot.OnCallback := EscolheuBotao;
  FBot.OnError := DeuErro;

  FTelegram := TRALChatTelegram.Create(Self);
  FTelegram.TokenSource := tsEnvironment;      // o token vem da variável de ambiente
  FTelegram.TokenName := 'TELEGRAM_TOKEN';
  FTelegram.Bot := FBot;
  FBot.Channels.Add.Channel := FTelegram;

  FWebhook := TRALChatWebhookModule.Create(Self);
  FWebhook.Bot := FBot;
  FWebhook.Server := FServidor;                // qualquer servidor RAL: rota /telegram

Cada canal ganha uma rota com o seu ChannelName (/telegram, por exemplo). Os plugins do servidor (lista de endereços, limite de requisições) valem para ela como para qualquer rota.

Respondendo

procedure TForm1.ChegouMensagem(Sender: TObject; AChannel: TRALChatChannel;
  AMessage: TRALChatMessage);
var
  vResp: TRALChatMessage;
begin
  if AMessage.Kind <> ckText then
    Exit;
  vResp := TRALChatMessage.Create;
  try
    vResp.Text := 'Quer ver o seu pedido?';
    vResp.AddButton('sim', 'Sim');
    vResp.AddButton('nao', 'Não');
    FBot.Reply(AMessage, vResp);               // o robô copia: a mensagem continua sua
  finally
    vResp.Free;
  end;
end;

procedure TForm1.EscolheuBotao(Sender: TObject; AChannel: TRALChatChannel;
  AMessage: TRALChatMessage);
begin
  if AMessage.CallbackData = 'sim' then
    FBot.Reply(AMessage, 'Pedido 1234: saiu para entrega.');
end;
  • Reply responde na mesma conversa; Send(canal, mensagem) manda para qualquer conversa (ChatId); SendWait espera e devolve o id da mensagem enviada; Edit, Delete e SendTyping ("digitando...") onde o canal permite.
  • Tudo que sai entra numa fila por canal, com novas tentativas e os limites de cada plataforma (Rates do canal: total, por conversa e por par). O resultado chega em OnSent ou, depois das tentativas, em OnSendFailed.
  • A mensagem traz texto, botões (Buttons), teclado (AddKeyboardRow), listas, mídia (Media: imagem, áudio, vídeo, documento), localização, contato e ReplyTo. Com Raw (e KeepRaw no canal) você vê o que a plataforma mandou.

Comandos

Em vez de um if grande no OnMessage, cadastre os comandos em Commands (pelo editor da IDE ou no código):

  vCmd := FBot.Commands.Add;
  vCmd.Name := 'inicio';
  vCmd.Match := cmmCommand;    // /start
  vCmd.Pattern := 'start';
  vCmd.OnExecute := ComandoInicio;

procedure TForm1.ComandoInicio(Sender: TObject; AChannel: TRALChatChannel;
  AMessage: TRALChatMessage; var AHandled: Boolean);
begin
  FBot.Reply(AMessage, 'Olá! Mande o número do pedido.');
end;

Match diz como o texto é comparado: comando com barra (cmmCommand), a palavra inteira (cmmKeyword), começo (cmmPrefix), contém (cmmContains), expressão regular (cmmRegex) ou o id de um botão (cmmCallback). Channels limita o comando a alguns canais. Mensagem que nenhum comando pega vai para OnMessage (ou OnCallback).

O que o canal não sabe mostrar

Nem todo canal tem botões, listas ou edição. Supports(canal, ccButtons) pergunta; com Fallback = cfDegrade (o padrão) o robô transforma os botões numa lista numerada, e a resposta "2" volta como se a pessoa tivesse clicado no segundo botão. Com cfRaise o envio falha com ERALChatError.

Sessões

O robô guarda um estado por conversa (o passo de um cadastro, o carrinho):

  FBot.Sessions.SetValue(AMessage.ChannelName, AMessage.ChatId, 'passo', 'cpf');
  vPasso := FBot.Sessions.GetValue(AMessage.ChannelName, AMessage.ChatId, 'passo');
  • A sessão expira depois de SessionTimeout segundos sem mensagem (30 minutos).
  • Sem nada configurado ela fica na memória. Com PersistFile (ou um TRALChatStore em Store) cada mudança é gravada no disco antes de seguir: reiniciar o programa no meio de uma conversa não perde o passo.

O webhook

  • O pedido é conferido pela assinatura ou pelo segredo do canal antes de qualquer outra coisa; o que não confere recebe 401 e não chega ao robô.
  • A plataforma recebe 200 na hora e as mensagens vão para uma fila; Workers threads rodam os seus eventos, e as mensagens de uma mesma conversa chegam sempre em ordem. Os eventos rodam nessas threads, não na thread principal: para mexer na tela use TThread.Queue.
  • Uma mensagem reenviada pela plataforma (a mesma EventId dentro de DedupWindow) não chega duas vezes.
  • Fila cheia (MaxQueue) responde 503: a plataforma tenta de novo mais tarde.

O token

O token do canal nunca aparece em log nem em mensagem de erro. Ele pode vir de três lugares (TokenSource): da propriedade Token (fica no .dfm/.lfm: evite em repositório), de uma variável de ambiente (tsEnvironment, com o nome em TokenName) ou da primeira linha de um arquivo (tsFile).

Erros comuns

sintoma causa o que fazer
o webhook responde 401 segredo ou assinatura diferente do configurado na plataforma confira o segredo do canal e registre o webhook de novo
"access violation" ao mexer num controle da tela no evento o evento roda numa thread do módulo use TThread.Queue
mensagem respondida duas vezes duas instâncias do programa recebendo o mesmo canal uma instância por canal, ou webhook em uma só
botões chegam como lista numerada o canal não tem botões é o Fallback; use Supports para escolher outro texto

Veja também

Começar

Servidor

MQTT 🚧

E-mail 🚧

Chatbot 🚧

Cliente

Motores

Avançado

Ajuda

🚧 = em desenvolvimento, pode mudar

Clone this wiki locally