Bots: cómo crear bots con Microsoft Bot Framework y LUIS

Bot-1024x640

Como dijimos en el post anterior, Microsoft está apostando fuerte en el desarrollo de herramientas que nos permitan crear nuevos sistemas de interacción con el usuario.

Hoy quería hablaros un poco más en profundidad sobre dos herramientas que nos ayudarán mucho en la creación de bots. Estas son el Microsoft Bot Framework y el proyecto de inteligencia artificial denominado LUIS.

¿En que nos ayuda Microsoft Bot Framework?

Como su nombre indica, Microsoft ha creado todo un framework para que podamos desarrollar bots de una forma bastante sencilla. Este framework sigue las premisas multiplataformas que Microsoft quiere llevar a cabo con sus herramientas y podemos hacer uso de él tanto si somos desarrolladores JavaScript como si lo somos en C#.

Como podremos ver más adelante en el ejemplo que os explicaré, un bot creado con esta tecnología no deja de ser una aplicación con sus diferentes capas de presentación, lógica y datos. Microsoft Bot Framework está muy orientado a ayudarnos en la capa de presentación ya que nos proporcionará las herramientas necesarias para que podamos obtener peticiones del usuario y poder enviar respuestas de una manera determinada.

El framework se adapta muy bien a las tecnologías Web, nuestro bot acabará siendo una aplicación expuesta por medio de una API bastante flexible y que escucha cualquier respuesta por un endpoint común a todas las peticiones. Por lo que es importante que perdamos el miedo a este tipo de proyecto y que pensemos que es una nueva vuelta de tuerca hasta lo que ahora estamos familiarizados.

Lo bueno que tiene el framework y lo que lo diferencia de cualquier librería o framework dedicada exclusiva a peticiones REST es que contiene un gestor de patrones y expresiones regulares muy potente que nos ayudará a entender mejor lo que el usuario quiere y la acción que deberemos desencaminar.

Por seguir matizando, aunque, como digo veremos el código, para que os hagáis una idea, siempre me gusta explicar que Microsoft Bot Framework son los oídos, labios, manos, y piernas de nuestro bot. ¿Por qué? Pues porque como he dicho, se encarga de escuchar las peticiones, realizar las acciones y explicar al usuario que se ha hecho con la acción que se ha pedido.

Es una herramienta muy potente que sin embargo le falta algo de inteligencia.  Microsoft Bot Framework no es un gran aliado a la hora de tomar decisiones a partir de lo pedido por los usuarios. Es aquí donde el proyecto LUIS nos puede ayudar a encajar todas las piezas.

¿En que nos ayuda LUIS?

LUIS es un proyecto en BETA desarrollado por Microsoft encargado de entender el significado de un texto determinado. LUIS (que son las siglas de Language Understanding Intelligent Service) es un proyecto hospedado online que nos va ayudar a entender lo que un usuario quiere realizar. LUIS es el cerebro de nuestro bot.

LUIS nos proporciona un dashboard con el que poder crear diferentes modelos conceptuales. Este dashboard es una especie de espacio de entrenamiento donde nosotros configuramos cuales son las acciones que queremos que LUIS tenga en cuenta y cuales son los datos o entidades que a nosotros nos va a interesar sustraer de las peticiones de los usuarios.

A partir de aquí, podemos empezar a enviar oraciones a LUIS para que nos la interprete como una acción determinada. Si por un casual se equivocase en su predicción, podemos rectificar y enseñarle cual es la acción que se tiene que realizar. De esta manera, y después de unos cuantos minutos de entrenamiento, podemos ver como siempre LUIS indica la acción que el usuario ha deseado y señala los datos relevantes (una fecha, un lugar, una hora, un nombre con apellidos…) aportados en la frase.

Es una herramienta de inteligencia artificial muy potente que ayuda mucho a reducir las máquinas de estado de nuestra lógica y a tener que hacer un menor uso de expresiones regulares en nuestra API.

LUIS junto con Microsoft Bot Framework forma un tándem a tener en cuenta ya que se integran perfectamente para que trabajen juntos en nuestro sistema.

“Todo esto es muy bonito, pero enséñanos el código”

Como al final, lo importante es ver el código para comprobar como se integra todo correctamente y mostraros que no os miento, vamos a realizar un pequeño ejemplo que nos ayude a entender los conceptos mejor.

El ejemplo que vamos a hacer es uno de los más típicos y se trata de realizar un bot que sea capaz de pedir una pizza especialidad de la casa y que nos llegue a casa en media hora aproximadamente. Podremos ir preguntando al bot el estado de nuestro pedido y si por un casual ya no nos apetece, cancelar el pedido.

Enseñando a LUIS

Para ello vamos a empezar a enseñar a LUIS que acciones y entidades son necesarias para que nos entienda. Los pasos a seguir para esto son:

  1. Entramos a https://www.luis.ai/ y nos registramos.
  2. Pulsamos en New App.
  3. Creamos un nuevo modelo indicando el nombre (en este caso denominado PizzaDelAbismo), una descripción y la cultura en la que queremos que analice los texto. En nuestro caso queremos que comprenda castellano.

