Alexa skill – Qué pasa en Murcia!

Otro de los Alexa skill que están ya funcionando es el Qué pasa en Murcia.

En este caso, no es necesario utilizar el motor de Baúl de Noticias ya que los artículos que se leen son los publicados en la web http://quepasaenmurcia.net

El funcionamiento es el mismo que Noticias Albacete:

  • “Alexa, abre Noticias Albacete”
  • “Noticias de Albacete. Quieres la última noticia o te leo los titulares”
  • “Titulares”
  • DanzaEñe 2018. II Muestra de Danza Contemporánea Española
  • Nueve destacadas compañías han sido seleccionadas para mostrar sus creaciones durante tres intensos días, en los que se combinarán los espectáculos abiertos al público con el encuentro entre programadores internacionales y creadores […]

Esta skill no es más que otra manera de disfrutar de los artículos y reseñas del gran Nacho Ancho, sobre música, cine, teatro y danza de Murcia. Además está la página de Facebook y la ya mencionada página web.

Alexa skill – Noticias Albacete

Una de las aplicaciones del proyecto Baúl de Noticias – NewsChest es esta Alexa skill: Noticias Albacete

Los artículos se toman desde la categoría Albacete de esta página web.

El funcionamiento es muy sencillo:

Se añade un artículo nuevo cada hora acorde a los criterios definidos. En este caso, se priorizan los deportes, arte, espectáculos y relacionados con la administración (Ayuntamiento, JCCM …) Se deberían ver más de estos temas que de otros, como política y economía, por ejemplo.

En el tiempo que lleva funcionando, unos seis meses, los usuarios han penalizado (no les han gustado) los artículos que reflejaban conflicto y que contaban eventos planificados a futuro.

Por otro lado, se han valorado positivamente los artículos que cuentan sucesos inesperados.

Proyecto Baúl de Noticias – NewsChest

Cuando cualquiera de nosotros, humanos, empezamos a leer o escuchar una noticia, determinamos el nivel de interés o relevancia que tiene. Lo hacemos constantemente y de manera casi inconsciente.

Nuestro cerebro nos permite valorar múltiples factores simultáneamente sin ser plenamente conscientes de cuáles son y cuál es la importancia de cada uno de ellos. Después de unos segundos, a veces, una fracción de segundo, sabemos cómo de relevante es un texto o noticia para nosotros.

Por otra parte, nuestros intereses cambian y evolucionan de manera natural. Lo que nos parecía interesante a los 18, puede ya no serlo tanto a las 38 y quizá menos aún a los 48. Los criterios de valoración se adaptan en función de nuestra experiencia e influencias externas.

Pero ¿cómo puede valorar una máquina la relevancia o interés de una noticia? Las máquinas tienen potencial, pero hay que enseñárselo todo paso a paso. A partir de aquí voy a describir cómo lo hice yo, espero que os resulte interesante y relevante.

En este artículo (en inglés) de Wikipedia se explica el mecanismo utilizado por los medios de comunicación para seleccionar qué noticias se publican. Al final, hay una lista de criterios que he filtrado y tomado como base.

Cada uno de los criterios se puede asociar a una lista de palabras. Por ejemplo, las palabras enfrentamiento, contrario, desacuerdo y demanda indican conflicto. Por otro lado, inesperado, imprevisto, fortuito, de repente y sin previo aviso, indican imprevisibilidad (espero que exista).

Con este enfoque y la lista de criterios del artículo anterior se puede diseñar un motor de relevancia, que toma un artículo como entrada y da un valor entre 0 y 10, por ejemplo, como salida.

En un entorno estático y objetivo, la cosa se acabaría aquí, pero nos movemos en un mar de subjetividades, nada es absoluto, todo depende de quién, dónde y cuándo. Los criterios se deben adaptar a la audiencia y al entorno y quien debe marcar la dirección de esa evolución es el lector, el usuario, el que elige leer o no cada artículo.

