quarta-feira, 22 de fevereiro de 2017

BOT Framework e Integração com Aplicações

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 integrar 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, este é o Core do BOT Framework. Ao criar um BOT, você pode usar diversos serviços para hospedar o BOT, 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.
Facilidades do BOT
Figura 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 publica-los no Azure. Esta integração é feita através de serviços REST.
Conectores do BOT
Figura 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, o mesmo 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 https://www.microsoft.com/cognitive-services/en-us/language-understanding-intelligent-service-luis  http://luis.ai) para treinar este 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.
Estrutura da mensagem trocada em JSON
Figura 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.
Novo projeto BOT
Figura 4 – Novo projeto BOT
O mais importante neste projeto é que você pode publica-lo em qualquer servidor de internet onde 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 estas informações, mas quando registrarmos o BOT, elas são geradas e aí sim, basta copiar as informações 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 que 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. Neste 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($"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; 
}
Neste 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 rodando localmente
Figura 5 – BOT rodando localmente
No entanto, você não consegue interagir, então, a melhor coisa é instalar o emulador (http://aka.ms/bf-bc-emulator). 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. Neste 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, note que já é inserido o “/api/messages”. Note ainda, que você precisa fornecer o AppId e 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”, o qual é a que inserimos no código anterior. Isto porque já foi identificado que o tipo de mensagem é message.Type == "BotAddedToConversation".
Interação com emulador
Figura 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.
JSON da mensagem
Figura 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.
Desta 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) do mesmo. 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 = $"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 $"{nome} - preço: {preco:n2}"; 
        } 
        else 
        { 
            return $"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.
Retorno dos dados dos produtos
Figura 8 – Retorno dos dados dos produtos
Pronto, este 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 de 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 neste 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.
Publicação da aplicação no Azure
Figura 9 – Publicação da aplicação no Azure
Faça o login, caso precise, escolha a sua assinatura e o Serviços de Aplicativo já criado no Azure. Caso não tenha criado ainda, clique no botão New e preencha o formulário para cria-lo. Ao final, clique no botão OK, conforme a figura 10.
Publicação no Azure
Figura 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.
Credenciais para publicação no Azure
Figura 11 – Credenciais para publicação no Azure
Assim que a publicação finaliza, é aberto o navegador já com a URL criada. Isto é 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. Neste 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 seguido 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 isto 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 registrado com sucesso
Figura 12 – BOT registrado com sucesso
Agora é preciso fazer um ajuste necessário nas configurações da aplicação criada no VS 2015. Lembre-se que no arquivo Web.Config temos o AppId e o AppSecret? Pois bem, o projeto está publicado no Azure com credenciais default. Isto significa que se você testar o seu BOT agora, dará erro. No painel do lado esquerdo do BOT criado, há estas 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. Isto 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 = $"http://localhost:23736/api/ProdutosWebAPI/{id}"; 
        ... 
        //    return $"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 $"{prod.nome} - preço: {prod.preco:n2}"; 
        else 
            return $"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.
Teste real do BOT no Azure
Figura 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.
Teste diretamente no My Bots
Figura 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.
Conectores do BOT
Figura 15 – Conectores do BOT
É aberta uma nova janela no navegador para você seguir as etapas. Basicamente você precisa se 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.
Roteiro para integração com Slack
Figura 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.
Aplicação registrada no Slack
Figura 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.
URL do Slack
Figura 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.
Usuário associado ao Slack
Figura 19 – Usuário associado ao Slack
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 este 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.
Slack solicitando dados no BOT no Azure
Figura 19 – Slack solicitando dados no BOT no Azure
Agora que você já sabe o que e como usar o BOT, abra a sua mente e tente criar exemplos de como integrar o BOT aos conectores, afim 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 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.

Sobre o Autor

Renato Haddad ( rehaddad@msn.com  – www.renatohaddad.com) é MVP, MS Regional Director, MCPD e MCTS, palestrante em eventos da Microsoft em diversos países, ministra treinamentos focados em produtividade com o VS.NET 2013/2015, ASP.NET Core, 4/5, Power BI, Entity Framework, Reporting Services, Universal Windows Platform. Visite o blog http://weblogs.asp.net/renatohaddad.

Nenhum comentário:

Postar um comentário