Back-End

21 set, 2016

BOT Framework e integração com aplicações

Publicidade

A Microsoft criou o BOT, que é um framework capaz de trocar mensagens e integrar diversos tipos de conectores de aplicações famosas (Skype, Slack, Email no Office 365, SMS etc.) com a aplicação BOT no servidor.

O objetivo deste artigo é criar um serviço de BOT básico, armazenado no Azure, e depois integrá-lo com um banco de dados, de forma que as mensagens trocadas sejam enviadas e respondidas num emulador e numa aplicação integrada com o Slack. Utilizei o Visual Studio 2015 RC 2 para escrever este artigo.

O que é o BOT Framework?

BOT Framework é um serviço operado pela Microsoft baseado num SDK e seus conectores – esse é o core do BOT Framework. Ao criar um BOT, você pode usar diversos serviços para hospedá-lo, serviços de linguagem natural do Machine Learning (LUIS), reconhecimento de voz com as API, integração com o Azure, entre outras, conforme a figura 1.

bot-1Figura 1 – Facilidades do BOT.

Onde usar?

Você pode criar o seu BOT e integrá-lo diretamente nos seus negócios através da integração com conectores como chat, Email no Office 365, Skype, Slack, Telegram, SMS, GroupMe, entre outros, conforme a figura 2. O SDK permite criar projetos em C# + Node.js e publicá-los no Azure. Essa integração é feita através de serviços REST.

bot-2Figura 2 – Conectores do BOT

Funcionamento do BOT

O BOT é baseado em uma lógica que requisita e recebe textos de um Web Service, normalmente armazenado no Azure. Dependendo do texto solicitado ao servidor, ele trata a mensagem segundo uma inteligência que você cria, e responde à solicitação. Quando falo sobre inteligência, quero dizer que você pode e deve criar um conjunto de expressões, por exemplo, usar o LUIS (Language Understanding Intelligent Service) para treinar esse modelo de expressões. O treinamento é baseado no Machine Learning, que através dos diversos modelos matemáticos e estatísticos submete tais expressões.

Como um BOT é baseado em serviços REST, tenha em mente que todas as mensagens trocadas entre cliente e servidor são mapeadas em JSON; por exemplo, a figura 3 mostra o conector BOT para o canal SMS. Imagine que você quer fazer o pedido de uma pizza através de um conector, não importa qual seja, o servidor recebe a mensagem (text: “Diga fazer pedido para iniciar o pedido”), processa e entende que o cliente deseja iniciar o pedido. Então, o cliente recebe a mensagem texto do servidor dando as instruções. Veja que no JSON é definida a linguagem a ser usada, até o momento está disponível apenas para algumas.

bot-3Figura 3 – Estrutura da mensagem trocada em JSON

Como desenvolver um BOT?

O primeiro passo é instalar o template para BOT no Visual Studio 2015 (Update 1 no mínimo). Navegue no link http://aka.ms/bf-bc-vstemplate e faça o download. Quando finalizar, mova o .zip para a pasta de templates do VS, normalmente localizada em “%USERPROFILE%\Documents\Visual Studio 2015\Templates\ProjectTemplates\Visual C#”. Pronto, agora você já tem o template necessário para o BOT.

Em seguida, crie um novo projeto chamado BOTArtigoMSDN. Selecione o template Visual C# / Bot Application, conforme a figura 4, clique em OK e aguarde a criação do projeto.

bot-4Figura 4 – Novo projeto BOT

O mais importante nesse projeto é que você pode publicá-lo em qualquer servidor de Internet aos quais os conectores terão acesso. E todo BOT tem o AppId e a AppSecret descritos no Web.Config. Como o projeto foi criado agora, ainda não temos essas informações, mas quando registrarmos o BOT, elas são geradas e, aí sim, basta copiá-las aqui.