Esto nos lleva al objetivo del proyecto: implementar un sistema en el que personas con criterios (humanos) enseñen a las máquinas a aplicar esos criterios automáticamente. Es decir, un sistema de aprendizaje automático guiado por criterios humanos y adaptables.

Los resultados, a modo de ejemplo, del desarrollo de este sistema se pueden ver en:

Implementando adecuadamente lo anterior, se tiene un modelo dinámico que va ajustando los pesos de los criterios en función de las preferencias de los usuarios. Un sistema de este tipo, le daría a los lectores más de lo que más les gusta y menos de lo que menos les gusta.

Este es el enfoque utilizado por los motores de recomendación de Google, Facebook, Netflix … el objetivo de este artículo no es valorar si dicho enfoque es el adecuado o no. Pero es un tema interesante.

El resto del artículo explica cómo desarrollarlo y va en un tono un poco más técnico, sorry.

  1. Se establece una lista de criterios y se asocian los términos a cada criterio.
  2. Se asigna un peso inicial a cada criterio, digamos 10.
  3. Se diseña un mecanismo en el que el usuario/lector pueda aprobar o suspender un artículo, un +1 o un -1. A día de hoy, estas entradas vienen de botones en la página web y de patrones de uso de algunos Alexa skills.
  4. Se revisa cómo dicho artículo puntuó en cada criterio.
    1. Si el lector valoró negativamente el artículo
      1. los criterios en donde el artículo tuvo una puntuación alta deben tener menos peso. El 10 inicial se debe aumentar a un 10,001, por ejemplo.
      2. los criterios con una puntuación baja, deben tener más peso.
    2. Si el lector valoró positivamente el artículo
      1. se debe reducir el peso de los criterios con puntuación baja. El 10 inicial pasaría a algo así como 9,999
      2. se aumenta el peso de los criterios con puntuación alta.

Además de criterios asociados al contenido, se puede valorar el origen del artículo, es decir, dónde se ha publicado. Aquí el peso no se modifica, sino que se valora cada dominio.

Para terminar, uno de los factores clave es la novedad. Un artículo publicado ahora mismo tendrá la máxima puntuación que irá decreciendo con el tiempo hasta alcanzar, en mi caso, el valor cero en 72 horas.

Alexa skill: Palabras Encadenadas

Hoy Amazon ha publicado la versión completa del skill Palabras Encadenadas. Estoy contento de como ha quedado, la verdad.

El juego es muy sencillo, el jugador y Alexa enlazan palabras, la última letra de la palabra anterior es la primera de la siguiente. Algo así como “evento“-“organización“-“nebulosa” ….. Podría hacerse hecho enlazando sílabas en lugar de letras, pero no en todos los idiomas es sencillo.

Más allá del juego en sí, hay varias cosas interesantes que mencionar:

Multi-idioma y multi-país

Se puede jugar en tres idiomas:

  • inglés, se llama back to back words
  • español, palabras encadenadas
  • alemán, se llama schlangenwort

y las versiones en italiano y francés están en preparación.

Está disponible en ocho paises: UK, USA, Canadá, Australia, India, España, Mexico y Alemania. Cada país con su acento propio.

Diccionario va creciendo

Este skill cuenta con un diccionario para cada idioma de entre dos mil y cinco mil palabras. De ahí es de donde se eligen las palabras para el juego.

Durante el juego, cada palabra que el jugador utiliza se añade al diccionario para ir mejorándolo continuamente.

Análisis de la frecuencia de uso de palabras por región

El jugador tiene la opción de compartir su país y código postal para participar en este estudio. El objetivo es analizar si hay alguna correlación entre la región y las palabras más utilizadas.

Se hará para los ocho países pero habrá que esperar a tener muchos jugadores que hayan jugado muchas veces para que los resultados sean significativos.

Cómo desarrollar una Alexa Skill en 4 pasos

