a realistic\u00a0conversation.<\/strong><\/p>\nA trivial skill<\/h2>\n So far, we have not gone into too much detail when talking about the interaction model and the back-end.<\/p>\n
So here is an example:<\/p>\n
{\r\n \"interactionModel\": {\r\n \"languageModel\": {\r\n \"invocationName\": \"saluti\",\r\n \"intents\": [\r\n {\r\n \"name\": \"AMAZON.CancelIntent\",\r\n \"samples\": [\r\n \"no\",\r\n \"niente\",\r\n \"non fa niente\",\r\n \"lascia perdere\",\r\n \"annulla\"\r\n ]\r\n },\r\n {\r\n \"name\": \"AMAZON.HelpIntent\",\r\n \"samples\": []\r\n },\r\n {\r\n \"name\": \"AMAZON.StopIntent\",\r\n \"samples\": [\r\n \"abbandona\",\r\n \"esci\",\r\n \"fine\",\r\n \"stop\"\r\n ]\r\n },\r\n {\r\n \"name\": \"Salutare\",\r\n \"slots\": [],\r\n \"samples\": [\r\n \"salutarmi\",\r\n \"salutami\",\r\n \"saluti\",\r\n \"ciao\"\r\n ]\r\n }\r\n ],\r\n \"types\": []\r\n }\r\n }\r\n}\r\n<\/pre>\nThis model defines a single intent with the “Greeting”\u00a0 identification, plus the standard Amazon intent of “cancel”, “stop”, and “help”. No parameters are required. Rather, a few sample phrases are provided.<\/p>\n
It is a working model<\/strong> in its simplicity. Additionally, it fulfills the purpose of being greeted by Alexa.<\/p>\nThe back-end, meaning the service that is able to respond to the requests that Alexa performs once the intent has been identified is, however, missing.<\/p>\n
Here is a snippet to correctly answer calls related to the intent defined above, assuming the use of AWS Lambda.<\/p>\n
It involves a Nodejs function,<\/strong> whose code uses the Alexa SDK for each node. In red, we have highlighted in red the function that is invoked for the “Greeting” intent.<\/p>\nThe rest of the code is essentially a boilerplate. It remains almost completely unaltered, even for more complex skills.<\/p>\n
let speechOutput;\r\nlet reprompt;\r\nlet welcomeOutput = \"Benvenuto in 'Ciao' in italiano. Puoi salutarmi per essere salutato a tua volta\";\r\nlet welcomeReprompt = \"puoi solo dire 'ciao' per essere salutato\";\r\n\r\n\"use strict\";\r\nconst Alexa = require('alexa-sdk');\r\nconst APP_ID = undefined;\r\nspeechOutput = '';\r\nconst handlers = {\r\n'LaunchRequest': function() {\r\nthis.emit(':ask', welcomeOutput, welcomeReprompt);\r\n},\r\n'AMAZON.HelpIntent': function() {\r\nspeechOutput = 'Placeholder response for AMAZON.HelpIntent.';\r\nreprompt = '';\r\nthis.emit(':ask', speechOutput, reprompt);\r\n},\r\n'AMAZON.CancelIntent': function() {\r\nspeechOutput = 'Ok, annullato\u2019;\r\nthis.emit(':tell', speechOutput);\r\n},\r\n'AMAZON.StopIntent': function() {\r\nspeechOutput = 'Arrivederci';\r\nthis.emit(':tell', speechOutput);\r\n},\r\n'SessionEndedRequest': function() {\r\nspeechOutput = '';\r\nthis.emit(':tell', speechOutput);\r\n},\r\n'Salutare': function() {\r\nspeechOutput = '';\r\nspeechOutput = \"Ciao! Questo \u00e8 tutto quello che puoi fare per ora\u201d;\r\nthis.emit(\":tell\", speechOutput, speechOutput);\r\n},<\/span>\r\n'Unhandled': function() {\r\nspeechOutput = \"Non ho capito. Riprova\";\r\nthis.emit(':ask', speechOutput, speechOutput);\r\n}\r\n};\r\n\r\nexports.handler = (event, context) => {\r\nconst alexa = Alexa.handler(event, context);\r\nalexa.appId = APP_ID;\r\n\/\/ To enable string internationalization (i18n) features, set a resources object.\r\n\/\/alexa.resources = languageStrings;\r\nalexa.registerHandlers(handlers);\r\n\/\/alexa.dynamoDBTableName = 'DYNAMODB_TABLE_NAME'; \/\/uncomment this line to save attributes to DB\r\nalexa.execute();\r\n};\r\n\r\n\/\/ END of Intent Handlers {} ========================================================================================\r\n\/\/ 3. Helper Function =================================================================================================\r\n\r\nfunction resolveCanonical(slot) {\r\n\/\/this function looks at the entity resolution part of request and returns the slot value if a synonyms is provided\r\nlet canonical;\r\ntry {\r\ncanonical = slot.resolutions.resolutionsPerAuthority[0].values[0].value.name;\r\n}\r\ncatch (err) {\r\nconsole.log(err.message);\r\ncanonical = slot.value;\r\n};\r\nreturn canonical;\r\n};\r\n\r\nfunction delegateSlotCollection() {\r\nconsole.log(\"in delegateSlotCollection\");\r\nconsole.log(\"current dialogState: \" + this.event.request.dialogState);\r\nif (this.event.request.dialogState === \"STARTED\") {\r\nconsole.log(\"in Beginning\");\r\nlet updatedIntent = null;\r\n\/\/ updatedIntent=this.event.request.intent;\r\n\/\/optionally pre-fill slots: update the intent object with slot values for which\r\n\/\/you have defaults, then return Dialog.Delegate with this updated intent\r\n\/\/ in the updatedIntent property\r\n\/\/this.emit(\":delegate\", updatedIntent); \/\/uncomment this is using ASK SDK 1.0.9 or newer\r\n\r\n\/\/this code is necessary if using ASK SDK versions prior to 1.0.9 \r\nif (this.isOverridden()) {\r\nreturn;\r\n}\r\nthis.handler.response = buildSpeechletResponse({\r\nsessionAttributes: this.attributes,\r\ndirectives: getDialogDirectives('Dialog.Delegate', updatedIntent, null),\r\nshouldEndSession: false\r\n});\r\nthis.emit(':responseReady', updatedIntent);\r\n\r\n}\r\nelse if (this.event.request.dialogState !== \"COMPLETED\") {\r\nconsole.log(\"in not completed\");\r\n\/\/ return a Dialog.Delegate directive with no updatedIntent property.\r\n\/\/this.emit(\":delegate\"); \/\/uncomment this is using ASK SDK 1.0.9 or newer\r\n\r\n\/\/this code necessary is using ASK SDK versions prior to 1.0.9\r\nif (this.isOverridden()) {\r\nreturn;\r\n}\r\nthis.handler.response = buildSpeechletResponse({\r\nsessionAttributes: this.attributes,\r\ndirectives: getDialogDirectives('Dialog.Delegate', null, null),\r\nshouldEndSession: false\r\n});\r\nthis.emit(':responseReady');\r\n\r\n}\r\nelse {\r\nconsole.log(\"in completed\");\r\nconsole.log(\"returning: \" + JSON.stringify(this.event.request.intent));\r\n\/\/ Dialog is now complete and all required slots should be filled,\r\n\/\/ so call your normal intent handler.\r\nreturn this.event.request.intent;\r\n}\r\n}\r\n\r\n\r\nfunction randomPhrase(array) {\r\n\/\/ the argument is an array [] of words or phrases\r\nlet i = 0;\r\ni = Math.floor(Math.random() * array.length);\r\nreturn (array[i]);\r\n}\r\n\r\nfunction isSlotValid(request, slotName) {\r\nlet slot = request.intent.slots[slotName];\r\n\/\/console.log(\"request = \"+JSON.stringify(request)); \/\/uncomment if you want to see the request\r\nlet slotValue;\r\n\r\n\/\/if we have a slot, get the text and store it into speechOutput\r\nif (slot && slot.value) {\r\n\/\/we have a value in the slot\r\nslotValue = slot.value.toLowerCase();\r\nreturn slotValue;\r\n}\r\nelse {\r\n\/\/we didn't get a value in the slot.\r\nreturn false;\r\n}\r\n}\r\n\r\n\/\/These functions are here to allow dialog directives to work with SDK versions prior to 1.0.9\r\n\/\/will be removed once Lambda templates are updated with the latest SDK\r\n\r\nfunction createSpeechObject(optionsParam) {\r\nif (optionsParam && optionsParam.type === 'SSML') {\r\nreturn {\r\ntype: optionsParam.type,\r\nssml: optionsParam['speech']\r\n};\r\n}\r\nelse {\r\nreturn {\r\ntype: optionsParam.type || 'PlainText',\r\ntext: optionsParam['speech'] || optionsParam\r\n};\r\n}\r\n}\r\n\r\nfunction buildSpeechletResponse(options) {\r\nlet alexaResponse = {\r\nshouldEndSession: options.shouldEndSession\r\n};\r\n\r\nif (options.output) {\r\nalexaResponse.outputSpeech = createSpeechObject(options.output);\r\n}\r\n\r\nif (options.reprompt) {\r\nalexaResponse.reprompt = {\r\noutputSpeech: createSpeechObject(options.reprompt)\r\n};\r\n}\r\n\r\nif (options.directives) {\r\nalexaResponse.directives = options.directives;\r\n}\r\n\r\nif (options.cardTitle && options.cardContent) {\r\nalexaResponse.card = {\r\ntype: 'Simple',\r\ntitle: options.cardTitle,\r\ncontent: options.cardContent\r\n};\r\n\r\nif (options.cardImage && (options.cardImage.smallImageUrl || options.cardImage.largeImageUrl)) {\r\nalexaResponse.card.type = 'Standard';\r\nalexaResponse.card['image'] = {};\r\n\r\ndelete alexaResponse.card.content;\r\nalexaResponse.card.text = options.cardContent;\r\n\r\nif (options.cardImage.smallImageUrl) {\r\nalexaResponse.card.image['smallImageUrl'] = options.cardImage.smallImageUrl;\r\n}\r\n\r\nif (options.cardImage.largeImageUrl) {\r\nalexaResponse.card.image['largeImageUrl'] = options.cardImage.largeImageUrl;\r\n}\r\n}\r\n}\r\nelse if (options.cardType === 'LinkAccount') {\r\nalexaResponse.card = {\r\ntype: 'LinkAccount'\r\n};\r\n}\r\nelse if (options.cardType === 'AskForPermissionsConsent') {\r\nalexaResponse.card = {\r\ntype: 'AskForPermissionsConsent',\r\npermissions: options.permissions\r\n};\r\n}\r\n\r\nlet returnResult = {\r\nversion: '1.0',\r\nresponse: alexaResponse\r\n};\r\n\r\nif (options.sessionAttributes) {\r\nreturnResult.sessionAttributes = options.sessionAttributes;\r\n}\r\nreturn returnResult;\r\n}\r\n\r\nfunction getDialogDirectives(dialogType, updatedIntent, slotName) {\r\nlet directive = {\r\ntype: dialogType\r\n};\r\n\r\nif (dialogType === 'Dialog.ElicitSlot') {\r\ndirective.slotToElicit = slotName;\r\n}\r\nelse if (dialogType === 'Dialog.ConfirmSlot') {\r\ndirective.slotToConfirm = slotName;\r\n}\r\n\r\nif (updatedIntent) {\r\ndirective.updatedIntent = updatedIntent;\r\n}\r\nreturn [directive];\r\n}<\/pre>\nHere, we have covered the fundamental concepts underlying the Alexa functioning. We then analyzed the anatomy of a simple and functional skill,<\/strong> which is the first step in realizing more complex and potentially publishable skills.<\/p>\nHowever, for publication, there are compliance limitations and rules to be considered when designing a voice interface.<\/p>\n
We will address this and many other important aspects of the publication and implementation phase throughout the following articles. But first, we will publish a detailed tutorial for the creation of a non-“trivial” skill.<\/p>\n
We will not give you any hints \ud83d\ude42<\/p>\n
Stay tuned!<\/p>\n
Would you like to learn more about AWS Lambda or Serverless development?<\/strong><\/p>\nThen read our series of articles on these topics!<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"How many of you have an Alexa-enabled device or a voice assistant? These devices create a way of interacting with […]<\/p>\n","protected":false},"author":8,"featured_media":469,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[248],"tags":[340,342,264],"class_list":["post-461","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ai-ml-en","tag-amazon-alexa-en","tag-amazon-echo-en","tag-aws-lambda-en"],"yoast_head":"\n
Amazon Alexa: Anatomy of a Skill - Proud2beCloud Blog<\/title>\n \n \n \n \n \n \n \n \n \n \n \n \n\t \n\t \n\t \n \n \n \n \n \n \n\t \n\t \n\t \n