En el anterior post hablé del concepto de sesión en Alexa y qué tipo de información podemos manejar entre peticiones. Sentar esa base me venía bien para comentar lo que veremos en este post. Parte de esa información que podemos manejar en la sesión son los "atributos de sesión" pero no son los únicos que el SDK nos ofrece.

Tipos de atributos

El SDK de Alexa nos permite gestionar, persistir y recuperar atributos en nuestra skill a varios niveles:

  • Request: Los atributos de request viven dentro del contexto de una petición al back de nuestra skill. Están inicialmente vacíos en cada petición y son descartados una vez se produce una respuesta al front. Pueden ser de utilidad usados conjuntamente con los interceptores de request para incluir información adicional por cada petición y así tenerla disponible en el handler que toque.
  • Session: Los atributos de sesión persisten dentro de la sesión de una skill hasta que se cierre. Todas las peticiones realizadas dentro de una misma sesión tienen acceso a estos atributos y viajan en el JSON de request/response. No usan un sistema de almacenamiento aparte y solo están disponibles si se opera dentro de esa sesión. Se descartan cuando la sesión en curso muere. Son especialmente válidos para mantener información sobre la interacción actual del usuario con la skill.
  • Persistentes: Los atributos persistentes son el siguiente paso y están disponibles en todo momento. El sistema de almacenamiento es configurable, así como la key que se usa entre otras cosas. Para poder usarlos hay que configurar de forma explícita un adaptador en nuestra skill. Sin ese paso obtendremos un error si intentamos hacer uso de ellos. Son la solución usada si necesitamos persistir información que se recuperará en futuros usos de la skill o que serán consultados por otros sistemas.

Haciendo uso de estos atributos desde nuestro código

Para poder gestionar esos atributos en el back de nuestra skill el SDK nos ofrece un AttributesManager. Esta clase expone una serie de métodos que nos permiten recuperar y actualizar todos los tipos de atributos comentados antes.

El acceso al AttributesManager se hace vía el HandlerInput. Veamos con código de ejemplo cómo se maneja cada uno de los tipos disponibles.

Request Attributes

El uso de los atributos a nivel de request es muy sencillo. No es más que un mapa de clave/valor al cual se accede a través del InputHanlder. Pongo aquí un código de ejemplo cualquiera porque yo no lo uso en las skills que tengo.

Session Attributes

El manejo de los atributos de sesión es igual que lo visto para los de request. La diferencia radica en el tiempo de vida de cada uno. Los atributos de sesión estarán disponibles durante todo el tiempo que dure la sesión y viajan en cada ciclo de petición/respuesta.

Para ver su uso voy a usar el código de la skill de ejemplo que preparé para la charla conjunta con Jordi y Diego "Asistentes de voz, una charla para dominarlos a todos". Pensamos en una skill que pudiera servir para ilustrar ciertas features de cada una de las plataformas (Google, Alexa y Microsoft). Lo que hicimos fue un ejemplo básico de aplicación de voz para pedir comida a domicilio.

En esta skill necesitamos ir pidiendo al usuario cierta información dependiendo del contexto o estado en el cual se encuentra la interacción. Por ejemplo, el usuario no debería poder realizar el pedido final si antes no dijo qué comida quiere y a dónde hacer el pedido. Esos flujos de recogida de información los dividimos en distintos intents. Como si una máquina de estado (muy rudimentaria) se tratara usamos los atributos de sesión para persistir esa información e ir controlando el flujo de la skill.

En el código vemos un IntentHandler que recibe la comida que ha indicado el usuario y la guarda como atributo de sesión. Como decía antes el mecanismo es igual al de atributos de request pero cambiando el mapa donde guardamos ese valor. Eso hará que luego esa información persista a través de toda la sesión.

Para recuperar ese valor solo tenemos que acceder a través del mapa. Siguiendo nuestro ejemplo, el usuario ya ha elegido el tipo de comida y el restaurante donde quiere pedirla. El último paso sería realizar la orden de pedido. Una de las características de las aplicaciones de voz es que no fuerzan un flujo de pasos secuenciales y el usuario podría haber llegado al último paso con cierto utterance. Para controlar esto podemos validar los atributos de sesión que tenemos en el handler, ya sea en el método que controla la ejecución, canHandle, o en el método que lo procesa, handle.

En este código podemos ver el handler que realiza el pedido. Para su correcto funcionamiento necesita que el usuario ya haya indicado la comida que quiere y el restaurante. Eso lo controlamos mirando si tenemos esos valores en los atributos de sesión.

Ahora veamos cómo viajan los atributos de sesión entre petición y respuesta. Para eso usaremos la información que nos da el simulador de la Alexa Developer Console.

En la petición inicial no tenemos nada referente a los atributos de sesión. Tal y como contamos en el anterior post, la sesión se crea y se lanza un LaunchRequest al back.

Y en la respuesta del back tampoco tenemos nada referente a los atributos. Aquí por ahora simplemente tenemos el texto que tiene que decir Alexa y el flag que indica si se debe cerrar la sesión.

Sigamos evolucionando en el flujo de la skill y vamos a decirle qué nos apetece comer.

En la petición vemos cómo la sesión ya no es nueva y en la request llevamos el valor del slot correspondiente a la comida. Ese valor lo vamos a persistir en la sesión ya que nos hará falta para el paso final de la orden de pedido. Esto hará que sea parte de la siguiente respuesta al usuario.

Ahora ya ese valor será parte de la sesión durante el tiempo que ésta dure. Si avanzamos en el flujo de la skill veremos cómo aparece ya en la información de la request.

En el anterior JSON ya vemos que el tipo de comida elegido por el usuario anteriormente viaje entre peticiones. Así es como el back podrá hacer uso del valor tal como vimos en el código de los IntentHandler.


Aún nos falta por ver los atributos persistentes pero este post ya se hizo demasiado largo y he decidido dividir en dos el contenido. En el próximo veremos cómo manejar información persistente y elegir entre diferentes tipos de almacenamiento :)