Ayuda a tu bot a entender comandos con LUIS

En estos días te he contado cómo puedes crear bots gracias a Microsoft Bot Framework y también cómo interpretar los comandos de tus usuarios con LUIS. En este post vamos a ir un paso más allá integrando ambos para que tu bots también sepan qué es lo que el usuario quiere decir.

Crea un nuevo proyecto Bot Application e instala el paquete Microsoft.Bot.Builder

Nuget - Microsoft.Bot.Builder
Nuget – Microsoft.Bot.Builder

Crea una clase llamada TwitterDialog con el siguiente contenido:

using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Luis;
using Microsoft.Bot.Builder.Luis.Models;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Tweetinvi.Core.Interfaces;

namespace BotAndLuisDemo
{
    [LuisModel("APP_ID", "SUBSCRIPTION_KEY")]
    [Serializable]
    public class TwitterDialog : LuisDialog<object>
    {
        [LuisIntent("")] //None
        public async Task None(IDialogContext context, LuisResult result)
        {
            string message = $"Sorry I did not understand. Could you repeat?";
            await context.PostAsync(message);
            context.Wait(MessageReceived);
        }

        [LuisIntent("SearchUser")]
        public async Task SearchUser(IDialogContext context, LuisResult result)
        {
            var userName = result.Entities[0].Entity;

            try
            {
                await context.PostAsync("This is what he/she says: ");
                var user = TwitterService.GetUser(userName);
                await context.PostAsync(user.Description);

            }
            catch (Exception ex)
            {
                await context.PostAsync(ex.Message);
            }

            context.Wait(MessageReceived);
        }


        [LuisIntent("SearchKeyword")]
        public async Task SearchKeyword(IDialogContext context, LuisResult result)
        {
            IEnumerable<ITweet> tweets = TwitterService.GetKeyword(result.Entities[0].Entity);

            foreach (var tweet in tweets)
            {
                await context.PostAsync(tweet.Text);
            }

            context.Wait(MessageReceived);
        }
    }
}

Esta clase hereda de LuisDialog, la cual te permite interactuar con el servicio de LUIS de una forma muy sencilla. A nivel de clase se le indica cuál es el modelo, a través de su App ID, y cuál es la suscripcion key necesaria para llevar a cabo las peticiones. Estos valores puedes recuperarlos dentro de la aplicación en el portal de LUIS a través de la sección App Settings.

LUIS app - App Settings
LUIS app – App Settings

Cada uno de los métodos de esta clase está decorado con LuisIntent y el nombre de la intención que diste de alta en el post anterior, relacionado con LUIS y Twitter. La idea es que cuando LUIS reciba el comando por parte del usuario sea capaz de analizar y devolver la intención. Cuando esto ocurre atenderá uno de estos métodos, dependiendo de lo que se haya interpretado por el servicio.

Para hacer una demo un poco más elaborada, he utilizado TweetinviAPI que me permite hacer llamadas reales a Twitter dependiendo de la intención del usuario. Las mismas se encuentran en la clase TwitterService.

using System.Collections.Generic;
using System.Linq;
using Tweetinvi;
using Tweetinvi.Core.Interfaces;

namespace BotAndLuisDemo
{
    public static class TwitterService
    {
        static TwitterService()
        {
            const string consumerKey = ""; // The application's consumer key
            const string consumerSecret = ""; // The application's consumer secret
            const string accessToken = ""; // The access token granted after OAuth authorization
            const string accessTokenSecret = ""; // The access token secret granted after OAuth authorization

            Auth.SetUserCredentials(consumerKey, consumerSecret, accessToken, accessTokenSecret);
        }

        public static IUser GetUser(string name)
        {
            return User.GetUserFromScreenName(name);
        }

        public static IEnumerable<ITweet> GetKeyword(string keyword)
        {
            return Search.SearchTweets(keyword).Take(3);
        }
    }
}

Por último, debes modificar el método Post en MessagesController para que use la clase TwitterDialog:

        ///<summary>
        /// POST: api/Messages
        /// Receive a message from a user and reply to it
        /// </summary>


        public async Task<Message> Post([FromBody]Message message)
        {
            if (message.Type == "Message")
            {
                return await Conversation.SendAsync(message, () => new TwitterDialog());
            }
            else
            {
                return HandleSystemMessage(message);
            }
        }

Como puedes ver, se utiliza una clase estática llamada Conversation la cual permite gestionar una conversación, en cuanto a que envía a través de Post la respuesta y espera el siguiente mensajede forma transparente para el desarrollador.

Si ejecutas el ejemplo, podrás preguntar tu bot mejorado “Who is 0gis0?” o “What about Madrid?” y te responderá con el perfil del usuario que mencionas o bien con los últimos tweets que hablan del tema por el que preguntas.

Bot Fw Emulator - Demo with LUIS
Bot Fw Emulator – Demo with LUIS

¡Saludos!