
Compartilhar:
Steve é um ex-membro da equipe da Vonage. Ele atuou como Developer Advocate .NET na Vonage, engenheiro de software full-stack poliglota, especializado em IA/ML
Série do Advento do Papai Noel com o Nexmo em C#
Tempo de leitura: 8 minutos
É a época do Advento, um período tão agitado para tantos, mas para ninguém mais do que o bom Papai Noel, cuja festa é celebrada hoje pelo Rito Oriental. Em homenagem à época do Advento do C# que está chegando, vamos dar uma mãozinha ao Papai Noel automatizando parte de sua correspondência e oferecendo a ele meios mais modernos de responder às perguntas do que o serviço postal.
Para definir claramente nosso objetivo aqui, vamos criar um bot de perguntas frequentes para o Papai Noel que possa ser acessado e responder por meio do Facebook Messenger, do WhatsApp e de SMS.
Vamos criar isso com a ajuda do QnAMaker e, é claro, da Messages API da Nexmo
Pré-requisitos
Visual Studio 2019, versão 16.3 ou superior
Um Account do Azure
Opcional: Ngrok para implantação de teste
Opcional: Para o Facebook Messenger, precisaremos vincular uma Página do Facebook ao nosso Account da Nexmo — você pode ver as instruções passo a passo em Nexmo Developer. Concluindo a a parte 2 do guia criará um aplicativo Nexmo com uma página do Facebook vinculada; certifique-se de salvar o arquivo da chave privada gerado para esse aplicativo.
Observação: O código desta demonstração funcionará com mensagens do WhatsApp assim que o WhatsApp Business estiver configurado. Dito isso, o WhatsApp é mais voltado para o ambiente empresarial — para saber mais detalhes sobre como configurar um aplicativo para o WhatsApp, consulte o guia em Nexmo Developer
Criando nosso bot
Configuração
Para criar nosso bot, vamos acessar o site QnAMaker e faremos login usando um Account do Azure.
Clique em “Criar uma Base de Conhecimento”.
Siga as instruções da etapa 1 para criar um serviço QnA no Azure.
Na Etapa 2, defina o seguinte:
ID do diretório do Microsoft Azure
Nome da assinatura do Account do Azure
O serviço de perguntas e respostas que vamos usar (esse nome corresponderá ao nome do serviço que acabamos de criar no Portal do Azure)
O idioma do nosso bot

Na Etapa 3, vamos nomear nossa base de conhecimento como “Ajudante do Papai Noel no Nexmo”.
É no Passo 4 que o QnA Maker se destaca — alimentar a base de conhecimento desse bot é tão fácil quanto vinculá-lo a uma página de perguntas frequentes ou fazer o upload de um arquivo com essas perguntas. É claro que, para esta demonstração, vamos usar a página de perguntas frequentes.
Também vamos adicionar algumas conversas casuais ao nosso bot — já que ele vai ser um duende honorário, vamos usar a seleção de conversas espirituosas
Com tudo isso configurado, clique em “Criar Base de Conhecimento”.
Isso importará as perguntas frequentes (FAQs) que indicamos ao QnA Maker e nos levará a uma página com a seguinte aparência:

Edição, publicação e teste da nossa base de conhecimento
Esta é a tela de edição da nossa Base de Conhecimento. Daqui, podemos ver como ela se apresenta. Também podemos editá-la livremente, caso queiramos alterar algumas respostas; por exemplo, talvez encurtemos a resposta da pergunta “Quem é o Papai Noel?”.
Depois de editar a Base de Conhecimento como for necessário, clicar em Save and Train salvará e treinará o bot.
Para testar, clique no Test botão no canto superior direito. Isso abrirá a caixa de diálogo de teste; você pode enviar uma pergunta, por exemplo: how do reindeer fly? e o bot vai responder!

É até possível verificar como o bot chegou a essa conclusão. Clique no link “Inspecionar” e a janela de inspeção será exibida. Ela mostrará o nível de confiança do bot em sua resposta e algumas alternativas que ele sugeriu.

