Desenvolvimento

17 abr, 2017

Criando um chatbot de notícias para distribuir conteúdo através Messenger do Facebook

Publicidade

Neste artigo, veremos como você pode criar um chatbot de notícias no Facebook. Você poderá então utilizar os serviços do IBM Watson para melhorar o chatbot. Nesse tutorial, eu mostro como desenvolver e aplicar o chatbot na plataforma Facebook Messenger. O chatbot de notícias nessa série utiliza o conteúdo do developerWorks como exemplo, mas você pode alterar a fonte do conteúdo de acordo com sua necessidade. 

Como o chatbot do exemplo funciona 

O chatbot traz até você notícias e tutoriais, e para ele realizar esse trabalho, você deve identificar os tópicos pelos quais você se interessa.

1. No Messenger do Facebook, abra uma conversa com o developerWorks News Bot.

2. Especifique os tópicos que interessam a você.

3. Será mostrada a você uma lista dos tutoriais recentes baseada nos seus interesses.

4. Você pode ir diretamente para tópicos específicos. Para cada tutorial, o chatbot pode te passar um resumo ou mesmo ler o resumo em voz alta para você. A partir daí, você pode acessar o tutorial completo no site developerWorks.

O chatbot também suporta busca por arquivos utilizando pesquisas estilo Google.

Nota: Opcionalmente, você também pode interagir com o Chatbot do developerWorks News utilizando mensagens de texto ou de voz. Você pode utilizar o Messenger do Facebook para gravar uma mensagem de voz, e o chatbot transcreve a mensagem para texto antes de responder. Você também pode fazer com que o chatbot leia o resumo de um tutorial para você. Esse recurso de voz está disponível no código fonte para esse chatbot no GitHub, mas não está disponível na aplicação de demonstração. Você pode encontrar o código fonte completo dessa aplicação de chatbot no GitHub: https://github.com/juntao/dwnewsbot

Criando uma aplicação chatbot baseada em servlets Java

Como o chatbot estar no Messenger do Facebook, a aplicação que você desenvolve é um “webhook” que ouve as mensagens dos usuários do Facebook, e então envia as respostas do chatbot de volta ao Messenger do Facebook. No mundo das aplicações Java, você escreve um servlet que é mapeado para a URL do webhook.

Para utilizar o framework, você pode estender a classe abstrata BaseServlet e implementar o método converse. O parâmetro String Human do método converse é a mensagem de texto que o usuário do bate papo envia. Em um exemplo simples, o método converse pode retornar apenas uma resposta em formato String para o usuário. Por exemplo, a seguinte implantação simples ecoa a mensagem de volta ao usuário

public Object converse (String human, ConcurrentHashMap<String, Object> context) {
    return "You just said: " + human;
}

O método converse também pode retornar um JSONObject que especifique uma mensagem estruturada para as especificações do Messenger do Facebook. Por exemplo, o trecho de código abaixo retorna uma imagem com um botão que diz “Clique Aqui” abaixo dela. Se o usuário selecionar o botão, a próxima mensagem que o método converse receberá terá o CLICKME como entrada para o parâmetro Human.

public Object converse (String human, ConcurrentHashMap<String, Object> context) {
    try {
        JSONObject payload = new JSONObject();
        payload.put("template_type", "button");
        payload.put("image_url", "http://host.com/img.png");
         
        JSONArray buttons = new JSONArray ();
        buttons.put((new JSONObject())
            .put("type", "postback")
            .put("title", "Click me")
            .put("payload", "CLICKME"));
        payload.put("buttons", buttons);
 
        return payload;
    } catch (Exception e) {
        e.printStackTrace();
        return "";
    }
}

E se o chatbot precisar enviar múltiplas respostas para responder a um usuário? Bem, ele pode retornar uma coleção Java List que contenha uma mistura de objetos String e JSONObject.

Se o seu chatbot é um bot simples de comando e resposta, seu método converse pode conter apenas uma lista das declarações se/senão para mapear como responder à cada entrada. Mas a maioria dos chatbots são mais complexos do que isso. Os chatbots mais complexos precisam manter um estado da conversa para que eles possam responder baseados no contexto da conversa. Você pode salvar qualquer objeto de estado de conversa no parâmetro Java HashMap chamado context.

