Crie um chatbot do WhatsApp com Ruby, Sinatra e Twilio

February 17, 2020
Escrito por
Phil Nash
Twilion

Crie um chatbot do WhatsApp com Ruby, Sinatra e Twilio

Chatbots são programas que se comunicam de alguma forma com seres humanos. Eles podem ser muito básicos, responder a palavras-chave ou frases, ou usar algo como o Twilio Autopilot para aproveitar a compreensão de linguagem natural (CLN) para fornecer uma experiência mais rica e construir conversas mais complicadas.

Neste tutorial, veremos como é fácil começar a criar chatbots para WhatsApp usando a API da Twilio para WhatsApp e a estrutura da Web Sinatra em Ruby. Aqui está um exemplo da conversa que vamos construir:

exemplo de funcionamento do app no WhatsApp.

De que você vai precisar

Para criar seu próprio bot para WhatsApp junto com este tutorial, você precisará do seguinte:

Configure seu sandbox do WhatsApp

Para iniciar um bot no WhatsApp, você deve passar por um processo de aprovação com o WhatsApp, mas a Twilio permite que você crie e teste seus aplicativos do WhatsApp usando nosso sandbox. Vamos começar configurando o sandbox para usar com sua conta do WhatsApp.

O console da Twilio orienta você pelo processo, mas veja o que precisa fazer:

  1. Vá para o sandbox do WhatsApp na área do console da Twilio ou navegue do console para Programmable SMS (SMS programável) e, em seguida, WhatsApp
  2. A página terá o número do sandbox do WhatsApp nela. Abra seu aplicativo WhatsApp e inicie uma nova mensagem para esse número
  3. A página também tem a mensagem que você precisa enviar, que é "join" mais duas palavras aleatórias, como "join.flagrant-pigeon". Envie sua mensagem para o número do sandbox

Tela do console da Twilio com o número da Sandbox API e código de vínculo.

Quando receber uma mensagem de volta, você estará pronto para trabalhar com o sandbox.

Como criar o aplicativo em Ruby

Vamos iniciar um novo aplicativo em Ruby para criar nosso bot. Comece criando um novo diretório para trabalhar. Em seguida, inicialize um novo arquivo Gemfile no app e crie alguns arquivos necessários:

mkdir whatsapp-bot
cd whatsapp-bot
bundle init
mkdir config
touch bot.rb config.ru config/env.yml

Adicione as gems que usaremos para criar este aplicativo:

bundle add sinatra twilio-ruby http envyable

config/env.yml vai armazenar nossa configuração de aplicativo e o Envyable vai carregá-la no ambiente. Só precisamos armazenar uma parte da configuração para este aplicativo: seu token de autenticação da Twilio que você pode encontrar no Dashboard do console da Twilio. Adicione seu token de autenticação a config/env.yml:

TWILIO_AUTH_TOKEN: YOUR_TWILIO_AUTH_TOKEN

Usaremos config.ru para carregar o aplicativo e a configuração, e para executá-lo. Copie o seguinte para config.ru:

require 'bundler'
Bundler.require

Envyable.load('./config/env.yml')

require './bot.rb'
run WhatsAppBot

Vamos testar se tudo está funcionando como esperado, criando um aplicativo do Sinatra "Hello World!". Abra bot.rb e digite o seguinte código:

require "sinatra/base"

class WhatsAppBot < Sinatra::Base
  get '/' do
    "Hello World!"
  end
end

Na linha de comando, inicie o aplicativo com:

bundle exec rackup config.ru

O aplicativo será iniciado no localhost:9292. Abra-o em seu navegador e você verá o texto "Hello World!".

Como criar um chatbot

Agora que nosso aplicativo está configurado, podemos começar a criar nosso bot. Nesta publicação, criaremos um bot simples que responde a duas palavras-chave quando alguém envia uma mensagem para nosso número de WhatsApp. As palavras que procuraremos na mensagem são "dog" (cachorro) ou "cat" (gato), e nosso bot responderá com uma imagem aleatória e uma informação sobre cães ou gatos.

Webhooks

Com a API da Twilio para WhatsApp, quando seu número (ou conta sandbox) recebe uma mensagem, a Twilio faz uma solicitação de webhook para um URL que você define. Essa solicitação incluirá todas as informações sobre a mensagem, incluindo o corpo da mensagem.

Nosso aplicativo precisará definir uma rota que podemos configurar como URL da solicitação do webhook para receber essas mensagens recebidas, analisar se elas contêm as palavras que estamos procurando e responder com o uso de TwiML. TwiML é um conjunto de elementos XML que descreve como seu aplicativo se comunica com a Twilio.