<appSettings>
  <!-- update these with your appid and one of your appsecret keys-->
  <add key="AppId" value="YourAppId" />
  <add key="AppSecret" value="YourAppSecret" />
</appSettings>

Abra o arquivo MessagesController.cs e note a declaração do código a seguir. Aqui é o local onde é recebida a mensagem do usuário e enviada a resposta. Roda assíncrona e, se a mensagem for do tipo Message, o código trata e retorna uma expressão em CreateReplyMessage. Nesse exemplo padrão, o texto devolve a quantidade de caracteres contidas na expressão. Caso contrário, é disparado o HandleSystemMessage, que verifica qual interação foi identificada e retorna a mensagem.

public async Task<Message> Post([FromBody]Message message)
{
    if (message.Type == "Message")
    {
        // calculate something for us to return
        int length = (message.Text ?? string.Empty).Length;

        // return our reply to the user
        return message.CreateReplyMessage(quot;You sent {length} characters");
    }
    else
    {
        return HandleSystemMessage(message);
    }
}

private Message HandleSystemMessage(Message message)
{
    if (message.Type == "Ping")
    {
        Message reply = message.CreateReplyMessage();
        reply.Type = "Ping";
        return reply;
    }
    else if (message.Type == "DeleteUserData")
    {
        // Implement user deletion here
        // If we handle user deletion, return a real message
    }
    else if (message.Type == "BotAddedToConversation")
    {
    }
    else if (message.Type == "BotRemovedFromConversation")
    {
    }
    else if (message.Type == "UserAddedToConversation")
    {
    }
    else if (message.Type == "UserRemovedFromConversation")
    {
    }
    else if (message.Type == "EndOfConversation")
    {
    }

    return null;
}

Nesse exemplo, adicione o seguinte código, que retorna uma mensagem no IF a seguir:

else if (message.Type == "BotAddedToConversation")
{
    return message.CreateReplyMessage("Olá Bot MSDN");
}

Agora, compile e rode a aplicação (F5). Você pode abrir em qualquer navegador e verá a página default.htm, conforme a figura 5.

bot-5Figura 5 – BOT rodando localmente

No entanto, você não consegue interagir, então a melhor coisa é instalar o emulador. Veja que a mensagem no navegador diz que você pode navegar no site do BOT e, ao registrá-lo, é preciso adicionar o “/api/messages” no final da URL, afinal é um serviço REST. Nesse momento, copie a URL, deixe a aplicação rodando no VS e pode fechar o navegador. Abra o emulador, por default a porta usada é 3978, e note que já é inserido o “/api/messages”. Note ainda que você precisa fornecer o AppId e o AppSecret, caso seja diferente do padrão.

Conforme a figura 6, clique no botão Send e veja que a resposta é a expressão “Olá Bot MSDN”, que é a que inserimos no código anterior. Isso porque já foi identificado que o tipo de mensagem é message.Type == “BotAddedToConversation”.

bot-6Figura 6 – Interação com emulador

Agora, vamos enviar uma mensagem para o BOT; na caixa de texto no rodapé, digite um texto e clique na seta para enviar. Veja que no chat são mostradas todas as mensagens trocadas. Se você selecionar qualquer mensagem, será mostrado o JSON do lado direito, conforme a figura 7, assim você pode saber o que realmente está sendo enviado e recebido do servidor.

bot-7Figura 7 – JSON da mensagem

Sendo assim, você pode construir toda a sua camada de negócios de forma que a própria mensagem faça uma pesquisa no banco de dados ou em um serviço na web, a fim de retornar dados, por exemplo, valor da ação de uma empresa, cotação de moedas, se há estoque de um produto, emergências médicas, enfim, há uma infinidade de cenários.

Dessa forma, criei um serviço REST que contém um Controller com uma Action que recebe o ID de um produto e retorna dados (ID, nome e preço) dele. Foquei aqui somente no código, sem tratar qualquer HttpNotFound ou erros para que você entenda mais facilmente.

// GET api/ProdutosWebAPI/5
public class ProdutosWebAPIController : ApiController
{
    NORTHWNDEntities ctx = new NORTHWNDEntities(); 

public ProdViewModelAPI Get(int id)
{
    return ctx.Products
                .Select(p => new ProdViewModelAPI
                {
                    id = p.ProductID,
                    nome = p.ProductName,
                    preco = p.UnitPrice
                })
                .FirstOrDefault(p => p.id == id);
}
}

Em seguida, no projeto do BotArtigoMSDN, criei a classe ServiceProduto com o método GetProdutosAsync – tudo assíncrono, é claro, que recebe o ID, chama o serviço armazenado em algum servidor (no meu caso, localhost), passa o ID como parâmetro e aguarda o retorno.

public class ServiceProduto
{
    public static async Task<string> GetProdutosAsync(int id)
    {
        string url = quot;http://localhost:23736/api/ProdutosWebAPI/{id}";
        string dados;
        using (WebClient client = new WebClient())
        {
            dados = await client.DownloadStringTaskAsync(url).ConfigureAwait(false);
        }
        if (dados != "null")
        {
            string nome = dados.Split(',')[1].Split(':')[1].Split('\"')[1];
            double preco = Convert.ToDouble(dados.Split(',')[2].Split(':')[1].Replace("}", ""));
            return quot;{nome} - preço: {preco:n2}";
        }
        else
        {
            return quot;o produto {id} não consta no estoque";
        }
    }
}

Já no arquivo MessageController.cs, veja o Post que faz a chamada ao GetProdutos passando o Message como parâmetro, ou seja, o dado que o usuário enviou.

public async Task<Message> Post([FromBody]Message message)
{
    if (message.Type == "Message")
    {
        string msg = await GetProdutos(message);
        return message.CreateReplyMessage(msg);
    }
    else
    {
        return HandleSystemMessage(message);
    }
}

O método GetProdutos verifica se o conteúdo é um número ou não. Caso não seja, retorna a mensagem para fornecer um número. Caso contrário, chama o serviço (ServiceProduto.GetProdutoAsync) que irá na Web pesquisar o ID e retorna um REST tratado. Qualquer condição que seja, a mensagem (msg) será string.

private static async Task<string> GetProdutos(Message message)
{
    int id;
    string msg = string.Empty;
    bool EhNumero = int.TryParse(Convert.ToString(message.Text), out id);
    if (!EhNumero)
    {
        msg = "forneça um número, letras não são aceitas";
    }
    else
    {
        msg = await ServiceProduto.GetProdutosAsync(id);
    }
    return msg;
}

Executando a aplicação BOT no emulador, veja na figura 8 os dados retornados, conforme as condições que estabeleci.

bot-8Figura 8 – Retorno dos dados dos produtos

Pronto, esse BOT já está finalizado para ser publicado em algum servidor.

Publicar o BOT no Azure

Agora vamos publicar o BOT no Azure de forma que fique à disposição para quem quiser usar. Cabe ressaltar que você deverá ativar os recursos de Cognitive Services na sua conta do Azure. Para organizar os grupos no Azure, criei um grupo chamado BotFramework e toda vez que eu criar uma aplicação WEB de BOT, a insiro nesse grupo.

No Solution Explorer, clique no projeto do BOT e selecione Publish. Selecione a opção Microsoft Azure App Service. Clique no botão Next, conforme a figura 9.

bot-9Figura 9 – Publicação da aplicação no Azure

Faça o login, caso precise, escolha a sua assinatura e o Serviço de Aplicativo já criado no Azure. Caso não tenha criado ainda, clique no botão New e preencha o formulário para criá-lo. Ao final, clique no botão OK, conforme a figura 10.

bot-10Figura 10 – Publicação no Azure

Serão exibidas as informações referentes ao servidor, nome do site, login e url a ser criada. Clique no botão Next e nas demais telas, não há mistério, basta finalizar o assistente e aguardar a publicação, conforme a figura 11.

bot-11Figura 11 – Credenciais para publicação no Azure

Assim que a publicação finaliza, é aberto o navegador já com a URL criada. Isso é tudo o que precisamos até o momento, o projeto está publicado no Azure.

Registrar o BOT no Bot web site

O próximo passo é ir no site dev.botframework.com e registrar o seu BOT. Nesse site, você encontrará uma documentação, pode registrar ou alterar um BOT e ver quais BOTs existem. Faça o login, clique na opção “Register a bot” e preencha todos os campos necessários para o registro. Basicamente os campos são:

Name: nome do seu BOT

Description: breve descrição do seu BOT

Endpoint: será a Url gerada na publicação no Azure seguida da expressão “/api/messages”. É recomendado usar https caso use autorização básica. O link final no meu caso é: https://botartigomsdn.azurewebsites.net/api/messages

Publisher: coloque o seu nome

Bot Privacy URL: pode usar esta da MS http://go.microsoft.com/fwlink/?linkid=521839

Publisher Email: seu email

App ID: coloque um texto, apenas letras e você não poderá alterar isso depois que salvar o registro.

Ao final, clique no chekbox para concordar com os termos e clique no botão Register e aguarde. Conforme a figura 12, veja o painel da esquerda com todas as informações do BOT. E, no painel da direita, todos os conectores disponíveis para você associar ao BOT, ou seja, integrar o BOT ao Email, Skype, Slack etc.

bot-12Figura 12 – BOT registrado com sucesso

Agora é preciso fazer um ajuste necessário nas configurações da aplicação criada no VS 2015. Lembre-se de que no arquivo Web.Config temos o AppId e o AppSecret? Pois bem, o projeto está publicado no Azure com credenciais default. Isso significa que se você testar o seu BOT agora, dará erro. No painel do lado esquerdo do BOT criado, há essas duas chaves que precisamos, portanto, abra o Web.Config no VS 2015, copie e cole os dados do App ID e “Primary app secret”.

<appSettings>
  <!-- update these with your appid and one of your appsecret keys-->
  <add key="AppId" value="BuildArtigoMSDN" />
  <add key="AppSecret" value="a4c282d165ca41cdb5a724b718d6f69a" />
</appSettings>

No Solution Explorer, rode novamente o processo de Publish no Azure – é rápido, pois foi alterado apenas um arquivo. Mesmo assim, se você executar pelo emulador ou diretamente na janela de teste do MY BOTS, dará erro. Isso porque o projeto aponta para o banco de dados em localhost. Sendo assim, vamos alterar a classe ServiceProduto de forma que a pesquisa seja feita apenas em uma pequena lista de produtos. E não se esqueça de criar a classe Produto.

public class Produto
{
    public int ID { get; set; }
    public string nome { get; set; }
    public decimal preco { get; set; }
}

public class ServiceProduto
{
    public static async Task<string> GetProdutosAsync(int id)
    {
        #region teste local antes de publicar no Azure
        //string url = quot;http://localhost:23736/api/ProdutosWebAPI/{id}";
        ...
        //    return quot;o produto {id} não consta no estoque";
        //}
        #endregion

        #region teste depois de publicar no azure
        var lista = new List<Produto>
        {
            new Produto { ID=1, nome="Batata", preco=8},
            new Produto { ID=2, nome="Morango", preco=10},
            new Produto { ID=3, nome="Laranja", preco=22},
            new Produto { ID=4, nome="Melancia", preco=25},
        };
        var prod = lista.FirstOrDefault(p => p.ID == id);
        if (prod != null)
            return quot;{prod.nome} - preço: {prod.preco:n2}";
        else
            return quot;o produto {id} não consta no estoque";
        #endregion
    }

Salve tudo e novamente publique no Azure. Agora, sim, podemos testar à vontade no emulador. Certifique-se que a URL seja HTTPS seguida da mesma URL anterior https://botartigomsdn.azurewebsites.net/api/messages. Outra coisa importante é que o emulador está com as credenciais antigas, então altere para as que você gerou e inicie os testes, conforme a figura 13. Que fantástico, você já tem o BOT registrado e publicado no Azure.

bot-13Figura 13 – Teste real do BOT no Azure

Para garantir, faça o teste diretamente na janela do seu BOT em My BOTS. Como o seu BOT está selecionado, digite um número (ID do produto) na caixa de texto e clique no botão Send. Veja o resultado JSON completo do retorno da mensagem, conforme a figura 14.

bot-14Figura 14 – Teste diretamente no My Bots

Integração com SLACK

Agora chegou a hora de mostrar como integrar o BOT já publicado no Azure ao canal integrador. Como acho o Slack bem útil e de fácil entendimento, mostrarei o passo a passo. No site dev.botframework.com, uma vez logado, clique no “My BOTS”. Na lista de canais, o Slack está exibido, portanto, clique no botão Add, conforme a figura 15.

bot-15Figura 15 – Conectores do BOT

É aberta uma nova janela no navegador para você seguir as etapas. Basicamente, você precisa ter uma conta no Slack, se logar e criar a aplicação do seu BOT (https://api.slack.com/applications/new). Os três passos são fáceis de seguir porque o site já mostra o que você deve fazer para seguir o roteiro, conforme a figura 16.

bot-16Figura 16 – Roteiro para integração com Slack

A figura 17 exibe os dados da aplicação criada no Slack, contendo o Client ID, o Client Secret e a Redirect URI que foi colada quando gerada a aplicação no BOT.

bot-17Figura 17 – Aplicação registrada no Slack

A figura 18 mostra o link gerado a ser copiado e colado para o campo “Use this Redirect URI”, quando você cria a aplicação no BOT.

bot-18Figura 18 – URL do Slack

No site do Slack, desça até encontrar a sessão “Bot User”, conforme a figura 19. No site do BOT, seguindo o passo a passo, na sessão “Scroll down on page and create a bot”, clique no botão “Add a bot to this app” para adicionar o usuário ao Slack.

bot-19

E, para terminar, seguindo o passo a passo no site do BOT, localize a sessão “Submit your Client ID and Client Secret saved from above”. Aqui são solicitados dois dados (Client ID e Client Secret), os quais você deverá copiar e colar do site do Slack (gerados na figura 17). Clique no botão “Submit Slack Credentials” e pronto.

Nos bastidores, o Slack aprova e já disponibiliza em quais canais você quer que esse usuário seja chamado. Você pode associar à sessão #general.

Agora, vamos ao teste real das solicitações de dados ao BOT. Abra o Slack.com, faça o login e crie outro usuário para você testar ou pode pedir para um amigo aceitar. Na caixa de texto de mensagens, para você chamar o BOT no Azure passando o parâmetro, use @usuário (@botartigomsdn:) seguido de um número, que é o código do produto. Dê ENTER e aguarde o retorno do Auzre com os dados sobre o produto. Veja na figura 19 as várias solicitações feitas e seus devidos retornos.

bot-19Figura 19 – Slack solicitando dados no BOT no Azure

Agora que você já sabe como usar o BOT, abra a sua mente e tente criar exemplos de como integrar o BOT aos conectores, a fim de facilitar a vida de muitos usuários.

Conclusão

Integrar serviços armazenados em um servidor ou Azure diretamente com aplicações famosas, como Slack, Skype e outras, é o caminho para disseminar as informações e os serviços de forma simples, rápida e acessível de qualquer dispositivo. Portanto, estude o BOT e aplique o conhecimento ilustrado neste artigo.

Agradeço a oportunidade de poder compartilhar o conhecimento deste artigo. Qualquer dúvida e necessitando de treinamento, por favor me contate.