luis1Cuando sigamos estos paso tendremos acceso a un dashboard parecido a este:

luis4

La parte importante de esta imagen se encuentra en la parte izquierda de la pantalla, donde tenemos un menú desplegable con las siguientes opciones:

  • App Settings: nos permite modificar la configuración de los datos que indicamos anteriormente.
  • Publish: nos permite exponer nuestro modelo una vez que ya hemos entrenado LUIS a nuestra imagen y semejanza.
  • Intents: nos permite indicar una serie de intenciones en las que queremos entrenar a LUIS. A partir de las frases que le indiquemos siempre intentará emparejarlo con una de estas intenciones.
  • Entities: son datos o entidades que se encontrarán en nuestras fases y que aportan información. Podemos indicar el número de entidades que necesitemos.
  • Pre-build Entities: son una serie de entidades predefinidas por Microsoft que pueden usarse para que LUIS les marque automáticamente.

Como vemos en la imagen yo he definido 5 entidades:

  • Cancelar: es la intención que el usuario tendrá cuando quiera cancelar un pedido.
  • Comprobar: es la intención que tendrá el usuario cuando quiera comprobar como va un pedido.
  • None: es una intención que LUIS tiene por defecto y que es usada cuando no se tiene claro la intencionalidad del usuario.
  • Pedir: es la intención que el usuario tendrá cuando quiera pedir una pizza.
  • Saludar: es la intención que el usuario tendrá que LUIS compruebe que se está inicializando una conversación con un saludo.

En cuanto a las entidades he creado dos:

  • Pizza: que es la entidad que nos indica el tipo de pizza que quiere pedirnos el usuario
  • Datetime: que es una entidad preconstruida que nos permitirá obtener fechas y horas de las frases.

Una vez que tenemos bien definido estos campos, tenemos la parte más difícil de nuestro LUIS ya que delimitar bien las intenciones de una manera abstracta es complicado. Se podrá comprobar si queremos hacer modelos más complejos. Cuando más acotados y discretos sean las intenciones mejorar para conseguir lo que nos proponemos.

La siguiente fase trata de entrenar a LUIS con frases que queramos que sean relacionadas con las intenciones configurada. Para ello usamos la barra central del dashboard. Esta barra es nuestro canal de comunicación de LUIS. Podemos indicarle frases y el nos dirá qué intención tenemos. Iremos confirmando o corrigiendo el comportamiento de LUIS dependiendo de si acertó o falló en la predicción.

En la siguiente imagen vemos el proceso de estudio de una frase por parte de LUIS donde se ha acertado la intención y las entidades que puede sustraer de la oración:

luis2

Seguiremos entrenando a LUIS hasta que estemos seguros de que siempre acierta nuestra intención. Una vez que tengamos esto simplemente tendremos que exponerlo en Internet por medio del botón ‘Publish’. Cuando pulsamos en este botón, si todo ha ido bien, LUIS nos indicará una url donde se encuentra expuesto nuestro modelo:

luis3.png

Con esto podremos integrarlo en nuestro bot.

Creando nuestro bot

Como vamos a realizar nuestro bot con nodeJS, tenemos que empezar nuestro proyecto con npm. Para ello lo primero que vamos a hacer indicar donde queramos tener nuestro bot los siguientes comandos:

-- creamos la carpeta del proyecto
mkdir pizzas-del-abismo
cd pizzas-del-abismo

-- inicializamos el proyecto de node contestando las preguntas
npm init 

-- instalamos restify como librería API REST y botbuilder para tener 
-- Microsoft Bot Framework
npm install restify --save
npm install botbuilder --save

Una vez que tengamos el proyecto listo, desarrollaremos lo necesario y mínimo para tener nuestro bot funcionando. El mio es este:

Analicémoslo en detalle.

  • Lo primero que hacemos es importar las librerías necesarias. Estas son:
    • moment: que nos permite manipular fechas y horas de una forma sencilla.
    • botbuilder: Microsoft Bot Framework que nos permite hacer el bot.
    • restify: que nos permite exponer la API REST.
const moment = require('moment');
const builder = require('botbuilder');
const restify = require('restify');
const server = restify.createServer();
  • A continuación configuramos el conector del bot y creamos un objeto de de tipo UniversalBot. Existen varios tipos de bots, nosotros necesitamos el más genérico por eso hacemos uso de este y no de otro. El appID y el appPassword son parámetros de seguridad. Son necesarios a la hora de publicar el bot en Internet, los explicaremos con detenimiento en el próximo post.
