lunes, 29 de julio de 2019

Entidades en dialogflow

Entidades (Entities) en dialogflow


Las entidades en dialogflow es una forma de identificar o agrupar un segmento de datos junto con sus sinónimos dentro de un contexto especifico, las entidades son usadas para guardar segmentos de información especifica proveniente de las entradas del usuario.

Las entidades pueden representar información acercada de punto en particular, como la talla de un productos, los sabores de alguna bebida, las categorías de un producto servicio, los ingredientes de una alimento, las características de un celular, etc. Como podemos ver, son pequeños fragmentos de información acerca de algo.
Las entidades nos permite administrar y manejar la información del usuario de una manera más fácil y entendible.


Supongamos que usamos nuestro bot para nuestra tienda de ropa, podemos crear una entidad por cada categoría de ropa, o en ropa muy particular, una entidad por cada prenda. Ahora supongamos el caso de una pizzeria, puede ser útil una entidad por ingredientes, tipos de masa, tamaño, bebidas, y acompañamientos.


Ejemplo practico


Para entenderlo de forma practica vamos a crear un ejemplo de una agencia de autos, donde contamos con tres tipos de autos; Hatchback, Sendan y SUV. Nuestro bot podrá atender dos tipos de peticiones;


  • Indicar los autos que se venden.
  • Mostrar imágenes del vehículo deseado

Y los complementaremos con el uso de Webhook y Rich Messages(Mensajes enriquecido) como ya lo hemos visto en otro post para brindar una respuesta más visual y ver como se van complementando lo que hemos aprendido hasta el momento.


Pero como encajarían las entidades dentro de este ejemplo; pues bien, sería al momento de solicitar que nos muestre la imagen, la manera en que nos podemos referir a un mismo tipo de auto puede ser diferente, por ejemplo un auto Hatchback podemos referirnos ya sea por Hatchback, hb, cinco puertas, entre otros, así como también podemos usar el modelo para referirnos a dicho vehículo.


Vamos a ver un diagrama para entender un poco mejor el ejemplo que llevaremos a practica.






Una vez que la solicitud llegue a nuestro backend ejecutándose en node mediante el webhook de dialogflow este responderá con un mensaje enriquecido al agente brindado un respuesta más visual.





Datos de ejemplo

Para nuestro ejemplo de una agencia de autos, emplearemos tres vehículos de la marca Mazda, que son el Mazda 3, el Mazda 6 y la CX5 también de Mazda.
Cada uno de estos autos representa una categoría especifica; Hatchback, Sedan y SUV y se puede referir a cada uno de ellos de más de una forma; por ejemplo podemos preguntar por la SUV o por el modelo CX5 y ambos se refieren al mismo vehículo para nosotros.


Crear agente

Antes que nada sera necesario crear un agente en dialogflow o bien usar uno existente, asegúrate de configurarlo en idioma español, en mi caso se olvido, y lo deje en ingles, pero para este ejemplo no hubo alguna repercusión

Entidades

En esta ocación vamos comenzar a crear la Entidad antes de los Intentos, esto por fines prácticos, pero no es necesario seguir este orden.
Vamos al menú de dialogflow para crear nuestra entidad


Y creamos una entidad llamada tipo_auto





Agregamos tres entradas Hatchback, SUV, Sedan y vamos a definir los diferentes sinónimos que podemos usar para referirnos a ellos, aquí he usado los que he considerado, pero te puedes sentir con la libertad de usar otros que consideres más adecuados.





Aquí también podemos considerar algunos errores de dedo que pueda llegar a cometer el usuario y de esta forma poder brindar la respuesta correcta.



Intentos


Ahora es momento de crear los intentos que empleara nuestro agente para entender las peticiones del usuario y brindar una respuesta acorde a ello. Cuando se creo el agente, de forma automática se crearon dos intentos llamados Default Fallback Intent y Default Welcome Intent, nosotros los dejaremos tal cual están, comenzamos creando el primer intento que se llamara preguntar_autos el cual se encargara de brindar información acerca de los vehículos que se manejan en nuestro ejemplo.





Como pueden ver he elegido algunas frases de entrenamiento para nuestro agente que pregunta de manera genera que tipo de autos manejamos o vendemos.