Nota: este artículo está basado en la documentación publicada por Amazon y en mi propia experiencia de desarrollo de Alexa skills y Actions on Google Assistant.

Paso 1: Diseñar el interfaz de voz

Para desarrollar una skill, lo primero que se necesita es tener una idea de la función que realizaría. Como (casi) todos tenemos un smartphone, seguro que tenemos ideas de apps. Ese puede ser un principio. Luego hay que pensar en las particularidades que tienen los SmartSpeakers como Alexa.

La interacción debe diseñarse exclusiva y específicamente para voz

En la pantalla de un móvil se puede mostrar mucha información y la usuaria tendrá tiempo para mirar, pensar y elegir qué hacer. Por voz, la situación es distinta, típicamente, se puede retener entre tres y cinco opciones en mente, pero si hay más, es probable que no se recuerden las anteriores y se tengan que repetir. Hay que estructurar bien las frases y tener muy en cuenta el contexto para excluir la información poco relevante.

Por otra parte, cuando se tiene una conversación con una persona, aunque las palabras aportan una buena parte del significado, la entonación y los gestos son claves. En una conversación con Alexa no habrá gestos y la entonación no se tiene en cuenta. Esto hace que las palabras deban ser muy precisas y que haya que pensar muy bien qué se va a decir y cómo.

El nivel de privacidad es distinto al de un móvil

Este tipo de dispositivo puede estar en el salón, en la cocina, en el coche, donde varias personas pueden oir los mensajes, no solo la usuaria. Creo que los bancos aún no han entrado en este sector y tengo curiosidad de ver como se manejan cosas como claves de acceso, saldos de cuentas bancarias, número de tarjeta de crédito, etc.

La búsqueda no es su fuerte

Imáginate que quieres poner una canción de Pablo Milanés pero no te acuerdas del título de la canción ni del disco. La conversación con Alexa sería una cosa así:

  • Tú: Alexa, dime los álbumes de Pablo Milanes
  • Alexa: La carrera discográfica de Pablo Milanés comenzó en 1968 con una colaboración en el álbum “Canción protesta. Casa de las Américas”. ¿Es este el disco que buscabas?
  • Tú: No, sigue
  • Alexa: En 1969 colaboró en otros cinco discos: “Vietnam canta a Cuba”. ¿Es este el disco que buscabas?
  • Tú: No, sigue
  • Alexa: “26 de Julio. Los nuevos héroes”. ¿Es este el disco que buscabas?
  • Tú: Si, gracias. ¿Qué canciones hay en ese disco?
  • Alexa: “Canción del elegido”. ¿Es esa la canción que buscabas?
  • Tú: No, sigue
  • Alexa: Hay un almanaque lleno de 26. ¿Es este el disco que buscabas?

Bueno, creo que el problema está claro. Si lo que quieres es buscar una canción o cualquier otro tipo de contenido, la pantalla táctil de tu móvil o, mejor aún, tu ordenador son herramientas mucho mejores que Alexa u otro SmartSpeaker/ Virtual Assistant.

Haces la búsqueda en Google o Spotify con los datos que recuerdes y luego, una vez identificada la canción, dices “Alexa, pon la canción Moncada de Pablo Milanés”.

Paso 2: Preparación del Interaction Model

Prefiero mantener los términos en inglés, al fin y al cabo la documentación no está en español y el portal de desarrollo tampoco (solo en inglés y japonés).

Salvando el tema del idioma, diseñar y preparar un interaction model no requiere conocimientos técnicos y está al alcance de cualquiera de vosotros. De hecho, os animo a intentarlo.

El interaction model es básicamente cómo Alexa va a estructurar lo que el usuario dice, es decir, las instrucciones que podemos darle dentro de este skill. Se ve mejor con un ejemplo, sea un skill (llamado Baúl de Noticias) que te puede dar las noticias de varios temas:

  • Alexa, lee los titulares de Albacete
  • Alexa, lee el primer artículo
  • Alexa, siguiente
  • Alexa, repite
  • Alexa, para

Los intents en este caso serían

  • Intent.ReadHeadline: “lee los titulares de” + <tema>
  • Intent.ReadArticle: “lee el artículo de” + <tema>
  • Intent.Next: “siguiente” | “adelante”
  • Intent.Repeat: “repite” | “otra vez”
  • Intent.Stop: “para” | “por favor, para” | “salir”

Donde <tema> puede ser, por ejemplo: “Albacete | Robótica| Euskadi | Sushi”. Una vez que el usuario elige el tema, se asume que se continúa con el mismo, para que no tenga que repetirse, hasta que se asigne otro.

Paso 3: Desarrollar la función de respuesta

Para esta parte sí que se necesitan ciertos conocimientos técnicos y de programación, pero si no los tenéis, os animo a que aprendáis Javascript, lleva algún tiempo, pero merece la pena.

En el apartado anterior se estructuraban las instrucciones del usuario, en éste se ve cómo preparar la respuesta para cada instrucción.

Hay dos modos de desarrollar esa función, uno es por tu cuenta y riesgo y otro es en aws.amazon.com (la nube de Amazon). Yo he optado por la segunda opción por varias razones: está muy bien pensada y diseñada, es gratis si tomas ciertas precauciones y así lo tienes todo con Amazon que se ocupará de que todo funcione bien para que su muy querida Alexa tenga éxito.

AWS proporciona muchos servicios, en este caso nos centramos en Lambda para implementar la función en node.js que reciba las instrucciones del usuario y construya la respuesta:

  1. Crear una función Lambda, tomando como ejemplo alguno de los blueprints que empiezan con “alexa-….”
  2. El tema de los permisos en AWS es tedioso y lioso, pero hay que hacerse con ello. Creas un custom role con acceso a CloudWatch y DynamoDB y le das “Create Function”
  3. Desde la parte izquierda, añades Alexa Skill Kit como trigger. Para que tu función solo sea llamada por tu skill, pon el Skill ID en Skill Verification y guarda los cambios. Puedes encontrar el Skill ID en la pantalla EndPoint de tu skill (en developer.amazon.com)
  4. En el index.js de la función, ya tienes código que puedes usar para desarrollar tu propio función. Borra lo que no te interese pero mantén la estructura del código, Amazon te asegura que ese código funciona.
  5. Arriba a la derecha verás un identificador que empieza por arn:aws:lambda: y que acaba con :function:nombre_de_tu_funcion. Eso es lo que tienes que poner en el tu skill, pantalla EndPoint como AWS Lambda ARN. Así es como se enlaza una parte con la otra.

Paso 4: Pruebas, certificación y publicación

Se puede hacer pruebas a varios niveles

Prueba unitaria de la función Lambda

Desde el propio editor de la función se pueden crear casos de prueba. Pincha en el drop-down de Test para crear eventos de prueba. Se debe tener, al menos, un evento por cada intent. Si la función considera estados, habrá que tenerlos en cuenta durante las pruebas.

A este nivel es suficiente con que la función devuelva una respuesta sin errores y con los mensajes correctos. Intentar probar secuencias de eventos aquí es muy complicado y no merece la pena.

Prueba integrada desde el simulador

En la consola de desarrollo cada skill tiene una pantalla de Test, desde ahí puedes simular las instrucciones del usuario y comprobar que las respuestas son las correctas.

También se puede probar que Alexa lee correctamente tus mensajes. Siempre hay cosas que leídas parece que están bien, pero luego al leerlas vemos que no, sobre todo con caracteres no alfanuméricos: “…” a veces lo lee como “punto, punto, punto”, “-“ lo puede leer como “menos”

Prueba end-to-end desde Amazon Echo

Si activas tu Amazon Echo con la misma cuenta que usas en el portal de desarrollo, podrás probar el skill antes de que esté aprobado.