// Setup bot
const connector = new builder.ChatConnector({
    appId: process.env.MICROSOFT_APP_ID,
    appPassword: process.env.MICROSOFT_APP_PASSWORD
});
const bot = new builder.UniversalBot(connector);
  • Lo siguiente en hacer es integrar LUIS dentro de nuestro bot, de esta manera haremos que el bot sepa nuestras intenciones. Como vemos, hay que indicar la url, que LUIS nos proporcionó, de esta manera y usar la clase LuisRecognizer. Obtenemos también un objeto diálogo de tipo Intent. El objeto intent contendrá eventos que se lanzará cuando LUIS haya acertado una intención.
// Setup LUIS
const recognizer = new builder.LuisRecognizer('https://api.projectoxford.ai...);
const intents = new builder.IntentDialog({ recognizers: [recognizer] });
  • Lo siguiente es registrar los diferentes Intents para que el bot realice lo que nosotros deseemos. Tenemos las 5 intenciones con eventos:
  • La intención ‘Saludar‘ que lo único que hace es enviar un mensaje al usuario indicando que qué podemos hacer por él.
intents.matches('Saludar', function (session, results) {
    session.send('Hola ¿En que te puedo ayudar?');
});
  • La intención ‘Pedir‘ que es la más compleja pues tiene una serie de preguntas enlazadas. Está muy bien porque el framework tiene una técnica denominada diálogo en cascada en la que, si por algún casual, no hemos podido obtener toda la información necesaria de una frase podemos seguir haciendo preguntas al usuario sin salirnos de la intención. El bot sabrá el orden de ejecución de las preguntas. A nivel técnico esto se convierte en un array de funciones que se van ejecutando una detrás de otro. Son middleware típicos como los que tenemos en muchas de las librerías de node. En este caso comprobamos si LUIS ha reconocido la pizza que desea el usuario, si no es así se lo pedidos al usuario por medio de un prompt especial que nos permite crear un multichoice. Si lo ha adivinado, pasamos de preguntar y continuamos con nuestro flujo
intents.matches('Pedir', [function (session, args, next) {
    const pizzas = ['Carbonara', 'Barbacoa', 'Margarita', 'Especialidad'];
    const entityPizza = builder.EntityRecognizer
         .findEntity(args.entities, 'Pizza');

    if (entityPizza) {
       const match = builder.EntityRecognizer.findBestMatch(pizzas, 
            entityPizza.entity);
    }

    if (!match) {
       builder.Prompts.choice(session, 
            'Ahora mismo tenemos estas pizzas disponibles, 
            ¿Cual te gustaría probar?', pizzas);
    } else {
       next({ response: match });
    }
}, function (session, results) {
    if (results.response) {
        const time = moment().add(30, 'm');

        session.dialogData.time = time.format('HH:mm');
        session.send("De acuerdo, tu pizza %s llegará a las %s.", 
                results.response.entity, session.dialogData.time);
    } else {
        session.send('De acuerdo, si no te gustan, intenta la próxima vez :)');
    }
}]);
  • Las intenciones ‘Cancelar’, ‘Comprobar’ y ‘default’ simplemente envían un mensaje al usuario para confirmar la acción a realizar. Lógicamente esta funcionalidad se puede complicar todo lo que necesitemos y podremos hacer lo que cualquier API haría: acceder a disco, a sistema de ficheros, a base de datos a otras APIS, consultar a otros bots, etc.
intents.matches('Cancelar', function (session, results) {
    session.send('Pedido cancelado correctamente. ¡Vuelva pronto!');
});

intents.matches('Comprobar', function (session, results) {
    session.send('Tu pizza llegará a las %s', session.dialogData.time);
});

intents.onDefault(builder.DialogAction.send(
        'No he entendido lo que quieres decir'));
  • Después incluimos todas estas intenciones como un diálogo del bot.
bot.dialog('/', intents);
  • Y por último lo exponemos en una API con el enpoint ‘/api/messages’ de tipo POST que serán por donde entren todas las peticiones al bot e indicamos  un puerto establecido como cualquier aplicación node.
// Setup Restify Server
server.post('/api/messages', connector.listen());

server.listen(process.env.port || process.env.PORT || 3978, function () {
    console.log('%s escuchando %s', server.name, server.url);
});

Cómo veis, sencillo y para toda la familia.

Conclusión

Aunque el tutorial es algo extenso, creo que se extrae la esencia de lo que quería enseñaros. El uso de estas tecnologías es sencillo y nos va a dar muchas alegrías en el futuro.

Si queréis ver el ejemplo funcionando, lo tenéis disponible en mi github. En él encontraréis una rama con la estructura ‘didáctica’ expuesto aquí (todo en un único fichero). Pronto lo refactorizaré para que veáis el bot con una estructura más del mundo real que nos permita escalar y mantener mejor nuestro bot.

Para profundizar en las clases, métodos y atributos que ofrece el framework podéis acudir a la documentación oficial.

En próximos posts explicaremos cómo depurar y probar nuestro bots y cómo exponerlo al mundo exterior de una forma sencilla para un gran número de plataformas de chat diferentes. Hasta el momento esto es todo.

Espero que os haya gustado.

Nos leemos 🙂

Imagen portada | msftinsider

Anuncios