En este intento que acabamos de crear no fijaremos ninguna respuesta, ya que en nuestro backend se encargara de brindar la respuesta adecuada, y solo nos dirigimos al final del Intento y habilitamos el Fullfilment.





Vamos a dejar al final la programación del backend en node y crearemos otro intento que llamaremos solicitar_imagenes, la intención de este intento sera



como pueden apreciar en la imagen usamos frases de entrenamiento para dicho propósito de mostrar la fotos del vehículo deseado, aquí es donde asignaremos la entidad creada dentro de un parámetro, para ello seleccionamos la palabra auto y se desplegara un menú emergente donde le asignaremos el tipo de dato @tipo_auto







Si no ves el tipo de dato, puedes escribirlo en el campo de filtrado


Haremos esta asignación en cada frase de entrenamiento de este intento, y de forma automática el tipo de dato @tipo_auto se agregara a la sección de Action and parameters, en donde definiremos que es un parámetro obligatorio




Para ello marcamos la casilla de Required y definimos la entrada Prompts para indicar un mensaje en caso de que no sea especificado este parámetro







En el caso de este intento también debemos habilitar el webhook para que sea nuestro backend el que responda a la petición del usuario.





Antes de continuar con la programación, también debemos habilitar el agente de dialogflow la opción de fullfilment, en donde indicamos la url pública de nuestro backend.





La url nos la proporciona el sfotware Ngrok que nos permite obtener una url pública y redirigir el trafico hacia nuestro equipo de una manera fácil y rápida; para ello solo basta con correr el comando ngrok http 3000 en tu consola CMD donde 3000 representa el puerto que escucha tu aplicación, puede ser cualquier otro, solo que este disponible y usar el mismo al correr el comando que el que escucha tu aplicación.





Debes usar la url que comienza con https, ya que dialogflow solo permite direcciones que utilicen el puerto seguro 443 que emplea el https, y a esta url agregar la ruta "/entidades"


Backend


Para el caso de nuestro backend como ya lo hemos hecho anteriormente en otro post emplearemos node con el framework Express para nuestra aplicación web, también haremos uso de  mensajes enriquecidos de dialogflow  que también hemos visto con anterioridad


Debido a que dialogflow usa la misma url para el backed, tenemos que identificar por cada petición recibida a que intento corresponde, y para ello es necesario revisar los parámetros de la solicitud revida de la siguiente manera


req.body.queryResult.intent.displayName;


Simplemente usaremos alguna condición para verificar que intento es, y procesar la información  acorde a ello, recuerda que el nombre debe estar escrito de manera exacta al que asignaste al intento que intentas verificar.


Otro punto importen es obtener la variable @tipo_auto que creamos a partir de una entidad, ello lo podemos realizar de la siguiente forma


req.body.queryResult.parameters.tipo_auto;


Una vez dicho esto, y visto previamente el uso de node como backend para dialogflow y el uso de mensajes enriquecidos, un punto muy importante es que para el caso de imágenes, la imagen como tal debes estar una url pública empleando el protocolo https, y debe terminar en .jpg o .png; existen algunos servicios para el alojamiento de imágenes, pero en general solo te da una url sin exención del archivo y suelen emplear un visor; por lo que dicho mecanismo no sirve para los fines que empleamos en este mecanismo.

Dicho lo anterior el código quedaría de la siguiente manera





Puedes correr el programa con la instrucción node app.js donde app.js es nombre del archivo que contiene el código



