Creando una Alexa Skill de video en cuestión de minutos (Java/Kotlin edition)

En el artículo anterior contaba cómo hacer una skill de audio en pocos pasos usando un template del back ya generado en Kotlin. También hice un vídeo contando el proceso.

A raíz de ese ejemplo de skill se me ocurrió aplicar el mismo concepto para crear una skill que reproduzca un vídeo, por cubrir el otro elemento multimedia en un dispositivo Alexa. He creado un código base a modo de plantilla para tener una skill muy simple que reproduzca un vídeo a partir de una URL pública, hosteando el back en AWS Lambda.

En este post voy a contar cómo crear esa skill paso a paso (sin entrar en el código o en el proceso de distribución ni certificación). Si hay muchos conceptos que desconoces puedes ver mis primeros posts, que cuentan gran parte de la teoría. El código está liberado y con licencia GPL-3.0. Hay pasos que son pura configuración y burocracia de trabajar con AWS pero no son complicados.

Crearé también un video sobre el proceso, así que si te da pereza leer, puedes esperarte a la película ;)

Casos de uso

Con una skill de este tipo, con el código base, se puede crear una skill que reproduzca un video al que se debe acceder a partir de una URL pública, HTTPs y en uno de los formatos soportados documentados aquí.

En el ejemplo vamos a hacer uso de la VideoApp Interface de Alexa, que permite reproducir un vídeo en un dispositivo con pantalla. La limitación es que no se pueden encolar varios vídeos, algo que se podía hacer con el audio. Si queremos hacer cosas más elaboradas con vídeo ya habría que crear algo usando APL. Lo tengo en la recámara también, espero no tardar mucho en poder contaros cómo :)

De todas formas ese vídeo vamos a poder "cambiarlo en caliente", sin desplegar código, porque lo he creado usando variables de entorno en AWS Lambda. Así como el vídeo, podrás configurar otros dos campos que son obligatorios: título y subtítulo.

No tiene opciones para personalizar respuestas de Alexa porque en principio el caso de uso está orientado a reproducir el video con simplemente arrancar la skill y, aunque tiene un intent por ser obligatorio, invocarlo de forma one-shot tendrá el mismo resultado que arrancar la skill con un launch request. Si el dispositivo que ejecuta la skill no tiene pantalla, Alexa informará al usuario.

Una vez esté reproduciéndose el vídeo Alexa toma el control de forma nativa. De esa forma vamos a poder realizar acciones táctiles, con un mando o con la propia voz. Por ejemplo podremos pararlo, avanzar unos segundos, volver al inicio del vídeo, etc.

Creando la skill en la Alexa Developer Console

Lo primero que tenemos que hacer es crear una skill y para ello podemos hacer uso de la Alexa Developer Console. Ya tengo otros posts donde se cuentan los pasos iniciales, por lo que no me voy a repetir aquí pero como resumen:

  • Elegimos la plantilla básica para el modelo de interacción. Luego vamos a sustituir lo que se cree, entonces no será problema.
  • Elegimos el invocation name.
  • El modelo de interacción creado ya tiene un Intent custom que se llama HelloWorldIntent. Vamos a sustituir ese Intent por uno propio. Es cierto que para usar esta skill no vamos a necesitar un intent pero es obligatorio tener uno propio. En el editor JSON sustituimos el código de ese intent por:
  • Al ser una skill que va a reproducir un vídeo tenemos que activar la interface de VideoApp o nuestra skill fallará al intentar reproducirse en un dispositivo.

Llegados a este punto deberíais poder construir el modelo de forma exitosa. Nos faltaría el paso de declarar el endpoint correcto pero eso lo haremos después de configurar la función lambda.

Creando la función AWS Lambda

Al igual que antes ya había explicado en posts anteriores cómo crear una función lambda para usarla como endpoint de nuestra skill. Voy a resumir los pasos:

  • Nos tenemos que crear una cuenta de desarrollador de Amazon para los servicios AWS. Así tendremos acceso al servicio de AWS Lambda (entre otros).
  • Creamos una función (ojo con la región, para España la mejor opción actual es la de París). El código de mi proyecto está en Kotlin con lo que seleccionaremos el lenguaje Java 8 (es donde lo tengo ya probado). Vamos a crear también un rol nuevo a no ser que ya tengas uno de antes con permisos correctos para el lambda y los logs de CloudWatch.