Aquí la prueba será ya hablada, dando las instrucciones al Amazon Echo como el usuario las dará en su momento. Si todo te funciona bien aquí, puedes estar seguro que el skill está listo.

 

Si has llegado hasta aquí, primero, gracias por leerlo todo y segundo, entiendo que realmente te interesa el desarrollo de Alexa skills.

Hay otro post en este blog con una descripción de cómo desarrollar Alexa skills avanzados. Es decir, casos en los que además de la conversación en sí, hay funcionalidades complejas detrás. Todo está desarrollado en AWS.

 

Alexa skills – Nivel avanzado – Usar AWS-S3 como almacenamiento intermedio

En algunas skills, como mi Baúl de Noticias, se utiliza almacenamiento intermedio que no necesita estar en Base de datos.

Baúl de Noticias lee artículos de varios RSS, que se generan en https://blaya.club/NewsChest utilizando WordPress. Os voy a contar cómo la solución ha evolucionado desde la más básica hasta la actual con la que estoy bastante contento.

Solución inicial:

Cada vez que un usuario solicita leer un artículo, se hace una llamada GET a la URL donde se encuentra la RSS. El problema es que el rendimiento no es bueno (el tiempo de respuesta estaba entre 1 y 2 segundos) y el tráfico de datos puede ser significativo (el RSS generado por WordPress tiene unos 25Kb)

Solución mejorada:

Dentro de una misma sesión, el usuario puede leer varios artículos, así que la primer mejora fue leer la RSS sólo una vez al principio de la sesión y guardarla como parte de la estructura session.attributes. Ver este post en donde se explica cómo hacerlo.

El problema aquí era que los 25Kb, aunque se leían solo una vez de la RSS externa, viajaban mucho entre AWS y el servidor de las skills, haciendo que el rendimiento no fuese bueno y que además saltase la alarma del free-tier  (Amazon iba a empezar a cobrarme por el tráfico de datos)

Solución optimizada:

El contenido de la RSS se almacena en AWS S3 y se refresca cada hora. Cómo?

La función Lambda accede a S3 y comprueba la hora de actualización

Si fué actualizada hace más de una hora, se lee la RSS externa y se remplaza

Si fué hace menos de una hora, se lee el contenido del objeto S3.

Esto hace que solamente se acceda a la RSS externa una vez por hora como mucho (esa sigue tardando entre 1 y dos segundos). Además no se tiene por qué guardar la RSS en session.attributes con lo que disminuye el consumo de memoria y los accesos a DynamoDB.

El tiempo de respuesta que tengo así es de entre 200 y 500 msegs.

Os paso el código que está funcionando – perdón por la indentación.


