Tutorial parte 3: Desarrolla aplicaciones de voz multiplataforma con VOXA

Lógica principal del juego, obtener perfil de usuario y guardar progreso en AWS DynamoDB

Octavio Menocal
8 min readOct 10, 2019

--

Foto de Rodion Kutsaev en Unsplash

En el artículo anterior, creamos la Alexa skill y la action para Google Assistant. También creamos las hojas de Excel VUI donde cualquier persona en tu equipo puede colaborar, al agregar intents, uterancias, y respuestas para tus aplicaciones de voz. Además, aprendimos que podemos descargar toda esta información a nuestro proyecto VOXA con el VOXA-CLI, así como crear un proyecto desde zero. Finalmente, agregamos Account Linking a la Alexa skill y Google Sign-In a la Google action. En este artículo, vamos a crear la lógica básica de nuestro juego, obtener el perfil del usuario, y guardar el progreso del juego en AWS DynamoDB.

Así que, empecemos!

Imagen vía www.pixabay.com

Como aprendimos en la primera parte de esta serie, VOXA toma ventaja del modelo MVC para separar el proyecto en 3 capas diferentes: modelo, vista, y controladores. Vamos a tratar de seguir ese modelo en nuestra aplicación de la siguiente manera:

  • El Modelo estará en el archivo /src/app/model.js.
  • Las Vistas estarán en el folder /src/languageResources.
  • Los Controladores estarán en el folder /src/app/states.

Puedes descargar el código fuente de la plantilla de quick maths que he subido a mi repositorio de GitHub en la rama part3.

Revisemos el archivo model.js. El archivo es demasiado largo para mostrarlo acá, así que sigue este link para revisarlo en el repositorio.

Hay 2 métodos importantes para generar la lógica principal del juego:

selectOperation(voxaEvent)

y

isAnswerRight(result)

En selectOperation, escogemos de forma aleatoria los números y la operación para que el usuario calcule el resultado. Lo dejamos simple por el momento: solamente 2 números y una operación a la vez. También nos aseguramos que el resultado nunca sea negativo. No queremos que al usuario le cuesta trabajo calcular por ejemplo 51–78, lo cual es todavía una operación sencilla, pero queremos que el usuario se entretenga con nuestra aplicación. Si preguntamos este tipo de operación cuando ellos empiecen a usar nuestra aplicación, ellos podrían dejar de usarla inmediatamente!

if (this.user.isFirstTime) {
this.level = _.head(levels);
} else if (this.user.sessionCount <= 3) {
this.level = _.nth(levels, this.user.sessionCount);
} else {
this.level = _.sample(levels);
}

Con esta porción de código, nos aseguramos que el nivel de dificultad sea acorde al número de veces que el usuario ha abierto la skill.

También, puedes encontrar interesante esta porción de código:

const wordsNumber1 = ntw.toWords(this.number1);
const wordsNumber2 = ntw.toWords(this.number2);
const params = {
operatorName: this.operatorName,
wordsNumber1,
wordsNumber2,
};
const speech = voxaEvent.t('Operation.Expression.calculation', params);
const durationTime = readingTime(speech);
console.log('speech', speech);
console.log('durationTime', durationTime);
this.speechTimeDiff += durationTime.time;

Recuerda que vamos a dar puntos al usuario basado en el tiempo que le tomó calcular el resultado, pero debemos considerar el tiempo que Alexa le tomó en decir:

  • How much is 55 * 2?
  • How much is 105 + 203?
  • How much is 3512–512?

Ese tiempo no puede ser una cantidad fija, así que usamos los paquetes NPM number-to-words y reading-time para calcularlo. Este tiempo calculado no es 100% preciso — va a variar dependiendo de la conexión a internet entre Alexa/Google y el servidor dónde está guardado el código. Con los valores actuales, verás que no es 100% preciso cuando pruebas tu skill localmente, pero yo encontré que es muy exacto cuando subes el código a una función de AWS Lambda.

En el métodoisAnswerRight, obtenemos el número de segundos que le tomó al usuario calcular la operación y le otorgamos los puntos acorde al tiempo:

if (timeDiff <= 3000) {
pointsEarned += 10;
} else if (timeDiff <= 6000) {
pointsEarned += 8;
} else if (timeDiff <= 9000) {
pointsEarned += 4;
} else {
pointsEarned += 2;
}

En el archivo /src/app/states/main.states.js puedes ver los principales estados que usamos para controlar el proceso:

Manejadores de estados de VOXA

La conversación va de esta manera:

Usuario: Alexa, open quick maths

Alexa: Welcome back to Quick Maths! Should we start with the game?

Usuario: Yes

Alexa: How much is 995–213?

Usuario: 782

Alexa: Excellent! You get 2 points. Should we try again?

Usuario: Yes

Alexa: How much is 7 * 9?

Usuario: 73

Alexa: No! It’s 63. Should we try again?

Usuario: No

Alexa: Ok. Goodbye.

En VOXA, controlamos las vistas que queremos regresar y el estado de la siguiente interacción. Por ejemplo:

return {
reply: [‘RightAnswerExpression’, ‘RightAnswer’],
to: ‘begin’,
};

RightAnswerExpression es una vista con una única directiva: say. En VOXA esto significa que el contenido de esta vista será agregado a la siguiente vista que usemos en el mismo estado o en el siguiente estado hasta que determinemos el punto de retorno de la respuesta para Alexa, o Google.

RightAnswer es una vista con 3 directivas:

  • ask: la respuesta principal que Alexa o Google responderá. Esto indica que la respuesta debe ser retornada a la plataforma de voz y no a otro estado de VOXA.
  • reprompt: el reprompt que Alexa, o Google responderá si el usuario permanece en silencio después de la respuesta principal.
  • dialogflowSuggestions: sugerencias mostradas en la parte de abajo de las pantallas en Google Assistant.

