Creando un custom skill para Alexa (IV): Código básico del backend en Java 8
Como el anterior post me iba a quedar demasiado largo decidí crear uno nuevo para enseñar cosas del código.
Antes de nada, el código del lambda de mi skill lo iré subiendo a un repo de GitHub. Como decía, no he sido muy cuidadoso con temas de gestión de ramas y tampoco tiene test automáticos. Además, voy a integrarlo con la parte del modelo y preparar todo para desplegarlo usando la línea de comandos sin tener que pasar por la consola de alexa o de aws. Os lo contaré también en las próximas semanas.
Lo que voy a usar es el ASK SDK para Java que nos permitirá crear todo lo necesario para el backend. En mi caso usaré la versión 2 que, según la guía, es la última. Lo que voy a contar no es nada del otro mundo que no podáis leer en la doc oficial (inglés).
Configurando el proyecto con Maven
Para montarlo decidí usar Maven (tenéis la opción de Gradle como hizo Iván) y está totalmente documentado. Lo mínimo que hay que añadir el pom.xml es:
Podemos destacar:
- La dependencia de
ask-sdk
. Es el sdk que nos permitirá construir el código para que interactue con un skill desde lambda. - Las dependencias relacionadas con logs en lambda. Creo que no tengo todavía 100% bien configurado esto pero al menos consigo ver logs en la consola de AWS. Podéis ver más info sobre este tema en la doc.
Una vez tenemos configurado Maven con las dependencias necesarias podemos empezar a escribir código que usará todo lo que nos facilita el sdk. Hay dos tipos de clases básicas que tendremos que crear:
- Tantos
RequestHandler
como necesitemos para manejar los intents que vengan del skill. Un mismoRequestHandler
puede manejar más de un intent. - Un
SkillStreamHandler
que será la clase principal de nuestro backend. Aquí registraremos los handlers que hayamos creado previamente.
Estructura básica de un RequestHandler
Para crear nuestros handler sólo tenemos que extender de la clase RequestHandler
que nos provee el sdk y sobrescribir dos métodos:
- El método
canHandle
se usa para checkear si el handler puede manejar la petición que llega. Aquí la lógica básica que se suele hacer es mirar el nombre del intent de la request. En el ejemplo se puede ver cómo chequeo si el intent es el de cancelar o el de parar. Puse este ejemplo para ver que un handler podría gestionar más de un intent. - El método
handle
es el encargado de recibir el input y construir la respuesta para el usuario a partir de su request. Es el método donde irá el código más interesante del handler. En el caso del ejemplo me gustaría destacar tres cosas:withSpeech
, le estamos dando a la respuesta el texto que Alexa dirá de voz al usuario.withSimpleCard
, aquí construimos una salida para Alexa que será util para dispositivos con pantalla, como la app del móvil.withShouldEndSession
, con esto le indicamos a Alexa que, una vez manejada la request, no esperamos otra interacción con el usuario y cerramos la sesión, es decir, el skill.
En este ejemplo, muy básico, podemos ver cómo queremos manejar un par de intents y elaborar una respuesta de dos tipos: texto que dirá Alexa con voz y, además, información para construir una "tarjeta" que mostrará Alexa en pantalla. Por último, con la opción de finalizar la sesión indicamos que no esperamos una interacción posterior. Sería un handler orientado a una petición concreta y sin diálogo.
En el caso de que nuestro handler quiera indicar a Alexa que esperamos seguir interactuando con el usuario tenemos que construir la respuesta con withReprompt
. Con esto no haría falta indicar con withShouldEndSession
que no queremos cerrar la sesión ya que va implícito usando el reprompt.
Punto de entrada del backend
Como decía al principio, aparte de los RequestHandler
tenemos que escribir otra clase que será la "main" de nuestro proyecto lambda. Esta clase tiene que extender de SkillStreamHandler
provista por el SDK:
Es una clase muy simple donde en el constructor tenemos que pasar un objeto de tipo Skill
que habremos construido añadiendo los handlers que tengamos. Ojo, el orden de los handlers importa a la hora de decidir cuál usará para manejar la petición del usuario. Irá validando los handlers en el orden que los hemos registrado y usará el primero que retorne true
en la validación del método canHandle
.
Building!!
Y una vez tenemos todo lo anterior, ya podremos empaquetar nuestro proyecto para subirlo a AWS Lambda. Ya que hemos usado Maven podemos hacer esto con un comando:
mvn org.apache.maven.plugins:maven-assembly-plugin:2.6:assembly -DdescriptorId=jar-with-dependencies package
El resultado del comando lo tendremos en la carpeta target
del proyecto y tenemos que subir el fichero: *-jar-with-dependencies.jar
desde la consola de AWS Lambda.
Como detalle importante, el Handler que hay que indicar será la referencia completa a vuestra clase "main", incluyendo su nombre. Si pinchais en "info" os lo explica.
Y con esto ya tendríamos publicado un skill completo que podríamos lanzarnos a probar desde la consola de Alexa o, incluso, desde un dispositivo/app mobile asociado a la misma cuenta Amazon con la que nos hayamos registrado. Los skills no se instalan en ningún sitio sino que están en la nube. Al ejecutarlos con su nombre, Alexa irá a buscar su última versión de producción o, en este caso, la versión de desarrollo a la cual, por ser nuestro, tendríamos acceso.
En el siguiente post veremos opciones para probar el skill, tanto desde la consola de Alexa como desde la consola de AWS Lambda. Además, evolucionaremos nuestro interaction model para poder manejar un slot de tiempo en nuestro custom intent :)