Created
November 15, 2018 00:55
-
-
Save germanviscuso/8225fe8dadff228ad6153c0915d55cba to your computer and use it in GitHub Desktop.
Alexa Skill Basics: User Dialogue Restart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"interactionModel": { | |
"languageModel": { | |
"invocationName": "busca camisetas", | |
"intents": [ | |
{ | |
"name": "AMAZON.CancelIntent", | |
"samples": [] | |
}, | |
{ | |
"name": "AMAZON.HelpIntent", | |
"samples": [] | |
}, | |
{ | |
"name": "AMAZON.StopIntent", | |
"samples": [] | |
}, | |
{ | |
"name": "AMAZON.NavigateHomeIntent", | |
"samples": [] | |
}, | |
{ | |
"name": "RecommendationIntent", | |
"slots": [ | |
{ | |
"name": "color", | |
"type": "tipoColor", | |
"samples": [ | |
"{quiero} color {color}", | |
"color {color}", | |
"{quiero} {color}", | |
"{color}" | |
] | |
}, | |
{ | |
"name": "talla", | |
"type": "tipoTalla", | |
"samples": [ | |
"{quiero} talla {talla}", | |
"{quiero} tamaño {talla}", | |
"{quiero} {talla}", | |
"{talla}", | |
"talla {talla}", | |
"tamaño {talla}", | |
"{talla}", | |
"de talla {talla}", | |
"de tamaño {talla}" | |
] | |
}, | |
{ | |
"name": "marca", | |
"type": "tipoMarca" | |
}, | |
{ | |
"name": "precio", | |
"type": "tipoPrecio" | |
}, | |
{ | |
"name": "quiero", | |
"type": "tipoQuiero" | |
}, | |
{ | |
"name": "camiseta", | |
"type": "tipoCamiseta" | |
}, | |
{ | |
"name": "un", | |
"type": "tipoArticulo" | |
}, | |
{ | |
"name": "conector", | |
"type": "tipoConector" | |
}, | |
{ | |
"name": "reiniciar", | |
"type": "tipoReiniciar" | |
} | |
], | |
"samples": [ | |
"{reiniciar}", | |
"{un} {camiseta}", | |
"{quiero} {un} {camiseta} {color}", | |
"{quiero} {un} {camiseta} {precio}", | |
"{quiero} {un} {camiseta} marca {marca}", | |
"{quiero} {un} {camiseta}", | |
"{quiero} {un} {camiseta} {color} de talla {talla}", | |
"{quiero} {camiseta} {color}", | |
"{quiero} {camiseta} {precio}", | |
"{quiero} {camiseta} marca {marca}", | |
"{quiero} marca {marca}", | |
"{quiero} {un} {marca}", | |
"{quiero} {camiseta}", | |
"{quiero} {camiseta} {color} de talla {talla}", | |
"{quiero} {color} de talla {talla}", | |
"{quiero} {color} y talla {talla}", | |
"{quiero} {un} {camiseta} {talla} de color {color}", | |
"{quiero} {talla} de color {color}", | |
"{quiero} {un} {camiseta} {color} de talla {talla} y {precio}", | |
"{quiero} talla {talla} marca {marca} color {color}", | |
"{quiero} talla {talla}", | |
"talla {talla}", | |
"talla {talla} color {color}", | |
"color {color}", | |
"color {color} talla {talla}", | |
"{quiero} {un} {color}", | |
"{quiero} {talla}", | |
"{quiero} {color}", | |
"{quiero} {color} {talla} {precio} marca {marca}", | |
"{color} {talla} {precio} marca {marca}", | |
"{quiero} {talla} {color} {precio} marca {marca}", | |
"{talla} {color} {precio} marca {marca}", | |
"{quiero} {precio} {talla} {color} marca {marca}", | |
"{precio} {talla} {color} marca {marca}", | |
"{quiero} {color} {talla} {precio} {conector} marca {marca}", | |
"{color} {talla} {precio} {conector} marca {marca}", | |
"{quiero} {talla} {color} {precio} {conector} marca {marca}", | |
"{talla} {color} {precio} {conector} marca {marca}", | |
"{quiero} {precio} {talla} {color} {conector} marca {marca}", | |
"{precio} {talla} {color} {conector} marca {marca}", | |
"{color} {talla} {precio} {conector} marca {marca}", | |
"{talla} {color} {precio} {conector} marca {marca}", | |
"{quiero} {precio} {talla} {color} {conector} marca {marca}", | |
"{precio} {talla} {color} {conector} marca {marca}", | |
"{quiero} {un} color {color} talla {talla} marca {marca} {conector} precio {precio}", | |
"{quiero} {un} talla {talla} color {color} marca {marca} {conector} precio {precio}", | |
"{quiero} {un} marca {marca} color {color} talla {talla} {conector} precio {precio}" | |
] | |
}, | |
{ | |
"name": "AMAZON.StartOverIntent", | |
"samples": [] | |
} | |
], | |
"types": [ | |
{ | |
"name": "tipoPrecio", | |
"values": [ | |
{ | |
"name": { | |
"value": "caro", | |
"synonyms": [ | |
"de lujo", | |
"caras", | |
"costosas", | |
"cara" | |
] | |
} | |
}, | |
{ | |
"name": { | |
"value": "intermedio", | |
"synonyms": [ | |
"promedio", | |
"termino medio", | |
"de precio normal" | |
] | |
} | |
}, | |
{ | |
"name": { | |
"value": "barato", | |
"synonyms": [ | |
"asequibles", | |
"baratas", | |
"barata" | |
] | |
} | |
} | |
] | |
}, | |
{ | |
"name": "tipoMarca", | |
"values": [ | |
{ | |
"name": { | |
"value": "adidas" | |
} | |
}, | |
{ | |
"name": { | |
"value": "puma" | |
} | |
}, | |
{ | |
"name": { | |
"value": "ralph lauren" | |
} | |
}, | |
{ | |
"name": { | |
"value": "tommy hilfiger" | |
} | |
}, | |
{ | |
"name": { | |
"value": "gap" | |
} | |
}, | |
{ | |
"name": { | |
"value": "lacoste" | |
} | |
} | |
] | |
}, | |
{ | |
"name": "tipoTalla", | |
"values": [ | |
{ | |
"name": { | |
"value": "xxl", | |
"synonyms": [ | |
"gigante", | |
"super grande" | |
] | |
} | |
}, | |
{ | |
"name": { | |
"value": "xl", | |
"synonyms": [ | |
"amplia", | |
"extra grande" | |
] | |
} | |
}, | |
{ | |
"name": { | |
"value": "l", | |
"synonyms": [ | |
"grande" | |
] | |
} | |
}, | |
{ | |
"name": { | |
"value": "m", | |
"synonyms": [ | |
"intermedia", | |
"mediano", | |
"mediana", | |
"medio", | |
"media" | |
] | |
} | |
}, | |
{ | |
"name": { | |
"value": "s", | |
"synonyms": [ | |
"pequeño", | |
"pequeña" | |
] | |
} | |
}, | |
{ | |
"name": { | |
"value": "xs", | |
"synonyms": [ | |
"muy pequeño", | |
"muy pequeña", | |
"pequeñita", | |
"diminuta" | |
] | |
} | |
} | |
] | |
}, | |
{ | |
"name": "tipoQuiero", | |
"values": [ | |
{ | |
"name": { | |
"value": "recomiéndame" | |
} | |
}, | |
{ | |
"name": { | |
"value": "busco" | |
} | |
}, | |
{ | |
"name": { | |
"value": "quisiera" | |
} | |
}, | |
{ | |
"name": { | |
"value": "búscame" | |
} | |
}, | |
{ | |
"name": { | |
"value": "busca" | |
} | |
}, | |
{ | |
"name": { | |
"value": "queremos" | |
} | |
}, | |
{ | |
"name": { | |
"value": "me gusta" | |
} | |
}, | |
{ | |
"name": { | |
"value": "me gustaría" | |
} | |
}, | |
{ | |
"name": { | |
"value": "quisiera" | |
} | |
}, | |
{ | |
"name": { | |
"value": "quiero" | |
} | |
}, | |
{ | |
"name": { | |
"value": "me va" | |
} | |
}, | |
{ | |
"name": { | |
"value": "me vale" | |
} | |
} | |
] | |
}, | |
{ | |
"name": "tipoCamiseta", | |
"values": [ | |
{ | |
"name": { | |
"value": "camisa" | |
} | |
}, | |
{ | |
"name": { | |
"value": "camiseta" | |
} | |
}, | |
{ | |
"name": { | |
"value": "camisetas" | |
} | |
} | |
] | |
}, | |
{ | |
"name": "tipoArticulo", | |
"values": [ | |
{ | |
"name": { | |
"value": "los" | |
} | |
}, | |
{ | |
"name": { | |
"value": "el" | |
} | |
}, | |
{ | |
"name": { | |
"value": "las" | |
} | |
}, | |
{ | |
"name": { | |
"value": "la" | |
} | |
}, | |
{ | |
"name": { | |
"value": "unas" | |
} | |
}, | |
{ | |
"name": { | |
"value": "unos" | |
} | |
}, | |
{ | |
"name": { | |
"value": "una" | |
} | |
}, | |
{ | |
"name": { | |
"value": "un" | |
} | |
} | |
] | |
}, | |
{ | |
"name": "tipoColor", | |
"values": [ | |
{ | |
"name": { | |
"value": "rosa", | |
"synonyms": [ | |
"rosadas", | |
"rosados", | |
"rosada", | |
"rosado", | |
"rosas" | |
] | |
} | |
}, | |
{ | |
"name": { | |
"value": "marrón", | |
"synonyms": [ | |
"marrones" | |
] | |
} | |
}, | |
{ | |
"name": { | |
"value": "blanco", | |
"synonyms": [ | |
"blancas", | |
"blanca" | |
] | |
} | |
}, | |
{ | |
"name": { | |
"value": "negro", | |
"synonyms": [ | |
"negras", | |
"negra" | |
] | |
} | |
}, | |
{ | |
"name": { | |
"value": "verde" | |
} | |
}, | |
{ | |
"name": { | |
"value": "amarillo", | |
"synonyms": [ | |
"amarillas", | |
"amarilla" | |
] | |
} | |
}, | |
{ | |
"name": { | |
"value": "azul", | |
"synonyms": [ | |
"azules", | |
"azulada" | |
] | |
} | |
}, | |
{ | |
"name": { | |
"value": "rojo", | |
"synonyms": [ | |
"rojas", | |
"colorada", | |
"roja" | |
] | |
} | |
} | |
] | |
}, | |
{ | |
"name": "tipoConector", | |
"values": [ | |
{ | |
"name": { | |
"value": "y de" | |
} | |
}, | |
{ | |
"name": { | |
"value": "y" | |
} | |
} | |
] | |
}, | |
{ | |
"name": "tipoReiniciar", | |
"values": [ | |
{ | |
"name": { | |
"value": "reiniciar" | |
} | |
}, | |
{ | |
"name": { | |
"value": "empezamos de nuevo" | |
} | |
}, | |
{ | |
"name": { | |
"value": "empieza de nuevo" | |
} | |
}, | |
{ | |
"name": { | |
"value": "empezamos otra vez" | |
} | |
}, | |
{ | |
"name": { | |
"value": "empieza otra vez" | |
} | |
}, | |
{ | |
"name": { | |
"value": "reinicia" | |
} | |
} | |
] | |
} | |
] | |
}, | |
"dialog": { | |
"intents": [ | |
{ | |
"name": "RecommendationIntent", | |
"confirmationRequired": true, | |
"prompts": { | |
"confirmation": "Confirm.Intent.181259956199" | |
}, | |
"slots": [ | |
{ | |
"name": "color", | |
"type": "tipoColor", | |
"confirmationRequired": false, | |
"elicitationRequired": true, | |
"prompts": { | |
"elicitation": "Elicit.Slot.1292632413709.1011723684445" | |
} | |
}, | |
{ | |
"name": "talla", | |
"type": "tipoTalla", | |
"confirmationRequired": false, | |
"elicitationRequired": true, | |
"prompts": { | |
"elicitation": "Elicit.Slot.1292632413709.537210718424" | |
} | |
}, | |
{ | |
"name": "marca", | |
"type": "tipoMarca", | |
"confirmationRequired": false, | |
"elicitationRequired": false, | |
"prompts": {} | |
}, | |
{ | |
"name": "precio", | |
"type": "tipoPrecio", | |
"confirmationRequired": false, | |
"elicitationRequired": false, | |
"prompts": {} | |
}, | |
{ | |
"name": "quiero", | |
"type": "tipoQuiero", | |
"confirmationRequired": false, | |
"elicitationRequired": false, | |
"prompts": {} | |
}, | |
{ | |
"name": "camiseta", | |
"type": "tipoCamiseta", | |
"confirmationRequired": false, | |
"elicitationRequired": false, | |
"prompts": {} | |
}, | |
{ | |
"name": "un", | |
"type": "tipoArticulo", | |
"confirmationRequired": false, | |
"elicitationRequired": false, | |
"prompts": {} | |
} | |
] | |
} | |
] | |
}, | |
"prompts": [ | |
{ | |
"id": "Confirm.Intent.181259956199", | |
"variations": [ | |
{ | |
"type": "PlainText", | |
"value": "¿Entonces buscamos color {color} , talla {talla} , precio {precio} y marca {marca} ?" | |
}, | |
{ | |
"type": "PlainText", | |
"value": "¿Entonces buscamos color {color} , talla {talla} y marca {marca} ?" | |
}, | |
{ | |
"type": "PlainText", | |
"value": "¿Entonces buscamos color {color} , talla {talla} y precio {precio} ?" | |
}, | |
{ | |
"type": "PlainText", | |
"value": "¿Entonces buscamos color {color} y talla {talla} ?" | |
}, | |
{ | |
"type": "PlainText", | |
"value": "¿Estás seguro?" | |
} | |
] | |
}, | |
{ | |
"id": "Elicit.Slot.1292632413709.537210718424", | |
"variations": [ | |
{ | |
"type": "PlainText", | |
"value": "Vale. color {color} , pero porfi dime la talla" | |
}, | |
{ | |
"type": "PlainText", | |
"value": "Debes indicarme una talla para continuar" | |
} | |
] | |
}, | |
{ | |
"id": "Elicit.Slot.1292632413709.1011723684445", | |
"variations": [ | |
{ | |
"type": "PlainText", | |
"value": "Dime ahora de que color la prefieres" | |
}, | |
{ | |
"type": "PlainText", | |
"value": "Vale. talla {talla}, pero porfi dime el color" | |
} | |
] | |
} | |
] | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Only valid for one dialogue based intent. If you need to restart multiple intents | |
// tale a look at Cecil's response here: https://stackoverflow.com/questions/53175962/how-can-i-restart-a-dialog-in-alexa-skill | |
const Alexa = require("ask-sdk"); | |
const LaunchRequestHandler = { | |
canHandle(handlerInput) { | |
const request = handlerInput.requestEnvelope.request; | |
return request.type === 'LaunchRequest'; | |
}, | |
handle(handlerInput) { | |
const responseBuilder = handlerInput.responseBuilder; | |
let speechOutput = '¡Hola y bienvenido a busca camisetas! Puedo recomendarte camisetas en base a una talla y color. Por ejemplo, puedes pedirme que te recomiende una camiseta roja de talla grande. Puedes decir reiniciar durante el diálogo si te arrepientes. '; | |
return responseBuilder | |
.speak(speechOutput) | |
.reprompt('prueba otra vez, ' + speechOutput) | |
.getResponse(); | |
}, | |
}; | |
const CancelStopIntentHandler = { | |
canHandle(handlerInput) { | |
const request = handlerInput.requestEnvelope.request; | |
return request.type === 'IntentRequest' && | |
(request.intent.name === 'AMAZON.CancelIntent'|| request.intent.name === 'AMAZON.StopIntent'); | |
}, | |
handle(handlerInput) { | |
const responseBuilder = handlerInput.responseBuilder; | |
let speechOutput = 'Vale. ¡Hasta luego! '; | |
return responseBuilder | |
.speak(speechOutput) | |
.withShouldEndSession(true) | |
.getResponse(); | |
}, | |
}; | |
const HelpIntentHandler = { | |
canHandle(handlerInput) { | |
const request = handlerInput.requestEnvelope.request; | |
return request.type === 'IntentRequest' && request.intent.name === 'AMAZON.HelpIntent' ; | |
}, | |
handle(handlerInput) { | |
const responseBuilder = handlerInput.responseBuilder; | |
let speechOutput = 'Puedo recomendarte camisetas en base a una talla y color. Por ejemplo, puedes pedirme que te recomiende una camiseta roja de talla grande'; | |
return responseBuilder | |
.speak(speechOutput) | |
.reprompt('preuba otra vez, ' + speechOutput) | |
.getResponse(); | |
}, | |
}; | |
const NavigateHomeIntentHandler = { | |
canHandle(handlerInput) { | |
const request = handlerInput.requestEnvelope.request; | |
return request.type === 'IntentRequest' && request.intent.name === 'AMAZON.NavigateHomeIntent' ; | |
}, | |
handle(handlerInput) { | |
const responseBuilder = handlerInput.responseBuilder; | |
let speechOutput = 'Navegar a casa no está implementado. '; | |
return responseBuilder | |
.speak(speechOutput) | |
.reprompt('prueba otra vez, ' + speechOutput) | |
.getResponse(); | |
}, | |
}; | |
const InProgressRecommendationIntentHandler = { | |
canHandle(handlerInput) { | |
const request = handlerInput.requestEnvelope.request; | |
return request.type === 'IntentRequest' | |
&& request.intent.name === 'RecommendationIntent' | |
&& request.dialogState !== 'COMPLETED'; | |
}, | |
handle(handlerInput) { | |
const request = handlerInput.requestEnvelope.request; | |
const responseBuilder = handlerInput.responseBuilder; | |
const intent = request.intent; | |
if(intent.slots.reiniciar.value){ | |
console.log('INFO: User wants to restart'); | |
//clear slots of this intent | |
delete intent.slots.color.value; delete intent.slots.color.resolutions; | |
delete intent.slots.talla.value; delete intent.slots.talla.resolutions; | |
delete intent.slots.marca.value; delete intent.slots.marca.resolutions; | |
delete intent.slots.precio.value; delete intent.slots.precio.resolutions; | |
//clear the restart slot | |
delete intent.slots.reiniciar.value; delete intent.slots.reiniciar.resolutions; | |
} | |
return responseBuilder | |
.addDelegateDirective(intent) | |
.getResponse(); | |
}, | |
}; | |
const CompletedRecommendationIntentHandler = { | |
canHandle(handlerInput) { | |
const request = handlerInput.requestEnvelope.request; | |
return request.type === 'IntentRequest' | |
&& request.intent.name === 'RecommendationIntent'; | |
}, | |
handle(handlerInput) { | |
const request = handlerInput.requestEnvelope.request; | |
const responseBuilder = handlerInput.responseBuilder; | |
const intent = request.intent; | |
let speechOutput = 'I didn\'t catch your confirmation'; | |
if(intent.confirmationStatus === 'DENIED') { | |
speechOutput = 'Vale. ¡Cancelamos y volvemos a empezar!'; | |
return responseBuilder | |
.speak(speechOutput) | |
.reprompt('¿Qué tipo de camiseta quieres?') | |
.getResponse(); | |
} | |
speechOutput = 'Buscando... '; | |
let data = [ | |
{ id: 1, producto: 'camiseta de elastano para corredores', marca: 'puma', precio: 'intermedio', color: ['negro', 'blanco', 'rojo'], talla: ['xs', 's', 'm', 'l'] }, | |
{ id: 2, producto: 'camiseta casual urbana', marca: 'adidas', precio: 'barato', color: ['verde', 'azul'], talla: ['m', 'l', 'xl', 'xxl'] } | |
]; | |
let slotValues = getSlotValues(request.intent.slots); | |
// getSlotValues returns .heardAs, .resolved, and .isValidated for each slot, according to request slot status codes ER_SUCCESS_MATCH, ER_SUCCESS_NO_MATCH, or traditional simple request slot without resolutions | |
let color = slotValues.color.resolved; | |
let talla = slotValues.talla.resolved; | |
let precio = slotValues.precio.resolved; | |
let marca = slotValues.marca.resolved; | |
var filteredArray = data.filter(el=> { | |
let condition = el.color.some(e => { | |
return color == e; | |
}); | |
condition = condition && el.talla.some(e => { | |
return talla == e; | |
}); | |
if(precio) | |
condition = condition && el.precio == precio; | |
if(marca) | |
condition = condition && el.marca == marca; | |
return condition | |
}); | |
if(filteredArray.length == 0) | |
speechOutput += '¡Vaya! No he encontrado ninguna camiseta con esas características. Por favor realiza otra búsqueda'; | |
else { | |
speechOutput += '!He encontrado lo que buscabas! ' | |
+ filteredArray[0].producto + ' de marca ' + filteredArray[0].marca + ' con un precio ' + filteredArray[0].precio | |
+ ', disponible en tallas ' + filteredArray[0].talla + ' y colores ' + filteredArray[0].color; | |
speechOutput += ' . Puedes realizar otra búsqueda o terminar diciendo para' | |
} | |
return responseBuilder | |
.speak(speechOutput) | |
.reprompt('prueba otra vez, ' + speechOutput) | |
.getResponse(); | |
} | |
}; | |
const SessionEndedHandler = { | |
canHandle(handlerInput) { | |
const request = handlerInput.requestEnvelope.request; | |
return request.type === 'SessionEndedRequest'; | |
}, | |
handle(handlerInput) { | |
console.log(`Session ended with reason: ${handlerInput.requestEnvelope.request.reason}`); | |
return handlerInput.responseBuilder.getResponse(); | |
} | |
}; | |
const ErrorHandler = { | |
canHandle() { | |
return true; | |
}, | |
handle(handlerInput, error) { | |
const request = handlerInput.requestEnvelope.request; | |
console.log(`Error handled: ${error.message}`); | |
// console.log(`Original Request was: ${JSON.stringify(request, null, 2)}`); | |
return handlerInput.responseBuilder | |
.speak(`Perdona. Ha ocurrido un error. ${error.message} `) | |
.reprompt(`Perdona. Ha ocurrido un error. ${error.message} `) | |
.getResponse(); | |
} | |
}; | |
function randomElement(myArray) { | |
return(myArray[Math.floor(Math.random() * myArray.length)]); | |
} | |
function getSlotValues(filledSlots) { | |
const slotValues = {}; | |
Object.keys(filledSlots).forEach((item) => { | |
const name = filledSlots[item].name; | |
if (filledSlots[item] && | |
filledSlots[item].resolutions && | |
filledSlots[item].resolutions.resolutionsPerAuthority[0] && | |
filledSlots[item].resolutions.resolutionsPerAuthority[0].status && | |
filledSlots[item].resolutions.resolutionsPerAuthority[0].status.code) { | |
switch (filledSlots[item].resolutions.resolutionsPerAuthority[0].status.code) { | |
case 'ER_SUCCESS_MATCH': | |
slotValues[name] = { | |
heardAs: filledSlots[item].value, | |
resolved: filledSlots[item].resolutions.resolutionsPerAuthority[0].values[0].value.name, | |
ERstatus: 'ER_SUCCESS_MATCH' | |
}; | |
break; | |
case 'ER_SUCCESS_NO_MATCH': | |
slotValues[name] = { | |
heardAs: filledSlots[item].value, | |
resolved: '', | |
ERstatus: 'ER_SUCCESS_NO_MATCH' | |
}; | |
break; | |
default: | |
break; | |
} | |
} else { | |
slotValues[name] = { | |
heardAs: filledSlots[item].value || '', // may be null | |
resolved: '', | |
ERstatus: '' | |
}; | |
} | |
}, this); | |
return slotValues; | |
} | |
const skillBuilder = Alexa.SkillBuilders.standard(); | |
exports.handler = skillBuilder | |
.addRequestHandlers( | |
CancelStopIntentHandler, | |
HelpIntentHandler, | |
NavigateHomeIntentHandler, | |
InProgressRecommendationIntentHandler, | |
CompletedRecommendationIntentHandler, | |
LaunchRequestHandler, | |
SessionEndedHandler | |
) | |
.addErrorHandlers(ErrorHandler) | |
.lambda(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment