├── .github └── PULL_REQUEST_TEMPLATE.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── README.md ├── design-assets ├── APL Worksheet.docx ├── Caketime Worksheets.docx ├── README.md ├── caketime-sd.xd └── script.pdf ├── final ├── en-US.json ├── index.js └── package.json ├── i18n ├── ask-resources.json ├── lambda │ ├── index.js │ ├── languageStrings.js │ ├── package.json │ └── util.js └── skill-package │ ├── interactionModels │ └── custom │ │ ├── en-AU.json │ │ ├── en-CA.json │ │ ├── en-GB.json │ │ ├── en-IN.json │ │ ├── en-US.json │ │ ├── es-ES.json │ │ ├── es-MX.json │ │ ├── es-US.json │ │ ├── fr-CA.json │ │ ├── fr-FR.json │ │ ├── hi-IN.json │ │ ├── it-IT.json │ │ └── ja-JP.json │ └── skill.json ├── module-1 ├── README.md ├── en-US.json └── index.js ├── module-2 ├── README.md ├── en-US.json └── index.js ├── module-3 ├── README.md ├── en-US.json ├── index.js └── package.json └── module-4 ├── README.md ├── en-US.json ├── index.js └── package.json /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | *Issue #, if available:* 2 | 3 | *Description of changes:* 4 | 5 | 6 | By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. 7 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check [existing open](https://github.com/alexa/skill-sample-nodejs-first-skill/issues), or [recently closed](https://github.com/alexa/skill-sample-nodejs-first-skill/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *master* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/alexa/skill-sample-nodejs-first-skill/labels/help%20wanted) issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](https://github.com/alexa/skill-sample-nodejs-first-skill/blob/master/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | 61 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Amazon Software License 1.0 2 | 3 | This Amazon Software License ("License") governs your use, reproduction, and 4 | distribution of the accompanying software as specified below. 5 | 6 | 1. Definitions 7 | 8 | "Licensor" means any person or entity that distributes its Work. 9 | 10 | "Software" means the original work of authorship made available under this 11 | License. 12 | 13 | "Work" means the Software and any additions to or derivative works of the 14 | Software that are made available under this License. 15 | 16 | The terms "reproduce," "reproduction," "derivative works," and 17 | "distribution" have the meaning as provided under U.S. copyright law; 18 | provided, however, that for the purposes of this License, derivative works 19 | shall not include works that remain separable from, or merely link (or bind 20 | by name) to the interfaces of, the Work. 21 | 22 | Works, including the Software, are "made available" under this License by 23 | including in or with the Work either (a) a copyright notice referencing the 24 | applicability of this License to the Work, or (b) a copy of this License. 25 | 26 | 2. License Grants 27 | 28 | 2.1 Copyright Grant. Subject to the terms and conditions of this License, 29 | each Licensor grants to you a perpetual, worldwide, non-exclusive, 30 | royalty-free, copyright license to reproduce, prepare derivative works of, 31 | publicly display, publicly perform, sublicense and distribute its Work and 32 | any resulting derivative works in any form. 33 | 34 | 2.2 Patent Grant. Subject to the terms and conditions of this License, each 35 | Licensor grants to you a perpetual, worldwide, non-exclusive, royalty-free 36 | patent license to make, have made, use, sell, offer for sale, import, and 37 | otherwise transfer its Work, in whole or in part. The foregoing license 38 | applies only to the patent claims licensable by Licensor that would be 39 | infringed by Licensor's Work (or portion thereof) individually and 40 | excluding any combinations with any other materials or technology. 41 | 42 | 3. Limitations 43 | 44 | 3.1 Redistribution. You may reproduce or distribute the Work only if 45 | (a) you do so under this License, (b) you include a complete copy of this 46 | License with your distribution, and (c) you retain without modification 47 | any copyright, patent, trademark, or attribution notices that are present 48 | in the Work. 49 | 50 | 3.2 Derivative Works. You may specify that additional or different terms 51 | apply to the use, reproduction, and distribution of your derivative works 52 | of the Work ("Your Terms") only if (a) Your Terms provide that the use 53 | limitation in Section 3.3 applies to your derivative works, and (b) you 54 | identify the specific derivative works that are subject to Your Terms. 55 | Notwithstanding Your Terms, this License (including the redistribution 56 | requirements in Section 3.1) will continue to apply to the Work itself. 57 | 58 | 3.3 Use Limitation. The Work and any derivative works thereof only may be 59 | used or intended for use with the web services, computing platforms or 60 | applications provided by Amazon.com, Inc. or its affiliates, including 61 | Amazon Web Services, Inc. 62 | 63 | 3.4 Patent Claims. If you bring or threaten to bring a patent claim against 64 | any Licensor (including any claim, cross-claim or counterclaim in a 65 | lawsuit) to enforce any patents that you allege are infringed by any Work, 66 | then your rights under this License from such Licensor (including the 67 | grants in Sections 2.1 and 2.2) will terminate immediately. 68 | 69 | 3.5 Trademarks. This License does not grant any rights to use any 70 | Licensor's or its affiliates' names, logos, or trademarks, except as 71 | necessary to reproduce the notices described in this License. 72 | 73 | 3.6 Termination. If you violate any term of this License, then your rights 74 | under this License (including the grants in Sections 2.1 and 2.2) will 75 | terminate immediately. 76 | 77 | 4. Disclaimer of Warranty. 78 | 79 | THE WORK IS PROVIDED "AS IS" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 80 | EITHER EXPRESS OR IMPLIED, INCLUDING WARRANTIES OR CONDITIONS OF 81 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE OR 82 | NON-INFRINGEMENT. YOU BEAR THE RISK OF UNDERTAKING ANY ACTIVITIES UNDER 83 | THIS LICENSE. SOME STATES' CONSUMER LAWS DO NOT ALLOW EXCLUSION OF AN 84 | IMPLIED WARRANTY, SO THIS DISCLAIMER MAY NOT APPLY TO YOU. 85 | 86 | 5. Limitation of Liability. 87 | 88 | EXCEPT AS PROHIBITED BY APPLICABLE LAW, IN NO EVENT AND UNDER NO LEGAL 89 | THEORY, WHETHER IN TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE 90 | SHALL ANY LICENSOR BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY DIRECT, 91 | INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR 92 | RELATED TO THIS LICENSE, THE USE OR INABILITY TO USE THE WORK (INCLUDING 93 | BUT NOT LIMITED TO LOSS OF GOODWILL, BUSINESS INTERRUPTION, LOST PROFITS 94 | OR DATA, COMPUTER FAILURE OR MALFUNCTION, OR ANY OTHER COMM ERCIAL DAMAGES 95 | OR LOSSES), EVEN IF THE LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF 96 | SUCH DAMAGES. 97 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Skill Sample: Node.js First Skill 2 | 3 | Editor's Note: We have changed the name of the Alexa skill in our beginner tutorial from Cake Walk to Cake Time given the term's racially insensitive history. 4 | 5 | Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Workshop Building A Simple Skill 2 | 3 | This workshop is designed to teach you how to learn the core fundamentals of building an Alexa skill.It is modular so if you know the basics you can skip to the module that interests you the most. In this repository you will find the necessary JSON and code files for each module. 4 | 5 | # Step-by-step Instructions 6 | 7 | You can get started here: [Tutorial: Build an Engaging Alexa Skill](https://developer.amazon.com/en-US/alexa/alexa-skills-kit/get-deeper/tutorials-code-samples/build-an-engaging-alexa-skill) 8 | 9 | # The Skill 10 | 11 | Cake time is a skill that celebrates your birthday! Tell it your birthday to have it count down the days. Interact with the skill on your special day to hear a happy birthday message. 12 | 13 | # What You'll Learn 14 | 15 | * [Alexa Skills Kit](https://developer.amazon.com/alexa-skills-kit) 16 | * [Alexa Hosted Skills](https://developer.amazon.com/docs/hosted-skills/build-a-skill-end-to-end-using-an-alexa-hosted-skill.html) 17 | * [Intents, Utterances, Slots](https://developer.amazon.com/docs/custom-skills/create-intents-utterances-and-slots.html) 18 | * [Auto Delegation](https://developer.amazon.com/docs/custom-skills/delegate-dialog-to-alexa.html#automatically-delegate-simple-dialogs-to-alexa) 19 | * [Ask NodeJS SDK](https://ask-sdk-for-nodejs.readthedocs.io/en/latest/) 20 | * [Persistent Attributes](https://ask-sdk-for-nodejs.readthedocs.io/en/latest/Managing-Attributes.html) with [Amazon S3](https://aws.amazon.com/s3/) 21 | * [Alexa Settings API](https://developer.amazon.com/docs/smapi/alexa-settings-api-reference.html) 22 | 23 | # Workshop 24 | 25 | * [Module 1: Build A Simple Skill In 5 Minutes](./module-1/README.md) 26 | * [Module 2: Collect Slots Turn-by-turn](./module-2/README.md) 27 | * [Module 3: Add Memory To Your Skill](./module-3/README.md) 28 | * [Module 4: Use the Settings API ](./module-4/README.md) 29 | 30 | ## Community Resources 31 | 32 | * [Tutorial: Build an Engaging Alexa Skill](https://developer.amazon.com/en-US/alexa/alexa-skills-kit/get-deeper/tutorials-code-samples/build-an-engaging-alexa-skill) 33 | * [Amazon Developer Forums](https://forums.developer.amazon.com/spaces/165/index.html) 34 | * [Alexa Skills - User Voice](https://alexa.uservoice.com/forums/906892-alexa-skills-developer-voice-and-vote) 35 | 36 | 37 | ## License 38 | 39 | This library is licensed under the Amazon Software License -------------------------------------------------------------------------------- /design-assets/APL Worksheet.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexa-samples/skill-sample-nodejs-first-skill/1abdb0bf7d6e0f1a19a3c9e0e471965e86d5ef2e/design-assets/APL Worksheet.docx -------------------------------------------------------------------------------- /design-assets/Caketime Worksheets.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexa-samples/skill-sample-nodejs-first-skill/1abdb0bf7d6e0f1a19a3c9e0e471965e86d5ef2e/design-assets/Caketime Worksheets.docx -------------------------------------------------------------------------------- /design-assets/README.md: -------------------------------------------------------------------------------- 1 | # Cake Time Design Assets 2 | 3 | This folder contains situational design assets for cake time. You'll will need [Adobe XD](https://www.adobe.com/products/xd.html) to view the file. For more on situational design, please see: 4 | 5 | * [New Alexa Design Guide: Create Engaging Alexa Skills Using Situational Design](https://developer.amazon.com/blogs/alexa/post/ee0e00c9-37cd-46ac-8695-06552e0885b0/new-alexa-design-guide-create-engaging-alexa-skills-using-situational-design) 6 | * [Alexa Design Guide](https://developer.amazon.com/docs/alexa-design/get-started.html) 7 | * [Situational Design Templates](https://build.amazonalexadev.com/vui-vs-gui-guide-ww.html) 8 | * [Video: How to Shift from ScreenFirst to Voice-First Design](https://www.twitch.tv/videos/409503308) -------------------------------------------------------------------------------- /design-assets/caketime-sd.xd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexa-samples/skill-sample-nodejs-first-skill/1abdb0bf7d6e0f1a19a3c9e0e471965e86d5ef2e/design-assets/caketime-sd.xd -------------------------------------------------------------------------------- /design-assets/script.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexa-samples/skill-sample-nodejs-first-skill/1abdb0bf7d6e0f1a19a3c9e0e471965e86d5ef2e/design-assets/script.pdf -------------------------------------------------------------------------------- /final/en-US.json: -------------------------------------------------------------------------------- 1 | { 2 | "interactionModel": { 3 | "languageModel": { 4 | "invocationName": "cake time", 5 | "intents": [ 6 | { 7 | "name": "AMAZON.CancelIntent", 8 | "samples": [] 9 | }, 10 | { 11 | "name": "AMAZON.HelpIntent", 12 | "samples": [] 13 | }, 14 | { 15 | "name": "AMAZON.StopIntent", 16 | "samples": [] 17 | }, 18 | { 19 | "name": "AMAZON.NavigateHomeIntent", 20 | "samples": [] 21 | }, 22 | { 23 | "name": "CaptureBirthdayIntent", 24 | "slots": [ 25 | { 26 | "name": "month", 27 | "type": "AMAZON.Month" 28 | }, 29 | { 30 | "name": "day", 31 | "type": "AMAZON.Ordinal" 32 | }, 33 | { 34 | "name": "year", 35 | "type": "AMAZON.FOUR_DIGIT_NUMBER" 36 | } 37 | ], 38 | "samples": [ 39 | "{month} {day}", 40 | "{month} {day} {year}", 41 | "{month} {year}", 42 | "I was born on {month} {day} ", 43 | "I was born on {month} {day} {year}", 44 | "I was born on {month} {year}" 45 | ] 46 | } 47 | ], 48 | "types": [] 49 | }, 50 | "dialog": { 51 | "intents": [ 52 | { 53 | "name": "CaptureBirthdayIntent", 54 | "confirmationRequired": false, 55 | "prompts": {}, 56 | "slots": [ 57 | { 58 | "name": "month", 59 | "type": "AMAZON.Month", 60 | "confirmationRequired": false, 61 | "elicitationRequired": true, 62 | "prompts": { 63 | "elicitation": "Elicit.Slot.303899476312.795077103633" 64 | } 65 | }, 66 | { 67 | "name": "day", 68 | "type": "AMAZON.Ordinal", 69 | "confirmationRequired": false, 70 | "elicitationRequired": true, 71 | "prompts": { 72 | "elicitation": "Elicit.Slot.303899476312.985837334781" 73 | } 74 | }, 75 | { 76 | "name": "year", 77 | "type": "AMAZON.FOUR_DIGIT_NUMBER", 78 | "confirmationRequired": false, 79 | "elicitationRequired": true, 80 | "prompts": { 81 | "elicitation": "Elicit.Slot.303899476312.27341833344" 82 | } 83 | } 84 | ] 85 | } 86 | ], 87 | "delegationStrategy": "ALWAYS" 88 | }, 89 | "prompts": [ 90 | { 91 | "id": "Elicit.Slot.303899476312.795077103633", 92 | "variations": [ 93 | { 94 | "type": "PlainText", 95 | "value": "I was born in November. When what were you born?" 96 | }, 97 | { 98 | "type": "PlainText", 99 | "value": "What month were you born?" 100 | } 101 | ] 102 | }, 103 | { 104 | "id": "Elicit.Slot.303899476312.985837334781", 105 | "variations": [ 106 | { 107 | "type": "PlainText", 108 | "value": "I was born on the sixth. What day were you born?" 109 | } 110 | ] 111 | }, 112 | { 113 | "id": "Elicit.Slot.303899476312.27341833344", 114 | "variations": [ 115 | { 116 | "type": "PlainText", 117 | "value": "I was born in two thousand fourteen, what year were you born?" 118 | } 119 | ] 120 | } 121 | ] 122 | } 123 | } -------------------------------------------------------------------------------- /final/index.js: -------------------------------------------------------------------------------- 1 | // This sample demonstrates handling intents from an Alexa skill using the Alexa Skills Kit SDK (v2). 2 | // Please visit https://alexa.design/cookbook for additional examples on implementing slots, dialog management, 3 | // session persistence, api calls, and more. 4 | const Alexa = require('ask-sdk-core'); 5 | const persistenceAdapter = require('ask-sdk-s3-persistence-adapter'); 6 | 7 | 8 | const HasBirthdayLaunchRequestHandler = { 9 | canHandle(handlerInput) { 10 | console.log(JSON.stringify(handlerInput.requestEnvelope.request)); 11 | const attributesManager = handlerInput.attributesManager; 12 | const sessionAttributes = attributesManager.getSessionAttributes() || {}; 13 | 14 | const year = sessionAttributes.hasOwnProperty('year') ? sessionAttributes.year : 0; 15 | const month = sessionAttributes.hasOwnProperty('month') ? sessionAttributes.month : 0; 16 | const day = sessionAttributes.hasOwnProperty('day') ? sessionAttributes.day : 0; 17 | 18 | return handlerInput.requestEnvelope.request.type === 'LaunchRequest' && 19 | year && 20 | month && 21 | day; 22 | }, 23 | async handle(handlerInput) { 24 | 25 | const serviceClientFactory = handlerInput.serviceClientFactory; 26 | const deviceId = handlerInput.requestEnvelope.context.System.device.deviceId; 27 | 28 | const attributesManager = handlerInput.attributesManager; 29 | const sessionAttributes = attributesManager.getSessionAttributes() || {}; 30 | 31 | const year = sessionAttributes.hasOwnProperty('year') ? sessionAttributes.year : 0; 32 | const month = sessionAttributes.hasOwnProperty('month') ? sessionAttributes.month : 0; 33 | const day = sessionAttributes.hasOwnProperty('day') ? sessionAttributes.day : 0; 34 | 35 | let userTimeZone; 36 | try { 37 | const upsServiceClient = serviceClientFactory.getUpsServiceClient(); 38 | userTimeZone = await upsServiceClient.getSystemTimeZone(deviceId); 39 | } catch (error) { 40 | if (error.name !== 'ServiceError') { 41 | return handlerInput.responseBuilder.speak("There was a problem connecting to the service.").getResponse(); 42 | } 43 | console.log('error', error.message); 44 | } 45 | console.log('userTimeZone', userTimeZone); 46 | 47 | const oneDay = 24*60*60*1000; 48 | 49 | // getting the current date with the time 50 | const currentDateTime = new Date(new Date().toLocaleString("en-US", {timeZone: userTimeZone})); 51 | // removing the time from the date because it affects our difference calculation 52 | const currentDate = new Date(currentDateTime.getFullYear(), currentDateTime.getMonth(), currentDateTime.getDate()); 53 | let currentYear = currentDate.getFullYear(); 54 | 55 | console.log('currentDateTime:', currentDateTime); 56 | console.log('currentDate:', currentDate); 57 | 58 | // getting the next birthday 59 | let nextBirthday = Date.parse(`${month} ${day}, ${currentYear}`); 60 | 61 | // adjust the nextBirthday by one year if the current date is after their birthday 62 | if (currentDate.getTime() > nextBirthday) { 63 | nextBirthday = Date.parse(`${month} ${day}, ${currentYear + 1}`); 64 | currentYear++; 65 | } 66 | 67 | // setting the default speakOutput to Happy xth Birthday!! 68 | // Alexa will automatically correct the ordinal for you. 69 | // no need to worry about when to use st, th, rd 70 | let speakOutput = `Happy ${currentYear - year}th birthday!`; 71 | if (currentDate.getTime() !== nextBirthday) { 72 | const diffDays = Math.round(Math.abs((currentDate.getTime() - nextBirthday)/oneDay)); 73 | speakOutput = `Welcome back. It looks like there are ${diffDays} days until your ${currentYear - year}th birthday.` 74 | } 75 | 76 | return handlerInput.responseBuilder 77 | .speak(speakOutput) 78 | .getResponse(); 79 | } 80 | }; 81 | const LaunchRequestHandler = { 82 | canHandle(handlerInput) { 83 | return handlerInput.requestEnvelope.request.type === 'LaunchRequest'; 84 | }, 85 | handle(handlerInput) { 86 | const speakOutput = 'Hello! Welcome to Cake time. What is your birthday?'; 87 | const repromptOutput = 'I was born Nov. 6th, 2014. When were you born?'; 88 | 89 | return handlerInput.responseBuilder 90 | .speak(speakOutput) 91 | .reprompt(repromptOutput) 92 | .getResponse(); 93 | } 94 | }; 95 | const BirthdayIntentHandler = { 96 | canHandle(handlerInput) { 97 | return handlerInput.requestEnvelope.request.type === 'IntentRequest' 98 | && handlerInput.requestEnvelope.request.intent.name === 'CaptureBirthdayIntent'; 99 | }, 100 | async handle(handlerInput) { 101 | const year = handlerInput.requestEnvelope.request.intent.slots.year.value; 102 | const month = handlerInput.requestEnvelope.request.intent.slots.month.value; 103 | const day = handlerInput.requestEnvelope.request.intent.slots.day.value; 104 | 105 | const attributesManager = handlerInput.attributesManager; 106 | 107 | const birthdayAttributes = { 108 | "year": year, 109 | "month": month, 110 | "day": day 111 | 112 | }; 113 | attributesManager.setPersistentAttributes(birthdayAttributes); 114 | await attributesManager.savePersistentAttributes(); 115 | 116 | const speakOutput = `Thanks, I'll remember that you were born ${month} ${day} ${year}.`; 117 | return handlerInput.responseBuilder 118 | .speak(speakOutput) 119 | //.reprompt('add a reprompt if you want to keep the session open for the user to respond') 120 | .getResponse(); 121 | } 122 | }; 123 | 124 | const HelpIntentHandler = { 125 | canHandle(handlerInput) { 126 | return handlerInput.requestEnvelope.request.type === 'IntentRequest' 127 | && handlerInput.requestEnvelope.request.intent.name === 'AMAZON.HelpIntent'; 128 | }, 129 | handle(handlerInput) { 130 | const speakOutput = 'You can say hello to me! How can I help?'; 131 | 132 | return handlerInput.responseBuilder 133 | .speak(speakOutput) 134 | .reprompt(speakOutput) 135 | .getResponse(); 136 | } 137 | }; 138 | const CancelAndStopIntentHandler = { 139 | canHandle(handlerInput) { 140 | return handlerInput.requestEnvelope.request.type === 'IntentRequest' 141 | && (handlerInput.requestEnvelope.request.intent.name === 'AMAZON.CancelIntent' 142 | || handlerInput.requestEnvelope.request.intent.name === 'AMAZON.StopIntent'); 143 | }, 144 | handle(handlerInput) { 145 | const speakOutput = 'Goodbye!'; 146 | return handlerInput.responseBuilder 147 | .speak(speakOutput) 148 | .getResponse(); 149 | } 150 | }; 151 | const SessionEndedRequestHandler = { 152 | canHandle(handlerInput) { 153 | return handlerInput.requestEnvelope.request.type === 'SessionEndedRequest'; 154 | }, 155 | handle(handlerInput) { 156 | // Any cleanup logic goes here. 157 | return handlerInput.responseBuilder.getResponse(); 158 | } 159 | }; 160 | 161 | // The intent reflector is used for interaction model testing and debugging. 162 | // It will simply repeat the intent the user said. You can create custom handlers 163 | // for your intents by defining them above, then also adding them to the request 164 | // handler chain below. 165 | const IntentReflectorHandler = { 166 | canHandle(handlerInput) { 167 | return handlerInput.requestEnvelope.request.type === 'IntentRequest'; 168 | }, 169 | handle(handlerInput) { 170 | const intentName = handlerInput.requestEnvelope.request.intent.name; 171 | const speakOutput = `You just triggered ${intentName}`; 172 | 173 | return handlerInput.responseBuilder 174 | .speak(speakOutput) 175 | //.reprompt('add a reprompt if you want to keep the session open for the user to respond') 176 | .getResponse(); 177 | } 178 | }; 179 | 180 | // Generic error handling to capture any syntax or routing errors. If you receive an error 181 | // stating the request handler chain is not found, you have not implemented a handler for 182 | // the intent being invoked or included it in the skill builder below. 183 | const ErrorHandler = { 184 | canHandle() { 185 | return true; 186 | }, 187 | handle(handlerInput, error) { 188 | console.log(`~~~~ Error handled: ${error.message}`); 189 | const speakOutput = `Sorry, I couldn't understand what you said. Please try again.`; 190 | 191 | return handlerInput.responseBuilder 192 | .speak(speakOutput) 193 | .reprompt(speakOutput) 194 | .getResponse(); 195 | } 196 | }; 197 | 198 | const LoadBirthdayInterceptor = { 199 | async process(handlerInput) { 200 | const attributesManager = handlerInput.attributesManager; 201 | const sessionAttributes = await attributesManager.getPersistentAttributes() || {}; 202 | 203 | const year = sessionAttributes.hasOwnProperty('year') ? sessionAttributes.year : 0; 204 | const month = sessionAttributes.hasOwnProperty('month') ? sessionAttributes.month : 0; 205 | const day = sessionAttributes.hasOwnProperty('day') ? sessionAttributes.day : 0; 206 | 207 | if (year && month && day) { 208 | attributesManager.setSessionAttributes(sessionAttributes); 209 | } 210 | } 211 | } 212 | 213 | // The SkillBuilder acts as the entry point for your skill, routing all request and response 214 | // payloads to the handlers above. Make sure any new handlers or interceptors you've 215 | // defined are included below. The order matters - they're processed top to bottom. 216 | exports.handler = Alexa.SkillBuilders.custom() 217 | .withPersistenceAdapter( 218 | new persistenceAdapter.S3PersistenceAdapter({bucketName:process.env.S3_PERSISTENCE_BUCKET}) 219 | ) 220 | .addRequestHandlers( 221 | HasBirthdayLaunchRequestHandler, 222 | LaunchRequestHandler, 223 | BirthdayIntentHandler, 224 | HelpIntentHandler, 225 | CancelAndStopIntentHandler, 226 | SessionEndedRequestHandler, 227 | IntentReflectorHandler) // make sure IntentReflectorHandler is last so it doesn't override your custom intent handlers 228 | .addErrorHandlers( 229 | ErrorHandler) 230 | .addRequestInterceptors( 231 | LoadBirthdayInterceptor 232 | ) 233 | .withApiClient(new Alexa.DefaultApiClient()) 234 | .lambda(); 235 | -------------------------------------------------------------------------------- /final/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cake-time", 3 | "version": "0.9.0", 4 | "description": "alexa utility for quickly building skills", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Amazon Alexa", 10 | "license": "ISC", 11 | "dependencies": { 12 | "ask-sdk-core": "^2.0.7", 13 | "ask-sdk-model": "^1.4.1", 14 | "aws-sdk": "^2.326.0", 15 | "ask-sdk-s3-persistence-adapter": "^2.0.0" 16 | } 17 | } -------------------------------------------------------------------------------- /i18n/ask-resources.json: -------------------------------------------------------------------------------- 1 | { 2 | "askcliResourcesVersion": "2020-03-31", 3 | "profiles": { 4 | "default": { 5 | "skillMetadata": { 6 | "src": "./skill-package" 7 | }, 8 | "code": { 9 | "default": { 10 | "src": "lambda" 11 | } 12 | }, 13 | "skillInfrastructure": { 14 | "userConfig": { 15 | "runtime": "nodejs10.x", 16 | "handler": "index.handler", 17 | "awsRegion": "us-east-1" 18 | }, 19 | "type": "@ask-cli/lambda-deployer" 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /i18n/lambda/index.js: -------------------------------------------------------------------------------- 1 | // This sample demonstrates handling intents from an Alexa skill using the Alexa Skills Kit SDK (v2). 2 | // Please visit https://alexa.design/cookbook for additional examples on implementing slots, dialog management, 3 | // session persistence, api calls, and more. 4 | 5 | ///////////////////////////////// 6 | // Modules Definition 7 | ///////////////////////////////// 8 | 9 | // ASK SDK 10 | const Alexa = require('ask-sdk-core'); 11 | // ASK SDK adapter to connecto to Amazon S3 12 | const persistenceAdapter = require('ask-sdk-s3-persistence-adapter'); 13 | // i18n library dependency, we use it below in a localisation interceptor 14 | const i18n = require('i18next'); 15 | // We import a language strings object containing all of our strings. 16 | // The keys for each string will then be referenced in our code, e.g. handlerInput.t('WELCOME_MSG') 17 | const languageStrings = require('./languageStrings'); 18 | 19 | // We will use the moment.js package in order to make sure that we calculate the remaining days to the user's birthday correctly 20 | const moment = require('moment'); 21 | 22 | ///////////////////////////////// 23 | // Handlers Definition 24 | ///////////////////////////////// 25 | 26 | /** 27 | * Handles LaunchRequest requests sent by Alexa when a birthdate has been registered 28 | * Note : this type of request is send when the user invokes your skill without providing a specific intent. 29 | */ 30 | const HasBirthdayLaunchRequestHandler = { 31 | canHandle(handlerInput) { 32 | const { attributesManager } = handlerInput; 33 | const sessionAttributes = attributesManager.getSessionAttributes() || {}; 34 | 35 | const year = sessionAttributes.hasOwnProperty('year') ? sessionAttributes.year : 0; 36 | const month = sessionAttributes.hasOwnProperty('month') ? sessionAttributes.month : 0; 37 | const day = sessionAttributes.hasOwnProperty('day') ? sessionAttributes.day : 0; 38 | 39 | return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest' 40 | && year 41 | && month 42 | && day; 43 | }, 44 | async handle(handlerInput) { 45 | const { serviceClientFactory, requestEnvelope, attributesManager } = handlerInput; 46 | const deviceId = Alexa.getDeviceId(requestEnvelope) 47 | const sessionAttributes = attributesManager.getSessionAttributes() || {}; 48 | 49 | const year = sessionAttributes.hasOwnProperty('year') ? sessionAttributes.year : 0; 50 | const month = sessionAttributes.hasOwnProperty('month') ? sessionAttributes.month : 0; 51 | const day = sessionAttributes.hasOwnProperty('day') ? sessionAttributes.day : 0; 52 | 53 | let userTimeZone; 54 | try { 55 | const upsServiceClient = serviceClientFactory.getUpsServiceClient(); 56 | userTimeZone = await upsServiceClient.getSystemTimeZone(deviceId); 57 | } catch (error) { 58 | if (error.name !== 'ServiceError') { 59 | const errorSpeechText = handlerInput.t('ERROR_TIMEZONE_MSG'); 60 | return handlerInput.responseBuilder.speak(errorSpeechText).getResponse(); 61 | } 62 | console.log('error', error.message); 63 | } 64 | console.log('userTimeZone', userTimeZone); 65 | 66 | // getting the current date with the time 67 | const locale = Alexa.getLocale(requestEnvelope); 68 | const currentDateTime = new Date(new Date().toLocaleString(locale, { timeZone: userTimeZone })); 69 | // removing the time from the date because it affects our difference calculation 70 | const currentDate = moment(new Date(currentDateTime.getFullYear(), currentDateTime.getMonth(), currentDateTime.getDate())); 71 | const currentYear = currentDate.year(); 72 | 73 | console.log('currentDateTime:', currentDateTime); 74 | console.log('currentDate:', currentDate.toString()); 75 | 76 | // getting the next birthday 77 | let dateStr = currentYear.toString() + ' ' + month + ' ' + day.toString(); 78 | let nextBirthday = moment(dateStr, 'YYYY MMM DD', locale); 79 | console.log('nextBirthday:', nextBirthday.toString()) 80 | 81 | // check the difference between the current date and the next birthday 82 | let diffDays = nextBirthday.diff(currentDate, 'days'); 83 | 84 | // setting the default speakOutput to Happy xth Birthday!! 85 | // Alexa will automatically correct the ordinal for you. 86 | // no need to worry about when to use st, th, rd 87 | let age = currentYear - year; 88 | 89 | let speakOutput = handlerInput.t('HAPPY_BIRTHDAY_MSG', { age: age }); 90 | // checking if birthday still this year or 91 | if (diffDays > 0) { 92 | speakOutput = handlerInput.t('WELCOME_BACK_MSG', { count: diffDays, age: age }); 93 | } 94 | // has already happened 95 | else if (diffDays < 0) { 96 | nextBirthday = nextBirthday.add(1, 'Y'); 97 | diffDays = nextBirthday.diff(currentDate, 'days') 98 | age++ 99 | speakOutput = handlerInput.t('WELCOME_BACK_MSG', { count: diffDays, age: age }); 100 | } 101 | 102 | return handlerInput.responseBuilder 103 | .speak(speakOutput) 104 | .getResponse(); 105 | } 106 | }; 107 | 108 | /** 109 | * Handles LaunchRequest requests sent by Alexa when no birthdate has been registered 110 | * Note : this type of request is send when the user invokes your skill without providing a specific intent. 111 | */ 112 | const LaunchRequestHandler = { 113 | canHandle(handlerInput) { 114 | return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest'; 115 | }, 116 | handle(handlerInput) { 117 | const speakOutput = handlerInput.t('WELCOME_MSG'); 118 | const repromptOutput = handlerInput.t('WELCOME_REPROMPT_MSG'); 119 | 120 | return handlerInput.responseBuilder 121 | .speak(speakOutput) 122 | .reprompt(repromptOutput) 123 | .getResponse(); 124 | } 125 | }; 126 | 127 | /** 128 | * Handles CaptureBirthdayIntent requests sent by Alexa (when a user specify a birthdate) 129 | * Note : this request is sent when the user makes a request that corresponds to CaptureBirthdayIntent intent defined in your intent schema. 130 | */ 131 | const BirthdayIntentHandler = { 132 | canHandle(handlerInput) { 133 | return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' 134 | && Alexa.getIntentName(handlerInput.requestEnvelope) === 'CaptureBirthdayIntent'; 135 | }, 136 | async handle(handlerInput) { 137 | const { attributesManager, requestEnvelope } = handlerInput; 138 | 139 | const year = Alexa.getSlotValue(requestEnvelope, 'year'); 140 | const month = Alexa.getSlotValue(requestEnvelope, 'month'); 141 | const day = Alexa.getSlotValue(requestEnvelope, 'day'); 142 | 143 | const birthdayAttributes = { 144 | "year": year, 145 | "month": month, 146 | "day": day 147 | 148 | }; 149 | attributesManager.setPersistentAttributes(birthdayAttributes); 150 | await attributesManager.savePersistentAttributes(); 151 | 152 | const speakOutput = handlerInput.t('REGISTER_BIRTHDAY_MSG', { month: month, day: day, year: year }); 153 | return handlerInput.responseBuilder 154 | .speak(speakOutput) 155 | //.reprompt('add a reprompt if you want to keep the session open for the user to respond') 156 | .withShouldEndSession(true) // force the skill to close the session after confirming the birthday date 157 | .getResponse(); 158 | } 159 | }; 160 | 161 | /** 162 | * Handles AMAZON.HelpIntent requests sent by Alexa 163 | * Note : this request is sent when the user makes a request that corresponds to AMAZON.HelpIntent intent defined in your intent schema. 164 | */ 165 | const HelpIntentHandler = { 166 | canHandle(handlerInput) { 167 | return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' 168 | && Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.HelpIntent'; 169 | }, 170 | handle(handlerInput) { 171 | const speakOutput = handlerInput.t('HELP_MSG'); 172 | 173 | return handlerInput.responseBuilder 174 | .speak(speakOutput) 175 | .reprompt(speakOutput) 176 | .getResponse(); 177 | } 178 | }; 179 | 180 | /** 181 | * Handles AMAZON.CancelIntent & AMAZON.StopIntent requests sent by Alexa 182 | * Note : this request is sent when the user makes a request that corresponds to AMAZON.CancelIntent & AMAZON.StopIntent intents defined in your intent schema. 183 | */ 184 | const CancelAndStopIntentHandler = { 185 | canHandle(handlerInput) { 186 | return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' 187 | && (Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.CancelIntent' 188 | || Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.StopIntent'); 189 | }, 190 | handle(handlerInput) { 191 | const speakOutput = handlerInput.t('GOODBYE_MSG'); 192 | 193 | return handlerInput.responseBuilder 194 | .speak(speakOutput) 195 | .getResponse(); 196 | } 197 | }; 198 | 199 | /* * 200 | * SessionEndedRequest notifies that a session was ended. This handler will be triggered when a currently open 201 | * session is closed for one of the following reasons: 1) The user says "exit" or "quit". 2) The user does not 202 | * respond or says something that does not match an intent defined in your voice model. 3) An error occurs 203 | * */ 204 | const SessionEndedRequestHandler = { 205 | canHandle(handlerInput) { 206 | return Alexa.getRequestType(handlerInput.requestEnvelope) === 'SessionEndedRequest'; 207 | }, 208 | handle(handlerInput) { 209 | // Any cleanup logic goes here. 210 | return handlerInput.responseBuilder.getResponse(); 211 | } 212 | }; 213 | 214 | /* * 215 | * The intent reflector is used for interaction model testing and debugging. 216 | * It will simply repeat the intent the user said. You can create custom handlers for your intents 217 | * by defining them above, then also adding them to the request handler chain below 218 | * */ 219 | const IntentReflectorHandler = { 220 | canHandle(handlerInput) { 221 | return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'; 222 | }, 223 | handle(handlerInput) { 224 | const intentName = Alexa.getIntentName(handlerInput.requestEnvelope); 225 | const speakOutput = handlerInput.t('REFLECTOR_MSG', { intentName: intentName }); 226 | 227 | return handlerInput.responseBuilder 228 | .speak(speakOutput) 229 | //.reprompt('add a reprompt if you want to keep the session open for the user to respond') 230 | .getResponse(); 231 | } 232 | }; 233 | 234 | /** 235 | * Generic error handling to capture any syntax or routing errors. If you receive an error 236 | * stating the request handler chain is not found, you have not implemented a handler for 237 | * the intent being invoked or included it in the skill builder below 238 | * */ 239 | const ErrorHandler = { 240 | canHandle() { 241 | return true; 242 | }, 243 | handle(handlerInput, error) { 244 | console.log(`~~~~ Error handled: ${error.message}`); 245 | const speakOutput = handlerInput.t('ERROR_MSG'); 246 | 247 | return handlerInput.responseBuilder 248 | .speak(speakOutput) 249 | .reprompt(speakOutput) 250 | .getResponse(); 251 | } 252 | }; 253 | 254 | ///////////////////////////////// 255 | // Interceptors Definition 256 | ///////////////////////////////// 257 | 258 | /** 259 | * This request interceptor will log all incoming requests in the associated Logs (CloudWatch) of the AWS Lambda functions 260 | */ 261 | const LoggingRequestInterceptor = { 262 | process(handlerInput) { 263 | const { requestEnvelope } = handlerInput; 264 | const type = Alexa.getRequestType(requestEnvelope); 265 | const locale = Alexa.getLocale(requestEnvelope); 266 | if (type !== 'IntentRequest') { 267 | console.log(`[INFO] ${type} (${locale})`); 268 | } else { 269 | console.log(`[INFO] ${handlerInput.requestEnvelope.request.intent.name} (${locale})`); 270 | } 271 | console.log("\n" + "********** REQUEST *********\n" + 272 | JSON.stringify(handlerInput, null, 4)); 273 | } 274 | }; 275 | 276 | /** 277 | * This response interceptor will log all outgoing responses in the associated Logs (CloudWatch) of the AWS Lambda functions 278 | */ 279 | const LoggingResponseInterceptor = { 280 | process(handlerInput, response) { 281 | if (response) console.log("\n" + "************* RESPONSE **************\n" 282 | + JSON.stringify(response, null, 4)); 283 | } 284 | }; 285 | 286 | /** 287 | * This request interceptor will bind a translation function 't' to the handlerInput 288 | */ 289 | const LocalisationRequestInterceptor = { 290 | process(handlerInput) { 291 | i18n.init({ 292 | lng: Alexa.getLocale(handlerInput.requestEnvelope), 293 | resources: languageStrings 294 | }).then((t) => { 295 | handlerInput.t = (...args) => t(...args); 296 | }); 297 | } 298 | }; 299 | 300 | /* * 301 | * This request interceptor will load the persistent attributes as sessions attributes whatever handler is called. 302 | * 303 | * Note: Below we use async and await ( more info: javascript.info/async-await ) 304 | * It's a way to wrap promises and wait for the result of an external async operation 305 | * Like getting and saving the persistent attributes 306 | * */ 307 | const LoadBirthdayInterceptor = { 308 | async process(handlerInput) { 309 | const { attributesManager } = handlerInput; 310 | const sessionAttributes = await attributesManager.getPersistentAttributes() || {}; 311 | 312 | const year = sessionAttributes.hasOwnProperty('year') ? sessionAttributes.year : 0; 313 | const month = sessionAttributes.hasOwnProperty('month') ? sessionAttributes.month : 0; 314 | const day = sessionAttributes.hasOwnProperty('day') ? sessionAttributes.day : 0; 315 | 316 | if (year && month && day) { 317 | attributesManager.setSessionAttributes(sessionAttributes); 318 | } 319 | } 320 | } 321 | 322 | ///////////////////////////////// 323 | // SkillBuilder Definition 324 | ///////////////////////////////// 325 | 326 | /** 327 | * The SkillBuilder acts as the entry point for your skill, routing all request and response 328 | * payloads to the handlers above. Make sure any new handlers or interceptors you've 329 | * defined are included below. The order matters - they're processed top to bottom. 330 | */ 331 | exports.handler = Alexa.SkillBuilders.custom() 332 | .withPersistenceAdapter( 333 | new persistenceAdapter.S3PersistenceAdapter({ bucketName: process.env.S3_PERSISTENCE_BUCKET }) 334 | ) 335 | .addRequestHandlers( 336 | HasBirthdayLaunchRequestHandler, 337 | LaunchRequestHandler, 338 | BirthdayIntentHandler, 339 | HelpIntentHandler, 340 | CancelAndStopIntentHandler, 341 | SessionEndedRequestHandler, 342 | IntentReflectorHandler) // make sure IntentReflectorHandler is last so it doesn't override your custom intent handlers 343 | .addErrorHandlers( 344 | ErrorHandler) 345 | .addRequestInterceptors( 346 | LocalisationRequestInterceptor, 347 | LoggingRequestInterceptor, 348 | LoadBirthdayInterceptor 349 | ) 350 | .addResponseInterceptors( 351 | LoggingResponseInterceptor) 352 | .withApiClient(new Alexa.DefaultApiClient()) 353 | .lambda(); -------------------------------------------------------------------------------- /i18n/lambda/languageStrings.js: -------------------------------------------------------------------------------- 1 | /* * 2 | * We create a language strings object containing all of our strings. 3 | * The keys for each string will then be referenced in our code, e.g. handlerInput.t('WELCOME_MSG'). 4 | * The localisation interceptor in index.js will automatically choose the strings 5 | * that match the request's locale. 6 | * */ 7 | 8 | module.exports = { 9 | en: { 10 | translation: { 11 | WELCOME_MSG: `Hello! Welcome to Cake time. What is your birthday?`, 12 | WELCOME_REPROMPT_MSG: `I was born Nov. 6th, 2014. When were you born?`, 13 | WELCOME_BACK_MSG: `Welcome back. It looks like there is {{count}} day until your {{age}}th birthday.`, 14 | WELCOME_BACK_MSG_plural: `Welcome back. It looks like there are {{count}} days until your {{age}}th birthday.`, 15 | HAPPY_BIRTHDAY_MSG: `Happy {{age}}th birthday!`, 16 | REGISTER_BIRTHDAY_MSG: `Thanks, I'll remember that you were born {{month}} {{day}} {{year}}.`, 17 | HELP_MSG: `You can tell me your date of birth and I'll take note. You can also just say, "register my birthday" and I will guide you. Which one would you like to try?`, 18 | GOODBYE_MSG: `Goodbye!`, 19 | REFLECTOR_MSG: `You just triggered {{intentName}}`, 20 | ERROR_MSG: `Sorry, I couldn't understand what you said. Can you reformulate?`, 21 | ERROR_TIMEZONE_MSG: `I can't determine your timezone. Please check your device settings and make sure a timezone was selected. After that please reopen the skill and try again!` 22 | } 23 | }, 24 | fr: { 25 | translation: { 26 | WELCOME_MSG: `Bonjour! Bienvenue sur le Génie des Anniversaires. Quelle est votre date de naissance ?`, 27 | WELCOME_REPROMPT_MSG: `Je suis née le 6 novembre 2014. Et vous, quand êtes-vous né ?`, 28 | WELCOME_BACK_MSG: `Content de vous revoir! Il vous reste {{count}} jour avant d'avoir {{age}} ans.`, 29 | WELCOME_BACK_MSG_plural: `Content de vous revoir! Il vous reste {{count}} jours avant d'avoir {{age}} ans.`, 30 | HAPPY_BIRTHDAY_MSG: `Joyeux Anniversaire! Aujourd'hui, vous avez {{count}} an!`, 31 | HAPPY_BIRTHDAY_MSG_plural: `Joyeux Anniversaire! Aujourd'hui, vous avez {{count}} ans!`, 32 | REGISTER_BIRTHDAY_MSG: `Merci, je vais me rappeler que vous êtes né le {{day}} {{month}} {{year}}.`, 33 | HELP_MSG: `Je peux me souvenir de votre date de naissance. Dites-moi votre jour, mois et année de naissance ou bien dites-moi simplement "enregistre mon anniversaire" et je vous guiderai. Quel est votre choix ?`, 34 | GOODBYE_MSG: `Au revoir!`, 35 | REFLECTOR_MSG: `Vous avez invoqué l'intention {{intentName}}`, 36 | ERROR_MSG: `Désolé, je n'ai pas compris. Pouvez-vous reformuler ?`, 37 | ERROR_TIMEZONE_MSG: `Je n'ai pas réussi à déterminer votre fuseau horaire. Veuillez vérifier les paramètres de votre appareil et réessayez.` 38 | } 39 | }, 40 | "fr-CA": { 41 | translation: { 42 | WELCOME_MSG: `Bonjour! Bienvenue sur le Génie des Fêtes. Quelle est votre date de naissance ?`, 43 | HAPPY_BIRTHDAY_MSG: `Bonne Fête! Aujourd'hui, vous avez {{count}} an!`, 44 | HAPPY_BIRTHDAY_MSG_plural: `Bonne Fête! Aujourd'hui, vous avez {{count}} ans!`, 45 | HELP_MSG: `Je peux me souvenir de votre date de naissance. Dites-moi votre jour, mois et année de naissance ou bien dites-moi simplement "sauve ma fête" et je vous guiderai. Quel est votre choix ?`, 46 | } 47 | }, 48 | it: { 49 | translation: { 50 | WELCOME_MSG: `Ciao! Benvenuti a Buon Compleanno. Qual'è la tua data di nascita?`, 51 | WELCOME_REPROMPT_MSG: `Io sono nata il 6 novembre 2014. E tu invece?`, 52 | WELCOME_BACK_MSG: `Ciao di nuovo! Manca {{count}} giorno a quando avrai {{age}} anni.`, 53 | WELCOME_BACK_MSG_plural: `Ciao di nuovo! Mancano {{count}} giorni a quando avrai {{age}} anni.`, 54 | HAPPY_BIRTHDAY_MSG: `Buon compleanno! Oggi compi {{count}} anno!`, 55 | HAPPY_BIRTHDAY_MSG_plural: `Buon compleanno! Oggi compi {{count}} anni!`, 56 | REGISTER_BIRTHDAY_MSG: `Grazie, mi ricorderò la tua data di nascita: {{day}} {{month}} {{year}}.`, 57 | HELP_MSG: `Posso segnarmi la tua data di nascita. Dimmi pure la data oppure dimmi di ricordami il tuo compleanno. Cosa preferisci?`, 58 | GOODBYE_MSG: `A presto!`, 59 | REFLECTOR_MSG: `Hai invocato l'intento {{intentName}}`, 60 | ERROR_MSG: `Scusa, non ho capito. Puoi ripetere?`, 61 | ERROR_TIMEZONE_MSG: `Non ho potuto determinare il tuo fuso orario. Verifica la configurazione del tuo dispositivo, e riprova.` 62 | } 63 | }, 64 | es: { 65 | translation: { 66 | WELCOME_MSG: `Hola! Bienvenidos a Feliz Cumpleaños. Cual es tu fecha de nacimiento?`, 67 | WELCOME_REPROMPT_MSG: `Yo nací el 6 de noviembre 2014. Y tú?`, 68 | WELCOME_BACK_MSG: `Hola otra vez! Falta {{count}} día para que cumplas {{age}} año.`, 69 | WELCOME_BACK_MSG_plural: `Hola otra vez! Faltan {{count}} días para que cumplas {{age}} años.`, 70 | HAPPY_BIRTHDAY_MSG: `Feliz Cumpleaños! Hoy cumples {{count}} año!`, 71 | HAPPY_BIRTHDAY_MSG_plural: `Feliz Cumpleaños! Hoy cumples {{count}} años!`, 72 | REGISTER_BIRTHDAY_MSG: `Gracias, me acordaré de tu fecha de nacimiento: {{day}} {{month}} {{year}}.`, 73 | HELP_MSG: `Puedo apuntarme tu fecha de nacimiento. Dime la fecha o dime de acordarme de tu cumpleaños. Qué prefieres?`, 74 | GOODBYE_MSG: `Hasta luego!`, 75 | REFLECTOR_MSG: `Has invocado {{intentName}}`, 76 | ERROR_MSG: `Perdona, no entendido. Puedes repetir?`, 77 | ERROR_TIMEZONE_MSG: `No he potido determinar tu zona horaria. Verifica la configuración de tu dispositivo, y intenta otra vez.` 78 | } 79 | }, 80 | "ja-JP": { 81 | translation: { 82 | WELCOME_MSG: `こんにちは、ケークウォークへようこそ。あなたの誕生日はいつですか?`, 83 | WELCOME_REPROMPT_MSG: `私は2004年10月6日に生まれました。あなたの誕生日はいつですか?`, 84 | WELCOME_BACK_MSG: `おかえりなさい。{{age}}歳のお誕生日まで、あと{{count}}日です。`, 85 | WELCOME_BACK_MSG_plural: `おかえりなさい。{{age}}歳のお誕生日まで、残り{{count}}日です。`, 86 | HAPPY_BIRTHDAY_MSG: `{{age}}歳のお誕生日、おめでとうございます!`, 87 | REGISTER_BIRTHDAY_MSG: `ありがとうございます。誕生日は {{year}}年 {{month}}月 {{day}}日ですね?`, 88 | HELP_MSG: `あなたの誕生日を言うと、その日付を記憶します。もしくは、「私の誕生日を登録して」と言うと、詳しくご案内します。どちらにしますか?`, 89 | GOODBYE_MSG: `さようなら`, 90 | REFLECTOR_MSG: `{{intentName}}がトリガーされました。`, 91 | ERROR_MSG: `ごめんなさい、うまく理解できませんでした。もう一度言ってみてください。`, 92 | ERROR_TIMEZONE_MSG: `タイムゾーンを特定できませんでした。Alexaアプリでデバイスの設定を開き、タイムゾーンが正しく選択されていることを確認したあとで、もう一度試してください。` 93 | } 94 | }, 95 | "hi-IN": { 96 | translation: { 97 | WELCOME_MSG: `नमस्ते. Cake time में आपका स्वागत. आपका जनमदिन कब हैं?`, 98 | WELCOME_REPROMPT_MSG: `मेरा जन्म 6 नवंबर, 2014 को हुआ था. आप कब पैदा हुए थे?`, 99 | WELCOME_BACK_MSG: `वापसी पर स्वागत है. आपके {{age}} वे जनमदिन तक {{count}} दिन हैं`, 100 | WELCOME_BACK_MSG_plural: `आपके {{age}} वे जनमदिन तक {{count}} दिन हैं`, 101 | HAPPY_BIRTHDAY_MSG: `{{age}} वां जन्मदिन मुबारक हो`, 102 | REGISTER_BIRTHDAY_MSG: `शुक्रिया. मुझे याद होगा कि आप {{month}} {{day}} {{year}} मैं पैदा हुए थेैं`, 103 | HELP_MSG: `आप मुझे अपनी जन्मतिथि बता सकते हैं और मैं note कर लूंगा. आप यह भी कह सकते हैं, "मेरा जन्मदिन register करें. आप कौन सा प्रयास करना चाहेंगे?`, 104 | GOODBYE_MSG: `अलवादी `, 105 | REFLECTOR_MSG: `आपने {{intentName}} trigger किया हैं `, 106 | ERROR_MSG: `Sorry, मैं वो समझ नहीं पायी. क्या आप दोहरा सकते हैं `, 107 | ERROR_TIMEZONE_MSG: `Sorry. मैं आपके समयक्षेत्र का निर्धारण नहीं कर सकता. आपकी Device Settings में timezone select कर दो और एक और बार skill खोलो.` 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /i18n/lambda/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hello-world", 3 | "version": "1.1.0", 4 | "description": "alexa utility for quickly building skills", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Amazon Alexa", 10 | "license": "ISC", 11 | "dependencies": { 12 | "ask-sdk-core": "^2.6.0", 13 | "ask-sdk-model": "^1.18.0", 14 | "ask-sdk-s3-persistence-adapter": "^2.0.0", 15 | "aws-sdk": "^2.326.0", 16 | "i18next": "^15.0.5", 17 | "moment": "^2.24.0" 18 | } 19 | } -------------------------------------------------------------------------------- /i18n/lambda/util.js: -------------------------------------------------------------------------------- 1 | const AWS = require('aws-sdk'); 2 | 3 | const s3SigV4Client = new AWS.S3({ 4 | signatureVersion: 'v4' 5 | }); 6 | 7 | module.exports.getS3PreSignedUrl = function getS3PreSignedUrl(s3ObjectKey) { 8 | 9 | const bucketName = process.env.S3_PERSISTENCE_BUCKET; 10 | const s3PreSignedUrl = s3SigV4Client.getSignedUrl('getObject', { 11 | Bucket: bucketName, 12 | Key: s3ObjectKey, 13 | Expires: 60*1 // the Expires is capped for 1 minute 14 | }); 15 | console.log(`Util.s3PreSignedUrl: ${s3ObjectKey} URL ${s3PreSignedUrl}`); 16 | return s3PreSignedUrl; 17 | 18 | } -------------------------------------------------------------------------------- /i18n/skill-package/interactionModels/custom/en-AU.json: -------------------------------------------------------------------------------- 1 | { 2 | "interactionModel": { 3 | "languageModel": { 4 | "invocationName": "cake time", 5 | "intents": [ 6 | { 7 | "name": "AMAZON.CancelIntent", 8 | "samples": [] 9 | }, 10 | { 11 | "name": "AMAZON.HelpIntent", 12 | "samples": [] 13 | }, 14 | { 15 | "name": "AMAZON.StopIntent", 16 | "samples": [] 17 | }, 18 | { 19 | "name": "AMAZON.NavigateHomeIntent", 20 | "samples": [] 21 | }, 22 | { 23 | "name": "CaptureBirthdayIntent", 24 | "slots": [ 25 | { 26 | "name": "month", 27 | "type": "AMAZON.Month" 28 | }, 29 | { 30 | "name": "day", 31 | "type": "AMAZON.Ordinal" 32 | }, 33 | { 34 | "name": "year", 35 | "type": "AMAZON.FOUR_DIGIT_NUMBER" 36 | } 37 | ], 38 | "samples": [ 39 | "{month} {day}", 40 | "{month} {day} {year}", 41 | "{month} {year}", 42 | "I was born on {month} {day} ", 43 | "I was born on {month} {day} {year}", 44 | "I was born on {month} {year}" 45 | ] 46 | } 47 | ], 48 | "types": [] 49 | }, 50 | "dialog": { 51 | "intents": [ 52 | { 53 | "name": "CaptureBirthdayIntent", 54 | "confirmationRequired": false, 55 | "prompts": {}, 56 | "slots": [ 57 | { 58 | "name": "month", 59 | "type": "AMAZON.Month", 60 | "confirmationRequired": false, 61 | "elicitationRequired": true, 62 | "prompts": { 63 | "elicitation": "Elicit.Slot.303899476312.795077103633" 64 | } 65 | }, 66 | { 67 | "name": "day", 68 | "type": "AMAZON.Ordinal", 69 | "confirmationRequired": false, 70 | "elicitationRequired": true, 71 | "prompts": { 72 | "elicitation": "Elicit.Slot.303899476312.985837334781" 73 | } 74 | }, 75 | { 76 | "name": "year", 77 | "type": "AMAZON.FOUR_DIGIT_NUMBER", 78 | "confirmationRequired": false, 79 | "elicitationRequired": true, 80 | "prompts": { 81 | "elicitation": "Elicit.Slot.303899476312.27341833344" 82 | } 83 | } 84 | ] 85 | } 86 | ], 87 | "delegationStrategy": "ALWAYS" 88 | }, 89 | "prompts": [ 90 | { 91 | "id": "Elicit.Slot.303899476312.795077103633", 92 | "variations": [ 93 | { 94 | "type": "PlainText", 95 | "value": "I was born in November. When what were you born?" 96 | }, 97 | { 98 | "type": "PlainText", 99 | "value": "What month were you born?" 100 | } 101 | ] 102 | }, 103 | { 104 | "id": "Elicit.Slot.303899476312.985837334781", 105 | "variations": [ 106 | { 107 | "type": "PlainText", 108 | "value": "I was born on the sixth. What day were you born?" 109 | } 110 | ] 111 | }, 112 | { 113 | "id": "Elicit.Slot.303899476312.27341833344", 114 | "variations": [ 115 | { 116 | "type": "PlainText", 117 | "value": "I was born in two thousand fourteen, what year were you born?" 118 | } 119 | ] 120 | } 121 | ] 122 | } 123 | } -------------------------------------------------------------------------------- /i18n/skill-package/interactionModels/custom/en-CA.json: -------------------------------------------------------------------------------- 1 | { 2 | "interactionModel": { 3 | "languageModel": { 4 | "invocationName": "cake time", 5 | "intents": [ 6 | { 7 | "name": "AMAZON.CancelIntent", 8 | "samples": [] 9 | }, 10 | { 11 | "name": "AMAZON.HelpIntent", 12 | "samples": [] 13 | }, 14 | { 15 | "name": "AMAZON.StopIntent", 16 | "samples": [] 17 | }, 18 | { 19 | "name": "AMAZON.NavigateHomeIntent", 20 | "samples": [] 21 | }, 22 | { 23 | "name": "CaptureBirthdayIntent", 24 | "slots": [ 25 | { 26 | "name": "month", 27 | "type": "AMAZON.Month" 28 | }, 29 | { 30 | "name": "day", 31 | "type": "AMAZON.Ordinal" 32 | }, 33 | { 34 | "name": "year", 35 | "type": "AMAZON.FOUR_DIGIT_NUMBER" 36 | } 37 | ], 38 | "samples": [ 39 | "{month} {day}", 40 | "{month} {day} {year}", 41 | "{month} {year}", 42 | "I was born on {month} {day} ", 43 | "I was born on {month} {day} {year}", 44 | "I was born on {month} {year}", 45 | "register my birthday" 46 | ] 47 | } 48 | ], 49 | "types": [] 50 | }, 51 | "dialog": { 52 | "intents": [ 53 | { 54 | "name": "CaptureBirthdayIntent", 55 | "confirmationRequired": false, 56 | "prompts": {}, 57 | "slots": [ 58 | { 59 | "name": "month", 60 | "type": "AMAZON.Month", 61 | "confirmationRequired": false, 62 | "elicitationRequired": true, 63 | "prompts": { 64 | "elicitation": "Elicit.Slot.303899476312.795077103633" 65 | } 66 | }, 67 | { 68 | "name": "day", 69 | "type": "AMAZON.Ordinal", 70 | "confirmationRequired": false, 71 | "elicitationRequired": true, 72 | "prompts": { 73 | "elicitation": "Elicit.Slot.303899476312.985837334781" 74 | } 75 | }, 76 | { 77 | "name": "year", 78 | "type": "AMAZON.FOUR_DIGIT_NUMBER", 79 | "confirmationRequired": false, 80 | "elicitationRequired": true, 81 | "prompts": { 82 | "elicitation": "Elicit.Slot.303899476312.27341833344" 83 | } 84 | } 85 | ] 86 | } 87 | ], 88 | "delegationStrategy": "ALWAYS" 89 | }, 90 | "prompts": [ 91 | { 92 | "id": "Elicit.Slot.303899476312.795077103633", 93 | "variations": [ 94 | { 95 | "type": "PlainText", 96 | "value": "I was born in November. What month were you born?" 97 | }, 98 | { 99 | "type": "PlainText", 100 | "value": "What month were you born?" 101 | } 102 | ] 103 | }, 104 | { 105 | "id": "Elicit.Slot.303899476312.985837334781", 106 | "variations": [ 107 | { 108 | "type": "PlainText", 109 | "value": "I was born on the sixth. What day were you born?" 110 | } 111 | ] 112 | }, 113 | { 114 | "id": "Elicit.Slot.303899476312.27341833344", 115 | "variations": [ 116 | { 117 | "type": "PlainText", 118 | "value": "I was born in two thousand fourteen, what year were you born?" 119 | } 120 | ] 121 | } 122 | ] 123 | } 124 | } -------------------------------------------------------------------------------- /i18n/skill-package/interactionModels/custom/en-GB.json: -------------------------------------------------------------------------------- 1 | { 2 | "interactionModel": { 3 | "languageModel": { 4 | "invocationName": "cake time", 5 | "intents": [ 6 | { 7 | "name": "AMAZON.CancelIntent", 8 | "samples": [] 9 | }, 10 | { 11 | "name": "AMAZON.HelpIntent", 12 | "samples": [] 13 | }, 14 | { 15 | "name": "AMAZON.StopIntent", 16 | "samples": [] 17 | }, 18 | { 19 | "name": "AMAZON.NavigateHomeIntent", 20 | "samples": [] 21 | }, 22 | { 23 | "name": "CaptureBirthdayIntent", 24 | "slots": [ 25 | { 26 | "name": "month", 27 | "type": "AMAZON.Month" 28 | }, 29 | { 30 | "name": "day", 31 | "type": "AMAZON.Ordinal" 32 | }, 33 | { 34 | "name": "year", 35 | "type": "AMAZON.FOUR_DIGIT_NUMBER" 36 | } 37 | ], 38 | "samples": [ 39 | "{month} {day}", 40 | "{month} {day} {year}", 41 | "{month} {year}", 42 | "I was born on {month} {day} ", 43 | "I was born on {month} {day} {year}", 44 | "I was born on {month} {year}", 45 | "register my birthday" 46 | ] 47 | } 48 | ], 49 | "types": [] 50 | }, 51 | "dialog": { 52 | "intents": [ 53 | { 54 | "name": "CaptureBirthdayIntent", 55 | "confirmationRequired": false, 56 | "prompts": {}, 57 | "slots": [ 58 | { 59 | "name": "month", 60 | "type": "AMAZON.Month", 61 | "confirmationRequired": false, 62 | "elicitationRequired": true, 63 | "prompts": { 64 | "elicitation": "Elicit.Slot.303899476312.795077103633" 65 | } 66 | }, 67 | { 68 | "name": "day", 69 | "type": "AMAZON.Ordinal", 70 | "confirmationRequired": false, 71 | "elicitationRequired": true, 72 | "prompts": { 73 | "elicitation": "Elicit.Slot.303899476312.985837334781" 74 | } 75 | }, 76 | { 77 | "name": "year", 78 | "type": "AMAZON.FOUR_DIGIT_NUMBER", 79 | "confirmationRequired": false, 80 | "elicitationRequired": true, 81 | "prompts": { 82 | "elicitation": "Elicit.Slot.303899476312.27341833344" 83 | } 84 | } 85 | ] 86 | } 87 | ], 88 | "delegationStrategy": "ALWAYS" 89 | }, 90 | "prompts": [ 91 | { 92 | "id": "Elicit.Slot.303899476312.795077103633", 93 | "variations": [ 94 | { 95 | "type": "PlainText", 96 | "value": "I was born in November. What month were you born?" 97 | }, 98 | { 99 | "type": "PlainText", 100 | "value": "What month were you born?" 101 | } 102 | ] 103 | }, 104 | { 105 | "id": "Elicit.Slot.303899476312.985837334781", 106 | "variations": [ 107 | { 108 | "type": "PlainText", 109 | "value": "I was born on the sixth. What day were you born?" 110 | } 111 | ] 112 | }, 113 | { 114 | "id": "Elicit.Slot.303899476312.27341833344", 115 | "variations": [ 116 | { 117 | "type": "PlainText", 118 | "value": "I was born in two thousand fourteen, what year were you born?" 119 | } 120 | ] 121 | } 122 | ] 123 | } 124 | } -------------------------------------------------------------------------------- /i18n/skill-package/interactionModels/custom/en-IN.json: -------------------------------------------------------------------------------- 1 | { 2 | "interactionModel": { 3 | "languageModel": { 4 | "invocationName": "cake time", 5 | "intents": [ 6 | { 7 | "name": "AMAZON.CancelIntent", 8 | "samples": [] 9 | }, 10 | { 11 | "name": "AMAZON.HelpIntent", 12 | "samples": [] 13 | }, 14 | { 15 | "name": "AMAZON.StopIntent", 16 | "samples": [] 17 | }, 18 | { 19 | "name": "AMAZON.NavigateHomeIntent", 20 | "samples": [] 21 | }, 22 | { 23 | "name": "CaptureBirthdayIntent", 24 | "slots": [ 25 | { 26 | "name": "month", 27 | "type": "AMAZON.Month" 28 | }, 29 | { 30 | "name": "day", 31 | "type": "AMAZON.NUMBER" 32 | }, 33 | { 34 | "name": "year", 35 | "type": "AMAZON.FOUR_DIGIT_NUMBER" 36 | } 37 | ], 38 | "samples": [ 39 | "{month} {day}", 40 | "{month} {day} {year}", 41 | "{month} {year}", 42 | "I was born on {month} {day} ", 43 | "I was born on {month} {day} {year}", 44 | "I was born on {month} {year}" 45 | ] 46 | } 47 | ], 48 | "types": [] 49 | }, 50 | "dialog": { 51 | "intents": [ 52 | { 53 | "name": "CaptureBirthdayIntent", 54 | "confirmationRequired": false, 55 | "prompts": {}, 56 | "slots": [ 57 | { 58 | "name": "month", 59 | "type": "AMAZON.Month", 60 | "confirmationRequired": false, 61 | "elicitationRequired": true, 62 | "prompts": { 63 | "elicitation": "Elicit.Slot.303899476312.795077103633" 64 | } 65 | }, 66 | { 67 | "name": "day", 68 | "type": "AMAZON.NUMBER", 69 | "confirmationRequired": false, 70 | "elicitationRequired": true, 71 | "prompts": { 72 | "elicitation": "Elicit.Slot.303899476312.985837334781" 73 | } 74 | }, 75 | { 76 | "name": "year", 77 | "type": "AMAZON.FOUR_DIGIT_NUMBER", 78 | "confirmationRequired": false, 79 | "elicitationRequired": true, 80 | "prompts": { 81 | "elicitation": "Elicit.Slot.303899476312.27341833344" 82 | } 83 | } 84 | ] 85 | } 86 | ], 87 | "delegationStrategy": "ALWAYS" 88 | }, 89 | "prompts": [ 90 | { 91 | "id": "Elicit.Slot.303899476312.795077103633", 92 | "variations": [ 93 | { 94 | "type": "PlainText", 95 | "value": "I was born in November. When what were you born?" 96 | }, 97 | { 98 | "type": "PlainText", 99 | "value": "What month were you born?" 100 | } 101 | ] 102 | }, 103 | { 104 | "id": "Elicit.Slot.303899476312.985837334781", 105 | "variations": [ 106 | { 107 | "type": "PlainText", 108 | "value": "I was born on the sixth. What day were you born?" 109 | } 110 | ] 111 | }, 112 | { 113 | "id": "Elicit.Slot.303899476312.27341833344", 114 | "variations": [ 115 | { 116 | "type": "PlainText", 117 | "value": "I was born in two thousand fourteen, what year were you born?" 118 | } 119 | ] 120 | } 121 | ] 122 | } 123 | } -------------------------------------------------------------------------------- /i18n/skill-package/interactionModels/custom/en-US.json: -------------------------------------------------------------------------------- 1 | { 2 | "interactionModel": { 3 | "languageModel": { 4 | "invocationName": "cake time", 5 | "intents": [ 6 | { 7 | "name": "AMAZON.CancelIntent", 8 | "samples": [] 9 | }, 10 | { 11 | "name": "AMAZON.HelpIntent", 12 | "samples": [] 13 | }, 14 | { 15 | "name": "AMAZON.StopIntent", 16 | "samples": [] 17 | }, 18 | { 19 | "name": "AMAZON.NavigateHomeIntent", 20 | "samples": [] 21 | }, 22 | { 23 | "name": "CaptureBirthdayIntent", 24 | "slots": [ 25 | { 26 | "name": "month", 27 | "type": "AMAZON.Month" 28 | }, 29 | { 30 | "name": "day", 31 | "type": "AMAZON.Ordinal" 32 | }, 33 | { 34 | "name": "year", 35 | "type": "AMAZON.FOUR_DIGIT_NUMBER" 36 | } 37 | ], 38 | "samples": [ 39 | "{month} {day}", 40 | "{month} {day} {year}", 41 | "{month} {year}", 42 | "I was born on {month} {day} ", 43 | "I was born on {month} {day} {year}", 44 | "I was born on {month} {year}", 45 | "register my birthday" 46 | ] 47 | } 48 | ], 49 | "types": [] 50 | }, 51 | "dialog": { 52 | "intents": [ 53 | { 54 | "name": "CaptureBirthdayIntent", 55 | "confirmationRequired": false, 56 | "prompts": {}, 57 | "slots": [ 58 | { 59 | "name": "month", 60 | "type": "AMAZON.Month", 61 | "confirmationRequired": false, 62 | "elicitationRequired": true, 63 | "prompts": { 64 | "elicitation": "Elicit.Slot.303899476312.795077103633" 65 | } 66 | }, 67 | { 68 | "name": "day", 69 | "type": "AMAZON.Ordinal", 70 | "confirmationRequired": false, 71 | "elicitationRequired": true, 72 | "prompts": { 73 | "elicitation": "Elicit.Slot.303899476312.985837334781" 74 | } 75 | }, 76 | { 77 | "name": "year", 78 | "type": "AMAZON.FOUR_DIGIT_NUMBER", 79 | "confirmationRequired": false, 80 | "elicitationRequired": true, 81 | "prompts": { 82 | "elicitation": "Elicit.Slot.303899476312.27341833344" 83 | } 84 | } 85 | ] 86 | } 87 | ], 88 | "delegationStrategy": "ALWAYS" 89 | }, 90 | "prompts": [ 91 | { 92 | "id": "Elicit.Slot.303899476312.795077103633", 93 | "variations": [ 94 | { 95 | "type": "PlainText", 96 | "value": "I was born in November. What month were you born?" 97 | }, 98 | { 99 | "type": "PlainText", 100 | "value": "What month were you born?" 101 | } 102 | ] 103 | }, 104 | { 105 | "id": "Elicit.Slot.303899476312.985837334781", 106 | "variations": [ 107 | { 108 | "type": "PlainText", 109 | "value": "I was born on the sixth. What day were you born?" 110 | } 111 | ] 112 | }, 113 | { 114 | "id": "Elicit.Slot.303899476312.27341833344", 115 | "variations": [ 116 | { 117 | "type": "PlainText", 118 | "value": "I was born in two thousand fourteen, what year were you born?" 119 | } 120 | ] 121 | } 122 | ] 123 | } 124 | } -------------------------------------------------------------------------------- /i18n/skill-package/interactionModels/custom/es-ES.json: -------------------------------------------------------------------------------- 1 | { 2 | "interactionModel": { 3 | "languageModel": { 4 | "invocationName": "feliz cumpleaños", 5 | "intents": [ 6 | { 7 | "name": "AMAZON.CancelIntent", 8 | "samples": [] 9 | }, 10 | { 11 | "name": "AMAZON.HelpIntent", 12 | "samples": [] 13 | }, 14 | { 15 | "name": "AMAZON.StopIntent", 16 | "samples": [] 17 | }, 18 | { 19 | "name": "AMAZON.NavigateHomeIntent", 20 | "samples": [] 21 | }, 22 | { 23 | "name": "CaptureBirthdayIntent", 24 | "slots": [ 25 | { 26 | "name": "month", 27 | "type": "AMAZON.Month" 28 | }, 29 | { 30 | "name": "day", 31 | "type": "AMAZON.Number" 32 | }, 33 | { 34 | "name": "year", 35 | "type": "AMAZON.Number" 36 | } 37 | ], 38 | "samples": [ 39 | "{month} del {year}", 40 | "{day} de {month}", 41 | "el año {year}", 42 | "en {year}", 43 | "nací en {year}", 44 | "nací en {year}", 45 | "el {day} de {month}", 46 | "el día {day} de {month}", 47 | "mi fecha de nacimiento es el {day} de {month} de {year}", 48 | "mi fecha de nacimiento es el {day} de {month} {year}", 49 | "nací el {day} de {month} {year}", 50 | "mi cumpleaños es el {day} de {month} {year}", 51 | "registra mi cumpleaños", 52 | "apunta mi cumpleaños", 53 | "apunta mi fecha de nacimiento", 54 | "registra mi fecha de nacimiento", 55 | "recuerda mi cumpleaños", 56 | "acuérdate de mi cumpleaños", 57 | "apúntate mi cumple" 58 | ] 59 | } 60 | ], 61 | "types": [] 62 | }, 63 | "dialog": { 64 | "intents": [ 65 | { 66 | "name": "CaptureBirthdayIntent", 67 | "confirmationRequired": false, 68 | "prompts": {}, 69 | "slots": [ 70 | { 71 | "name": "month", 72 | "type": "AMAZON.Month", 73 | "confirmationRequired": false, 74 | "elicitationRequired": true, 75 | "prompts": { 76 | "elicitation": "Elicit.Slot.303899476312.795077103633" 77 | } 78 | }, 79 | { 80 | "name": "day", 81 | "type": "AMAZON.Ordinal", 82 | "confirmationRequired": false, 83 | "elicitationRequired": true, 84 | "prompts": { 85 | "elicitation": "Elicit.Slot.303899476312.985837334781" 86 | } 87 | }, 88 | { 89 | "name": "year", 90 | "type": "AMAZON.FOUR_DIGIT_NUMBER", 91 | "confirmationRequired": false, 92 | "elicitationRequired": true, 93 | "prompts": { 94 | "elicitation": "Elicit.Slot.303899476312.27341833344" 95 | } 96 | } 97 | ] 98 | } 99 | ], 100 | "delegationStrategy": "ALWAYS" 101 | }, 102 | "prompts": [ 103 | { 104 | "id": "Elicit.Slot.303899476312.795077103633", 105 | "variations": [ 106 | { 107 | "type": "PlainText", 108 | "value": "Yo nací en noviembre. Y tú?" 109 | }, 110 | { 111 | "type": "PlainText", 112 | "value": "Cual es tu mes de nacimiento?" 113 | } 114 | ] 115 | }, 116 | { 117 | "id": "Elicit.Slot.303899476312.985837334781", 118 | "variations": [ 119 | { 120 | "type": "PlainText", 121 | "value": "Nací el 6. Qué día del mes es tu cumpleaños?" 122 | } 123 | ] 124 | }, 125 | { 126 | "id": "Elicit.Slot.303899476312.27341833344", 127 | "variations": [ 128 | { 129 | "type": "PlainText", 130 | "value": "Nací en dos mil catorce, y tú en qué año?" 131 | } 132 | ] 133 | } 134 | ] 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /i18n/skill-package/interactionModels/custom/es-MX.json: -------------------------------------------------------------------------------- 1 | { 2 | "interactionModel": { 3 | "languageModel": { 4 | "invocationName": "feliz cumpleaños", 5 | "intents": [ 6 | { 7 | "name": "AMAZON.CancelIntent", 8 | "samples": [] 9 | }, 10 | { 11 | "name": "AMAZON.HelpIntent", 12 | "samples": [] 13 | }, 14 | { 15 | "name": "AMAZON.StopIntent", 16 | "samples": [] 17 | }, 18 | { 19 | "name": "AMAZON.NavigateHomeIntent", 20 | "samples": [] 21 | }, 22 | { 23 | "name": "CaptureBirthdayIntent", 24 | "slots": [ 25 | { 26 | "name": "month", 27 | "type": "AMAZON.Month" 28 | }, 29 | { 30 | "name": "day", 31 | "type": "AMAZON.Number" 32 | }, 33 | { 34 | "name": "year", 35 | "type": "AMAZON.Number" 36 | } 37 | ], 38 | "samples": [ 39 | "{month} del {year}", 40 | "{day} de {month}", 41 | "el año {year}", 42 | "en {year}", 43 | "nací en {year}", 44 | "nací en {year}", 45 | "el {day} de {month}", 46 | "el día {day} de {month}", 47 | "mi fecha de nacimiento es el {day} de {month} de {year}", 48 | "mi fecha de nacimiento es el {day} de {month} {year}", 49 | "nací el {day} de {month} {year}", 50 | "mi cumpleaños es el {day} de {month} {year}", 51 | "registra mi cumpleaños", 52 | "apunta mi cumpleaños", 53 | "apunta mi fecha de nacimiento", 54 | "registra mi fecha de nacimiento", 55 | "recuerda mi cumpleaños", 56 | "acuérdate de mi cumpleaños", 57 | "apúntate mi cumple" 58 | ] 59 | } 60 | ], 61 | "types": [] 62 | }, 63 | "dialog": { 64 | "intents": [ 65 | { 66 | "name": "CaptureBirthdayIntent", 67 | "confirmationRequired": false, 68 | "prompts": {}, 69 | "slots": [ 70 | { 71 | "name": "month", 72 | "type": "AMAZON.Month", 73 | "confirmationRequired": false, 74 | "elicitationRequired": true, 75 | "prompts": { 76 | "elicitation": "Elicit.Slot.303899476312.795077103633" 77 | } 78 | }, 79 | { 80 | "name": "day", 81 | "type": "AMAZON.Ordinal", 82 | "confirmationRequired": false, 83 | "elicitationRequired": true, 84 | "prompts": { 85 | "elicitation": "Elicit.Slot.303899476312.985837334781" 86 | } 87 | }, 88 | { 89 | "name": "year", 90 | "type": "AMAZON.FOUR_DIGIT_NUMBER", 91 | "confirmationRequired": false, 92 | "elicitationRequired": true, 93 | "prompts": { 94 | "elicitation": "Elicit.Slot.303899476312.27341833344" 95 | } 96 | } 97 | ] 98 | } 99 | ], 100 | "delegationStrategy": "ALWAYS" 101 | }, 102 | "prompts": [ 103 | { 104 | "id": "Elicit.Slot.303899476312.795077103633", 105 | "variations": [ 106 | { 107 | "type": "PlainText", 108 | "value": "Yo nací en noviembre. Y tú?" 109 | }, 110 | { 111 | "type": "PlainText", 112 | "value": "Cual es tu mes de nacimiento?" 113 | } 114 | ] 115 | }, 116 | { 117 | "id": "Elicit.Slot.303899476312.985837334781", 118 | "variations": [ 119 | { 120 | "type": "PlainText", 121 | "value": "Nací el 6. Qué día del mes es tu cumpleaños?" 122 | } 123 | ] 124 | }, 125 | { 126 | "id": "Elicit.Slot.303899476312.27341833344", 127 | "variations": [ 128 | { 129 | "type": "PlainText", 130 | "value": "Nací en dos mil catorce, y tú en qué año?" 131 | } 132 | ] 133 | } 134 | ] 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /i18n/skill-package/interactionModels/custom/es-US.json: -------------------------------------------------------------------------------- 1 | { 2 | "interactionModel": { 3 | "languageModel": { 4 | "invocationName": "feliz cumpleaños", 5 | "intents": [ 6 | { 7 | "name": "AMAZON.CancelIntent", 8 | "samples": [] 9 | }, 10 | { 11 | "name": "AMAZON.HelpIntent", 12 | "samples": [] 13 | }, 14 | { 15 | "name": "AMAZON.StopIntent", 16 | "samples": [] 17 | }, 18 | { 19 | "name": "AMAZON.NavigateHomeIntent", 20 | "samples": [] 21 | }, 22 | { 23 | "name": "CaptureBirthdayIntent", 24 | "slots": [ 25 | { 26 | "name": "month", 27 | "type": "AMAZON.Month" 28 | }, 29 | { 30 | "name": "day", 31 | "type": "AMAZON.Number" 32 | }, 33 | { 34 | "name": "year", 35 | "type": "AMAZON.Number" 36 | } 37 | ], 38 | "samples": [ 39 | "{month} del {year}", 40 | "{day} de {month}", 41 | "el año {year}", 42 | "en {year}", 43 | "nací en {year}", 44 | "nací en {year}", 45 | "el {day} de {month}", 46 | "el día {day} de {month}", 47 | "mi fecha de nacimiento es el {day} de {month} de {year}", 48 | "mi fecha de nacimiento es el {day} de {month} {year}", 49 | "nací el {day} de {month} {year}", 50 | "mi cumpleaños es el {day} de {month} {year}", 51 | "registra mi cumpleaños", 52 | "apunta mi cumpleaños", 53 | "apunta mi fecha de nacimiento", 54 | "registra mi fecha de nacimiento", 55 | "recuerda mi cumpleaños", 56 | "acuérdate de mi cumpleaños", 57 | "apúntate mi cumple" 58 | ] 59 | } 60 | ], 61 | "types": [] 62 | }, 63 | "dialog": { 64 | "intents": [ 65 | { 66 | "name": "CaptureBirthdayIntent", 67 | "confirmationRequired": false, 68 | "prompts": {}, 69 | "slots": [ 70 | { 71 | "name": "month", 72 | "type": "AMAZON.Month", 73 | "confirmationRequired": false, 74 | "elicitationRequired": true, 75 | "prompts": { 76 | "elicitation": "Elicit.Slot.303899476312.795077103633" 77 | } 78 | }, 79 | { 80 | "name": "day", 81 | "type": "AMAZON.Ordinal", 82 | "confirmationRequired": false, 83 | "elicitationRequired": true, 84 | "prompts": { 85 | "elicitation": "Elicit.Slot.303899476312.985837334781" 86 | } 87 | }, 88 | { 89 | "name": "year", 90 | "type": "AMAZON.FOUR_DIGIT_NUMBER", 91 | "confirmationRequired": false, 92 | "elicitationRequired": true, 93 | "prompts": { 94 | "elicitation": "Elicit.Slot.303899476312.27341833344" 95 | } 96 | } 97 | ] 98 | } 99 | ], 100 | "delegationStrategy": "ALWAYS" 101 | }, 102 | "prompts": [ 103 | { 104 | "id": "Elicit.Slot.303899476312.795077103633", 105 | "variations": [ 106 | { 107 | "type": "PlainText", 108 | "value": "Yo nací en noviembre. Y tú?" 109 | }, 110 | { 111 | "type": "PlainText", 112 | "value": "Cual es tu mes de nacimiento?" 113 | } 114 | ] 115 | }, 116 | { 117 | "id": "Elicit.Slot.303899476312.985837334781", 118 | "variations": [ 119 | { 120 | "type": "PlainText", 121 | "value": "Nací el 6. Qué día del mes es tu cumpleaños?" 122 | } 123 | ] 124 | }, 125 | { 126 | "id": "Elicit.Slot.303899476312.27341833344", 127 | "variations": [ 128 | { 129 | "type": "PlainText", 130 | "value": "Nací en dos mil catorce, y tú en qué año?" 131 | } 132 | ] 133 | } 134 | ] 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /i18n/skill-package/interactionModels/custom/fr-CA.json: -------------------------------------------------------------------------------- 1 | { 2 | "interactionModel": { 3 | "languageModel": { 4 | "invocationName": "le génie des fêtes", 5 | "intents": [ 6 | { 7 | "name": "AMAZON.CancelIntent", 8 | "samples": [] 9 | }, 10 | { 11 | "name": "AMAZON.HelpIntent", 12 | "samples": [] 13 | }, 14 | { 15 | "name": "AMAZON.StopIntent", 16 | "samples": [] 17 | }, 18 | { 19 | "name": "AMAZON.NavigateHomeIntent", 20 | "samples": [] 21 | }, 22 | { 23 | "name": "CaptureBirthdayIntent", 24 | "slots": [ 25 | { 26 | "name": "day", 27 | "type": "AMAZON.NUMBER", 28 | "samples": [ 29 | "{day}", 30 | "le {day}", 31 | "le {day} {month}", 32 | "le {day} {month} {year}", 33 | "je suis né le {day} {month}", 34 | "je suis né le {day} {month} {year}" 35 | ] 36 | }, 37 | { 38 | "name": "month", 39 | "type": "AMAZON.Month", 40 | "samples": [ 41 | "mon mois de naissance est {month}", 42 | "je suis né le mois de {month}", 43 | "{month}", 44 | "en {month}" 45 | ] 46 | }, 47 | { 48 | "name": "year", 49 | "type": "AMAZON.NUMBER", 50 | "samples": [ 51 | "je suis né en {year}", 52 | "mon année de naissance est {year}", 53 | "en {year}", 54 | "l'année {year}", 55 | "l'an {year}", 56 | "{year}" 57 | ] 58 | } 59 | ], 60 | "samples": [ 61 | "le {day} {month} {year}", 62 | "le {day} {month}", 63 | "le {day} du mois de {month}", 64 | "le {day} du mois d' {month}", 65 | "le {day} {month} de l'année {year}", 66 | "sauve ma date de naissance", 67 | "sauver ma date de naissance", 68 | "sauver ma fête", 69 | "sauve ma fête", 70 | "enregistre ma date de naissance", 71 | "enregistre ma fête", 72 | "enregistrer ma date de naissance", 73 | "enregistrer ma fête", 74 | "ma fête est le {day} {month} {year}", 75 | "ma fête est le {day} {month}", 76 | "ma date de naissance est le {day} {month} {year}", 77 | "ma date de naissance est le {day} {month}", 78 | "je suis né un {day} {month} {year}", 79 | "je suis né un {day} {month} ", 80 | "je suis né le {day} {month} {year}", 81 | "je suis né le {day} {month}", 82 | "je suis né en {month} {year}", 83 | "je suis né en {year}" 84 | ] 85 | } 86 | ], 87 | "types": [] 88 | }, 89 | "dialog": { 90 | "intents": [ 91 | { 92 | "name": "CaptureBirthdayIntent", 93 | "confirmationRequired": false, 94 | "prompts": {}, 95 | "slots": [ 96 | { 97 | "name": "day", 98 | "type": "AMAZON.NUMBER", 99 | "confirmationRequired": false, 100 | "elicitationRequired": true, 101 | "prompts": { 102 | "elicitation": "Elicit.Slot.303899476312.985837334781" 103 | } 104 | }, 105 | { 106 | "name": "month", 107 | "type": "AMAZON.Month", 108 | "confirmationRequired": false, 109 | "elicitationRequired": true, 110 | "prompts": { 111 | "elicitation": "Elicit.Slot.303899476312.795077103633" 112 | } 113 | }, 114 | { 115 | "name": "year", 116 | "type": "AMAZON.NUMBER", 117 | "confirmationRequired": false, 118 | "elicitationRequired": true, 119 | "prompts": { 120 | "elicitation": "Elicit.Slot.303899476312.27341833344" 121 | } 122 | } 123 | ] 124 | } 125 | ], 126 | "delegationStrategy": "ALWAYS" 127 | }, 128 | "prompts": [ 129 | { 130 | "id": "Elicit.Slot.303899476312.795077103633", 131 | "variations": [ 132 | { 133 | "type": "PlainText", 134 | "value": "Je suis née en Novembre. Et vous, quel mois êtes-vous né ?" 135 | }, 136 | { 137 | "type": "PlainText", 138 | "value": "Quel est votre mois de naissance ?" 139 | } 140 | ] 141 | }, 142 | { 143 | "id": "Elicit.Slot.303899476312.985837334781", 144 | "variations": [ 145 | { 146 | "type": "PlainText", 147 | "value": "Quel jour êtes-vous né ?" 148 | } 149 | ] 150 | }, 151 | { 152 | "id": "Elicit.Slot.303899476312.27341833344", 153 | "variations": [ 154 | { 155 | "type": "PlainText", 156 | "value": "Je suis née en 2014. Et vous, quelle est votre année de naissance ?" 157 | } 158 | ] 159 | } 160 | ] 161 | } 162 | } -------------------------------------------------------------------------------- /i18n/skill-package/interactionModels/custom/fr-FR.json: -------------------------------------------------------------------------------- 1 | { 2 | "interactionModel": { 3 | "languageModel": { 4 | "invocationName": "le génie des anniversaires", 5 | "intents": [ 6 | { 7 | "name": "AMAZON.CancelIntent", 8 | "samples": [] 9 | }, 10 | { 11 | "name": "AMAZON.HelpIntent", 12 | "samples": [] 13 | }, 14 | { 15 | "name": "AMAZON.StopIntent", 16 | "samples": [] 17 | }, 18 | { 19 | "name": "AMAZON.NavigateHomeIntent", 20 | "samples": [] 21 | }, 22 | { 23 | "name": "CaptureBirthdayIntent", 24 | "slots": [ 25 | { 26 | "name": "day", 27 | "type": "AMAZON.NUMBER", 28 | "samples": [ 29 | "{day}", 30 | "le {day}", 31 | "le {day} {month}", 32 | "le {day} {month} {year}", 33 | "je suis né le {day} {month}", 34 | "je suis né le {day} {month} {year}" 35 | ] 36 | }, 37 | { 38 | "name": "month", 39 | "type": "AMAZON.Month", 40 | "samples": [ 41 | "mon mois de naissance est {month}", 42 | "je suis né le mois de {month}", 43 | "{month}", 44 | "en {month}" 45 | ] 46 | }, 47 | { 48 | "name": "year", 49 | "type": "AMAZON.NUMBER", 50 | "samples": [ 51 | "je suis né en {year}", 52 | "mon année de naissance est {year}", 53 | "en {year}", 54 | "l'année {year}", 55 | "l'an {year}", 56 | "{year}" 57 | ] 58 | } 59 | ], 60 | "samples": [ 61 | "le {day} {month} {year}", 62 | "le {day} {month}", 63 | "le {day} du mois de {month}", 64 | "le {day} du mois d' {month}", 65 | "le {day} {month} de l'année {year}", 66 | "enregistre ma date de naissance", 67 | "enregistre mon anniversaire", 68 | "enregistrer ma date de naissance", 69 | "enregistrer mon anniversaire", 70 | "mon anniversaire est le {day} {month} {year}", 71 | "mon anniversaire est le {day} {month}", 72 | "ma date de naissance est le {day} {month} {year}", 73 | "ma date de naissance est le {day} {month}", 74 | "je suis né un {day} {month} {year}", 75 | "je suis né un {day} {month} ", 76 | "je suis né le {day} {month} {year}", 77 | "je suis né le {day} {month}", 78 | "je suis né en {month} {year}", 79 | "je suis né en {year}" 80 | ] 81 | } 82 | ], 83 | "types": [] 84 | }, 85 | "dialog": { 86 | "intents": [ 87 | { 88 | "name": "CaptureBirthdayIntent", 89 | "confirmationRequired": false, 90 | "prompts": {}, 91 | "slots": [ 92 | { 93 | "name": "day", 94 | "type": "AMAZON.NUMBER", 95 | "confirmationRequired": false, 96 | "elicitationRequired": true, 97 | "prompts": { 98 | "elicitation": "Elicit.Slot.303899476312.985837334781" 99 | } 100 | }, 101 | { 102 | "name": "month", 103 | "type": "AMAZON.Month", 104 | "confirmationRequired": false, 105 | "elicitationRequired": true, 106 | "prompts": { 107 | "elicitation": "Elicit.Slot.303899476312.795077103633" 108 | } 109 | }, 110 | { 111 | "name": "year", 112 | "type": "AMAZON.NUMBER", 113 | "confirmationRequired": false, 114 | "elicitationRequired": true, 115 | "prompts": { 116 | "elicitation": "Elicit.Slot.303899476312.27341833344" 117 | } 118 | } 119 | ] 120 | } 121 | ], 122 | "delegationStrategy": "ALWAYS" 123 | }, 124 | "prompts": [ 125 | { 126 | "id": "Elicit.Slot.303899476312.795077103633", 127 | "variations": [ 128 | { 129 | "type": "PlainText", 130 | "value": "Je suis née en Novembre. Et vous, quel mois êtes-vous né ?" 131 | }, 132 | { 133 | "type": "PlainText", 134 | "value": "Quel est votre mois de naissance ?" 135 | } 136 | ] 137 | }, 138 | { 139 | "id": "Elicit.Slot.303899476312.985837334781", 140 | "variations": [ 141 | { 142 | "type": "PlainText", 143 | "value": "Quel jour êtes-vous né ?" 144 | } 145 | ] 146 | }, 147 | { 148 | "id": "Elicit.Slot.303899476312.27341833344", 149 | "variations": [ 150 | { 151 | "type": "PlainText", 152 | "value": "Je suis née en 2014. Et vous, quelle est votre année de naissance ?" 153 | } 154 | ] 155 | } 156 | ] 157 | } 158 | } -------------------------------------------------------------------------------- /i18n/skill-package/interactionModels/custom/hi-IN.json: -------------------------------------------------------------------------------- 1 | { 2 | "interactionModel": { 3 | "languageModel": { 4 | "invocationName": "cake time", 5 | "intents": [ 6 | { 7 | "name": "AMAZON.CancelIntent", 8 | "samples": [] 9 | }, 10 | { 11 | "name": "AMAZON.HelpIntent", 12 | "samples": [] 13 | }, 14 | { 15 | "name": "AMAZON.StopIntent", 16 | "samples": [] 17 | }, 18 | { 19 | "name": "AMAZON.NavigateHomeIntent", 20 | "samples": [] 21 | }, 22 | { 23 | "name": "CaptureBirthdayIntent", 24 | "slots": [ 25 | { 26 | "name": "month", 27 | "type": "AMAZON.NUMBER" 28 | }, 29 | { 30 | "name": "day", 31 | "type": "AMAZON.NUMBER" 32 | }, 33 | { 34 | "name": "year", 35 | "type": "AMAZON.FOUR_DIGIT_NUMBER" 36 | } 37 | ], 38 | "samples": [ 39 | "{month} {day}", 40 | "{month} {day} {year}", 41 | "{month} {year}", 42 | "मेरा जन्मदिन {month} {day} मैं था ", 43 | "मेरा जन्मदिन {month} {day} {year} था ", 44 | "मेरा जन्मदिन {month} {year} था ", 45 | "register my birthday", 46 | "जनमदिन register कर दो", 47 | "जनमदिन register करो", 48 | "जन्मदिन register कर दो", 49 | "जन्मदिन register करो" 50 | ] 51 | } 52 | ], 53 | "types": [] 54 | }, 55 | "dialog": { 56 | "intents": [ 57 | { 58 | "name": "CaptureBirthdayIntent", 59 | "confirmationRequired": false, 60 | "prompts": {}, 61 | "slots": [ 62 | { 63 | "name": "month", 64 | "type": "AMAZON.NUMBER", 65 | "confirmationRequired": false, 66 | "elicitationRequired": true, 67 | "prompts": { 68 | "elicitation": "Elicit.Slot.303899476312.795077103633" 69 | } 70 | }, 71 | { 72 | "name": "day", 73 | "type": "AMAZON.NUMBER", 74 | "confirmationRequired": false, 75 | "elicitationRequired": true, 76 | "prompts": { 77 | "elicitation": "Elicit.Slot.303899476312.985837334781" 78 | } 79 | }, 80 | { 81 | "name": "year", 82 | "type": "AMAZON.FOUR_DIGIT_NUMBER", 83 | "confirmationRequired": false, 84 | "elicitationRequired": true, 85 | "prompts": { 86 | "elicitation": "Elicit.Slot.303899476312.27341833344" 87 | } 88 | } 89 | ] 90 | } 91 | ], 92 | "delegationStrategy": "ALWAYS" 93 | }, 94 | "prompts": [ 95 | { 96 | "id": "Elicit.Slot.303899476312.795077103633", 97 | "variations": [ 98 | { 99 | "type": "PlainText", 100 | "value": "मेरा जन्म नवंबर में हुआ था. आपका जन्मदिन कब हैं?" 101 | }, 102 | { 103 | "type": "PlainText", 104 | "value": "किस महीना में आपका जन्म हुआ था." 105 | } 106 | ] 107 | }, 108 | { 109 | "id": "Elicit.Slot.303899476312.985837334781", 110 | "variations": [ 111 | { 112 | "type": "PlainText", 113 | "value": "मेरा जन्म छठे पर हुआ था. आप किस दिन पैदा हुए थे?" 114 | } 115 | ] 116 | }, 117 | { 118 | "id": "Elicit.Slot.303899476312.27341833344", 119 | "variations": [ 120 | { 121 | "type": "PlainText", 122 | "value": "मेरा जन्म 2014 में हुआ था, आप किस वर्ष पैदा हुए थे?" 123 | } 124 | ] 125 | } 126 | ] 127 | } 128 | } -------------------------------------------------------------------------------- /i18n/skill-package/interactionModels/custom/it-IT.json: -------------------------------------------------------------------------------- 1 | { 2 | "interactionModel": { 3 | "languageModel": { 4 | "invocationName": "buon compleanno", 5 | "intents": [ 6 | { 7 | "name": "AMAZON.CancelIntent", 8 | "samples": [] 9 | }, 10 | { 11 | "name": "AMAZON.HelpIntent", 12 | "samples": [] 13 | }, 14 | { 15 | "name": "AMAZON.StopIntent", 16 | "samples": [] 17 | }, 18 | { 19 | "name": "AMAZON.NavigateHomeIntent", 20 | "samples": [] 21 | }, 22 | { 23 | "name": "CaptureBirthdayIntent", 24 | "slots": [ 25 | { 26 | "name": "month", 27 | "type": "AMAZON.Month", 28 | "samples": [ 29 | "sono nata a {month}", 30 | "sono nato a {month}", 31 | "sono nato ad {month}", 32 | "il mese di {month}", 33 | "{month}" 34 | ] 35 | }, 36 | { 37 | "name": "day", 38 | "type": "AMAZON.NUMBER", 39 | "samples": [ 40 | "il {day}", 41 | "sono nato il {day}", 42 | "{day}" 43 | ] 44 | }, 45 | { 46 | "name": "year", 47 | "type": "AMAZON.NUMBER", 48 | "samples": [ 49 | "sono del {year}", 50 | "nell'anno {year}", 51 | "nel {year}", 52 | "{year}" 53 | ] 54 | } 55 | ], 56 | "samples": [ 57 | "{month} del {year}", 58 | "{day} di {month}", 59 | "l'anno {year}", 60 | "nel {year}", 61 | "sono nato nel {year}", 62 | "nacqui nel {year}", 63 | "il {day} di {month}", 64 | "nel giorno {day} di {month}", 65 | "la mia data di nascita è il {day} di {month} del {year}", 66 | "la mia data di nascita è il {day} {month} {year}", 67 | "sono nato il {day} {month} {year}", 68 | "il mio compleanno è il {day} {month} {year}", 69 | "ricorda il mio compleanno", 70 | "registra il mio compleanno", 71 | "registra la mia data di nascita", 72 | "ricordati il mio compleanno", 73 | "segnati il mio comple", 74 | "prendi nota del mio comple", 75 | "prendi nota del mio compleanno" 76 | ] 77 | } 78 | ], 79 | "types": [] 80 | }, 81 | "dialog": { 82 | "intents": [ 83 | { 84 | "name": "CaptureBirthdayIntent", 85 | "confirmationRequired": false, 86 | "prompts": {}, 87 | "slots": [ 88 | { 89 | "name": "month", 90 | "type": "AMAZON.Month", 91 | "confirmationRequired": false, 92 | "elicitationRequired": true, 93 | "prompts": { 94 | "elicitation": "Elicit.Slot.303899476312.795077103633" 95 | } 96 | }, 97 | { 98 | "name": "day", 99 | "type": "AMAZON.NUMBER", 100 | "confirmationRequired": false, 101 | "elicitationRequired": true, 102 | "prompts": { 103 | "elicitation": "Elicit.Slot.303899476312.985837334781" 104 | } 105 | }, 106 | { 107 | "name": "year", 108 | "type": "AMAZON.NUMBER", 109 | "confirmationRequired": false, 110 | "elicitationRequired": true, 111 | "prompts": { 112 | "elicitation": "Elicit.Slot.303899476312.27341833344" 113 | } 114 | } 115 | ] 116 | } 117 | ], 118 | "delegationStrategy": "ALWAYS" 119 | }, 120 | "prompts": [ 121 | { 122 | "id": "Elicit.Slot.303899476312.795077103633", 123 | "variations": [ 124 | { 125 | "type": "PlainText", 126 | "value": "Io sono nata il mese di novembre. E tu?" 127 | }, 128 | { 129 | "type": "PlainText", 130 | "value": "Quale è il tuo mese di nascita?" 131 | } 132 | ] 133 | }, 134 | { 135 | "id": "Elicit.Slot.303899476312.985837334781", 136 | "variations": [ 137 | { 138 | "type": "PlainText", 139 | "value": "Io sono nata il sei. Che giorno del mese è il tuo compleanno?" 140 | } 141 | ] 142 | }, 143 | { 144 | "id": "Elicit.Slot.303899476312.27341833344", 145 | "variations": [ 146 | { 147 | "type": "PlainText", 148 | "value": "Sono nata nel due mila quattordici, tu in che anno?" 149 | } 150 | ] 151 | } 152 | ] 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /i18n/skill-package/interactionModels/custom/ja-JP.json: -------------------------------------------------------------------------------- 1 | { 2 | "interactionModel": { 3 | "languageModel": { 4 | "invocationName": "ケークウォーク", 5 | "intents": [ 6 | { 7 | "name": "AMAZON.CancelIntent", 8 | "samples": [] 9 | }, 10 | { 11 | "name": "AMAZON.HelpIntent", 12 | "samples": [] 13 | }, 14 | { 15 | "name": "AMAZON.StopIntent", 16 | "samples": [] 17 | }, 18 | { 19 | "name": "AMAZON.NavigateHomeIntent", 20 | "samples": [] 21 | }, 22 | { 23 | "name": "CaptureBirthdayIntent", 24 | "slots": [ 25 | { 26 | "name": "month", 27 | "type": "AMAZON.NUMBER" 28 | }, 29 | { 30 | "name": "year", 31 | "type": "AMAZON.FOUR_DIGIT_NUMBER" 32 | }, 33 | { 34 | "name": "day", 35 | "type": "AMAZON.NUMBER" 36 | } 37 | ], 38 | "samples": [ 39 | "{month} 月 {day} 日", 40 | "{year} 年 {month} 月 {day} 日", 41 | "{year} 年 {month} 月", 42 | "私は {month} 月 {day} 日に生まれました", 43 | "私は {year} 年 {month} 月に生まれました", 44 | "私は {year} 年 {month} 月 {day} 日に生まれました" 45 | ] 46 | } 47 | ], 48 | "types": [] 49 | }, 50 | "dialog": { 51 | "intents": [ 52 | { 53 | "name": "CaptureBirthdayIntent", 54 | "confirmationRequired": false, 55 | "prompts": {}, 56 | "slots": [ 57 | { 58 | "name": "month", 59 | "type": "AMAZON.NUMBER", 60 | "confirmationRequired": false, 61 | "elicitationRequired": true, 62 | "prompts": { 63 | "elicitation": "Elicit.Slot.14711719886.1482199472435" 64 | } 65 | }, 66 | { 67 | "name": "year", 68 | "type": "AMAZON.FOUR_DIGIT_NUMBER", 69 | "confirmationRequired": false, 70 | "elicitationRequired": true, 71 | "prompts": { 72 | "elicitation": "Elicit.Slot.14711719886.451582299768" 73 | } 74 | }, 75 | { 76 | "name": "day", 77 | "type": "AMAZON.NUMBER", 78 | "confirmationRequired": false, 79 | "elicitationRequired": true, 80 | "prompts": { 81 | "elicitation": "Elicit.Slot.14711719886.1502672692542" 82 | } 83 | } 84 | ] 85 | } 86 | ], 87 | "delegationStrategy": "ALWAYS" 88 | }, 89 | "prompts": [ 90 | { 91 | "id": "Elicit.Slot.14711719886.1482199472435", 92 | "variations": [ 93 | { 94 | "type": "PlainText", 95 | "value": "何月生まれですか?" 96 | } 97 | ] 98 | }, 99 | { 100 | "id": "Elicit.Slot.14711719886.451582299768", 101 | "variations": [ 102 | { 103 | "type": "PlainText", 104 | "value": "何年生まれですか?" 105 | } 106 | ] 107 | }, 108 | { 109 | "id": "Elicit.Slot.14711719886.1502672692542", 110 | "variations": [ 111 | { 112 | "type": "PlainText", 113 | "value": "何日生まれですか?" 114 | } 115 | ] 116 | } 117 | ] 118 | } 119 | } -------------------------------------------------------------------------------- /i18n/skill-package/skill.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest": { 3 | "publishingInformation": { 4 | "locales": { 5 | "en-US": { 6 | "name": "Cake Time" 7 | }, 8 | "en-GB": { 9 | "name": "Cake Time" 10 | }, 11 | "en-CA": { 12 | "name": "Cake Time" 13 | }, 14 | "fr-FR": { 15 | "name": "Joyeux Anniversaire" 16 | }, 17 | "fr-CA": { 18 | "name": "Bonne Fête" 19 | }, 20 | "it-IT": { 21 | "name": "Buon Compleanno" 22 | }, 23 | "ja-JP": { 24 | "name": "ケークウォーク" 25 | }, 26 | "en-IN": { 27 | "name": "cake time" 28 | }, 29 | "hi-IN": { 30 | "name": "cake time" 31 | }, 32 | "es-ES": { 33 | "name": "feliz cumpleaños" 34 | }, 35 | "es-MX": { 36 | "name": "feliz cumpleaños" 37 | }, 38 | "es-US": { 39 | "name": "feliz cumpleaños" 40 | } 41 | }, 42 | "isAvailableWorldwide": true, 43 | "testingInstructions": "Sample Testing Instructions.", 44 | "distributionCountries": [] 45 | }, 46 | "apis": { 47 | "custom": {} 48 | }, 49 | "manifestVersion": "1.0" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /module-1/README.md: -------------------------------------------------------------------------------- 1 | # Cake Time 2 | 3 | ## Module 1: Build A Simple Skill In 5 Minutes 4 | 5 | The files in this folder represent how Calk Time should appear at the end of this module. If you're stuck you can compare your files with these to figure out where you went wrong. You can also use these files to skip ahead. 6 | 7 | **If you are coming from the [Tutorial: Build an Engaging Alexa Skill](https://developer.amazon.com/en-US/alexa/alexa-skills-kit/get-deeper/tutorials-code-samples/build-an-engaging-alexa-skill)**: This folder maps to [Workshop Module 3](https://developer.amazon.com/en-US/alexa/alexa-skills-kit/get-deeper/tutorials-code-samples/build-an-engaging-alexa-skill/module-3) 8 | 9 | ### Step-by-step Instructions 10 | 11 | You can find the instructions here: [Create a skill in 5 minutes](https://developer.amazon.com/en-US/alexa/alexa-skills-kit/get-deeper/tutorials-code-samples/build-an-engaging-alexa-skill/module-3) 12 | 13 | When you're ready check out [Module 2: Collect Slots Turn-by-turn](../module-2/README.md). 14 | 15 | ### Contents 16 | 17 | * [en-US.json](./en-US.json) 18 | * [index.js](./index.js) 19 | 20 | #### en-US.json 21 | --- 22 | This is your skill's interaction model. You can use this file to create your voice user interface. To use this file: 23 | 24 | 1. From the [alexa developer console](https://developer.amazon.com) click on the **Build** tab. 25 | 2. On the left hand side click on **JSON Editor**. 26 | 3. Copy the contents of [en-US.json](./en-US.json) and paste it over the contents of the editor. 27 | 4. Click **Save Model** 28 | 5. Click **Build Model** 29 | 30 | #### index.js 31 | --- 32 | This is your skill's backend code. It's the logic that handles the requests that are sent to your skill. To use this file: 33 | 34 | 1. From the [alexa developer console](https://developer.amazon.com) click on the **code** tab. 35 | 2. Open the **index.js** file by selecting the tab or double-clicking on the file name on the right-hand side. 36 | 3. Copy the contents of [index.js](./index.js) paste it over the data in your browser. 37 | 4. Click **Save**. 38 | 5. Click **Deploy**. 39 | -------------------------------------------------------------------------------- /module-1/en-US.json: -------------------------------------------------------------------------------- 1 | { 2 | "interactionModel": { 3 | "languageModel": { 4 | "invocationName": "cake time", 5 | "intents": [ 6 | { 7 | "name": "AMAZON.CancelIntent", 8 | "samples": [] 9 | }, 10 | { 11 | "name": "AMAZON.HelpIntent", 12 | "samples": [] 13 | }, 14 | { 15 | "name": "AMAZON.StopIntent", 16 | "samples": [] 17 | }, 18 | { 19 | "name": "HelloWorldIntent", 20 | "slots": [], 21 | "samples": [ 22 | "hello", 23 | "how are you", 24 | "say hi world", 25 | "say hi", 26 | "hi", 27 | "say hello world", 28 | "say hello" 29 | ] 30 | }, 31 | { 32 | "name": "AMAZON.NavigateHomeIntent", 33 | "samples": [] 34 | } 35 | ], 36 | "types": [] 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /module-1/index.js: -------------------------------------------------------------------------------- 1 | // This sample demonstrates handling intents from an Alexa skill using the Alexa Skills Kit SDK (v2). 2 | // Please visit https://alexa.design/cookbook for additional examples on implementing slots, dialog management, 3 | // session persistence, api calls, and more. 4 | const Alexa = require('ask-sdk-core'); 5 | 6 | const LaunchRequestHandler = { 7 | canHandle(handlerInput) { 8 | return handlerInput.requestEnvelope.request.type === 'LaunchRequest'; 9 | }, 10 | handle(handlerInput) { 11 | const speakOutput = 'Hello! Welcome to cake time. That was a piece of cake! Bye!'; 12 | return handlerInput.responseBuilder 13 | .speak(speakOutput) 14 | //.reprompt(speakOutput) 15 | .getResponse(); 16 | } 17 | }; 18 | const HelloWorldIntentHandler = { 19 | canHandle(handlerInput) { 20 | return handlerInput.requestEnvelope.request.type === 'IntentRequest' 21 | && handlerInput.requestEnvelope.request.intent.name === 'HelloWorldIntent'; 22 | }, 23 | handle(handlerInput) { 24 | const speakOutput = 'Hello World!'; 25 | return handlerInput.responseBuilder 26 | .speak(speakOutput) 27 | //.reprompt('add a reprompt if you want to keep the session open for the user to respond') 28 | .getResponse(); 29 | } 30 | }; 31 | const HelpIntentHandler = { 32 | canHandle(handlerInput) { 33 | return handlerInput.requestEnvelope.request.type === 'IntentRequest' 34 | && handlerInput.requestEnvelope.request.intent.name === 'AMAZON.HelpIntent'; 35 | }, 36 | handle(handlerInput) { 37 | const speakOutput = 'You can say hello to me! How can I help?'; 38 | 39 | return handlerInput.responseBuilder 40 | .speak(speakOutput) 41 | .reprompt(speakOutput) 42 | .getResponse(); 43 | } 44 | }; 45 | const CancelAndStopIntentHandler = { 46 | canHandle(handlerInput) { 47 | return handlerInput.requestEnvelope.request.type === 'IntentRequest' 48 | && (handlerInput.requestEnvelope.request.intent.name === 'AMAZON.CancelIntent' 49 | || handlerInput.requestEnvelope.request.intent.name === 'AMAZON.StopIntent'); 50 | }, 51 | handle(handlerInput) { 52 | const speakOutput = 'Goodbye!'; 53 | return handlerInput.responseBuilder 54 | .speak(speakOutput) 55 | .getResponse(); 56 | } 57 | }; 58 | const SessionEndedRequestHandler = { 59 | canHandle(handlerInput) { 60 | return handlerInput.requestEnvelope.request.type === 'SessionEndedRequest'; 61 | }, 62 | handle(handlerInput) { 63 | // Any cleanup logic goes here. 64 | return handlerInput.responseBuilder.getResponse(); 65 | } 66 | }; 67 | 68 | // The intent reflector is used for interaction model testing and debugging. 69 | // It will simply repeat the intent the user said. You can create custom handlers 70 | // for your intents by defining them above, then also adding them to the request 71 | // handler chain below. 72 | const IntentReflectorHandler = { 73 | canHandle(handlerInput) { 74 | return handlerInput.requestEnvelope.request.type === 'IntentRequest'; 75 | }, 76 | handle(handlerInput) { 77 | const intentName = handlerInput.requestEnvelope.request.intent.name; 78 | const speakOutput = `You just triggered ${intentName}`; 79 | 80 | return handlerInput.responseBuilder 81 | .speak(speakOutput) 82 | //.reprompt('add a reprompt if you want to keep the session open for the user to respond') 83 | .getResponse(); 84 | } 85 | }; 86 | 87 | // Generic error handling to capture any syntax or routing errors. If you receive an error 88 | // stating the request handler chain is not found, you have not implemented a handler for 89 | // the intent being invoked or included it in the skill builder below. 90 | const ErrorHandler = { 91 | canHandle() { 92 | return true; 93 | }, 94 | handle(handlerInput, error) { 95 | console.log(`~~~~ Error handled: ${error.message}`); 96 | const speakOutput = `Sorry, I couldn't understand what you said. Please try again.`; 97 | 98 | return handlerInput.responseBuilder 99 | .speak(speakOutput) 100 | .reprompt(speakOutput) 101 | .getResponse(); 102 | } 103 | }; 104 | 105 | // The SkillBuilder acts as the entry point for your skill, routing all request and response 106 | // payloads to the handlers above. Make sure any new handlers or interceptors you've 107 | // defined are included below. The order matters - they're processed top to bottom. 108 | exports.handler = Alexa.SkillBuilders.custom() 109 | .addRequestHandlers( 110 | LaunchRequestHandler, 111 | HelloWorldIntentHandler, 112 | HelpIntentHandler, 113 | CancelAndStopIntentHandler, 114 | SessionEndedRequestHandler, 115 | IntentReflectorHandler) // make sure IntentReflectorHandler is last so it doesn't override your custom intent handlers 116 | .addErrorHandlers( 117 | ErrorHandler) 118 | .lambda(); 119 | -------------------------------------------------------------------------------- /module-2/README.md: -------------------------------------------------------------------------------- 1 | # Cake Time 2 | 3 | ## Module 2: Collect Slots Turn-by-turn 4 | 5 | The files in this folder represent how Calk Time should appear at the end this module. If you're stuck you can compare your files with these to figure out where you went wrong. You can also use these files to skip ahead. 6 | 7 | **If you are coming from the [Tutorial: Build an Engaging Alexa Skill](https://developer.amazon.com/alexa/alexa-skills-kit/get-deeper/tutorials-code-samples/build-an-engaging-alexa-skill)**: This folder maps to [Workshop Module 4](https://developer.amazon.com/en-US/alexa/alexa-skills-kit/get-deeper/tutorials-code-samples/build-an-engaging-alexa-skill/module-4) 8 | 9 | ### Step-by-step Instructions 10 | 11 | You can find the instructions here: [Collecting slots turn-by-turn](https://developer.amazon.com/en-US/alexa/alexa-skills-kit/get-deeper/tutorials-code-samples/build-an-engaging-alexa-skill/module-4) 12 | 13 | When you're ready check out [Module 3: Add Memory To Your Skill](../module-3/README.md). 14 | 15 | ### Contents 16 | 17 | * [en-US.json](./en-US.json) 18 | * [index.js](./index.js) 19 | 20 | #### en-US.json 21 | --- 22 | This is your skill's interaction model. You can use this file to create your voice user interface. To use this file: 23 | 24 | 1. From the [alexa developer console](https://developer.amazon.com) click on the **Build** tab. 25 | 2. On the left hand side click on **JSON Editor**. 26 | 3. Copy the contents of [en-US.json](./en-US.json) and paste it over the contents of the editor 27 | 4. Click **Save Model** 28 | 5. Click **Build Model** 29 | 30 | #### index.js 31 | --- 32 | This is your skill's backend code. It's the logic that handles the requests that are sent to your skill. To use this file: 33 | 34 | 1. From the [alexa developer console](https://developer.amazon.com) click on the **Code** tab. 35 | 2. Open the **index.js** file by selecting the tab or double-clicking on the file name on the right-hand side. 36 | 3. Copy the contents of [index.js](./index.js) paste it over the data in your browser. 37 | 4. Click **Save**. 38 | 5. Click **Deploy**. 39 | -------------------------------------------------------------------------------- /module-2/en-US.json: -------------------------------------------------------------------------------- 1 | { 2 | "interactionModel": { 3 | "languageModel": { 4 | "invocationName": "cake time", 5 | "intents": [ 6 | { 7 | "name": "AMAZON.CancelIntent", 8 | "samples": [] 9 | }, 10 | { 11 | "name": "AMAZON.HelpIntent", 12 | "samples": [] 13 | }, 14 | { 15 | "name": "AMAZON.StopIntent", 16 | "samples": [] 17 | }, 18 | { 19 | "name": "AMAZON.NavigateHomeIntent", 20 | "samples": [] 21 | }, 22 | { 23 | "name": "CaptureBirthdayIntent", 24 | "slots": [ 25 | { 26 | "name": "month", 27 | "type": "AMAZON.Month" 28 | }, 29 | { 30 | "name": "day", 31 | "type": "AMAZON.Ordinal" 32 | }, 33 | { 34 | "name": "year", 35 | "type": "AMAZON.FOUR_DIGIT_NUMBER" 36 | } 37 | ], 38 | "samples": [ 39 | "{month} {day}", 40 | "{month} {day} {year}", 41 | "{month} {year}", 42 | "I was born on {month} {day} ", 43 | "I was born on {month} {day} {year}", 44 | "I was born on {month} {year}" 45 | ] 46 | } 47 | ], 48 | "types": [] 49 | }, 50 | "dialog": { 51 | "intents": [ 52 | { 53 | "name": "CaptureBirthdayIntent", 54 | "confirmationRequired": false, 55 | "prompts": {}, 56 | "slots": [ 57 | { 58 | "name": "month", 59 | "type": "AMAZON.Month", 60 | "confirmationRequired": false, 61 | "elicitationRequired": true, 62 | "prompts": { 63 | "elicitation": "Elicit.Slot.303899476312.795077103633" 64 | } 65 | }, 66 | { 67 | "name": "day", 68 | "type": "AMAZON.Ordinal", 69 | "confirmationRequired": false, 70 | "elicitationRequired": true, 71 | "prompts": { 72 | "elicitation": "Elicit.Slot.303899476312.985837334781" 73 | } 74 | }, 75 | { 76 | "name": "year", 77 | "type": "AMAZON.FOUR_DIGIT_NUMBER", 78 | "confirmationRequired": false, 79 | "elicitationRequired": true, 80 | "prompts": { 81 | "elicitation": "Elicit.Slot.303899476312.27341833344" 82 | } 83 | } 84 | ] 85 | } 86 | ], 87 | "delegationStrategy": "ALWAYS" 88 | }, 89 | "prompts": [ 90 | { 91 | "id": "Elicit.Slot.303899476312.795077103633", 92 | "variations": [ 93 | { 94 | "type": "PlainText", 95 | "value": "I was born in November. When what were you born?" 96 | }, 97 | { 98 | "type": "PlainText", 99 | "value": "What month were you born?" 100 | } 101 | ] 102 | }, 103 | { 104 | "id": "Elicit.Slot.303899476312.985837334781", 105 | "variations": [ 106 | { 107 | "type": "PlainText", 108 | "value": "I was born on the sixth. What day were you born?" 109 | } 110 | ] 111 | }, 112 | { 113 | "id": "Elicit.Slot.303899476312.27341833344", 114 | "variations": [ 115 | { 116 | "type": "PlainText", 117 | "value": "I was born in two thousand fourteen, what year were you born?" 118 | } 119 | ] 120 | } 121 | ] 122 | } 123 | } -------------------------------------------------------------------------------- /module-2/index.js: -------------------------------------------------------------------------------- 1 | // This sample demonstrates handling intents from an Alexa skill using the Alexa Skills Kit SDK (v2). 2 | // Please visit https://alexa.design/cookbook for additional examples on implementing slots, dialog management, 3 | // session persistence, api calls, and more. 4 | const Alexa = require('ask-sdk-core'); 5 | 6 | const LaunchRequestHandler = { 7 | canHandle(handlerInput) { 8 | return handlerInput.requestEnvelope.request.type === 'LaunchRequest'; 9 | }, 10 | handle(handlerInput) { 11 | const speakOutput = 'Hello! This is Cake time. What is your birthday?'; 12 | const repromptText = 'I was born Nov. 6th, 2014. When were you born?'; 13 | return handlerInput.responseBuilder 14 | .speak(speakOutput) 15 | .reprompt(repromptText) 16 | .getResponse(); 17 | } 18 | }; 19 | 20 | const CaptureBirthdayIntentHandler = { 21 | canHandle(handlerInput) { 22 | return handlerInput.requestEnvelope.request.type === 'IntentRequest' 23 | && handlerInput.requestEnvelope.request.intent.name === 'CaptureBirthdayIntent'; 24 | }, 25 | handle(handlerInput) { 26 | const year = handlerInput.requestEnvelope.request.intent.slots.year.value; 27 | const month = handlerInput.requestEnvelope.request.intent.slots.month.value; 28 | const day = handlerInput.requestEnvelope.request.intent.slots.day.value; 29 | 30 | const speakOutput = `Thanks, I'll remember that you were born ${month} ${day} ${year}.`; 31 | return handlerInput.responseBuilder 32 | .speak(speakOutput) 33 | //.reprompt('add a reprompt if you want to keep the session open for the user to respond') 34 | .getResponse(); 35 | } 36 | }; 37 | 38 | const HelpIntentHandler = { 39 | canHandle(handlerInput) { 40 | return handlerInput.requestEnvelope.request.type === 'IntentRequest' 41 | && handlerInput.requestEnvelope.request.intent.name === 'AMAZON.HelpIntent'; 42 | }, 43 | handle(handlerInput) { 44 | const speakOutput = 'You can say hello to me! How can I help?'; 45 | 46 | return handlerInput.responseBuilder 47 | .speak(speakOutput) 48 | .reprompt(speakOutput) 49 | .getResponse(); 50 | } 51 | }; 52 | const CancelAndStopIntentHandler = { 53 | canHandle(handlerInput) { 54 | return handlerInput.requestEnvelope.request.type === 'IntentRequest' 55 | && (handlerInput.requestEnvelope.request.intent.name === 'AMAZON.CancelIntent' 56 | || handlerInput.requestEnvelope.request.intent.name === 'AMAZON.StopIntent'); 57 | }, 58 | handle(handlerInput) { 59 | const speakOutput = 'Goodbye!'; 60 | return handlerInput.responseBuilder 61 | .speak(speakOutput) 62 | .getResponse(); 63 | } 64 | }; 65 | const SessionEndedRequestHandler = { 66 | canHandle(handlerInput) { 67 | return handlerInput.requestEnvelope.request.type === 'SessionEndedRequest'; 68 | }, 69 | handle(handlerInput) { 70 | // Any cleanup logic goes here. 71 | return handlerInput.responseBuilder.getResponse(); 72 | } 73 | }; 74 | 75 | // The intent reflector is used for interaction model testing and debugging. 76 | // It will simply repeat the intent the user said. You can create custom handlers 77 | // for your intents by defining them above, then also adding them to the request 78 | // handler chain below. 79 | const IntentReflectorHandler = { 80 | canHandle(handlerInput) { 81 | return handlerInput.requestEnvelope.request.type === 'IntentRequest'; 82 | }, 83 | handle(handlerInput) { 84 | const intentName = handlerInput.requestEnvelope.request.intent.name; 85 | const speakOutput = `You just triggered ${intentName}`; 86 | 87 | return handlerInput.responseBuilder 88 | .speak(speakOutput) 89 | //.reprompt('add a reprompt if you want to keep the session open for the user to respond') 90 | .getResponse(); 91 | } 92 | }; 93 | 94 | // Generic error handling to capture any syntax or routing errors. If you receive an error 95 | // stating the request handler chain is not found, you have not implemented a handler for 96 | // the intent being invoked or included it in the skill builder below. 97 | const ErrorHandler = { 98 | canHandle() { 99 | return true; 100 | }, 101 | handle(handlerInput, error) { 102 | console.log(`~~~~ Error handled: ${error.message}`); 103 | const speakOutput = `Sorry, I couldn't understand what you said. Please try again.`; 104 | 105 | return handlerInput.responseBuilder 106 | .speak(speakOutput) 107 | .reprompt(speakOutput) 108 | .getResponse(); 109 | } 110 | }; 111 | 112 | 113 | // The SkillBuilder acts as the entry point for your skill, routing all request and response 114 | // payloads to the handlers above. Make sure any new handlers or interceptors you've 115 | // defined are included below. The order matters - they're processed top to bottom. 116 | exports.handler = Alexa.SkillBuilders.custom() 117 | .addRequestHandlers( 118 | LaunchRequestHandler, 119 | CaptureBirthdayIntentHandler, 120 | HelpIntentHandler, 121 | CancelAndStopIntentHandler, 122 | SessionEndedRequestHandler, 123 | IntentReflectorHandler) // make sure IntentReflectorHandler is last so it doesn't override your custom intent handlers 124 | .addErrorHandlers( 125 | ErrorHandler) 126 | .lambda(); -------------------------------------------------------------------------------- /module-3/README.md: -------------------------------------------------------------------------------- 1 | # Cake Time 2 | 3 | ## Module 3: Add Memory To Your Skill 4 | 5 | The files in this folder represent how Calk Time should appear at the end of this module. If you're stuck you can compare your files with these to figure out where you went wrong. You can also use these files to skip ahead. 6 | 7 | 8 | **If you are coming from the [Tutorial: Build an Engaging Alexa Skill](https://developer.amazon.com/alexa/alexa-skills-kit/get-deeper/tutorials-code-samples/build-an-engaging-alexa-skill)**: This folder maps to [Workshop Module 5](https://developer.amazon.com/alexa/alexa-skills-kit/get-deeper/tutorials-code-samples/build-an-engaging-alexa-skill/module-5) 9 | 10 | ### Step-by-step Instructions 11 | 12 | You can find the instructions here: [Adding memory to your skill](https://developer.amazon.com/alexa/alexa-skills-kit/get-deeper/tutorials-code-samples/build-an-engaging-alexa-skill/module-5) 13 | 14 | Once you're ready you move on to [Module 4: Use the Settings API ](../module-4/README.md) 15 | 16 | ### Contents 17 | 18 | * [en-US.json](./en-US.json) 19 | * [index.js](./index.js) 20 | * [package.json](./package.json) 21 | 22 | #### en-US.json 23 | --- 24 | This is your skill's interaction model. You can use this file to create your voice user interface. To use this file: 25 | 26 | 1. From the [alexa developer console](https://developer.amazon.com) click on the **Build** tab. 27 | 2. On the left hand side click on **JSON Editor**. 28 | 3. Copy the contents of [en-US.json](./en-US.json) and paste it over the contents of the editor 29 | 4. Click **Save Model** 30 | 5. Click **Build Model** 31 | 32 | #### index.js 33 | --- 34 | This is your skill's backend code. It's the logic that handles the requests that are sent to your skill. To use this file: 35 | 36 | 1. From the [alexa developer console](https://developer.amazon.com) click on the **Code** tab. 37 | 2. Open the **index.js** file by selecting the tab or double-clicking on the file name on the right-hand side. 38 | 3. Copy the contents of [index.js](./index.js) and paste it over the data in your browser. 39 | 4. Click **Save**. 40 | 5. Click **Deploy**. 41 | 42 | #### package.json 43 | --- 44 | This file describes your project. It includes various meta data including the dependencies of your project. We are dependent on the [ASK SDK](https://ask-sdk-for-nodejs.readthedocs.io/en/latest/) which is automatically included when we created Alexa Hosted skill. We added a new dependency on the **ask-sdk-s3-persistence-adapter**, so we've updated in the code. To this this file: 45 | 46 | 1. From the [alexa developer console](https://developer.amazon.com) click on the **code** tab. 47 | 2. Open the **package.json** file by selecting the tab or double-clicking on the file name on the right-hand side. 48 | 3. Copy the contents of [package.json](./package.json) and paste it over the data in your browser. 49 | 4. Click **Save**. 50 | 5. Click **Deploy**. 51 | -------------------------------------------------------------------------------- /module-3/en-US.json: -------------------------------------------------------------------------------- 1 | { 2 | "interactionModel": { 3 | "languageModel": { 4 | "invocationName": "cake time", 5 | "intents": [ 6 | { 7 | "name": "AMAZON.CancelIntent", 8 | "samples": [] 9 | }, 10 | { 11 | "name": "AMAZON.HelpIntent", 12 | "samples": [] 13 | }, 14 | { 15 | "name": "AMAZON.StopIntent", 16 | "samples": [] 17 | }, 18 | { 19 | "name": "AMAZON.NavigateHomeIntent", 20 | "samples": [] 21 | }, 22 | { 23 | "name": "CaptureBirthdayIntent", 24 | "slots": [ 25 | { 26 | "name": "month", 27 | "type": "AMAZON.Month" 28 | }, 29 | { 30 | "name": "day", 31 | "type": "AMAZON.Ordinal" 32 | }, 33 | { 34 | "name": "year", 35 | "type": "AMAZON.FOUR_DIGIT_NUMBER" 36 | } 37 | ], 38 | "samples": [ 39 | "{month} {day}", 40 | "{month} {day} {year}", 41 | "{month} {year}", 42 | "I was born on {month} {day} ", 43 | "I was born on {month} {day} {year}", 44 | "I was born on {month} {year}" 45 | ] 46 | } 47 | ], 48 | "types": [] 49 | }, 50 | "dialog": { 51 | "intents": [ 52 | { 53 | "name": "CaptureBirthdayIntent", 54 | "confirmationRequired": false, 55 | "prompts": {}, 56 | "slots": [ 57 | { 58 | "name": "month", 59 | "type": "AMAZON.Month", 60 | "confirmationRequired": false, 61 | "elicitationRequired": true, 62 | "prompts": { 63 | "elicitation": "Elicit.Slot.303899476312.795077103633" 64 | } 65 | }, 66 | { 67 | "name": "day", 68 | "type": "AMAZON.Ordinal", 69 | "confirmationRequired": false, 70 | "elicitationRequired": true, 71 | "prompts": { 72 | "elicitation": "Elicit.Slot.303899476312.985837334781" 73 | } 74 | }, 75 | { 76 | "name": "year", 77 | "type": "AMAZON.FOUR_DIGIT_NUMBER", 78 | "confirmationRequired": false, 79 | "elicitationRequired": true, 80 | "prompts": { 81 | "elicitation": "Elicit.Slot.303899476312.27341833344" 82 | } 83 | } 84 | ] 85 | } 86 | ], 87 | "delegationStrategy": "ALWAYS" 88 | }, 89 | "prompts": [ 90 | { 91 | "id": "Elicit.Slot.303899476312.795077103633", 92 | "variations": [ 93 | { 94 | "type": "PlainText", 95 | "value": "I was born in November. When what were you born?" 96 | }, 97 | { 98 | "type": "PlainText", 99 | "value": "What month were you born?" 100 | } 101 | ] 102 | }, 103 | { 104 | "id": "Elicit.Slot.303899476312.985837334781", 105 | "variations": [ 106 | { 107 | "type": "PlainText", 108 | "value": "I was born on the sixth. What day were you born?" 109 | } 110 | ] 111 | }, 112 | { 113 | "id": "Elicit.Slot.303899476312.27341833344", 114 | "variations": [ 115 | { 116 | "type": "PlainText", 117 | "value": "I was born in two thousand fourteen, what year were you born?" 118 | } 119 | ] 120 | } 121 | ] 122 | } 123 | } -------------------------------------------------------------------------------- /module-3/index.js: -------------------------------------------------------------------------------- 1 | // This sample demonstrates handling intents from an Alexa skill using the Alexa Skills Kit SDK (v2). 2 | // Please visit https://alexa.design/cookbook for additional examples on implementing slots, dialog management, 3 | // session persistence, api calls, and more. 4 | const Alexa = require('ask-sdk-core'); 5 | const persistenceAdapter = require('ask-sdk-s3-persistence-adapter'); 6 | 7 | const LaunchRequestHandler = { 8 | canHandle(handlerInput) { 9 | return handlerInput.requestEnvelope.request.type === 'LaunchRequest'; 10 | }, 11 | handle(handlerInput) { 12 | const speakOutput = 'Hello! Welcome to Cake time. What is your birthday?'; 13 | const repromptText = 'I was born Nov. 6th, 2014. When were you born?'; 14 | 15 | return handlerInput.responseBuilder 16 | .speak(speakOutput) 17 | .reprompt(repromptText) 18 | .getResponse(); 19 | } 20 | }; 21 | const HasBirthdayLaunchRequestHandler = { 22 | canHandle(handlerInput) { 23 | 24 | const attributesManager = handlerInput.attributesManager; 25 | const sessionAttributes = attributesManager.getSessionAttributes() || {}; 26 | 27 | const year = sessionAttributes.hasOwnProperty('year') ? sessionAttributes.year : 0; 28 | const month = sessionAttributes.hasOwnProperty('month') ? sessionAttributes.month : 0; 29 | const day = sessionAttributes.hasOwnProperty('day') ? sessionAttributes.day : 0; 30 | 31 | return handlerInput.requestEnvelope.request.type === 'LaunchRequest' && 32 | year && 33 | month && 34 | day; 35 | 36 | }, 37 | handle(handlerInput) { 38 | 39 | const attributesManager = handlerInput.attributesManager; 40 | const sessionAttributes = attributesManager.getSessionAttributes() || {}; 41 | 42 | const year = sessionAttributes.hasOwnProperty('year') ? sessionAttributes.year : 0; 43 | const month = sessionAttributes.hasOwnProperty('month') ? sessionAttributes.month : 0; 44 | const day = sessionAttributes.hasOwnProperty('day') ? sessionAttributes.day : 0; 45 | 46 | // TODO:: Use the settings API to get current date and then compute how many days until user's birthday 47 | // TODO:: Say Happy birthday on the user's birthday 48 | 49 | const speakOutput = `Welcome back. It looks like there are X more days until your y-th birthday.`; 50 | 51 | return handlerInput.responseBuilder 52 | .speak(speakOutput) 53 | .getResponse(); 54 | } 55 | }; 56 | const CaptureBirthdayIntentHandler = { 57 | canHandle(handlerInput) { 58 | return handlerInput.requestEnvelope.request.type === 'IntentRequest' 59 | && handlerInput.requestEnvelope.request.intent.name === 'CaptureBirthdayIntent'; 60 | }, 61 | async handle(handlerInput) { 62 | const year = handlerInput.requestEnvelope.request.intent.slots.year.value; 63 | const month = handlerInput.requestEnvelope.request.intent.slots.month.value; 64 | const day = handlerInput.requestEnvelope.request.intent.slots.day.value; 65 | 66 | const attributesManager = handlerInput.attributesManager; 67 | 68 | let birthdayAttributes = { 69 | "year": year, 70 | "month": month, 71 | "day": day 72 | 73 | }; 74 | attributesManager.setPersistentAttributes(birthdayAttributes); 75 | await attributesManager.savePersistentAttributes(); 76 | 77 | const speakOutput = `Thanks, I'll remember that you were born ${month} ${day} ${year}.`; 78 | return handlerInput.responseBuilder 79 | .speak(speakOutput) 80 | //.reprompt('add a reprompt if you want to keep the session open for the user to respond') 81 | .getResponse(); 82 | } 83 | }; 84 | 85 | const HelpIntentHandler = { 86 | canHandle(handlerInput) { 87 | return handlerInput.requestEnvelope.request.type === 'IntentRequest' 88 | && handlerInput.requestEnvelope.request.intent.name === 'AMAZON.HelpIntent'; 89 | }, 90 | handle(handlerInput) { 91 | const speakOutput = 'You can say hello to me! How can I help?'; 92 | 93 | return handlerInput.responseBuilder 94 | .speak(speakOutput) 95 | .reprompt(speakOutput) 96 | .getResponse(); 97 | } 98 | }; 99 | const CancelAndStopIntentHandler = { 100 | canHandle(handlerInput) { 101 | return handlerInput.requestEnvelope.request.type === 'IntentRequest' 102 | && (handlerInput.requestEnvelope.request.intent.name === 'AMAZON.CancelIntent' 103 | || handlerInput.requestEnvelope.request.intent.name === 'AMAZON.StopIntent'); 104 | }, 105 | handle(handlerInput) { 106 | const speakOutput = 'Goodbye!'; 107 | return handlerInput.responseBuilder 108 | .speak(speakOutput) 109 | .getResponse(); 110 | } 111 | }; 112 | const SessionEndedRequestHandler = { 113 | canHandle(handlerInput) { 114 | return handlerInput.requestEnvelope.request.type === 'SessionEndedRequest'; 115 | }, 116 | handle(handlerInput) { 117 | // Any cleanup logic goes here. 118 | return handlerInput.responseBuilder.getResponse(); 119 | } 120 | }; 121 | 122 | // The intent reflector is used for interaction model testing and debugging. 123 | // It will simply repeat the intent the user said. You can create custom handlers 124 | // for your intents by defining them above, then also adding them to the request 125 | // handler chain below. 126 | const IntentReflectorHandler = { 127 | canHandle(handlerInput) { 128 | return handlerInput.requestEnvelope.request.type === 'IntentRequest'; 129 | }, 130 | handle(handlerInput) { 131 | const intentName = handlerInput.requestEnvelope.request.intent.name; 132 | const speakOutput = `You just triggered ${intentName}`; 133 | 134 | return handlerInput.responseBuilder 135 | .speak(speakOutput) 136 | //.reprompt('add a reprompt if you want to keep the session open for the user to respond') 137 | .getResponse(); 138 | } 139 | }; 140 | 141 | // Generic error handling to capture any syntax or routing errors. If you receive an error 142 | // stating the request handler chain is not found, you have not implemented a handler for 143 | // the intent being invoked or included it in the skill builder below. 144 | const ErrorHandler = { 145 | canHandle() { 146 | return true; 147 | }, 148 | handle(handlerInput, error) { 149 | console.log(`~~~~ Error handled: ${error.message}`); 150 | const speakOutput = `Sorry, I couldn't understand what you said. Please try again.`; 151 | 152 | return handlerInput.responseBuilder 153 | .speak(speakOutput) 154 | .reprompt(speakOutput) 155 | .getResponse(); 156 | } 157 | }; 158 | 159 | const LoadBirthdayInterceptor = { 160 | async process(handlerInput) { 161 | const attributesManager = handlerInput.attributesManager; 162 | const sessionAttributes = await attributesManager.getPersistentAttributes() || {}; 163 | 164 | const year = sessionAttributes.hasOwnProperty('year') ? sessionAttributes.year : 0; 165 | const month = sessionAttributes.hasOwnProperty('month') ? sessionAttributes.month : 0; 166 | const day = sessionAttributes.hasOwnProperty('day') ? sessionAttributes.day : 0; 167 | 168 | if (year && month && day) { 169 | attributesManager.setSessionAttributes(sessionAttributes); 170 | } 171 | } 172 | } 173 | 174 | // The SkillBuilder acts as the entry point for your skill, routing all request and response 175 | // payloads to the handlers above. Make sure any new handlers or interceptors you've 176 | // defined are included below. The order matters - they're processed top to bottom. 177 | exports.handler = Alexa.SkillBuilders.custom() 178 | .withPersistenceAdapter( 179 | new persistenceAdapter.S3PersistenceAdapter({bucketName:process.env.S3_PERSISTENCE_BUCKET}) 180 | ) 181 | .addRequestHandlers( 182 | HasBirthdayLaunchRequestHandler, 183 | LaunchRequestHandler, 184 | CaptureBirthdayIntentHandler, 185 | HelpIntentHandler, 186 | CancelAndStopIntentHandler, 187 | SessionEndedRequestHandler, 188 | IntentReflectorHandler) // make sure IntentReflectorHandler is last so it doesn't override your custom intent handlers 189 | .addRequestInterceptors( 190 | LoadBirthdayInterceptor 191 | ) 192 | .addErrorHandlers( 193 | ErrorHandler) 194 | .lambda(); 195 | -------------------------------------------------------------------------------- /module-3/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cake-time", 3 | "version": "0.9.0", 4 | "description": "alexa utility for quickly building skills", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Amazon Alexa", 10 | "license": "ISC", 11 | "dependencies": { 12 | "ask-sdk-core": "^2.0.7", 13 | "ask-sdk-model": "^1.4.1", 14 | "aws-sdk": "^2.326.0", 15 | "ask-sdk-s3-persistence-adapter": "^2.0.0" 16 | } 17 | } -------------------------------------------------------------------------------- /module-4/README.md: -------------------------------------------------------------------------------- 1 | # Cake Time 2 | 3 | ## Module 4: Use The Settings API 4 | 5 | The files in this folder represent how Calk Time should appear at the end of this module. If you're stuck you can compare your files with these to figure out where you went wrong. You can also use these files to skip Module 1, 2 and 3. 6 | 7 | **If you are coming from the [Tutorial: Build an Engaging Alexa Skill](https://developer.amazon.com/alexa/alexa-skills-kit/get-deeper/tutorials-code-samples/build-an-engaging-alexa-skill)**: This folder maps to [Workshop Module 6](https://developer.amazon.com/alexa/alexa-skills-kit/get-deeper/tutorials-code-samples/build-an-engaging-alexa-skill/module-6)** 8 | 9 | ### Step-by-step Instructions 10 | 11 | You can find the instructions here: [Using the Alexa Settings API](https://developer.amazon.com/alexa/alexa-skills-kit/get-deeper/tutorials-code-samples/build-an-engaging-alexa-skill/module-6) 12 | 13 | If for some reason your code is isn't working you can check out the final version [here](../final). 14 | 15 | When you're done, continue on to the [Tutorial: Build an Engaging Alexa Skill Module 7](https://developer.amazon.com/alexa/alexa-skills-kit/get-deeper/tutorials-code-samples/build-an-engaging-alexa-skill/module-7) for tips on preparing your skill for certification and publication. 16 | 17 | ### Contents 18 | 19 | * [en-US.json](./en-US.json) 20 | * [index.js](./index.js) 21 | * [package.json](./package.json) 22 | 23 | #### en-US.json 24 | --- 25 | This is your skill's interaction model. You can use this file to create your voice user interface. To use this file: 26 | 27 | 1. From the [alexa developer console](https://developer.amazon.com) click on the **Build** tab. 28 | 2. On the left hand side click on **JSON Editor**. 29 | 3. Copy the contents of [en-US.json](./en-US.json) and paste it over the contents of the editor. 30 | 4. Click **Save Model** 31 | 5. Click **Build Model** 32 | 33 | #### index.js 34 | --- 35 | This is your skill's backend code. It's the logic that handles the requests that are sent to your skill. To use this file: 36 | 37 | 1. From the [alexa developer console](https://developer.amazon.com) click on the **Code** tab. 38 | 2. Open the **index.js** file by selecting the tab or double-clicking on the file name on the right-hand side. 39 | 3. Copy the contents of [en-US.json](./en-US.json) and paste it over the contents of the editor 40 | 4. Click **Save**. 41 | 5. Click **Deploy**. 42 | 43 | #### package.json 44 | --- 45 | This file describes your project. It includes various meta data inclucding the dependencies of your project. 46 | 47 | 1. From the [alexa developer console](https://developer.amazon.com) click on the **code** tab. 48 | 2. Open the **package.json** file by selecting the tab or double-clicking on the file name on the right-hand side. 49 | 3. Copy the contents of [index.js](./index.js) paste it over the data in your browser. 50 | 4. Click **Save**. 51 | 5. Click **Deploy**. 52 | -------------------------------------------------------------------------------- /module-4/en-US.json: -------------------------------------------------------------------------------- 1 | { 2 | "interactionModel": { 3 | "languageModel": { 4 | "invocationName": "cake time", 5 | "intents": [ 6 | { 7 | "name": "AMAZON.CancelIntent", 8 | "samples": [] 9 | }, 10 | { 11 | "name": "AMAZON.HelpIntent", 12 | "samples": [] 13 | }, 14 | { 15 | "name": "AMAZON.StopIntent", 16 | "samples": [] 17 | }, 18 | { 19 | "name": "AMAZON.NavigateHomeIntent", 20 | "samples": [] 21 | }, 22 | { 23 | "name": "CaptureBirthdayIntent", 24 | "slots": [ 25 | { 26 | "name": "month", 27 | "type": "AMAZON.Month" 28 | }, 29 | { 30 | "name": "day", 31 | "type": "AMAZON.Ordinal" 32 | }, 33 | { 34 | "name": "year", 35 | "type": "AMAZON.FOUR_DIGIT_NUMBER" 36 | } 37 | ], 38 | "samples": [ 39 | "{month} {day}", 40 | "{month} {day} {year}", 41 | "{month} {year}", 42 | "I was born on {month} {day} ", 43 | "I was born on {month} {day} {year}", 44 | "I was born on {month} {year}" 45 | ] 46 | } 47 | ], 48 | "types": [] 49 | }, 50 | "dialog": { 51 | "intents": [ 52 | { 53 | "name": "CaptureBirthdayIntent", 54 | "confirmationRequired": false, 55 | "prompts": {}, 56 | "slots": [ 57 | { 58 | "name": "month", 59 | "type": "AMAZON.Month", 60 | "confirmationRequired": false, 61 | "elicitationRequired": true, 62 | "prompts": { 63 | "elicitation": "Elicit.Slot.303899476312.795077103633" 64 | } 65 | }, 66 | { 67 | "name": "day", 68 | "type": "AMAZON.Ordinal", 69 | "confirmationRequired": false, 70 | "elicitationRequired": true, 71 | "prompts": { 72 | "elicitation": "Elicit.Slot.303899476312.985837334781" 73 | } 74 | }, 75 | { 76 | "name": "year", 77 | "type": "AMAZON.FOUR_DIGIT_NUMBER", 78 | "confirmationRequired": false, 79 | "elicitationRequired": true, 80 | "prompts": { 81 | "elicitation": "Elicit.Slot.303899476312.27341833344" 82 | } 83 | } 84 | ] 85 | } 86 | ], 87 | "delegationStrategy": "ALWAYS" 88 | }, 89 | "prompts": [ 90 | { 91 | "id": "Elicit.Slot.303899476312.795077103633", 92 | "variations": [ 93 | { 94 | "type": "PlainText", 95 | "value": "I was born in November. When what were you born?" 96 | }, 97 | { 98 | "type": "PlainText", 99 | "value": "What month were you born?" 100 | } 101 | ] 102 | }, 103 | { 104 | "id": "Elicit.Slot.303899476312.985837334781", 105 | "variations": [ 106 | { 107 | "type": "PlainText", 108 | "value": "I was born on the sixth. What day were you born?" 109 | } 110 | ] 111 | }, 112 | { 113 | "id": "Elicit.Slot.303899476312.27341833344", 114 | "variations": [ 115 | { 116 | "type": "PlainText", 117 | "value": "I was born in two thousand fourteen, what year were you born?" 118 | } 119 | ] 120 | } 121 | ] 122 | } 123 | } -------------------------------------------------------------------------------- /module-4/index.js: -------------------------------------------------------------------------------- 1 | // This sample demonstrates handling intents from an Alexa skill using the Alexa Skills Kit SDK (v2). 2 | // Please visit https://alexa.design/cookbook for additional examples on implementing slots, dialog management, 3 | // session persistence, api calls, and more. 4 | const Alexa = require('ask-sdk-core'); 5 | const persistenceAdapter = require('ask-sdk-s3-persistence-adapter'); 6 | 7 | const LaunchRequestHandler = { 8 | canHandle(handlerInput) { 9 | return handlerInput.requestEnvelope.request.type === 'LaunchRequest'; 10 | }, 11 | handle(handlerInput) { 12 | const speakOutput = 'Hello! Welcome to Cake time. What is your birthday?'; 13 | const repromptText = 'I was born Nov. 6th, 2014. When were you born?'; 14 | 15 | return handlerInput.responseBuilder 16 | .speak(speakOutput) 17 | .reprompt(repromptText) 18 | .getResponse(); 19 | } 20 | }; 21 | const HasBirthdayLaunchRequestHandler = { 22 | canHandle(handlerInput) { 23 | console.log(JSON.stringify(handlerInput.requestEnvelope.request)); 24 | const attributesManager = handlerInput.attributesManager; 25 | const sessionAttributes = attributesManager.getSessionAttributes() || {}; 26 | 27 | const year = sessionAttributes.hasOwnProperty('year') ? sessionAttributes.year : 0; 28 | const month = sessionAttributes.hasOwnProperty('month') ? sessionAttributes.month : 0; 29 | const day = sessionAttributes.hasOwnProperty('day') ? sessionAttributes.day : 0; 30 | 31 | return handlerInput.requestEnvelope.request.type === 'LaunchRequest' && 32 | year && 33 | month && 34 | day; 35 | }, 36 | async handle(handlerInput) { 37 | 38 | const serviceClientFactory = handlerInput.serviceClientFactory; 39 | const deviceId = handlerInput.requestEnvelope.context.System.device.deviceId; 40 | 41 | const attributesManager = handlerInput.attributesManager; 42 | const sessionAttributes = attributesManager.getSessionAttributes() || {}; 43 | 44 | const year = sessionAttributes.hasOwnProperty('year') ? sessionAttributes.year : 0; 45 | const month = sessionAttributes.hasOwnProperty('month') ? sessionAttributes.month : 0; 46 | const day = sessionAttributes.hasOwnProperty('day') ? sessionAttributes.day : 0; 47 | 48 | let userTimeZone; 49 | try { 50 | const upsServiceClient = serviceClientFactory.getUpsServiceClient(); 51 | userTimeZone = await upsServiceClient.getSystemTimeZone(deviceId); 52 | } catch (error) { 53 | if (error.name !== 'ServiceError') { 54 | return handlerInput.responseBuilder.speak("There was a problem connecting to the service.").getResponse(); 55 | } 56 | console.log('error', error.message); 57 | } 58 | console.log('userTimeZone', userTimeZone); 59 | 60 | const oneDay = 24*60*60*1000; 61 | 62 | // getting the current date with the time 63 | const currentDateTime = new Date(new Date().toLocaleString("en-US", {timeZone: userTimeZone})); 64 | // removing the time from the date because it affects our difference calculation 65 | const currentDate = new Date(currentDateTime.getFullYear(), currentDateTime.getMonth(), currentDateTime.getDate()); 66 | let currentYear = currentDate.getFullYear(); 67 | 68 | console.log('currentDateTime:', currentDateTime); 69 | console.log('currentDate:', currentDate); 70 | 71 | // getting the next birthday 72 | let nextBirthday = Date.parse(`${month} ${day}, ${currentYear}`); 73 | 74 | // adjust the nextBirthday by one year if the current date is after their birthday 75 | if (currentDate.getTime() > nextBirthday) { 76 | nextBirthday = Date.parse(`${month} ${day}, ${currentYear + 1}`); 77 | currentYear++; 78 | } 79 | 80 | // setting the default speakOutput to Happy xth Birthday!! 81 | // Alexa will automatically correct the ordinal for you. 82 | // no need to worry about when to use st, th, rd 83 | let speakOutput = `Happy ${currentYear - year}th birthday!`; 84 | if (currentDate.getTime() !== nextBirthday) { 85 | const diffDays = Math.round(Math.abs((currentDate.getTime() - nextBirthday)/oneDay)); 86 | speakOutput = `Welcome back. It looks like there are ${diffDays} days until your ${currentYear - year}th birthday.` 87 | } 88 | 89 | return handlerInput.responseBuilder 90 | .speak(speakOutput) 91 | .getResponse(); 92 | } 93 | }; 94 | const CaptureBirthdayIntentHandler = { 95 | canHandle(handlerInput) { 96 | return handlerInput.requestEnvelope.request.type === 'IntentRequest' 97 | && handlerInput.requestEnvelope.request.intent.name === 'CaptureBirthdayIntent'; 98 | }, 99 | async handle(handlerInput) { 100 | const year = handlerInput.requestEnvelope.request.intent.slots.year.value; 101 | const month = handlerInput.requestEnvelope.request.intent.slots.month.value; 102 | const day = handlerInput.requestEnvelope.request.intent.slots.day.value; 103 | 104 | const attributesManager = handlerInput.attributesManager; 105 | 106 | const birthdayAttributes = { 107 | "year": year, 108 | "month": month, 109 | "day": day 110 | 111 | }; 112 | attributesManager.setPersistentAttributes(birthdayAttributes); 113 | await attributesManager.savePersistentAttributes(); 114 | 115 | const speakOutput = `Thanks, I'll remember that you were born ${month} ${day} ${year}.`; 116 | return handlerInput.responseBuilder 117 | .speak(speakOutput) 118 | //.reprompt('add a reprompt if you want to keep the session open for the user to respond') 119 | .getResponse(); 120 | } 121 | }; 122 | 123 | const HelpIntentHandler = { 124 | canHandle(handlerInput) { 125 | return handlerInput.requestEnvelope.request.type === 'IntentRequest' 126 | && handlerInput.requestEnvelope.request.intent.name === 'AMAZON.HelpIntent'; 127 | }, 128 | handle(handlerInput) { 129 | const speakOutput = 'You can say hello to me! How can I help?'; 130 | 131 | return handlerInput.responseBuilder 132 | .speak(speakOutput) 133 | .reprompt(speakOutput) 134 | .getResponse(); 135 | } 136 | }; 137 | const CancelAndStopIntentHandler = { 138 | canHandle(handlerInput) { 139 | return handlerInput.requestEnvelope.request.type === 'IntentRequest' 140 | && (handlerInput.requestEnvelope.request.intent.name === 'AMAZON.CancelIntent' 141 | || handlerInput.requestEnvelope.request.intent.name === 'AMAZON.StopIntent'); 142 | }, 143 | handle(handlerInput) { 144 | const speakOutput = 'Goodbye!'; 145 | return handlerInput.responseBuilder 146 | .speak(speakOutput) 147 | .getResponse(); 148 | } 149 | }; 150 | const SessionEndedRequestHandler = { 151 | canHandle(handlerInput) { 152 | return handlerInput.requestEnvelope.request.type === 'SessionEndedRequest'; 153 | }, 154 | handle(handlerInput) { 155 | // Any cleanup logic goes here. 156 | return handlerInput.responseBuilder.getResponse(); 157 | } 158 | }; 159 | 160 | // The intent reflector is used for interaction model testing and debugging. 161 | // It will simply repeat the intent the user said. You can create custom handlers 162 | // for your intents by defining them above, then also adding them to the request 163 | // handler chain below. 164 | const IntentReflectorHandler = { 165 | canHandle(handlerInput) { 166 | return handlerInput.requestEnvelope.request.type === 'IntentRequest'; 167 | }, 168 | handle(handlerInput) { 169 | const intentName = handlerInput.requestEnvelope.request.intent.name; 170 | const speakOutput = `You just triggered ${intentName}`; 171 | 172 | return handlerInput.responseBuilder 173 | .speak(speakOutput) 174 | //.reprompt('add a reprompt if you want to keep the session open for the user to respond') 175 | .getResponse(); 176 | } 177 | }; 178 | 179 | // Generic error handling to capture any syntax or routing errors. If you receive an error 180 | // stating the request handler chain is not found, you have not implemented a handler for 181 | // the intent being invoked or included it in the skill builder below. 182 | const ErrorHandler = { 183 | canHandle() { 184 | return true; 185 | }, 186 | handle(handlerInput, error) { 187 | console.log(`~~~~ Error handled: ${error.message}`); 188 | const speakOutput = `Sorry, I couldn't understand what you said. Please try again.`; 189 | 190 | return handlerInput.responseBuilder 191 | .speak(speakOutput) 192 | .reprompt(speakOutput) 193 | .getResponse(); 194 | } 195 | }; 196 | 197 | const LoadBirthdayInterceptor = { 198 | async process(handlerInput) { 199 | const attributesManager = handlerInput.attributesManager; 200 | const sessionAttributes = await attributesManager.getPersistentAttributes() || {}; 201 | 202 | const year = sessionAttributes.hasOwnProperty('year') ? sessionAttributes.year : 0; 203 | const month = sessionAttributes.hasOwnProperty('month') ? sessionAttributes.month : 0; 204 | const day = sessionAttributes.hasOwnProperty('day') ? sessionAttributes.day : 0; 205 | 206 | if (year && month && day) { 207 | attributesManager.setSessionAttributes(sessionAttributes); 208 | } 209 | } 210 | } 211 | 212 | // The SkillBuilder acts as the entry point for your skill, routing all request and response 213 | // payloads to the handlers above. Make sure any new handlers or interceptors you've 214 | // defined are included below. The order matters - they're processed top to bottom. 215 | exports.handler = Alexa.SkillBuilders.custom() 216 | .withPersistenceAdapter( 217 | new persistenceAdapter.S3PersistenceAdapter({bucketName:process.env.S3_PERSISTENCE_BUCKET}) 218 | ) 219 | .addRequestHandlers( 220 | HasBirthdayLaunchRequestHandler, 221 | LaunchRequestHandler, 222 | CaptureBirthdayIntentHandler, 223 | HelpIntentHandler, 224 | CancelAndStopIntentHandler, 225 | SessionEndedRequestHandler, 226 | IntentReflectorHandler) // make sure IntentReflectorHandler is last so it doesn't override your custom intent handlers 227 | .addErrorHandlers( 228 | ErrorHandler) 229 | .addRequestInterceptors( 230 | LoadBirthdayInterceptor 231 | ) 232 | .withApiClient(new Alexa.DefaultApiClient()) 233 | .lambda(); 234 | -------------------------------------------------------------------------------- /module-4/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cake-time", 3 | "version": "0.9.0", 4 | "description": "alexa utility for quickly building skills", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Amazon Alexa", 10 | "license": "ISC", 11 | "dependencies": { 12 | "ask-sdk-core": "^2.0.7", 13 | "ask-sdk-model": "^1.4.1", 14 | "aws-sdk": "^2.326.0", 15 | "ask-sdk-s3-persistence-adapter": "^2.0.0" 16 | } 17 | } --------------------------------------------------------------------------------