No código a seguir, primeiro o chatbot pede para o usuário digitar uma consulta, e na próxima troca, ele lembra que o a entrada do usuário é uma consulta e realiza a busca utilizando o Hibernate Search e o Lucene. Os resultados da busca são salvos na variável context para que o chatbot saiba como navegar por eles quando o usuário clicar em “Próxima”.

public Object converse (String human, ConcurrentHashMap<String, Object> context) {
 
    String cstr = classifyText(human);
    if ("SEARCH".equalsIgnoreCase(cstr)) {
        context.put("search", true);
        return "Enter your search query here. For example, you can enter \"Java Stream\"";
    }
 
    if (context.get("search") != null) {
        List <NewsItem> items = dm.searchNewsItems(human);
        context.put("items", items);
        context.remove("search");
 
        List replies = new ArrayList();
        replies.add ("Search results for: " + human);
        replies.add(dm.replyItems(items, true));
        return replies;
    }
    ...
}

Como bônus do contextHashMap, o framework automaticamente o popula com os dados de escopo da sessão. Por exemplo, o método converse pode sempre acessar o ID do usuário do Facebook utilizando o campo sender_id na variável context. A aplicação do chatbot pode resgatar e salvar os dados do perfil do usuário.

public Object converse (String human, ConcurrentHashMap<String, Object> context) {
    User user = dm.getUser((String) context.get("sender_id"));
    if (user == null) {
        user = new User ();
        user.setFbId((String) context.get("sender_id"));
 
        HashMap profile = getUserProfile(user.getFbId());
        if (profile != null && !profile.isEmpty()) {
            user.setFirst_name((String) profile.get("first_name"));
            user.setLast_name((String) profile.get("last_name"));
             user.setProfile_pic((String) profile.get("profile_pic"));
            user.setLocale((String) profile.get("locale"));
            user.setGender((String) profile.get("gender"));
            try {
                user.setTimezone((Integer) profile.get("timezone"));
            } catch (Exception e) {
                user.setTimezone(0);
            }
        }
 
        dm.saveUser(user);
        new_user = true;
    }
    ...
}

Finalmente para um chatbot de notícias, é importante alcançar os usuários quando existem notícias. Em outras palavras, o chatbot não deveria sempre esperar para responder a um comando do usuário. Em um servidor de aplicação Java, isso é facilmente executado, configurando uma tarefa de agendamento Quartz. Eu configurei a tarefa da classe de operação SendNewsWorker para ser executada às 16:00 UTC três dias por semana no StartupServlet.

private static final String CRON_EXPRESSION_2 =
      "0 0 16 ? * MON,WED,FRI";
 
// ... ...
 
JobDetail jobDetail2 = new JobDetail(
      "MyJob2", "MyJobGroup", SendNewsWorker.class);
JobDataMap dataMap2 = new JobDataMap ();
dataMap2.put("emf", emf);
dataMap2.put("scontext", getServletContext());
jobDetail2.setJobDataMap (dataMap2);
 
CronTrigger cronTrigger2 = new CronTrigger(
      "MyTrigger2", "MyTriggerGroup");
CronExpression cexp2 = new CronExpression(CRON_EXPRESSION_2);
cronTrigger2.setCronExpression(cexp2);
 
scheduler.scheduleJob(jobDetail2, cronTrigger2);

O trecho de código abaixo é da classe SendNewsWorker. Ele envia notícias para o usuário como um carrossel JSONObject estruturado, utilizando o ID do usuário do Facebook recuperado do banco de dados.

// Get all users from database
List <User> users = dm.getActiveUsers();
for (User user : users) {
    List <String> faves = user.getFavesList();
    List <NewsItem> items = new ArrayList <NewsItem> ();
    for (String fave : faves) {
        List <NewsItem> nis = dm.getNewsItems(fave);
        if (nis == null || nis.isEmpty()) {
            continue;
        }
        for (NewsItem ni : nis) {
            items.add(ni);
        }
    }
 
    if (items.isEmpty()) {
        continue; // there is no update for today
    }
 
    // send the replies to the user proactively
    try {
        BaseServlet.sendReply("Hey, " + user.getFirst_name() + ", here are some tutorials you might have missed.", user.getFbId());
        BaseServlet.sendReply(dm.replyItems(items, true), user.getFbId());
        BaseServlet.sendReply("To stop future news delivery messages, please text STOP", user.getFbId());
    } catch (Exception e) {
        e.printStackTrace();
    }
 
    user.setUpdateDate(new Date ());
    dm.saveUser(user);
}