O aplicativo que criamos até agora pode responder a um webhook no caminho raiz, mas tudo o que ele faz é responder com "Hello World!". Então, vamos começar a trabalhar atualizando isso.

Vamos remover a rota "Hello World!" e adicionar uma rota /bot. Os webhooks da Twilio são solicitações POST por padrão. Então, vamos configurar a rota para lidar com isso também. Para tal, passamos um bloco para o método POST que o Sinatra define.

require "sinatra/base"

class WhatsAppBot < Sinatra::Base
  post '/bot' do

  end
end

Em seguida, vamos extrair o corpo da mensagem dos parâmetros de solicitação. Como vamos tentar combinar o conteúdo da mensagem com as palavras "dog" (cachorro) e "cat" (gato), também traduziremos o corpo para minúsculas.

class WhatsAppBot < Sinatra::Base
  post '/bot' do
    body = params["Body"].downcase
  end
end

Vamos responder à mensagem usando o TwiML, e a biblioteca twilio-ruby nos dá uma classe útil para construir nossa resposta: Twilio::TwiML::MessagingResponse. Inicialize uma nova resposta na próxima linha:

class WhatsAppBot < Sinatra::Base
  post '/bot' do
    body = params["Body"].downcase
    response = Twilio::TwiML::MessagingResponse.new
  end
end

O objeto MessagingResponse usa o padrão de construtor para gerar a resposta. Vamos criar uma mensagem e, em seguida, adicionar um corpo e uma mídia a ela. Podemos passar um bloco para o método Twilio::TwiML::MessagingResponse#message e isso aninhará esses elementos em um elemento<Message> no resultado.

class WhatsAppBot < Sinatra::Base
  post '/bot' do
    body = params["Body"].downcase
    response = Twilio::TwiML::MessagingResponse.new
    response.message do |message|
      # nested in a <Message>
    end
  end
end

Agora, precisamos começar a criar nossa resposta real. Verificaremos se o corpo inclui a palavra "dog" (cachorro) ou "cat" (gato) e adicionaremos as respostas relevantes. Se o corpo da mensagem não contiver nenhuma palavra, também devemos adicionar uma resposta padrão para informar ao usuário o que o bot pode responder.

class WhatsAppBot < Sinatra::Base
  post '/bot' do
    body = params["Body"].downcase
    response = Twilio::TwiML::MessagingResponse.new
    response.message do |message|
      if body.include?("dog")
        # add dog fact and picture to the message
      end
      if body.include?("cat")
        # add cat fact and picture to the message
      end
      if !(body.include?("dog") || body.include?("cat"))
        message.body("I only know about dogs or cats, sorry!")
      end
    end
  end
end

Atualmente não temos como obter informações de cachorros ou gatos. Felizmente, há algumas APIs que podemos usar para isso. Para cachorros, vamos usar a API Dog CEO para imagens e esta API de cachorros para informações. Para gatos, existe a TheCatAPI para imagens e a API de informações sobre gatos. Usaremos a biblioteca http.rb que instalamos anteriormente para fazer solicitações para cada uma dessas APIs.

Cada API funciona com solicitações GET. Para fazer uma solicitação GET com http.rb, você chama get no módulo HTTP passando o URL como uma string. O método get retorna um objeto de resposta cujo conteúdo você pode ler chamando to_s.

Para tornar o aplicativo agradável e organizado, vamos finalizar as chamadas de API para cada um desses serviços em um módulo Dog e Cat, cada um com um método fact e picture.

Adicione esses módulos à parte inferior bot.rb:

module Dog
  def self.fact
    response = HTTP.get("https://dog-api.kinduff.com/api/facts")
    JSON.parse(response.to_s)["facts"].first
  end

  def self.picture
    response = HTTP.get("https://dog.ceo/api/breeds/image/random")
    JSON.parse(response.to_s)["message"]
  end
end

module Cat
  def self.fact
    response = HTTP.get("https://catfact.ninja/fact")
    JSON.parse(response.to_s)["fact"]
  end

  def self.picture
    response = HTTP.get("https://api.thecatapi.com/v1/images/search")
    JSON.parse(response.to_s).first["url"]
  end
end

Agora, podemos usar esses módulos na resposta do webhook como:

class WhatsAppBot < Sinatra::Base
  post '/bot' do
    body = params["Body"].downcase
    response = Twilio::TwiML::MessagingResponse.new
    response.message do |message|
      if body.include?("dog")
        message.body(Dog.fact)
        message.media(Dog.picture)
      end
      if body.include?("cat")
        message.body(Cat.fact)
        message.media(Cat.picture)
      end
      if !(body.include?("dog") || body.include?("cat"))
        message.body("I only know about dogs or cats, sorry!")
      end
    end
  end
end

Para retornar a mensagem ao WhatsApp via Twilio, precisamos definir o tipo de conteúdo da resposta para "text/xml" e retornar a string XML.

class WhatsAppBot < Sinatra::Base
  post '/bot' do
    body = params["Body"].downcase
    response = Twilio::TwiML::MessagingResponse.new
    response.message do |message|
      if body.include?("dog")
        message.body(Dog.fact)
        message.media(Dog.picture)
      end
      if body.include?("cat")
        message.body(Cat.fact)
        message.media(Cat.picture)
      end
      if !(body.include?("dog") || body.include?("cat"))
        message.body("I only know about dogs or cats, sorry!")
      end
    end
    content_type "text/xml"
    response.to_xml
  end
end

Isso é tudo o que precisamos fazer de programação para o webhook, mas há mais uma coisa a considerar.

Segurança do webhook

Estes podem não ser os dados mais essenciais para retornar em uma solicitação de webhook, mas é recomendado proteger seus webhooks para garantir que responda apenas às solicitações do serviço que você está esperando. A Twilio assina todas as solicitações de webhook usando seu token de autenticação e você pode validar essa assinatura para validar a solicitação.

biblioteca twilio-ruby fornece middleware de rack para facilitar a validação de solicitações da Twilio: vamos adicionar isso ao aplicativo também. No topo de sua classe WhatsAppBot, inclua o middleware com o método use. Passe os três argumentos a seguir para use: a classe de middleware Rack::TwilioWebhookAuthentication, o token de autenticação e o caminho a ser protegido (neste caso, "/bot".)

class WhatsAppBot < Sinatra::Base
  use Rack::TwilioWebhookAuthentication, ENV['TWILIO_AUTH_TOKEN'], '/bot'
 
  post '/bot' do

Como conectar o bot ao WhatsApp

Na linha de comando, pare o aplicativo com ctrl/cmd + c e reinicie-o com:

bundle exec rackup config.ru

Agora precisamos ter certeza de que os webhooks da Twilio podem alcançar nosso aplicativo. É por isso que eu incluí o ngrok nos requisitos para este aplicativo. O ngrok nos permite conectar um URL público ao aplicativo em execução em nossa máquina. Se ainda não tiver o ngrok instalado, siga as instruções para baixar e instalar o ngrok.

Inicie o ngrok para fazer o túnel até a porta 9292 com o seguinte comando:

ngrok http 9292

Isso dará um URL do ngrok que agora você pode adicionar ao seu sandbox do WhatsApp para que as mensagens recebidas sejam direcionadas para seu aplicativo.

Tela do ngrok com a marcação do link para ser utilizado no webhook.

Pegue esse URL do ngrok e adicione o caminho para o bot para que ele se pareça com isto: https://YOUR_NGROK_SUBDOMAIN.ngrok.io/bot. Insira esse URL no administrador do sandbox do WhatsApp na entrada marcada como "When a message comes in" (Quando uma mensagem é recebida) e salve a configuração.

Tela do console da Twilio para configuração do webhook da Sandbox API do WhatsApp.

Como testar seu bot

Agora você pode enviar uma mensagem para o número do sandbox do WhatsApp e seu aplicativo entrará em ação para retornar fotos e informações sobre cães ou gatos.

Tela do WhatsApp com a demonstração em funcionamento no número da Sandbox.

Crie mais bots

Nesta publicação, vimos como configurar a API da Twilio para WhatsApp e conectá-la a um aplicativo em Ruby para retornar imagens e informações sobre cães ou gatos. Você pode obter todo o código desse bot no GitHub.

É um bot simples, mas fornece uma boa base para construir mais. Você pode experimentar receber imagens do WhatsApp para criar um bot visual ou enviar ou receber um local como parte da mensagem. Também podemos aproveitar isso para criar bots ainda mais inteligentes usando o piloto automático da Twilio.

Este artigo foi traduzido do original "Build a WhatsApp chatbot with Ruby". Enquanto melhoramos nossos processos de tradução, adoraríamos receber seus comentários em help@twilio.com - contribuições valiosas podem render brindes da Twilio.