Entre todo lo presentado en la reciente Build 2016 destacó la importancia que se le prestó al desarrollo de los Bots conversacionales.
En palabras del CEO de Microsoft, Satya Nadella: «We think this can have as profound an impact as the previous platform shifts have had.«, considerando que el desarrollo de bots que permitan entender el lenguaje natural puede ser la nueva forma de interactuar con los ordenadores/máquinas/dispositivos.
Para construir nuestros propios Bots se presentó el Bot Framework que, actualmente, consta de un conjunto de servicios más un SDK con los que podremos desarrollar nuestro Bot de forma sencilla:
- Bot Connector: Nos permite conectar nuestros bots a otros servicios como Slack, Skype o el Mail de office 365. Así mismo, nos proporciona herramientas para almacenar el estado de las conversaciones, servicios de traducción, telemetría…
- Bot Builder SDK: Disponible tanto en Node.js como en C#.
Además, para conseguir una mejor experiencia y construir bots más desarrollados, podemos conectarlo a otros servicios como LUIS, servicio de reconocimiento de imágenes, speech APIS…
1.- Preparando el entorno
Antes de comenzar, es necesario descargar un par de elementos:
- Bot Template: Template para Visual Studio que nos facilita el empezar un nuevo proyecto ya que tiene todas las referencias necesarias configuradas. Podemos descargarlo desde la siguiente dirección: http://aka.ms/bf-bc-vstemplate. Una vez descargado, copiamos el template a la carpeta correspondiente (%USERPROFILE%\Documents\Visual Studio 2015\Templates\ProjectTemplates\Visual C#), para tenerlo disponible desde Visual Studio.
- Bot Emulator: Que nos instala una especie de ventana de chat donde podemos probar el correcto funcionamiento de nuestro Bot. (http://download.botframework.com/botconnector/tools/emulator/setup.exe). Si lo ejecutamos se nos mostrará una ventana como ésta:
2.- Primer vistazo a la aplicación
En primer lugar, abrimos Visual Studio y creamos un nuevo proyecto. En la ventana emergente, elegimos el template que hemos introducido previamente (Bot Application), asignamos un nombre a nuestro proyecto (FirstBasicBot) y pulsamos en crear:
Vamos a repasar un poco la estructura que nos ha creado. Vemos que se trata, básicamente, de una WEB API;donde, además de la configuración básica (WebApiConfig), tenemos un controlador, llamado MessagesController. Dicho controlador se va a encargar de tratar los mensajes que se reciban del usuario y devolverá un nuevo mensaje como respuesta. Todo ello se lleva a cabo en el método Post del controlador:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public async Task<Message> Post([FromBody]Message message) { if (message.Type == "Message") { // calculate something for us to return int length = (message.Text ?? string.Empty).Length; // return our reply to the user return message.CreateReplyMessage($"You sent {length} characters"); } else { return HandleSystemMessage(message); } } |
Como vemos en el código, si el mensaje recibido es del tipo Message, se calcula el número de caracteres del mensaje y se devuelve la respuesta. En el caso de que no se trate de un mensaje de tipo Message, se llama al método HandleSystemMessage:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
private Message HandleSystemMessage(Message message) { if (message.Type == "Ping") { Message reply = message.CreateReplyMessage(); reply.Type = "Ping"; return reply; } else if (message.Type == "DeleteUserData") { // Implement user deletion here // If we handle user deletion, return a real message } else if (message.Type == "BotAddedToConversation") { } else if (message.Type == "BotRemovedFromConversation") { } else if (message.Type == "UserAddedToConversation") { } else if (message.Type == "UserRemovedFromConversation") { } else if (message.Type == "EndOfConversation") { } return null; } |
En este método, dependiendo del tipo de mensaje (se añade el bot a una conversación, se añade un usuario a una conversación, se termina la conversación…) podemos configurar el mensaje de respuesta deseado.
3.- Desarrollando una funcionalidad básica
Como hemos visto, el template que nos proporcionan simplemente hace que nuestro Bot responda a los mensajes del usuario contando la cantidad de caracteres que tienen. Nosotros vamos a modificar esta funcionalidad y vamos a hacer que nuestro bot nos traduzca cualquier mensaje introducido en español al japonés.
Para ello, utilizaremos la Microsoft Translation API (https://www.microsoft.com/en-us/translator). Esta API se ofrece a través de la Microsoft Azure Marketplace, por lo tanto, necesitarás una cuenta para poder usarla. Una vez identificados en el portal, nos dirigimos a https://datamarket.azure.com/dataset/bing/microsofttranslator y elegimos el plan de suscripción que deseemos (en nuestro caso el plan gratuito, que nos ofrece 2000000 de caracteres al mes de traducción). Pulsamos en registrar, vamos aceptando las condiciones de uso que nos vayan apareciendo hasta que lleguemos a la pantalla de confirmación:
El siguiente paso consiste en registrar nuestra aplicación en el sistema. Para ello, acudimos a la siguiente dirección: https://datamarket.azure.com/developer/applications/register, rellenamos el formulario y pulsamos en crear:
En la siguiente pantalla se nos informará si todo se ha desarrollado correctamente, junto con un listado de nuestras aplicaciones y si éstas se encuentran en modo activo o no.
Volvemos al código y creamos nuestra clase Translation, donde llamaremos al API de traducción con el mensaje que nos proporcione el usuario y obtenemos el mensaje traducido como respuesta:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public static async Task<string> GetTranslation(string messageToTranslate) { var token = await GetAccessToken(); var uri = string.Format("http://api.microsofttranslator.com/v2/Http.svc/Translate?text=" + System.Web.HttpUtility.UrlEncode(messageToTranslate) + "&from={0}" + "&to={1}", LanguageFromCode, LanguageToCode); using (var client = new HttpClient()) { client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); var response = await client.GetAsync(uri); var translatedStream = new StreamReader(await response.Content.ReadAsStreamAsync()); System.Xml.XmlDocument xTranslation = new System.Xml.XmlDocument(); xTranslation.LoadXml(translatedStream.ReadToEnd()); return xTranslation.InnerText; } } |
El método que presentamos es muy sencillo. En primer lugar, obtenemos un token de acceso para realizar nuestra llamada, posteriormente generamos la dirección pasándole la cadena a traducir, el idioma de origen (el inglés viene por defecto y añadimos el español) y el idioma destino (en nuestro caso, el japonés). Los códigos de idioma se pueden obtener en la siguiente dirección: https://msdn.microsoft.com/en-us/library/hh456380.aspx
Una vez hecho esto, realizamos la petición y procesamos la respuesta.
La obtención del token se realiza en el siguiente método:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
private static async Task<string> GetAccessToken() { var clientID = "YOUR CLIENT ID"; var clientSecret = "YOUR CLIENT SECRET var baseAddress = "https://datamarket.accesscontrol.windows.net/"; var keyValues = new List<KeyValuePair<string, string>> { new KeyValuePair<string, string>("grant_type", "client_credentials"), new KeyValuePair<string, string>("client_id", clientID), new KeyValuePair<string, string>("client_secret", clientSecret), new KeyValuePair<string, string>("scope", "http://api.microsofttranslator.com") }; using (var client = new HttpClient()) { client.DefaultRequestHeaders.Accept .Add(new MediaTypeWithQualityHeaderValue("application/json")); var request = new HttpRequestMessage(HttpMethod.Post, baseAddress + "v2/OAuth2-13") { Content = new FormUrlEncodedContent(keyValues) }; var response = await client.SendAsync(request); var content = await response.Content.ReadAsStringAsync(); var result = JsonConvert.DeserializeObject<AdmAccesToken>(content); return result.AccessToken; } |
Configuramos nuestra llamada con nuestras credenciales (client id y la app secret key) y realizamos una llamada post a la dirección web adecuada con esas credenciales. La respuesta la deserializamos utilizando una clase auxiliar llamada AdmAccessToken, de la cual nos interesa la propiedad AccessToken.
A la hora de publicar nuestro bot, hemos de considerar un aspecto que no hemos tenido en cuenta aún. Abrimos el fichero web.config y nos centramos en el apartado appSettings dentro de Configuration. En él aparecen dos variables a configurar que son el AppId y el AppSecret. Estas dos variables tendremos que actualizarlas cuando publiquemos nuestro bot. Por ahora, para probarlo en local, las dejamos de la siguiente forma:
Ejecutamos, la aplicación, y esperamos que nos salga la pantalla de confirmación de que el bot está corriendo en nuestro sistema. Como vemos, se habrá arrancado nuestro IIS local y el bot se encuentra en la dirección localhost:3978, quedando el endpoint para traducción de mensajes en localhost:3978/api/messages.
Abrimos el bot simulator, configuramos los párametros Url, AppId y AppSecret de la forma que se indica en la pantalla siguiente, y ya podemos probar nuestro bot:
4.- Publicando el bot
Para darle vida a nuestro bot pasamos a publicarlo
- En primer lugar, publicamos nuestro bot en Azure. Para ello, hacemos click en nuestro proyecto con el botón derecho y le damos a publish:
- Pulsamos en Microsoft Azure App Service y nos aparece la siguiente ventana:
- Pulsamos en New y completamos el formulario con los datos que deseemos:
- Pulsamos en Create, y seremos redirigidos a la pantalla previa de publicación, donde pulsaremos en publish. (importante poner la dirección https:// en lugar de http://)
- Perfecto, ya tenemos el bot publicado en Azure. Ahora tenemos que dar de alta un bot en la página bot framework y vincularlo con el servicio que acabamos de publicar. Para ello, acudimos a https://dev.botframework.com/#/bots/new , iniciamos con nuestra cuenta y vemos el siguiente formulario:
- Lo rellenamos con los datos apropiados, y pulsamos en register. Es importante considerar que, como endpoint tenemos que poner la dirección completa hacia el endpoint de mensajes, es decir, la uri base junto con /api/messages. Nos aparecerá un pop up avisándonos que el bot se ha creado correctamente.
- Se nos redirige a una página con la información de nuestro bot. A la izquierda, tenemos un panel con los detalles de nuestro bot y a la derecha el conjunto de servicios con los que podemos conectarlo. También, en la parte inferior izquierda, se nos muestra un pequeño panel para probar si el bot funciona correctamente o no.
- Observamos que el bot no funciona correctamente. Esto es debido a que tenemos que actualizar los variables que teníamos en el Web.config con los valores que nos proporciona la página. Para ello, volvemos a Visual Studio, abrimos el Web.config y copiamos el valor de App Id y el de Primary app secret. Cuando realizamos esto, tenemos que volver a publicar el bot en azure, haciendo click con el botón derecho en nuestra aplicación y pulsando en publish.
- Volvemos a la página de configuración del bot, y probamos si funciona correctamente:
En este caso, observamos el json que se utiliza en la comunicación entre el bot connector y nuestro bot.
4.1.- Publicación en Telegram
- Nos dirigimos a la parte derecha, donde se encuentran los canales, y pulsamos Add dentro de la sección de Telegram. Se nos redirigirá a la página de configuración del servicio, donde se nos muestra los pasos que tenemos que realizar para publicar nuestro bot en Telegram:
- Seguimos los pasos que nos presentan:
- Vistamos al bot father (https://telegram.me/botfather).
- Cuando se nos abra la pantalla de chat, introducimos el comando /newbot.
- Le damos un nombre y un nombre de usuario.
- Copiamos el token que nos proporciona bot father.
-
- Pegamos el token en la página de configuración previa y pulsamos en Submit.
- Cuando nos aparezca la confirmación de que se ha enviado correctamente, marcamos la casilla de activar el bot en telegram y pulsamos el botón de terminar configurando telegram.
No perdáis la oportunidad de usar el JapoBot en telegram 🙂 .
5.- Conclusiones
Es realmente sencillo configurar y poner en funcionamiento un bot utilizando estas nuevas herramientas. Tenemos ante nosotros un mundo de posibilidades que podemos explorar realizando bots cada vez más complejos y que nos proporcionen una utilidad destacable.
Este post es sólo un ejemplo de todo lo que podemos llevar a cabo. Si hay interés, en futuras entradas podemos conectar bots con servicios externos, como LUIS (language understanding intelligent service) para conseguir que el bot entienda el lenguaje natural o preparar una funcionalidad compleja.
6.- Referencias
Codigo en github: https://github.com/franmolmedo/japobot
http://www.theverge.com/2016/3/30/11331388/microsoft-chatbots-ai-build
Deja un comentario