O método replyItems que é mostrado no código exibe o carrossel de tutoriais em uma série de objetos List (ou seja titles, subtitles, image_urls, button_titles, e button_payloads). O método então chama o método BaseServletcreateCarousel para criar um objeto JSON para o carrossel de acordo com as especificações do Messenger do Facebook.

Conectar o chatbot ao Messenger do Facebook

Nessa sessão, passarei pelo processo de criar um chatbot para o Messenger do Facebook e conectar a aplicação a ele.

1. O “rosto” público de um bot para o Messenger do Facebook é a página do Facebook. Para criar uma nova página do Facebook, acesse https://www.facebook.com/pages/create/ e siga os passos. Depois que a página for criada, você poderá customizar a aparência adicionando um ícone e botões de chamada para ação.

2. Para criar o app do Facebook para o chatbot, acesse https://developers.facebook.com/ e entre com usuário e senha. A partir do menu Meus Aplicativos no canto superior direito, selecione Adicionar um novo aplicativo. Você pode selecionar Configuração Básica no final da janela pop-up porque você não precisa integrar com nada ainda.

3. Do painel de controle de aplicativos do Facebook, utilize o link Adicionar Produto no painel da esquerda para adicionar a integração com o Messenger.

4. Na aba de produto do Messenger, crie um token para conectar o seu aplicativo com a página. O webhook do seu aplicativo, que você vai configurar em breve, receberá as mensagens enviadas para uma página específica.

5. Coloque o token na classe NewsServlet na sua aplicação Java do chatbot. Note que a classe NewsServlet tem outros campos de chaves ou tokens vazios – eles são web services opcionais que o chatbot poderia utilizar para melhorar sua inteligencia. Esses serviços adicionais são cobertos em outros tutoriais da série.

6. Execute o comando a seguir de seu computador com o token de acesso à página para a assinatura surtir efeito.

curl -X POST "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=<PAGE_ACCESS_TOKEN>"

7. Na aba de produto do Messenger, na sessão Webhooks, inscreva o aplicativo na página que você criou. Certifique-se de selecionar as opções Mensagens e Postback de Mensagens para receber tanto as mensagens quanto os cliques nos botões do Messenger do Facebook.

Você precisa configurar uma URL do webhook para sua aplicação receber os eventos de mensagens em que foi inscrita. Para fazer isso, você deve implantar seu aplicativo com uma aplicação web pública. O IBM Bluemix é uma ótima escolha para a implantação.

Implantar o Chatbot no Bluemix

Agora você está pronto para implantar a aplicação web do chatbot no IBM Bluemix. Primeiro, você precisa configurar dois contêineres no Bluemix: um servidor de aplicação Apache Tomcat para executar o aplicativo web para o webhook e um banco de dados relacional MySQL para a aplicação armazenar seus dados (por exemplo, os dados dos perfis dos usuários do Facebook e os conteúdos dos tutoriais do developerWorks).

O IBM Bluemix é baseado na plataforma Cloud Foundry. Você vai precisar instalar as ferramentas de linha de comando do Cloud Foundry e suas extensões para Bluemix para gerenciar os contêineres da sua aplicação no Bluemix.

O contêiner do MySQL é fornecido pela ClearDB, uma fornecedora externa para a plataforma Bluemix. O plano gratuito da ClearDB limita o tamanho do banco de dados em 5MB, o que não é suficiente para sua aplicação porque o tutorial baixado do developerWorks excede 5MB. Você deve mudar para um plano pago do ClearDB se quiser executar o chatbot do developerWorks.

1. No IBM Bluemix, crie um contêiner Apache Tomcat

2. Crie um banco de dados MySQL e selecione o plano da ClearDB.

3. Conecte o banco de dados MySQL com a aplicação Tomcat

4. No painel de controle do IBM Bluemix, você pode abrir a aplicação Tomcat e revisar as configurações do banco de dados, incluindo a URL de conexão e o nome de usuário e senha gerados automaticamente.