var express = require('express');
var bodyParser = require('body-parser');
var request = require('request');
var app = express();
//El cuerpo de solicitudes recibidas sera fomateado con formato JSON
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
function respuestaMensaje(){
this.fulfillmentText = '';
this.fulfillmentMessages = [];
}
function mensajeText(){
this.text = {
text: []
};
}
function Image(imageUri, accessibilityText){
this.image = {
imageUri : imageUri,
accessibilityText : accessibilityText
}
}
function ImageCarousel(imageUri, accessibilityText){
this.imageUri = imageUri;
this.accessibilityText = accessibilityText;
}
function mensajeQuickReplies(){
this.quickReplies = {
title : '',
quickReplies : []
}
}
function mensajeCard(){
this.card = {
title : '',
subtitle : '',
imageUri : '',
buttons : []
}
}
function Buttons(text, posback){
this.text = text;
this.postback = posback;
}
function Button(title, uri){
this.title = title;
this.openUriAction = {
uri: uri
}
}
function mensajeSimpleResponse(){
this.simpleResponses = {
simpleResponses : []
}
}
function SimpleResponses(textToSpeech, ssml, displayText){
this.textToSpeech = textToSpeech;
this.ssml = ssml;
this.displayText = displayText;
}
function mensajeBasicCard(){
this.platform = 'ACTIONS_ON_GOOGLE';
this.basicCard = {
title : '',
subtitle : '',
formattedText : '',
image : {},
buttons : []
};
}
function mensajeSuggestions(){
this.platform = 'ACTIONS_ON_GOOGLE';
this.suggestions = {
suggestions : []
};
}
function suggestion(title){
this.title = title;
}
function mensajelinkOutSuggestion(destinationName, uri){
this.platform = 'ACTIONS_ON_GOOGLE';
this.linkOutSuggestion = {
destinationName : destinationName,
uri : uri
};
}
function mensajelistSelect(title){
this.platform = 'ACTIONS_ON_GOOGLE';
this.listSelect = {
title : title,
items : []
};
}
function item(info, title, description, image){
this.info = info;
this.title = title;
this.description = description;
this.image = image;
}
function SelectItemInfo(key, synonyms){
this.key = key,
this.synonyms = synonyms
}
function mensajecarouselSelect(){
this.platform = 'ACTIONS_ON_GOOGLE';
this.carouselSelect = {
items : []
};
}
app.post('/entidades', function(req, res){
var intento = req.body.queryResult.intent.displayName;
var respuesta = new respuestaMensaje();
if(intento == 'preguntar_autos'){
var tarjetaBasica = new mensajeBasicCard();
tarjetaBasica.basicCard.title = 'Mazda';
tarjetaBasica.basicCard.subtitle = 'Zoom-Zoom';
tarjetaBasica.basicCard.formattedText = 'Contamos con autos Sedan, Hatchback y SUVs, haz clic en los enlaces para concer más información';
tarjetaBasica.basicCard.image = new Image('http://media-dmg.assets-cdk.com/websites/content/198485f8a46a4dd7869f8df3e2355050_c1x0-1598x686.jpg', '').image;
tarjetaBasica.basicCard.buttons.push(new Button('Sedan', 'https://www.mazda.mx/vehiculos/mazda-3-sedan'));
tarjetaBasica.basicCard.buttons.push(new Button('Hatchback', 'https://www.mazda.mx/vehiculos/mazda-3-hatchback'));
tarjetaBasica.basicCard.buttons.push(new Button('SUVs', 'https://www.mazda.mx/vehiculos/cx-5'));
respuesta.fulfillmentMessages.push(tarjetaBasica);
}
else if(intento == 'solicitar_imagenes'){
var tipo_auto = req.body.queryResult.parameters.tipo_auto;
var carousel = new mensajecarouselSelect();
switch(tipo_auto){
case 'Hatchback':
carousel.carouselSelect.items.push(new item(new SelectItemInfo('1', []), 'Mazda3 Hatchback',
'Exterior', new ImageCarousel('https://www.mazda.mx/siteassets/mazda-mx/mycos-2019/mazda-3-hatchback/galeria/mazda-3-hatchback-galeria-01.jpg', 'Exterior'))
);
carousel.carouselSelect.items.push(new item(new SelectItemInfo('2', []), 'Mazda3 Hatchback',
'Calaberas', new ImageCarousel('https://www.mazda.mx/siteassets/mazda-mx/mycos-2019/mazda-3-hatchback/galeria/mazda-3-hatchback-galeria-03.jpg', 'Calaberas'))
);
carousel.carouselSelect.items.push(new item(new SelectItemInfo('2', []), 'Mazda3 Hatchback',
'Lateral', new ImageCarousel('https://www.mazda.mx/siteassets/mazda-mx/mycos-2019/mazda-3-hatchback/galeria/mazda-3-hatchback-galeria-09.jpg', 'Lateral'))
);
carousel.carouselSelect.items.push(new item(new SelectItemInfo('2', []), 'Mazda3 Hatchback',
'Interior', new ImageCarousel('https://www.mazda.mx/siteassets/mazda-mx/mycos-2019/mazda-3-hatchback/galeria/mazda-3-hatchback-galeria-02.jpg', 'Interiores'))
);
respuesta.fulfillmentMessages.push(carousel);
break;
case 'SUV':
carousel.carouselSelect.items.push(new item(new SelectItemInfo('1', []), 'Mazada CX5',
'Exterior', new ImageCarousel('https://www.mazda.mx/siteassets/mazda-mx/mycos-2019/mazda-cx-5/galeria/mazda-cx-5-fotos-galeria-01.jpg', 'Exterior'))
);
carousel.carouselSelect.items.push(new item(new SelectItemInfo('2', []), 'Mazada CX5',
'Calaberas', new ImageCarousel('https://www.mazda.mx/siteassets/mazda-mx/mycos-2019/mazda-cx-5/galeria/mazda-cx-5-fotos-galeria-04.jpg', 'Calaberas'))
);
carousel.carouselSelect.items.push(new item(new SelectItemInfo('2', []), 'Mazada CX5',
'Lateral', new ImageCarousel('https://www.mazda.mx/siteassets/mazda-mx/mycos-2019/mazda-cx-5/galeria/mazda-cx-5-galeria-02.jpg', 'Lateral'))
);
carousel.carouselSelect.items.push(new item(new SelectItemInfo('2', []), 'Mazada CX5',
'Interior', new ImageCarousel('https://www.mazda.mx/siteassets/mazda-mx/mycos-2019/mazda-cx-5/galeria/mazda-cx-5-galeria-03.jpg', 'Interior'))
);
respuesta.fulfillmentMessages.push(carousel);
break;
case 'Sedan':
carousel.carouselSelect.items.push(new item(new SelectItemInfo('1', []), 'Mazda 6',
'Exterior', new ImageCarousel('https://www.mazda.mx/siteassets/mazda-mx/mycos-2020/mazda6/galeria/mazda-6-galeria-5.jpg', 'Exterior'))
);
carousel.carouselSelect.items.push(new item(new SelectItemInfo('2', []), 'Mazda 6',
'Calaberas', new ImageCarousel('https://www.mazda.mx/siteassets/mazda-mx/mycos-2020/mazda6/galeria/mazda-6-galeria-12.jpg', 'Calaberas'))
);
carousel.carouselSelect.items.push(new item(new SelectItemInfo('2', []), 'Mazda 6',
'Lateral', new ImageCarousel('https://www.mazda.mx/siteassets/mazda-mx/mycos-2020/mazda6/galeria/mazda-6-galeria-11.jpg', 'Lateral'))
);
carousel.carouselSelect.items.push(new item(new SelectItemInfo('2', []), 'Mazda 6',
'Interior', new ImageCarousel('https://www.mazda.mx/siteassets/mazda-mx/mycos-2020/mazda6/galeria/mazda-6-galeria-10.jpg', 'Interiores'))
);
respuesta.fulfillmentMessages.push(carousel);
break;
default:
break;
}
}
res.json(respuesta);
});
//Bucle indefinido escuhando el puerto 3000, a la espera de peticiones
app.listen(3000, function () {
console.log('App escuchando puerto 3000');
});

Resultado


Vamos a probar el resultado del primer intento preguntar_autos



Recuerda cambiar de Default Response Actions on google para poder ver correctamente la respuesta, que se muestra en un mensaje enriquecido.





Ahora probemos con el intento solicitar_imagenes y veamos el resultado





Lo interesante aquí es que al emplear entidades podemos referirnos a una misma cosa con los diferentes sinónimos que se suelen emplear para hacer referencia a ello, vamos a pedir que nos muestre el mismo vehículo, pero usando otra palabra.




Hemos pedido que nos muestre la cx5 y obtenemos la misma información que pedir que nos muestre la suv, ya que para nuestro ejemplo representa el mismo vehículo.
Si nosotros no empleáramos las entidades tendríamos que repetir todas las frases de entrenamiento con su posibles sinónimos y esto a su vez dentro de cada intento donde queremos emplear dicha información.


Espero les sea de utilidad este post, y les ayude en su proyecto e ideas.

No hay comentarios:

Publicar un comentario

Que tipo de carga rápida usa mi celular

Lo bueno y lo malo de la carga rápida Con la introducción de la carga rápida sin duda ha sido una de las grandes mejoras y a la...