Quando o bot estiver pronto, clique em “Publicar” na parte superior da página e, em seguida, clique em “Publicar” na caixa de diálogo que aparecerá. Quando o processo for concluído, será exibida uma tela com algumas estruturas de solicitação úteis que podem ser usadas para gerar uma resposta do bot. Ela terá mais ou menos a seguinte aparência:
POST /knowledgebases/YOUR_KNOWLEDGE_BASE_ID/generateAnswer
Host: https://nexmofaqbot.azurewebsites.net/qnamaker
Authorization: EndpointKey YOUR_KNOWLEDGE_BASE_ENDPOINT_KEY
Content-Type: application/json
{"question":"YOUR_QUESTION"}Salve essa string — ela será usada para criar o WebService que controlará nosso bot por meio da Messages API.
Criando nosso aplicativo
Comece abrindo o Visual Studio e selecionando “Criar um novo projeto”. Na caixa de diálogo que se abre, selecione um Aplicativo Web ASP.NET Core. Nomeie-o com algo como “QnAMakerMessagesDemo”. Selecione ASP.NET Core 3.0, “Aplicativo Web (Model-View-Control)” como tipo e clique em “Criar”.
Instalar pacotes do NuGet
No Visual Studio, vá para Ferramentas -> Gerenciador de Pacotes NuGet -> Gerenciar Pacotes NuGet para a Solução.
Instale os seguintes pacotes do NuGet:
Newtonsoft.Json
Nexmo.Csharp.Client
Castelo Inflável
jose-jwt
Criando nosso gerador de tokens
Crie uma classe chamada TokenGenerator e adicione o seguinte código a ela:
public static string GenerateToken(IConfiguration config)
{
// retrieve appID and privateKey from configuration
var appId = config["Authentication:appId"];
var priavteKeyPath = config["Authentication:privateKey"];
string privateKey = "";
using (var reader = File.OpenText(priavteKeyPath)) // file containing RSA PKCS1 private key
privateKey = reader.ReadToEnd();
//generate claims list
const int SECONDS_EXPIRY = 3600;
var t = DateTime.UtcNow - new DateTime(1970, 1, 1);
var iat = new Claim("iat", ((Int32)t.TotalSeconds).ToString(), ClaimValueTypes.Integer32); // Unix Timestamp for right now
var application_id = new Claim("application_id", appId); // Current app ID
var exp = new Claim("exp", ((Int32)(t.TotalSeconds + SECONDS_EXPIRY)).ToString(), ClaimValueTypes.Integer32); // Unix timestamp for when the token expires
var jti = new Claim("jti", Guid.NewGuid().ToString()); // Unique Token ID
var claims = new List<Claim>() { iat, application_id, exp, jti };
//create rsa parameters
RSAParameters rsaParams;
using (var tr = new StringReader(privateKey))
{
var pemReader = new PemReader(tr);
var kp = pemReader.ReadObject();
var privateRsaParams = kp as RsaPrivateCrtKeyParameters;
rsaParams = DotNetUtilities.ToRSAParameters(privateRsaParams);
}
//generate and return JWT
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.ImportParameters(rsaParams);
Dictionary<string, object> payload = claims.ToDictionary(k => k.Type, v => (object)v.Value);
return Jose.JWT.Encode(payload, rsa, Jose.JwsAlgorithm.RS256);
}
}Isso irá gerar o JWT necessário para a autenticação no aplicativo Messages, criado como parte dos pré-requisitos.
Adicione o appId e o caminho da chave privada à configuração
O gerador de JWT requer que um appId e o caminho para a chave privada, salvos anteriormente, estejam no arquivo appsettings.json.
Abra este arquivo e adicione o seguinte ao objeto de configuração:
"Authentication": {
"appId": "NEXMO_APPLICATION_ID",
"privateKey": "C:\\Path\\to\\Private\\key.key"
} Criar estruturas de dados para receber e enviar dados
São necessários alguns POCOs para esta demonstração; eles são um pouco prolixos e não fazem nada além de definir os objetos de mensagem de acordo com o especificação, por isso a estrutura completa foi omitida desta postagem. Basta adicionar as seguintes classes ao projeto:
InboundMessage.cs MessageRequest.cs
Enviar mensagens
Com as estruturas definidas, o próximo passo é enviar mensagens por meio da Messages API da Nexmo. Crie uma classe chamada MessageSender; ela terá um único método estático SendMessage que simplesmente criará uma solicitação de mensagem, gerará um JWT, criará uma solicitação e a enviará para a Messages API — deve ficar mais ou menos assim:
public static void SendMessage(string message, string fromId, string toId, IConfiguration config, string type)
{
const string MESSAGING_URL = @"https://api.nexmo.com/v0.1/messages";
try
{
var jwt = TokenGenerator.GenerateToken(config);
//construct message Request
var requestObject = new MessageRequest()
{
to = new MessageRequest.To()
{
type = type
},
from = new MessageRequest.From()
{
type = type
},
message = new MessageRequest.Message()
{
content = new MessageRequest.Message.Content()
{
type = "text",
text = message
}
}
};
//special messenger request formatting (use to/from id rather than number, set category to RESPONSE)
if (type == "messenger")
{
requestObject.message.messenger = new MessageRequest.Message.Messenger()
{
category = "RESPONSE"
};
requestObject.to.id = toId;
requestObject.from.id = fromId;
}
else
{
requestObject.to.number = toId;
requestObject.from.number = fromId;
}
//Generate Request payload from requestObject
var requestPayload = JsonConvert.SerializeObject(requestObject, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore });
//build request
var httpWebRequest = (HttpWebRequest)WebRequest.Create(MESSAGING_URL);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Accept = "application/json";
httpWebRequest.Method = "POST";
httpWebRequest.PreAuthenticate = true;
httpWebRequest.Headers.Add("Authorization", "Bearer " + jwt);
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
streamWriter.Write(requestPayload);
}
//handle response
using (var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse())
{
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
Console.WriteLine(result);
Console.WriteLine("Message Sent");
}
}
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
}
} Faça uma pergunta ao bot e envie uma resposta
Agora é hora de interagir com o bot de perguntas frequentes do aplicativo. É aqui que entram em cena as chamadas REST de exemplo que o QnAMaker apresentou anteriormente. Lembre-se desta string que vimos antes.
POST /knowledgebases/YOUR_KNOWLEDGE_BASE_ID/generateAnswer
Host: https://AZURE_APP_NAME.azurewebsites.net/qnamaker
Authorization: EndpointKey YOUR_KNOWLEDGE_BASE_ENDPOINT_KEY
Content-Type: application/json
{"question":"YOUR_QUESTION"}Use essa string para criar algumas constantes úteis/variáveis somente leitura para o Questioner — preencha com os valores apropriados da string acima:
//TODO: fill in with Knowledgebase ID
const string kb_id = "YOUR_KNOWLEDGE_BASE_ID";
//TODO: fill in with Knowledgebase Endpoint key
const string ENDPOINT_KEY = "YOUR_KNOWLEDGE_BASE_ENDPOINT_KEY";
const string QUESTION_FORMAT = @"{{'question': '{0}'}}";
//TODO fill in base url
static readonly string URI = $"https://AZURE_APP_NAME.azurewebsites.net/qnamaker/knowledgebases/{kb_id}/generateAnswer";Em seguida, crie uma tarefa para fazer a seguinte pergunta:
public static async Task<string> RequestAnswer(string question)
{
using (var client = new HttpClient())
using (var request = new HttpRequestMessage())
{
request.Method = HttpMethod.Post;
request.RequestUri = new Uri(URI);
var formatted_question = string.Format(QUESTION_FORMAT, question);
request.Content = new StringContent(formatted_question, Encoding.UTF8, "application/json");
request.Headers.Add("Authorization", "EndpointKey " + ENDPOINT_KEY);
var response = await client.SendAsync(request);
var jsonResponse = await response.Content.ReadAsStringAsync();
JObject obj = JObject.Parse(jsonResponse);
var answer = ((JArray)obj["answers"])[0]["answer"];
return answer.ToString();
}
}
Isso simplesmente formata a pergunta a partir da Messages API e envia a solicitação como uma solicitação POST do tipo “generateAnswer” para o bot QnAMaker.
Por fim, crie um método para enviar a solicitação e retornar uma resposta.
public static async Task AskQuestion(string to, string from, string type, string question, IConfiguration config)
{
question = HttpUtility.JavaScriptStringEncode(question);
var response = await RequestAnswer(question);
MessageSender.SendMessage(response, from, to, config, type);
} Criar um controlador para receber mensagens recebidas
A peça final do quebra-cabeça é o controlador que irá lidar com o fluxo de mensagens provenientes da Messages API. Crie um controlador MVC vazio chamado MessagesController.
Injeção de dependências e configuração
Adicione um campo IConfiguration chamado _config a isso e configure a injeção de dependência de configuração criando um construtor do controlador que receba um objeto IConfiguration:
private IConfiguration _config;
public MessagesController(IConfiguration config)
{
_config = config;
} Solicitação de status
Em seguida, crie uma solicitação de Status Post que simplesmente não retorne nenhum conteúdo:
[HttpPost]
public HttpStatusCode Status()
{
return HttpStatusCode.NoContent;
} Mensagens recebidas
Em seguida, adicione uma solicitação POST para mensagens recebidas da Messages API.
Este método extrairá a mensagem recebida do corpo da solicitação e, em seguida, encaminhará as tarefas do Questioner com base no conteúdo do corpo da solicitação.
[HttpPost]
public HttpStatusCode Inbound([FromBody]InboundMessage message)
{
Debug.WriteLine(JsonConvert.SerializeObject(message));
if (message.from.type == "messenger")
{
_ = Questioner.AskQuestion(message.from.id, message.to.id, message.from.type, message.message.content.text, _config);
}
else
{
_ = Questioner.AskQuestion(message.from.number, message.to.number, message.from.type, message.message.content.text, _config);
}
return HttpStatusCode.NoContent;
} SMS recebidas
Por fim, adicione uma solicitação HttpGet para gerenciar as mensagens SMS recebidas. Da mesma forma, isso extrairá as informações necessárias da mensagem recebida e fará a pergunta ao usuário.
[HttpGet]
public HttpStatusCode InboundSms([FromQuery] SMS.SMSInbound inboundMessage)
{
_ = Questioner.AskQuestion(inboundMessage.msisdn, inboundMessage.to, "sms", inboundMessage.text, _config);
return HttpStatusCode.NoContent;
}Com isso resolvido, o serviço está pronto para ser implantado.
Testes
O último passo é iniciar o serviço, torná-lo acessível pela internet e configurar o aplicativo Nexmo Messages para enviar webhooks para o serviço.
Configuração do IIS Express
Para simplificar, esta demonstração utiliza o IIS. Para facilitar a configuração do ngrok, desative o SSL no IIS Express acessando as propriedades de depuração do projeto e desmarcando a opção “Ativar SSL”:

Anote o número da porta no campo da URL do aplicativo; ele será usado na próxima etapa.
Configurando o Ngrok
O próximo passo é expor esse endpoint à internet. Para esta demonstração, algo como ngrok pode ser usado para criar um túnel de volta para a porta do IIS Express. Após instalar o ngrok, use um comando como:
Para configurar o túnel, substitua “PORT_NUMBER” pelo número da porta do IIS Express anotado anteriormente. Isso gerará uma saída semelhante a esta:

Anote aqui a URL base http — na imagem acima, a URL base é http://dc0feb1d.ngrok.io.
Configurando webhooks
A etapa final antes de ativar o serviço é configurar os webhooks para que enviem respostas de retorno ao serviço.
SMS recebidas
Vá acessar o Painel da Nexmo e acesse Settings. Defina a URL de mensagens recebidas para SMS como ngrok_baseurl/messages/InboundSms, conforme o exemplo acima.
http://dc0feb1d.ngroke.io/messages/InboundSms Outras mensagens recebidas
No Painel da Nexmo , abra Mensagens e Envio -> Seus Applications. Abra o aplicativo associado às contas vinculadas e clique em “Editar”. Em “Recursos”, na seção “Mensagens”, configure a URL de entrada e a URL de status para corresponderem à URL base do ngrok /Messages/Inbound e /Messages/Status, respectivamente, e clique em “Salvar”.
Seguindo o exemplo do túnel do ngrok, ficará mais ou menos assim:

NOTA: Os 8 caracteres que precedem “ngrok.io” não são fixos no plano gratuito. Isso significa que, toda vez que o comando ngrok for executado, será necessário alterar o destino dos webhooks. É possível criar um nome de host estático ao fazer o upgrade para um plano pago do ngrok.
Ligue o motor e faça um teste
E pronto! O Nexmo Helper do Papai Noel está pronto para ser implantado. Inicie o IIS Express e comece a enviar mensagens. Ele pode ser acessado por qualquer canal configurado para se conectar ao aplicativo de mensagens.
Aqui está um exemplo do Facebook:

E uma mensagem de SMS:

Bem, aí está: o Nexmo Helper do Papai Noel já está em funcionamento.
Leituras complementares
O código-fonte completo desta demonstração pode ser encontrado em GitHub
Para mais informações sobre o QnAMaker, acesse o site deles aqui
Para bots totalmente interativos, confira Luis Ai
Para obter mais informações sobre a Messages API, consulte a documentação em Nexmo Developer
Para conhecer mais APIs da Nexmo, acesse nosso site para desenvolvedores
Para conhecer o SDK do Nexmo para .NET, dê uma olhada no nosso repositório no GitHub