Sunteți pe pagina 1din 14

SERIE BOTS

Bots: cómo crear bots con


Microsoft Bot Framework
y LUIS
Posted onagosto 10, 2016 by jdonsan
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.

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


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:
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:
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:

const moment = require('moment');


const builder = require('botbuilder');
const restify = require('restify');
const server = restify.createServer();

// 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);

// Setup LUIS
const recognizer = new builder.LuisRecognizer('https://api.projectoxford.ai/luis/v1/application?id=26f79385-d6b4-49ec-b4e3-24b6
const intents = new builder.IntentDialog({ recognizers: [recognizer] });

// Setup Intents
intents.matches('Saludar', function (session, results) {
session.send('Hola ¿En que te puedo ayudar?');
});

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 :)');
}
}]);

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'));

bot.dialog('/', intents);

// 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);
});

view rawbot-pizza.js hosted with by GitHub

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 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("Derdo, tu pizza %s llegará a las %s.",
results.response.entity, session.dialogData.time);
} else {
session.send('Deerdo, 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('Pedidocelado correctamente. ¡Vuelva pronto!');


});

intents.matches('Comprobar', function (session, results) {


session.send('Tuza 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/messagesonnector.listen());

server.listen(process.env.port || process.env.PORT || 3978, function () {


console.log('%suchando %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

S-ar putea să vă placă și