Desplegando el código de la función lambda

Llegados a este punto tenemos que generar un paquete para desplegarlo en la función lambda. Aquí hay dos opciones:

  1. Se puede construir en local a partir del código en el repositorio ejecutando la task de Gradle de shadowJar. Esto generará un fichero .jar en el directorio build/libs con el nombre alexa-skill-video-1.0-all.jar.
  2. Coger el paquete ya generado y que he metido en la raíz del repositorio con el nombre de alexa-skill-video-1.0-all.jar.

Una vez tenemos el paquete hay que desplegarlo en la función lambda. Aquí lo vamos a hacer a mano pero hay formas de integrar en Gradle esto.

Ahora pasamos a la configuración básica de la lambda (controlador, memoria, etc). Desde la última vez que lo usé he visto un cambio en la interfaz de la consola web de AWS Lambda y han separado en dos partes distintas indicar el controlador de otras opciones como la memoria.

  • Lo primero que hacemos es indicar el controlador poniendo la ruta tal como está en el código fuente: com.kinisoftware.videoSkill.VideoSkillStreamHandler
  • La memoria se puede bajar a 256 (incluso sobre 200) pero creo que cada ejecución usaba 160 o así (eso se puede ver en los logs).

Enganchando la skill

Ahora ya podemos pasar a enganchar la skill con nuestra función lambda. En la Alexa Developer Console habíamos dejado sin modificar la parte del endpoint. Eso es lo que vamos a preparar.

  • Copiamos el skill id desde la Alexa Developer Console > Endpoint. Ese id lo vamos a meter en la parte de la lambda.
  • Añadimos el trigger de Alexa en la función lambda. Y le ponemos el id de la skill.
  • Copiamos el ARN de la función lambda que será lo que llevemos al campo del endpoint en la Alexa Developer Console.

Y al guardar el endpoint se validará esto que acabamos de configurar de tal forma que sabremos si está todo bien.

¿Y dónde se indica la URL del video a reproducir?

Como os contaba antes, solo vamos a poder configurar un vídeo a reproducir. Además, junto con el vídeo vamos a poner un título y un subtítulo. Para ello vamos a usar variables de entorno.

  • En la zona de variables de entorno simplemente tenemos que añadir la variable con clave videoUrl y el valor será la URL que contenga el video.
  • De la misma forma, para el título usamos la variable title y para el subtítulo la de subtitlte.

Una vez tengamos la(s) variable(s) creada(s) y guardada(s) ya podremos usar nuestra skill. Para probarla necesitamos un dispositivo con Alexa que tenga pantalla (aquí el móvil no vale). Con el simulador no vamos a poder ver el vídeo ni inspeccionar que la respuesta es correcta porque al no ser compatible con VideoApp Interface, no se enviará la reproducción del vídeo desde el back.

One more thing...

Cuando haces una skill que reproduce un vídeo surge el reto de la resolución y el tamaño del vídeo. Si pones un vídeo muy pesado o con una resolución muy grande es posible que no tenga mucho sentido si la mayoría de dispositivos de tus usuarios no lo van a aprovechar. Y viceversa, si te basas en resoluciones pequeñas te puedes llevar una sorpresa si un usuario le da por invocar la skill con un FireTV.

¿Cómo puedo saber que dispositivos/resoluciones tienen mis usuarios?

En el template del backend de esta skill he metido un log adicional para así conocer la información del context, que es la parte de la request que nos da eso. Esto solo lo voy a meter como log si el dispositivo es compatible con la interface de VideoApp. Para los dispositivos que no la soporten no tiene sentido conocer esa info para nuestro caso.

Una vez vayamos teniendo usos de la skill vamos a poder usar esa información del context para identificar, por ejemplo, la resolución soportada por los dispositivos de los usuarios. Esto lo podemos hacer con una consulta en CloudWatch:

| stats count_distinct(System.user.userId) as devices by Viewport.currentPixelWidth
| filter @message like /(Context)/
| sort by devices desc

Y ya solo tendríamos que rellenar la info de distribución de la skill y mandarla a certificar :D

Para cualquier error no dudéis en contactarme por aquí o por twitter. Igualmente recordad que se pueden ver los logs de la AWS Lambda en la zona de "Monitorización" y ya está el código preparado para meter ahí peticiones y respuestas ;)