var objectID = (host+path).replace(/\//g,'-') + '.xml';
s3.headObject( {Bucket: bucket, Key: objectID}, function(err, data) {
var body='';
if( (err && err.code === 'NotFound')
|| (data && (((Date.now()-    Date.parse(data.LastModified))/(60*1000)) > 60) ) )
{
feed.get( {'host': host, 'path': path}, function(res) {
res.on( 'data', function (chunk) {
body += chunk;
});
res.on( 'end', function () {
s3.upload({Bucket: bucket, Key: objectID, Body: body},  function(err, data) {
if (err)
console.log("Error uploading data: ", err);
else
console.log("Uploaded: " + body.length + " bytes");
});
});
});
}
else {
s3.getObject( {Bucket: newschestBucket, Key: objectID}, function(err,data) {
if( err )
console.log( "Error: " + err );
if( data )
body = data.Body.toString('utf-8');
});
}
});

Alexa skills – Nivel avanzado – Utilizar datos de usuario

Se puede solicitar al usuario que autorice a una Alexa skill a utilizar ciertos datos. Para ello, se debe marcar en la pestaña “Permissions” los datos que se utilizarán.

Cuando el usuario active la skill, deberá dar la autorización.

En el back-end se hace una llamada GET de este tipo

Host: api.amazonalexa.com
Accept: application/json
Authorization: Bearer <access_token>
GET https://api.amazonalexa.com/v2/accounts/~current/settings/Profile.name

Host es específico de cada región AWS y viene como parte de la estructura JSON event en el campo apiEndpoint.

El access_token llega en el campo apiAccessToken.

En el resultado de la llamada GET, se recibe la información solicitada, por ejemplo:

{ email : yo@correo.com }

Alexa contra Google Home

Me he centrado en desarrollar Alexa skills pero también he hecho algún AoG (Actions on Google), el equivalente para Google Assistant.

Un día tuve curiosidad por ver a una hablando con el otro y compitiendo, así que  modifiqué la versión inglesa de mi skill Palabras Encadenadas y los puse a jugar. El resultado, creo que interesante y curioso, es este:

Alexa skills – Nivel Avanzado – Conexión de sensores IoT

Todos hemos leído sobre el IoT (Internet of Things, el Internet de las cosas). No es más que conectar aparatos que no van a ser manejados por humanos, es decir, que funcionan solos. Por ejemplos, sensores que activan la calefacción o el aire acondicionado a una determinada temperatura. También pueden ser sensores de humedad que activan el riego en los campos cuando hace falta o sensores que avisan al repartidor cuando la máquina expendedora se va a quedar sin latas de refresco. El uso del IoT está creciendo mucho y las posibles  aplicaciones son muy numerosas.

Amazon comercializa unos sensores que llama “AWS IoT Enterprise Button” por 25€ que una vez conectados a WiFI, se conectan fácilmente a AWS y desde ahí se pueden integrar con una Alexa skill. El botón distingue tres tipos de pulsación, sencilla, doble o larga. Por ejemplo, se podría utilizar a modo de detector de presencia o a modo de confirmación.

La parte de programación se resuelve fácilmente:

// Estructura JSON de event
// { "serialNumber": "GXXXXXXXXXXXXXXXXX",
// "batteryVoltage": "xxmV",
// "clickType": "SINGLE" | "DOUBLE" | "LONG" }

exports.handler = (event, context, callback) => {
    console.log('Received event:', JSON.stringify(event) );

    if( event.serialNumber != 'G1234567890' ) {
        console.log( "Dispositivo desconocido" );
        // Error lanzar alerta
        callback( event.serialNumber );
    }
    switch (event.clickType) {
    case 'SINGLE':
        // Realizar acción 1
        break;
    case 'DOUBLE'
        // Realizar acción 2
        break;
    case 'LONG'
        // Realizar acción 3
        break;
    default:
        callback( event.clickType );
    }
    callback( null, 'ok' );
}

Alexa skills – Nivel avanzado – Alertas

Una vez que la skill esté funcionando de manera estable, no hará falta que estemos mirando los logs cada rato, asumiremos que todo funciona bien. Pero como decía en otro post, la informática no es una ciencia exacta y los sistemas dejan de funcionar a veces sin razón aparente.

Además de las propias de AWS, es una buena práctica definir alarmas o alertas propias dentro de nuestro código. Algunos ejemplos: error al leer o escribir en la base de datos, error al enviar un mensaje SQS, intent no soportado …

Con AWS SNS se puede desarrollar una solución práctica y sencilla.

docClient.query( params, function(err, data) {
    if( err ) {
        var publishTextPromise = new AWS.SNS({apiVersion: '2010-03-31'})
            .publish({
                Subject: "Error en DynamoDB query",
                Message: JSON.stringify(err),
                TopicArn: SNS_TOPIC
            }).promise();
        publishTextPromise.then( function(data) {
            console.log( err );
        }).catch( function( err ) {
            console.error( err, err.stack );
        });
    }
}

Después se realiza una subscripción al SNS_TOPIC y se indica cómo se deben procesar los mensajes, por ejemplo, enviandolos por email.