VOXA tiene muchas directivas que pueden ser usadas para renderizar características específicas de cada plataforma. Por ejemplo:

  • alexaCard: renderiza una carta de account linking, simple, o básica en Alexa
  • alexaAPLTemplate: renderiza una directiva APL
  • alexaRenderTemplate: renderiza una directiva DisplayTemplate
  • dialogflowSuggestions: renderiza sugerencias para Google Assistant
  • dialogflowTable: renderiza una Tabla para Google Assistant
  • googleCompletePurchase: renderiza una directiva de DigitalGoods para Google Assistant

Sigue los siguientes links para revisar otras directivas de Alexa, y Google Assistant:

Directivas de Alexa

Directivas de Google Assistant

Integración con AWS DynamoDB

Vamos a usar una tabla de DynamoDB para guardar la información del usuario, su progreso, la fecha que fue creado, cuantas veces han abierto la skill, y cualquier otro dato que quieras guardar.

En tu cuenta de AWS crea una tabla de DynamoDB. Yo he creado 2 tablas: QuickMathsUsersStaging y QuickMathsUsersProduction, ya que quiero tener 2 skills diferentes, una para pruebas, y otra para certificación.

Vista de la tabla QuickMathsUsersProduction

Recuerda agregar este tipo de información a los valores de configuración en tu proyecto para que no tengas que definir valores importantes como este en varias partes de tu código. Ya que usamos una tabla con nombres distintos en los ambientes, es necesario ubicar el nombre de la tabla en tus archivos de configuración en el folder /src/config/.

Probando tu skill localmente

Primero, asegúrate que tienes un archivo de configuración local en tu proyecto. Si no lo tienes, simplemente copia el contenido del archivo /src/config/local.example.json y crea el archivo /src/config/local.json. Si usas la misma configuración de staging, puedes copiarte del archivo staging.json.

Vamos a usar una herramienta genial para hacer debugging localmente: Bespoken tools. Si no lo tienes instalado en tu computadora, descarga en instala el paquete de forma global.

Bespoken ofrece un comando proxy para redirigir las peticiones de tu Alexa skill o Google Action a tu máquina local, simplemente necesitas ejecutar este comando en tu terminal:

bst proxy http <PORT>

Al ejecutarlo, tendrás corriendo un proxy en el puerto de tu preferencia. Yo siempre trabajo con el puerto 3000, es mi favorito!

Servidor Bespoken corriendo localmente en el puerto 3000 de tu computadora

A la URL bespoken necesitas agregar un parámetro dependiendo de la plataforma con la que quieras probar:

Alexa: https://<YOUR-BESPOKEN-ID>.bespoken.link/alexa

Google: https://<YOUR-BESPOKEN-ID>.bespoken.link/googleAction

Ahora, abre una nueva ventana de la terminal, y en el folder principal de tu proyecto ejecuta:

yarn watch

Servidor VOXA iniciado para tu aplicación de voz con el comando yarn watch

Esto iniciará un servidor para tu proyecto, corriendo en el puerto 3000, esperando peticiones de Alexa, o Google Assistant.

En mi caso, yo prefiero trabajar con yarn, pero también puedes usar npm run watch.

Ve a Dialogflow y asegúrate que tienes todas los intents y uterancias actualizados. Puedes hacer esto creando un archivo zip con todo el contenido del folder de dialogflow: /speech-assets/dialogflow/<environment>, ya sea staging o production. En tu agente, ve al botón de configuraciones ⚙, luego a la pestaña Export and Import. Haz click en el botón RESTORE, y arrastra y suelta el archivo zip . Luego ve al menú Fulfillment en la parte izquierda y pega tu URL de bespoken: https://<YOUR-BESPOKEN-ID>.bespoken.link/googleAction.

Luego en la pestaña integrations, haz click en la integración para Google Assistant y haz click en el botón TEST. Esto te llevará a la página del simulador de tu Google action donde puedes comenzar a testear!

Vista principal de nuestra Google Action: Quick Maths

Si todo está funcionando, tendrás tu google action enviando peticiones a tu computadora. Al mismo tiempo, VOXA estará guardando los resultados en DynamoDB.

Ejemplo de una conversación con la Google Action: Quick Maths

En la terminal, verás como bespoken escribe las peticiones y respuestas, y como el servidor VOXA escribe algunos datos importantes. Puedes imprimir cualquier otro data que quieras revisar también.

Hasta este punto, ya tenemos una Alexa skill y Google Action lista para enviar a certificación. Solamente necesitamos crear una función lambda para subir nuestro código. Esta guía no cubre la subida del código pero te recomiendo que lo subas en 2 funciones Lambda distintas — una para la Alexa skill y otra para la Google Action.

Para la Google Action también necesitarás crear un API Gateway para exponer la función Lambda a través de un endpoint https al cual Dialogflow pueda enviar peticiones.

Final

Iremos un poco más con nuestro desarrollo. En el siguiente artículo, crearemos la lógica de competición. Esta competencia mostrará los mejores 10 jugadores con más puntaje en una tabla de liderazgo para hacer la aplicación más divertida. Agregaremos una suscripción a nuestra aplicación que costará solamente $0.99/al mes! Será una genial oportunidad para aprender cómo monetizar nuestras aplicaciones de voz. Usaremos la API de In-Skill purchases de Alexa, y Digital Goods de Google Assistant.

¡Gracias por leer! Asegúrate de leer los demás artículos de la serie.

Recuerda: ¡No tires basura al océano!

--

--

Octavio Menocal

Software engineer at Soar.com. Nicaraguan developing Amazon Alexa Skills and actions for Google Assistant. Pingpong lover, big fan of Ma Long!