5. Importe um script SQL para configurar o esquema do banco de dados. Você pode executar o seguinte comando a partir de qualquer computador com a biblioteca do cliente MySQL instalada. O arquivo “schema.sql” fica localizado no diretório “bin” do código fonte do projeto.

mysql -h HOST -u USERNAME -pPASSWORD DBNAME < schema.sql

6. No arquivo “context.xml” de sua aplicação web, adicione a URL de conexão com o banco de dados, usuário e senha. Esse arquivo fica localizado no diretório “src/main/resources/META-INF” do código fonte do projeto.

<?xml version='1.0' encoding='utf-8'?>
<Context>
  <Resource name="jdbc/dwnews" auth="Container"
    driverClass="com.mysql.jdbc.Driver"
    jdbcUrl="jdbc:mysql://host:3306/DBNAME?autoReconnect=true"
    user="USERNAME"
    password="PASSWORD"
    preferredTestQuery="SELECT 1"
    testConnectionOnCheckin="true"
    idleConnectionTestPeriod="300"
    factory="org.apache.naming.factory.BeanFactory"
    type="com.mchange.v2.c3p0.ComboPooledDataSource"
    maxPoolSize="4"
    minPoolSize="2"
    acquireIncrement="1"/>
</Context>

7. Para construir a aplicação Java que você acabou de desenvolver, você precisa do Apache Maven. Depois de instalar o Maven, utilize o seguinte comando para construir o arquivo WAR:

mvn clean package

Agora você pode implantar o arquivo WAR utilizando comando cf push do Bluemix. Leia a documentação do Bluemix para mais detalhes sobre como configurar o manifest.yml para implantar o arquivo WAR para seu contêiner Tomcat.

Seu webhook está disponível em https://your-bluemix-appname.mybluemix.net/facebook/ibmdw

Testar e Publicar seu Chatbot

Adicione a URL da aplicação Bluemix como a URL do webhook na aba Webhooks do console de aplicativos do Facebook. Para o campo “Verificar Token”, você pode adicionar qualquer texto que você queira, e o framework do seu chatbot vai tratar automaticamente.

Agora você pode testar o chatbot. Vá para a página do bot no Facebook e envie uma mensagem para a página. A janela do Messenger do Facebook abrirá e você verá a resposta.

Todos os chatbots para o Messenger do Facebook devem ser aprovados pelo Facebook antes de serem disponibilizados ao público. Durante o período de testes, você pode adicionar pessoas para testar a aplicação adicionando seus IDs de usuário do Facebook manualmente no painel de controle de aplicativos. Depois que você terminar os testes, você pode clicar em “Solicitar Permissão” para submeter sua aplicação para aprovação. Será solicitado que você forneça a política de privacidade (o https://www.iubenda.com/en é um site que pode gerar uma para você gratuitamente) e um vídeo de demonstração da aplicação em ação.

Nota: Devido à aplicação enviar novos tutoriais para o usuário três dias por semana, você deve selecionar a permissão pages_messaging_subscriptions para revisão. Sem essa permissão, o chatbot somente pode enviar mensagens para o usuário após ele iniciar as solicitações (ou seja, enviar respostas para o usuário dentro de uma janela de 24 horas após ele explicitamente enviou uma mensagem para o chatbot).

Vai levar alguns dias para o Facebook aprovar o chatbot, e você será notificado quando eles aprovarem. Nesse ponto, volte para o painel de aplicativos do Facebook e mude o aplicativo para público.

Resumo

Nesse tutorial, eu descrevi o processo de construção e publicação de um chatbot para o Messenger do Facebook na plataforma IBM Bluemix. Essa abordagem mostra para você as porcas e parafusos(o trocadilho foi intencional) de como um chatbot funciona, e dar para você mais liberdade em suas opções de hospedagem(como a programação Java é quase universalmente suportada entre os provedores de computação na nuvem e local).

 

 

***

Michael Yuan faz parte do time de colunistas internacionais do iMasters. A tradução do artigo é feita pela Redação iMasters, com autorização do autor, e você pode acompanhar o artigo em inglês no link: https://www.ibm.com/developerworks/library/cc-cognitive-chatbot-facebook/index.html