├── .ask
└── config
├── .github
└── PULL_REQUEST_TEMPLATE.md
├── Readme.md
├── hooks
├── post_new_hook.ps1
├── post_new_hook.sh
├── pre_deploy_hook.ps1
└── pre_deploy_hook.sh
├── instructions
├── 1-voice-user-interface.md
├── 2-lambda-function.md
├── 3-connect-vui-to-code.md
├── 4-testing.md
├── 5-customization.md
├── 6-publication.md
└── 7-cli.md
├── lambda
└── custom
│ ├── document
│ ├── oneSpeakItemCommand.json
│ ├── renderPage.json
│ └── twoSpeakItemsCommand.json
│ ├── index.js
│ ├── package.json
│ └── questions.js
├── models
├── de-DE.json
├── en-GB.json
└── en-US.json
└── skill.json
/.ask/config:
--------------------------------------------------------------------------------
1 | {
2 | "deploy_settings": {
3 | "default": {
4 | "skill_id": "",
5 | "was_cloned": false,
6 | "merge": {}
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | Regions: [🇯🇵](../../tree/ja-JP) [🇲🇽](../../tree/es-MX)
2 |
3 |
4 |
5 | # Build An Alexa Trivia Skill 🇺🇸
6 |
7 |
8 |
9 |
10 | This Alexa sample skill is a template for a basic trivia skill. Provided a list of interesting questions about a topic, Alexa will select a question at random and ask it of the user when the skill is invoked.
11 |
12 |
13 |
14 |
15 | To **Get Started** click the button below:
16 |
17 | [](./instructions/1-voice-user-interface.md)
18 |
19 | Or click [here](./instructions/7-cli.md) for instructions using the ASK CLI (command line interface).
20 |
21 | ## Additional Resources
22 |
23 | ### Community
24 | * [Amazon Developer Forums](https://forums.developer.amazon.com/spaces/165/index.html) - Join the conversation!
25 | * [Hackster.io](https://www.hackster.io/amazon-alexa) - See what others are building with Alexa.
26 |
27 | ### Tutorials & Guides
28 | * [Voice Design Guide](https://developer.amazon.com/designing-for-voice/) - A great resource for learning conversational and voice user interface design.
29 | * [Codecademy: Learn Alexa](https://www.codecademy.com/learn/learn-alexa) - Learn how to build an Alexa Skill from within your browser with this beginner friendly tutorial on Codecademy!
30 |
31 | ### Documentation
32 | * [Official Alexa Skills Kit Node.js SDK](https://www.npmjs.com/package/ask-sdk) - The Official Node.js SDK Documentation
33 | * [Official Alexa Skills Kit Documentation](https://developer.amazon.com/docs/ask-overviews/build-skills-with-the-alexa-skills-kit.html) - Official Alexa Skills Kit Documentation
34 |
--------------------------------------------------------------------------------
/hooks/post_new_hook.ps1:
--------------------------------------------------------------------------------
1 | # Powershell script for ask-cli post-new hook for Node.js
2 | # Script Usage: post_new_hook.ps1
3 |
4 | # SKILL_NAME is the preformatted name passed from the CLI, after removing special characters.
5 | # DO_DEBUG is boolean value for debug logging
6 |
7 | # Run this script one level outside of the skill root folder
8 |
9 | # The script does the following:
10 | # - Run "npm install" in each sourceDir in skill.json
11 |
12 | param(
13 | [string] $SKILL_NAME,
14 | [bool] $DO_DEBUG = $False
15 | )
16 |
17 | if ($DO_DEBUG) {
18 | Write-Output "###########################"
19 | Write-Output "###### post-new hook ######"
20 | Write-Output "###########################"
21 | }
22 |
23 | function install_dependencies ($CWD, $SOURCE_DIR) {
24 | $INSTALL_PATH = $SKILL_NAME + "\" +$SOURCE_DIR
25 | Set-Location $INSTALL_PATH
26 | Invoke-Expression "npm install" 2>&1 | Out-Null
27 | $EXEC_RESULT = $?
28 | Set-Location $CWD
29 | return $EXEC_RESULT
30 | }
31 |
32 | $SKILL_FILE_PATH = $SKILL_NAME + "\skill.json"
33 | $ALL_SOURCE_DIRS = Get-Content -Path $SKILL_FILE_PATH | select-string -Pattern "sourceDir" -CaseSensitive
34 | Foreach ($SOURCE_DIR in $ALL_SOURCE_DIRS) {
35 | $FILTER_SOURCE_DIR = $SOURCE_DIR -replace "`"", "" -replace "\s", "" -replace ",","" -replace "sourceDir:", ""
36 | $CWD = (Get-Location).Path
37 | if (install_dependencies $CWD $FILTER_SOURCE_DIR) {
38 | if ($DO_DEBUG) {
39 | Write-Output "Codebase ($FILTER_SOURCE_DIR) built successfully."
40 | }
41 | } else {
42 | if ($DO_DEBUG) {
43 | Write-Output "There was a problem installing dependencies for ($FILTER_SOURCE_DIR)."
44 | }
45 | exit 1
46 | }
47 | }
48 |
49 | if ($DO_DEBUG) {
50 | Write-Output "###########################"
51 | }
52 |
53 | exit 0
54 |
--------------------------------------------------------------------------------
/hooks/post_new_hook.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Shell script for ask-cli post-new hook for Node.js
3 | # Script Usage: post_new_hook.sh
4 |
5 | # SKILL_NAME is the preformatted name passed from the CLI, after removing special characters.
6 | # DO_DEBUG is boolean value for debug logging
7 |
8 | # Run this script one level outside of the skill root folder
9 |
10 | # The script does the following:
11 | # - Run "npm install" in each sourceDir in skill.json
12 |
13 | SKILL_NAME=$1
14 | DO_DEBUG=${2:-false}
15 |
16 | if [ $DO_DEBUG == false ]
17 | then
18 | exec > /dev/null 2>&1
19 | fi
20 |
21 | install_dependencies() {
22 | npm install --prefix "$SKILL_NAME/$1" >/dev/null 2>&1
23 | return $?
24 | }
25 |
26 | echo "###########################"
27 | echo "###### post-new hook ######"
28 | echo "###########################"
29 |
30 | grep "sourceDir" $SKILL_NAME/skill.json | cut -d: -f2 | sed 's/"//g' | sed 's/,//g' | while read -r SOURCE_DIR; do
31 | if install_dependencies $SOURCE_DIR; then
32 | echo "Codebase ($SOURCE_DIR) built successfully."
33 | else
34 | echo "There was a problem installing dependencies for ($SOURCE_DIR)."
35 | exit 1
36 | fi
37 | done
38 | echo "###########################"
39 |
40 | exit 0
41 |
42 |
--------------------------------------------------------------------------------
/hooks/pre_deploy_hook.ps1:
--------------------------------------------------------------------------------
1 | # Powershell script for ask-cli pre-deploy hook for Node.js
2 | # Script Usage: pre_deploy_hook.ps1
3 |
4 | # SKILL_NAME is the preformatted name passed from the CLI, after removing special characters.
5 | # DO_DEBUG is boolean value for debug logging
6 | # TARGET is the deploy TARGET provided to the CLI. (eg: all, skill, lambda etc.)
7 |
8 | # Run this script under the skill root folder
9 |
10 | # The script does the following:
11 | # - Run "npm install" in each sourceDir in skill.json
12 |
13 | param(
14 | [string] $SKILL_NAME,
15 | [bool] $DO_DEBUG = $False,
16 | [string] $TARGET = "all"
17 | )
18 |
19 | function install_dependencies ($CWD, $SOURCE_DIR) {
20 | Set-Location $SOURCE_DIR
21 | Invoke-Expression "npm install" 2>&1 | Out-Null
22 | $EXEC_RESULT = $?
23 | Set-Location $CWD
24 | return $EXEC_RESULT
25 | }
26 |
27 | if ($DO_DEBUG) {
28 | Write-Output "###########################"
29 | Write-Output "##### pre-deploy hook #####"
30 | Write-Output "###########################"
31 | }
32 |
33 | if ($TARGET -eq "all" -Or $TARGET -eq "lambda") {
34 | $ALL_SOURCE_DIRS = Get-Content -Path "skill.json" | select-string -Pattern "sourceDir" -CaseSensitive
35 | Foreach ($SOURCE_DIR in $ALL_SOURCE_DIRS) {
36 | $FILTER_SOURCE_DIR = $SOURCE_DIR -replace "`"", "" -replace "\s", "" -replace ",","" -replace "sourceDir:", ""
37 | $CWD = (Get-Location).Path
38 | if (install_dependencies $CWD $FILTER_SOURCE_DIR) {
39 | if ($DO_DEBUG) {
40 | Write-Output "Codebase ($FILTER_SOURCE_DIR) built successfully."
41 | }
42 | } else {
43 | if ($DO_DEBUG) {
44 | Write-Output "There was a problem installing dependencies for ($FILTER_SOURCE_DIR)."
45 | }
46 | exit 1
47 | }
48 | }
49 | if ($DO_DEBUG) {
50 | Write-Output "###########################"
51 | }
52 | }
53 |
54 | exit 0
--------------------------------------------------------------------------------
/hooks/pre_deploy_hook.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Shell script for ask-cli pre-deploy hook for Node.js
3 | # Script Usage: pre_deploy_hook.sh
4 |
5 | # SKILL_NAME is the preformatted name passed from the CLI, after removing special characters.
6 | # DO_DEBUG is boolean value for debug logging
7 | # TARGET is the deploy TARGET provided to the CLI. (eg: all, skill, lambda etc.)
8 |
9 | # Run this script under skill root folder
10 |
11 | # The script does the following:
12 | # - Run "npm install" in each sourceDir in skill.json
13 |
14 | SKILL_NAME=$1
15 | DO_DEBUG=${2:-false}
16 | TARGET=${3:-"all"}
17 |
18 | if [ $DO_DEBUG == false ]
19 | then
20 | exec > /dev/null 2>&1
21 | fi
22 |
23 | install_dependencies() {
24 | npm install --prefix "$1" >/dev/null 2>&1
25 | return $?
26 | }
27 |
28 | echo "###########################"
29 | echo "##### pre-deploy hook #####"
30 | echo "###########################"
31 |
32 | if [[ $TARGET == "all" || $TARGET == "lambda" ]]; then
33 | grep "sourceDir" ./skill.json | cut -d: -f2 | sed 's/"//g' | sed 's/,//g' | while read -r SOURCE_DIR; do
34 | if install_dependencies $SOURCE_DIR; then
35 | echo "Codebase ($SOURCE_DIR) built successfully."
36 | else
37 | echo "There was a problem installing dependencies for ($SOURCE_DIR)."
38 | exit 1
39 | fi
40 | done
41 | echo "###########################"
42 | fi
43 |
44 | exit 0
45 |
--------------------------------------------------------------------------------
/instructions/1-voice-user-interface.md:
--------------------------------------------------------------------------------
1 | # Build An Alexa Trivia Skill
2 |
3 |
4 | [](./1-voice-user-interface.md)[](./2-lambda-function.md)[](./3-connect-vui-to-code.md)[](./4-testing.md)[](./5-customization.md)[](./6-publication.md)
5 |
6 | 1. **Go to the [Amazon Developer Portal](http://developer.amazon.com?&sc_category=Owned&sc_channel=RD&sc_campaign=Evangelism2018&sc_publisher=github&sc_content=Survey&sc_detail=trivia-nodejs-V2_GUI-1&sc_funnel=Convert&sc_country=WW&sc_medium=Owned_RD_Evangelism2018_github_Survey_trivia-nodejs-V2_GUI-1_Convert_WW_beginnersdevs&sc_segment=beginnersdevs). In the top-right corner of the screen, click the "Sign In" button.**
7 | (If you don't already have an account, you will be able to create a new one for free.)
8 |
9 | 2. Once you have signed in, move your mouse over the **Your Alexa Consoles** text at the top of the screen and Select the **Skills (New)** Link.
10 |
11 | 3. From the **Alexa Skills Console (New Console)** select the **Create Skill** button near the top of the screen.
12 |
13 | 4. Give your new skill a **Name**. This is the name that will be shown in the Alexa Skills Store, and the name your users will refer to. Push Next.
14 |
15 | 5. Select the **Custom** model at the top of the page to add to your skill and select the **Create Skill** button at the top right.
16 |
17 | 6. **Build the Interaction Model for your skill**
18 | 1. On the left hand navigation panel. Select the **Invocation** tab. Enter a **Skill Invocation Name**. This is the name that your users will need to say to start your skill.
19 | 2. Next, select the **JSON Editor** tab. In the textfield provided, replace any existing code with the code provided in the [Interaction Model](../models) (make sure to pick the model that matches your skill's language), then click "Build Model".
20 |
21 | **Note:** You should notice that **Intents** and **Slot Types** will auto populate based on the JSON Interaction Model that you have now applied to your skill. Feel free to explore the changes here, to learn about **Intents**, **Slots**, and **Utterances** open our [technical documentation in a new tab](https://developer.amazon.com/docs/custom-skills/create-intents-utterances-and-slots.html?&sc_category=Owned&sc_channel=RD&sc_campaign=Evangelism2018&sc_publisher=github&sc_content=Survey&sc_detail=trivia-nodejs-V2_GUI-1&sc_funnel=Convert&sc_country=WW&sc_medium=Owned_RD_Evangelism2018_github_Survey_trivia-nodejs-V2_GUI-1_Convert_WW_beginnersdevs&sc_segment=beginnersdevs).
22 |
23 | 7. **Optional:** Select an intent by expanding the **Intents** from the left side navigation panel. Add some more sample utterances for your newly generated intents. Think of all the different ways that a user could request to make a specific intent happen. A few examples are provided. Be sure to click **Save Model** and **Build Model** after you're done making changes here.
24 |
25 | 8. If your interaction model builds successfully, proceed to the next step. If not, you should see an error. Try to resolve the errors. In our next step of this guide, we will be creating our Lambda function in the AWS developer console, but keep this browser tab open, because we will be returning here on [Page #3: Connect VUI to Code](./3-connect-vui-to-code.md).
26 |
27 |
28 | If you get an error from your interaction model, check through this list:
29 |
30 | * **Did you copy & paste the provided code correctly?**
31 | * **Did you accidentally add any characters to the Interaction Model or Sample Utterances?**
32 |
33 | [](./2-lambda-function.md)
34 |
--------------------------------------------------------------------------------
/instructions/2-lambda-function.md:
--------------------------------------------------------------------------------
1 | # Build An Alexa Trivia Skill
2 |
3 |
4 | [](./1-voice-user-interface.md)[](./2-lambda-function.md)[](./3-connect-vui-to-code.md)[](./4-testing.md)[](./5-customization.md)[](./6-publication.md)
5 |
6 | ## Setting Up A Lambda Function Using Amazon Web Services
7 |
8 | In the [first step of this guide](./1-voice-user-interface.md), we built the Voice User Interface (VUI) for our Alexa skill. On this page, we will be creating an AWS Lambda function using [Amazon Web Services](http://aws.amazon.com). You can [read more about what a Lambda function is](http://aws.amazon.com/lambda), but for the purposes of this guide, what you need to know is that AWS Lambda is where our code lives. When a user asks Alexa to use our skill, it is our AWS Lambda function that interprets the appropriate interaction, and provides the conversation back to the user.
9 |
10 | 1. **Go to http://aws.amazon.com and sign in to the console.** If you don't already have an account, you will need to create one. [If you don't have an AWS account, check out this quick walkthrough for setting it up](https://alexa.design/create-aws-account).
11 |
12 | [](https://console.aws.amazon.com/console/home)
13 |
14 | 2. **Click "Services" at the top of the screen, and type "Lambda" in the search box.** You can also find Lambda in the list of services. It is in the "Compute" section.
15 |
16 | [](https://console.aws.amazon.com/lambda/home)
17 |
18 | 3. **Check your AWS region.** AWS Lambda only works with the Alexa Skills Kit in these regions: US East (N. Virginia), US West (Oregon), Asia Pacific (Tokyo) and EU (Ireland). Make sure you choose the region closest to your customers.
19 | ß
20 | 
21 |
22 | 4. **Click the orange "Create function" button.** It should be near the top of your screen. (If you don't see this button, it is because you haven't created a Lambda function before. Click the blue "Get Started" button near the center of your screen.)
23 |
24 | 
25 |
26 | 5. There are three boxes labeled "Author from scratch", "Blueprints" and "Serverless Application Repository". **Click the radio button in the box titled "Serverless Application Repository"** We have created a repository as a shortcut to getting everything set up for your skill.
27 |
28 | 6. **Search for the application repository named "alexa-skills-kit-nodejs-triviaskill".** You can find it using the provided search box.
29 |
30 | 7. **Click on the repository.** This repository will create the Lambda function, add Alexa Skills Kit as it's trigger, and sets up an IAM role for you. It will also add the code from this GitHub repo and include it's dependencies to your Lambda function so that you don't have to upload it yourself.
31 |
32 |
33 | 8. **Click the deploy button** at the bottom of the page.
34 |
35 | 9. Wait for the status of all resources to change to **CREATE_COMPLETE**
36 |
37 | 10. Click the **Test App** button to go to the Lambda console.
38 |
39 | 11. **Open** the function that was **just created** by clicking on it.
40 |
41 | 12. If you want to **secure this Lambda function** follow the instructions found [here](https://alexa.design/secure-lambda-function)
42 |
43 | 13. Scroll down the page until you see a section called **Function code**.
44 |
45 | 14. Copy the [provided code from here](https://github.com/alexa/skill-sample-nodejs-trivia/blob/en-US/lambda/custom/index.js) into the Lambda function code box. Delete the contents of the code box, and paste the contents of the new code. Click "Save".
46 |
47 | 15. You should see the Amazon Resource Name (ARN) a unique identifier for this function in the top right corner of the page. **Copy the ARN value for this Lambda function** for use in the next section of the guide.
48 |
49 | 
50 |
51 |
52 | [](./3-connect-vui-to-code.md)
53 |
--------------------------------------------------------------------------------
/instructions/3-connect-vui-to-code.md:
--------------------------------------------------------------------------------
1 | # Build An Alexa Trivia Skill
2 |
3 |
4 | [](./1-voice-user-interface.md)[](./2-lambda-function.md)[](./3-connect-vui-to-code.md)[](./4-testing.md)[](./5-customization.md)[](./6-publication.md)
5 |
6 | ## Connecting Your Voice User Interface To Your Lambda Function
7 |
8 | On [page #1](./1-voice-user-interface.md) of this guide, we created a voice user interface for the intents and utterances we expect from our users. On [page #2](./2-lambda-function.md), we created a Lambda function that contains all of our logic for the skill. On this page, we need to connect those two pieces together.
9 |
10 | 1. **Go back to the [Amazon Developer Portal](https://developer.amazon.com/edw/home.html#/skills/list?&sc_category=Owned&sc_channel=RD&sc_campaign=Evangelism2018&sc_publisher=github&sc_content=Survey&sc_detail=trivia-nodejs-V2_GUI-3&sc_funnel=Convert&sc_country=WW&sc_medium=Owned_RD_Evangelism2018_github_Survey_trivia-nodejs-V2_GUI-3_Convert_WW_beginnersdevs&sc_segment=beginnersdevs) and select your skill from the list.** You may still have a browser tab open if you started at the beginning of this tutorial.
11 |
12 | 2. Select the **Endpoint** tab on the left side navigation panel.
13 |
14 | 3. **Select the "AWS Lambda ARN" option for your endpoint.** You have the ability to host your code anywhere that you would like, but for the purposes of simplicity and frugality, we are using AWS Lambda. ([Read more about Hosting Your Own Custom Skill Web Service](https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/developing-an-alexa-skill-as-a-web-service?&sc_category=Owned&sc_channel=RD&sc_campaign=Evangelism2018&sc_publisher=github&sc_content=Survey&sc_detail=trivia-nodejs-V2_GUI-3&sc_funnel=Convert&sc_country=WW&sc_medium=Owned_RD_Evangelism2018_github_Survey_trivia-nodejs-V2_GUI-3_Convert_WW_beginnersdevs&sc_segment=beginnersdevs).) With the AWS Free Tier, you get 1,000,000 free requests per month, up to 3.2 million seconds of compute time per month. Learn more at [aws.amazon.com/free](https://aws.amazon.com/free/). In addition, Amazon now offers [AWS Promotional Credits for developers who have live Alexa skills that incur costs on AWS related to those skills](https://developer.amazon.com/alexa-skills-kit/alexa-aws-credits?&sc_category=Owned&sc_channel=RD&sc_campaign=Evangelism2018&sc_publisher=github&sc_content=Survey&sc_detail=trivia-nodejs-V2_GUI-3&sc_funnel=Convert&sc_country=WW&sc_medium=Owned_RD_Evangelism2018_github_Survey_trivia-nodejs-V2_GUI-3_Convert_WW_beginnersdevs&sc_segment=beginnersdevs).
15 |
16 | 4. Paste your Lambda's ARN (Amazon Resource Name) into the textbox provided for **Default Region**.
17 |
18 | 5. Click the **Save Endpoints** button at the top of the main panel.
19 |
20 | 6. **Click the "Next" button to continue to page #4 of this guide.**
21 |
22 | [](./4-testing.md)
23 |
--------------------------------------------------------------------------------
/instructions/4-testing.md:
--------------------------------------------------------------------------------
1 | # Build An Alexa Trivia Skill
2 |
3 |
4 | [](./1-voice-user-interface.md)[](./2-lambda-function.md)[](./3-connect-vui-to-code.md)[](./4-testing.md)[](./5-customization.md)[](./6-publication.md)
5 |
6 | ## Testing Your Alexa Skill
7 |
8 | So far, we have [created a Voice User Interface](./1-voice-user-interface.md), [a Lambda function](./2-lambda-function.md), and [connected the two together](./3-connect-vui-to-code.md). Your skill is now ready to test.
9 |
10 | 1. **Go back to the [Amazon Developer Portal](https://developer.amazon.com/edw/home.html#/skills/list?&sc_category=Owned&sc_channel=RD&sc_campaign=Evangelism2018&sc_publisher=github&sc_content=Survey&sc_detail=trivia-nodejs-V2_GUI-4&sc_funnel=Convert&sc_country=WW&sc_medium=Owned_RD_Evangelism2018_github_Survey_trivia-nodejs-V2_GUI-4_Convert_WW_beginnersdevs&sc_segment=beginnersdevs) and select your skill from the list.** You may still have a browser tab open if you started at the beginning of this tutorial.
11 |
12 | 2. Open the **Test** Pane, by selecting the **Test** link from the top navigation menu.
13 |
14 | 3. Enable Testing by activating the **Test is enabled for this skill** slider. It should be underneath the top navigation menu.
15 |
16 | 4. To validate that your skill is working as expected, invoke your skill from the **Alexa Simulator**. You can either type or click and hold the mic from the input box to use your voice.
17 | 1. **Type** "Open" followed by the invocation name you gave your skill in [Step 1](./1-voice-user-interface.md). For example, "Open Reindeer Trivia".
18 | 2. **Use your voice** by clicking and holding the mic on the side panel and saying "Open" followed by the invocation name you gave your skill.
19 | 3. **If you've forgotten the invocation name** for your skill, revisit the **Build** panel on the top navigation menu and select Invocation from the sidebar to review it.
20 |
21 | 5. Ensure your skill works the way that you designed it to.
22 | * After you interact with the Alexa Simulator, you should see the Skill I/O **JSON Input** and **JSON Output** boxes get populated with JSON data. You can also view the **Device Log** to trace your steps.
23 | * If it's not working as expected, you can dig into the JSON to see exactly what Alexa is sending and receiving from the endpoint. If something is broken, AWS Lambda offers an additional testing tool to help you troubleshoot your skill.
24 |
25 | 6. **Configure a test event in AWS Lambda.** Now that you are familiar with the **request** and **response** boxes in the Service Simulator, it's important for you to know that you can use your **requests** to directly test your Lambda function every time you update it. To do this:
26 | 1. Enter an utterance in the service simulator, and copy the generated Lambda Request for the next step.
27 |
28 | 2. **Open your Lambda function in AWS, open the Actions menu, and select "Configure test events."**
29 |
30 | 
31 |
32 | 3. **Select "Create New Test Event". Choose "Alexa Start Session" as the Event Template from the dropdown list.** You can choose any test event in the list, as they are just templated event requests, but using "Alexa Start Session" is an easy one to remember.
33 |
34 | 
35 |
36 | 4. **Type in an Event Name into the Event Name Dialog box. Delete the contents of the code editor, and paste the Lambda request you copied above into the code editor.** The Event Name is only visible to you. Name your test event something descriptive and memorable. For our example, we entered an event name as "startSession". Additionally, by copying and pasting your Lambda Request from the service simulator, you can test different utterances and skill events beyond the pre-populated templates in Lambda.
37 |
38 | 
39 |
40 | 5. **Click the "Create" button.** This will save your test event and bring you back to the main configuration for your lambda function.
41 |
42 | 6. **Click the "Test" button to execute the "startSession" test event.**
43 |
44 | 
45 |
46 | This gives you visibility into four things:
47 |
48 | * **Your response, listed in the "Execution Result."**
49 |
50 | 
51 |
52 | * **A Summary of the statistics for your request.** This includes things like duration, resources, and memory used.
53 |
54 | 
55 |
56 | * **Log output.** By effectively using console.log() statements in your Lambda code, you can track what is happening inside your function, and help to figure out what is happening when something goes wrong. You will find the log to be incredibly valuable as you move into more advanced skills.
57 |
58 | 
59 |
60 | * **A link to your [CloudWatch](https://console.aws.amazon.com/cloudwatch/home?region=us-east-1#logs:) logs for this function.** This will show you **all** of the responses and log statements from every user interaction. This is very useful, especially when you are testing your skill from a device with your voice. (It is the "[Click here](https://console.aws.amazon.com/cloudwatch/home?region=us-east-1#logs:)" link in the Log Output description.)
61 |
62 | 7. **Other testing methods to consider:**
63 |
64 | * [Echosim.io](https://echosim.io) - a browser-based Alexa skill testing tool that makes it easy to test your skills without carrying a physical device everywhere you go.
65 | * [Unit Testing with Alexa](https://github.com/alexa/alexa-cookbook/tree/master/testing/postman/README.md) - a modern approach to unit testing your Alexa skills with [Postman](http://getpostman.com) and [Amazon API Gateway](http://aws.amazon.com/apigateway).
66 |
67 | 8. **If your sample skill is working properly, you can now customize your skill.**
68 |
69 | [](./5-customization.md)
70 |
--------------------------------------------------------------------------------
/instructions/5-customization.md:
--------------------------------------------------------------------------------
1 | # Build An Alexa Trivia Skill
2 |
3 |
4 | [](./1-voice-user-interface.md)[](./2-lambda-function.md)[](./3-connect-vui-to-code.md)[](./4-testing.md)[](./5-customization.md)[](./6-publication.md)
5 |
6 | ## Customize the Skill to be Yours
7 |
8 | At this point, you should have a working copy of our Trivia skill. In order to make it your own, you will need to customize it with data and responses that you create. Here are the things you will need to change:
9 |
10 | 1. **New data.** You will need to provide a set of trivia for your topic. We recommend a minimum of 25, but a total closer to 100 offers a better experience.
11 |
12 | 1. **Open a copy of index.js.** If you haven't already downloaded the code for this project, [you can find a copy of index.js here on GitHub](https://github.com/alexa/skill-sample-nodejs-trivia/blob/en-US/lambda/custom/index.js). You can use a simple, lightweight code editor like [Atom](http://atom.io), [Sublime Text](http://sublimetext.com), or [VSCode](http://code.visualstudio.com), but you also have the option to edit the code directly in your Lambda function.
13 |
14 | 2. **Search for the comment "TODO: Replace this data with your own."** This is the data for our skill. You can see that it is a simple list of facts.
15 |
16 | 3. **When you have replaced the data in index.js, copy the contents of your file to your Lambda function.** This should be as simple as copying the text, and pasting it into the code box for your Lambda.
17 |
18 | 
19 |
20 | 2. **New sentences to respond to your users.** There are several sentences and responses that you will want to customize for your skill.
21 |
22 | 1. **Go back to your copy of [index.js](https://github.com/alexa/skill-sample-nodejs-trivia/blob/en-US/lambda/custom/index.js).**
23 |
24 | 2. **Look for the comment "TODO: The items below this comment need your attention."** This is the beginning of the section where you need to customize several text strings for your skill.
25 |
26 | 3. **Continue through index.js until you reach the bottom of the file.** This will ensure that you cover each of the values that you need to update.
27 |
28 | 3. **New language.** If you are creating this skill for another language other than English, you will need to make sure Alexa's responses are also in that language.
29 |
30 | * For example, if you are creating your skill in German, every single response that Alexa makes has to be in German. You can't use English responses or your skill will fail certification.
31 |
32 | 4. **Once you have made the updates listed on this page, you can click "Next" to move on to Publishing and Certification of your skill.**
33 |
34 | 
35 |
36 |
37 | [](6-publication.md)
38 |
--------------------------------------------------------------------------------
/instructions/6-publication.md:
--------------------------------------------------------------------------------
1 | # Build An Alexa Trivia Skill
2 |
3 |
4 | [](./1-voice-user-interface.md)[](./2-lambda-function.md)[](./3-connect-vui-to-code.md)[](./4-testing.md)[](./5-customization.md)[](./6-publication.md)
5 | ## Get Your Skill Certified and Published
6 |
7 | We are almost done! The last step is to add the metadata that your skill will use in the [Skill Store](http://amazon.com/skills). This page will walk you through the remaining steps to launch your skill!
8 |
9 | 1. Select the **Launch** link from the top navigation menu.
10 |
11 | 2. Fill out the form fields per the guidance on the screen. Hover over the question mark icons for details regarding each respective field. **Fields marked with an Asterisk, are required!**
12 | * Take the time to get these right so that your skill will pass certification!
13 |
14 | 3. **Write your skill descriptions.**
15 |
16 | * **Spend some time coming up with an enticing, succinct description.** This is one of the few places you have an opportunity to attract new users, so make the most of it! These descriptions show up in the list of skills available in the [Alexa app](http://alexa.amazon.com/spa/index.html#skills) and the [skills store](http://www.amazon.com/skills).
17 |
18 | 4. For your example phrases, **come up with the three most exciting ways** a user can talk to your skill.
19 |
20 | * Make sure that each of your example phrases are a **perfect match with one of your Sample Utterances.** Incorrect example phrases are one of the most common reasons that skills fail certification, so we have provided a short list of things to consider as you write your example phrases:
21 |
22 | | Common Failure Points for Example Phrases |
23 | | ----------------------------------------- |
24 | | Example phrases **must** adhere to the [supported phrases](https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/supported-phrases-to-begin-a-conversation?&sc_category=Owned&sc_channel=RD&sc_campaign=Evangelism2018&sc_publisher=github&sc_content=Survey&sc_detail=trivia-nodejs-V2_GUI-6&sc_funnel=Convert&sc_country=WW&sc_medium=Owned_RD_Evangelism2018_github_Survey_trivia-nodejs-V2_GUI-6_Convert_WW_beginnersdevs&sc_segment=beginnersdevs). |
25 | | Example phrases **must** be based on sample utterances specified in your Intent Schema. |
26 | | Your first example phrase **must** include a wake word and your invocation name. |
27 | | Example phrases **must** provide a contextual response. |
28 |
29 | * **Choose three example phrases that are likely to be the most common ways that users will attempt to interact with your skill.** Make sure that each of them works well, and provides an excellent user experience.
30 |
31 | 5. **Create your skill's icons.** You need two sizes of your icon: 108x108px and 512x512px.
32 |
33 |
34 | * **Make sure you have the rights to the icons you create.** Please don't violate any trademarks or copyrights.
35 | * **If you don't have software to make icons, try one of these free options:**
36 |
37 | * [GIMP](https://www.gimp.org/) (Windows/Mac/Linux)
38 | * [Canva](https://www.canva.com/) (Web)
39 | * [Paint.NET](http://www.getpaint.net/index.html) (Windows)
40 | * [Inkscape](http://inkscape.org) (Windows/Mac/Linux)
41 | * [Iconion](http://iconion.com/) (Windows/Mac)
42 |
43 | * To make it easier to get started, we've created blank versions of these icons in both sizes for many formats:
44 |
45 | * [PSD](https://m.media-amazon.com/images/G/01/mobile-apps/dex/alexa/alexa-skills-kit/tutorials/general/icon-templates/psd._TTH_.zip)
46 | * [PNG](https://m.media-amazon.com/images/G/01/mobile-apps/dex/alexa/alexa-skills-kit/tutorials/general/icon-templates/png._TTH_.zip)
47 | * [GIF](https://m.media-amazon.com/images/G/01/mobile-apps/dex/alexa/alexa-skills-kit/tutorials/general/icon-templates/gif._TTH_.zip)
48 | * [PDF](https://m.media-amazon.com/images/G/01/mobile-apps/dex/alexa/alexa-skills-kit/tutorials/general/icon-templates/pdf._TTH_.zip)
49 | * [JPG](https://m.media-amazon.com/images/G/01/mobile-apps/dex/alexa/alexa-skills-kit/tutorials/general/icon-templates/jpg._TTH_.zip)
50 | * [SVG](https://m.media-amazon.com/images/G/01/mobile-apps/dex/alexa/alexa-skills-kit/tutorials/general/icon-templates/svg._TTH_.zip)
51 | * [PDN](https://m.media-amazon.com/images/G/01/mobile-apps/dex/alexa/alexa-skills-kit/tutorials/general/icon-templates/pdn._TTH_.zip) - for [Paint.NET](http://www.getpaint.net/index.html)
52 | * [XCF](https://m.media-amazon.com/images/G/01/mobile-apps/dex/alexa/alexa-skills-kit/tutorials/general/icon-templates/xcf._TTH_.zip) - for [GIMP](https://www.gimp.org/)
53 |
54 | 6. Choose the most appropriate category for your skill.
55 |
56 | 7. **Provide a comprehensive list of keywords for users that are searching for new skills.** This is an optional field, and searching the [Alexa app](http://alexa.amazon.com) or the [skill store](http://www.amazon.com/skills) will also find the words in your Skill Name and descriptions, so you don't need to overdo it. That being said, if there are words that you want users to find your skill with, you should include them here. Separate the keywords with commas.
57 |
58 | 8. **Privacy Policy URL.** This is an optional field, and should not be required for this Trivia skill sample. You can leave it blank.
59 |
60 | 9. **Terms of Use URL.** This is also optional, and you can leave it blank.
61 |
62 | 10. When you're ready, click **Save and Continue** at the bottom of the screen to move onto **Privacy & Compliance**
63 |
64 | 11. * **Does this skill allow users to make purchases or spend real money?** For this trivia skill, the answer is no. For future skills, make sure you answer this appropriately.
65 |
66 | * **Does this Alexa skill collect users' personal information?** Again, for this trivia skill, the answer is no. If you do collect information about a user, such as names, email addresses, phone numbers, and so forth, ensure that you answer Yes to this question.
67 | * Answering "yes" to this question will also require you to provide a link to your Privacy Policy at the bottom of the page.
68 |
69 | * **Is your skill directed to children under the age of 13?** Because you customized this skill with data you provided, it is possible that you created a skill that targets children under the age of 13. For this trivia skill, the answer is **no** because it doesn't target a specific age group.
70 | * Factors to consider in determining if this skill is directed to children under 13 include:
71 | * Subject matter of the skill
72 | * Presence of child-oriented activities and incentives
73 | * Type of language used in the skill
74 | * Music and other audio content in the skill
75 | * How the skill is described and marketed
76 | * Intended audience for the skill
77 |
78 | If you're not sure, please see the [FTC's COPPA Guidance and FAQ](https://www.ftc.gov/tips-advice/business-center/guidance/complying-coppa-frequently-asked-questions) for more information.
79 |
80 | 12. **Export Compliance.** Be certain that you agree with all of the conditions. If you do, make sure to check this box, as Amazon requires this permission to distribute your skill around the globe.
81 |
82 | 13. **Provide testing instructions.** Testing instructions give you an opportunity to explain your skill, and any special or possibly confusing features, to the certification team. A value is required in this box.
83 |
84 | * Since you are using our Sample, make sure to add a sentence to your Testing Instructions referencing the Sample you used. For example:
85 |
86 | ```
87 | This was built using the Trivia Sample.
88 | ```
89 |
90 | This will let the testing team understand what you're providing them, and should decrease the testing time required.
91 |
92 | **Note:** More details on certification are [available here.](https://alexa.design/certification)
93 |
94 | 14. If you feel that your skill is ready for certification, click the **Save and Continue** button at the bottom of the page.
95 |
96 |
97 | 15. **You're done with your submission!** Here are a few things you might need to know:
98 |
99 | * **Certification can take several days to complete.** Please be patient. It takes time because we want to get it right.
100 |
101 | * **Did something go wrong?** Our team of evangelists run [online office hours every Tuesday from 1-2pm Pacific Time](https://register.gotowebinar.com/rt/8924773651242797059). They can help answer any questions you might have.
102 |
103 | * **Want the coolest t-shirt you've ever seen?** Every month, we create a brand-new Alexa Developer t-shirt or hoodie, and send them out to developers that published a skill that month. [You can get yours here if you live in the US](https://developer.amazon.com/alexa-skills-kit/alexa-developer-skill-promotion?&sc_category=Owned&sc_channel=RD&sc_campaign=Evangelism2018&sc_publisher=github&sc_content=Survey&sc_detail=trivia-nodejs-V2_GUI-6&sc_funnel=Convert&sc_country=WW&sc_medium=Owned_RD_Evangelism2018_github_Survey_trivia-nodejs-V2_GUI-6_Convert_WW_beginnersdevs&sc_segment=beginnersdevs), [here for the UK](https://developer.amazon.com/en-gb/alexa-skills-kit/alexa-developer-skill-promotion?&sc_category=Owned&sc_channel=RD&sc_campaign=Evangelism2018&sc_publisher=github&sc_content=Survey&sc_detail=trivia-nodejs-V2_GUI-6&sc_funnel=Convert&sc_country=WW&sc_medium=Owned_RD_Evangelism2018_github_Survey_trivia-nodejs-V2_GUI-6_Convert_WW_beginnersdevs&sc_segment=beginnersdevs), and [here for Germany](https://developer.amazon.com/de-de/alexa-skills-kit/alexa-developer-skill-promotion?&sc_category=Owned&sc_channel=RD&sc_campaign=Evangelism2018&sc_publisher=github&sc_content=Survey&sc_detail=trivia-nodejs-V2_GUI-6&sc_funnel=Convert&sc_country=WW&sc_medium=Owned_RD_Evangelism2018_github_Survey_trivia-nodejs-V2_GUI-6_Convert_WW_beginnersdevs&sc_segment=beginnersdevs).
104 |
--------------------------------------------------------------------------------
/instructions/7-cli.md:
--------------------------------------------------------------------------------
1 | # Build An Alexa Trivia Skill
2 |
3 |
4 | ## Setup w/ ASK CLI
5 |
6 | ### About
7 | This readme assumes you have your developer environment ready to go and that you have some familiarity with CLI (Command Line Interface) Tools, [AWS](https://aws.amazon.com/), and the [ASK Developer Portal](https://developer.amazon.com/alexa-skills-kit?&sc_category=Owned&sc_channel=RD&sc_campaign=Evangelism2018&sc_publisher=github&sc_content=Content&sc_detail=trivia-nodejs-V2_CLI-1&sc_funnel=Convert&sc_country=WW&sc_medium=Owned_RD_Evangelism2018_github_Content_trivia-nodejs-V2_CLI-1_Convert_WW_beginnersdevs&sc_segment=beginnersdevs). If not, [click here](./1-voice-user-interface.md) for a more detailed walkthrough.
8 |
9 | ### Pre-requisites
10 |
11 | * Node.js (> v8)
12 | * Register for an [AWS Account](https://aws.amazon.com/)
13 | * Register for an [Amazon Developer Account](https://developer.amazon.com?&sc_category=Owned&sc_channel=RD&sc_campaign=Evangelism2018&sc_publisher=github&sc_content=Content&sc_detail=trivia-nodejs-V2_CLI-1&sc_funnel=Convert&sc_country=WW&sc_medium=Owned_RD_Evangelism2018_github_Content_trivia-nodejs-V2_CLI-1_Convert_WW_beginnersdevs&sc_segment=beginnersdevs)
14 | * Install and Setup [ASK CLI](https://developer.amazon.com/docs/smapi/quick-start-alexa-skills-kit-command-line-interface.html?&sc_category=Owned&sc_channel=RD&sc_campaign=Evangelism2018&sc_publisher=github&sc_content=Content&sc_detail=trivia-nodejs-V2_CLI-1&sc_funnel=Convert&sc_country=WW&sc_medium=Owned_RD_Evangelism2018_github_Content_trivia-nodejs-V2_CLI-1_Convert_WW_beginnersdevs&sc_segment=beginnersdevs)
15 |
16 | ### Installation
17 | 1. **Make sure** you are running the latest version of the CLI
18 |
19 | ```bash
20 | $ npm update -g ask-cli
21 | ```
22 |
23 | 2. **Clone** the repository.
24 |
25 | ```bash
26 | $ git clone https://github.com/alexa/skill-sample-nodejs-trivia/
27 | ```
28 |
29 | 3. If it's your first time using it, **initiatialize** the [ASK CLI](https://developer.amazon.com/docs/smapi/quick-start-alexa-skills-kit-command-line-interface.html?&sc_category=Owned&sc_channel=RD&sc_campaign=Evangelism2018&sc_publisher=github&sc_content=Content&sc_detail=trivia-nodejs-V2_CLI-1&sc_funnel=Convert&sc_country=WW&sc_medium=Owned_RD_Evangelism2018_github_Content_trivia-nodejs-V2_CLI-1_Convert_WW_beginnersdevs&sc_segment=beginnersdevs) by navigating into the repository and running npm command: `ask init`. Follow the prompts.
30 |
31 | ```bash
32 | $ cd skill-sample-nodejs-trivia
33 | $ ask init
34 | ```
35 |
36 | 4. Install npm dependencies by navigating into the `/lambda/custom` directory and running the npm command: `npm install --save`
37 |
38 | ```bash
39 | $ cd lambda/custom
40 | $ npm install
41 | ```
42 |
43 | ### Deployment
44 |
45 | ASK CLI **will create the skill and the lambda function for you**. The Lambda function will be created in ```us-east-1 (Northern Virginia)``` by default.
46 |
47 | 1. Navigate to the project's root directory. you should see a file named 'skill.json' there.
48 | 2. Deploy the skill and the lambda function in one step by running the following command:
49 |
50 | ```bash
51 | $ ask deploy
52 | ```
53 |
54 | ### Testing
55 |
56 | 1. To test, you need to login to Alexa Developer Console, and **enable the "Test" switch on your skill from the "Test" Tab**.
57 |
58 | 2. Simulate verbal interaction with your skill through the command line (this might take a few moments) using the following example:
59 |
60 | ```bash
61 | $ ask simulate -l en-GB -t "start reindeer trivia"
62 |
63 | ✓ Simulation created for simulation id: 4a7a9ed8-94b2-40c0-b3bd-fb63d9887fa7
64 | ◡ Waiting for simulation response{
65 | "status": "SUCCESSFUL",
66 | ...
67 | ```
68 |
69 | 3. Once the "Test" switch is enabled, your skill can be tested on devices associated with the developer account as well. Speak to Alexa from any enabled device, from your browser at [echosim.io](https://echosim.io/welcome), or through your Amazon Mobile App and say :
70 |
71 | ```text
72 | Alexa, start reindeer trivia
73 | ```
74 | ## Customization
75 |
76 | 1. ```./skill.json```
77 |
78 | Change the skill name, example phrase, icons, testing instructions etc ...
79 |
80 | Remember than many information are locale-specific and must be changed for each locale (en-GB and en-US)
81 |
82 | See the Skill [Manifest Documentation](https://developer.amazon.com/docs/smapi/skill-manifest.html?&sc_category=Owned&sc_channel=RD&sc_campaign=Evangelism2018&sc_publisher=github&sc_content=Survey&sc_detail=trivia-nodejs-V2_CLI-3&sc_funnel=Convert&sc_country=WW&sc_medium=Owned_RD_Evangelism2018_github_Survey_trivia-nodejs-V2_CLI-3_Convert_WW_beginnersdevs&sc_segment=beginnersdevs) for more information.
83 |
84 | 2. ```./lambda/custom/index.js```
85 |
86 | Modify messages, and trivia from the source code to customize the skill.
87 |
88 | 3. ```./models/*.json```
89 |
90 | Change the model definition to replace the invocation name and the sample phrase for each intent. Repeat the operation for each locale you are planning to support.
91 |
92 | 4. Remember to re-deploy your skill and lambda function for your changes to take effect.
93 |
--------------------------------------------------------------------------------
/lambda/custom/document/oneSpeakItemCommand.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "Sequential",
3 | "delay": 300,
4 | "commands": [
5 | {
6 | "type": "SpeakItem",
7 | "componentId": "text01",
8 | "highlightMode": "line"
9 | },
10 | {
11 | "delay" : "100" ,
12 | "type": "SetPage",
13 | "componentId": "pagerId",
14 | "position": "relative",
15 | "value": 1
16 | }
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/lambda/custom/document/renderPage.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "APL",
3 | "version": "1.0",
4 | "settings": {},
5 | "theme": "dark",
6 | "import": [
7 | {
8 | "name" : "alexa-styles",
9 | "version" : "1.0.0"
10 | }
11 | ],
12 | "resources": [
13 | {
14 | "colors" : {
15 | "SkillBackgroundColor" : "blue" ,
16 | "SkillHighlightTextColor" : "yellow" ,
17 | "SkillTextColor" : "white"
18 | }
19 | }
20 | ],
21 | "styles": {},
22 | "onMount": [],
23 | "graphics": {},
24 | "commands": {},
25 | "layouts": {
26 | "CenteredText" :
27 | {
28 | "parameters" : [
29 | "text",
30 | "speech"
31 | ] ,
32 | "item" :
33 | {
34 | "type" : "Text",
35 | "text" : "${text}",
36 | "speech" : "${speech}",
37 | "textAlign" : "center" ,
38 | "color" : "@SkillTextColor" ,
39 | "width" : "50%",
40 | "height" : "100%" ,
41 | "textAlignVertical": "center" ,
42 | "fontSize" : "@fontSizeRegular"
43 | }
44 | },
45 | "SkillLogo" :
46 | {
47 | "type" : "Frame" ,
48 | "item" : {
49 | "type" : "Image" ,
50 | "source" : "${payload.properties.logoUrl}",
51 | "height": "36",
52 | "width":"36"
53 | }
54 | }
55 | },
56 | "mainTemplate": {
57 | "parameters": [
58 | "payload"
59 | ],
60 | "items": [
61 | {
62 | "type" : "Frame" ,
63 | "backgroundColor" : "@SkillBackgroundColor" ,
64 | "width" : "100vw" ,
65 | "height" : "100vh" ,
66 | "item" : {
67 | "type": "Pager",
68 | "width" : "100vw" ,
69 | "height" : "100vh" ,
70 | "id" : "pagerId" ,
71 | "items": [
72 | {
73 | "type" : "Container" ,
74 | "width" : "100vw" ,
75 | "height" : "100vh" ,
76 | "direction" : "row" ,
77 | "items" : [
78 | {
79 | "when": "${@viewportProfile != @hubRoundSmall}",
80 | "type" : "SkillLogo" ,
81 | "position" : "absolute" ,
82 | "right" : "5vw" ,
83 | "top" : "5vh" ,
84 | "width": "15vw" ,
85 | "height" : "15vh"
86 | },
87 | {
88 | "type" : "CenteredText" ,
89 | "text" : "${payload.phrase.phraseText}",
90 | "width" : "80vw" ,
91 | "height" : "100vh" ,
92 | "paddingLeft" : "10vw",
93 | "id" : "text01" ,
94 | "speech" : "${payload.phrase.properties.phraseAsSpeech}"
95 | } ]
96 | },
97 | {
98 | "when": "${payload.nextPhrase.phraseText != 'none'}",
99 | "type" : "Container" ,
100 | "width" : "100vw" ,
101 | "height" : "100vh" ,
102 | "direction" : "row" ,
103 | "items" : [
104 | {
105 | "when": "${@viewportProfile != @hubRoundSmall}",
106 | "type" : "SkillLogo" ,
107 | "position" : "absolute" ,
108 | "right" : "5vw" ,
109 | "top" : "5vh" ,
110 | "width": "15vw" ,
111 | "height" : "15vh"
112 | },
113 | {
114 | "type" : "CenteredText" ,
115 | "text" : "${payload.nextPhrase.properties.phraseSsml}",
116 | "width" : "80vw" ,
117 | "height" : "100vh" ,
118 | "paddingLeft" : "10vw",
119 | "speech" : "${payload.nextPhrase.properties.nextPhraseAsSpeech}",
120 | "id" : "text02"
121 | } ]
122 | }
123 | ]
124 | }
125 | }
126 | ]
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/lambda/custom/document/twoSpeakItemsCommand.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "Sequential",
3 | "delay": 300,
4 | "commands": [
5 | {
6 | "type": "SpeakItem",
7 | "componentId": "text01",
8 | "highlightMode": "line"
9 | },
10 | {
11 | "delay" : "100" ,
12 | "type": "SetPage",
13 | "componentId": "pagerId",
14 | "position": "relative",
15 | "value": 1
16 | },
17 | {
18 | "delay" : "500" ,
19 | "type": "SpeakItem",
20 | "componentId": "text02",
21 | "highlightMode": "line"
22 | }
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/lambda/custom/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable func-names */
2 | /* eslint-disable no-console */
3 |
4 | const Alexa = require('ask-sdk-core');
5 | const questions = require('./questions');
6 | const i18n = require('i18next');
7 | const sprintf = require('i18next-sprintf-postprocessor');
8 |
9 | const ANSWER_COUNT = 4;
10 | const GAME_LENGTH = 5;
11 | const SKILL_NAME = 'Reindeer Trivia';
12 | const FALLBACK_MESSAGE = `The ${SKILL_NAME} skill can\'t help you with that. It can ask you questions about reindeer if you say start game. What can I help you with?`;
13 | const FALLBACK_REPROMPT = 'What can I help you with?';
14 | const APL_DOC = require ('./document/renderPage.json' ) ;
15 | const TWO_PAGER_COMMANDS = require ('./document/twoSpeakItemsCommand.json' ) ;
16 | const ONE_PAGER_COMMANDS = require ('./document/oneSpeakItemCommand.json' ) ;
17 | const TOKEN_ID = 'pagerSample';
18 | const firstTransformerList = [
19 | {
20 | "inputPath": "phraseSsml",
21 | "outputName": "phraseAsSpeech",
22 | "transformer": "ssmlToSpeech"
23 | }
24 | ];
25 | const secondTransformerList = [
26 | {
27 | "inputPath": "phraseSsml",
28 | "outputName": "nextPhraseAsSpeech",
29 | "transformer": "ssmlToSpeech"
30 | }
31 | ];
32 |
33 | function makePage(phraseText="",repromptText="",phraseSSMLProperty="",transformerList=[]) {
34 | return {
35 | "phraseText" : phraseText ,
36 | "repromptText":repromptText,
37 | "properties" : {
38 | "phraseSsml" : phraseSSMLProperty
39 | },
40 | "transformers": transformerList
41 | };
42 | }
43 |
44 | function supportsDisplay(handlerInput) {
45 | return handlerInput.requestEnvelope.context
46 | && handlerInput.requestEnvelope.context.System
47 | && handlerInput.requestEnvelope.context.System.device
48 | && handlerInput.requestEnvelope.context.System.device.supportedInterfaces
49 | && (handlerInput.requestEnvelope.context.System.device.supportedInterfaces['Alexa.Presentation.APL']
50 | || handlerInput.requestEnvelope.context.System.device.supportedInterfaces.Display)
51 | && handlerInput.requestEnvelope.context.Viewport;
52 | }
53 |
54 | function populateGameQuestions(translatedQuestions) {
55 | const gameQuestions = [];
56 | const indexList = [];
57 | let index = translatedQuestions.length;
58 | if (GAME_LENGTH > index) {
59 | throw new Error('Invalid Game Length.');
60 | }
61 |
62 | for (let i = 0; i < translatedQuestions.length; i += 1) {
63 | indexList.push(i);
64 | }
65 |
66 | for (let j = 0; j < GAME_LENGTH; j += 1) {
67 | const rand = Math.floor(Math.random() * index);
68 | index -= 1;
69 |
70 | const temp = indexList[index];
71 | indexList[index] = indexList[rand];
72 | indexList[rand] = temp;
73 | gameQuestions.push(indexList[index]);
74 | }
75 | return gameQuestions;
76 | }
77 |
78 | function populateRoundAnswers(
79 | gameQuestionIndexes,
80 | correctAnswerIndex,
81 | correctAnswerTargetLocation,
82 | translatedQuestions
83 | ) {
84 | const answers = [];
85 | const translatedQuestion = translatedQuestions[gameQuestionIndexes[correctAnswerIndex]];
86 | const answersCopy = translatedQuestion[Object.keys(translatedQuestion)[0]].slice();
87 | let index = answersCopy.length;
88 |
89 | if (index < ANSWER_COUNT) {
90 | throw new Error('Not enough answers for question.');
91 | }
92 |
93 | // Shuffle the answers, excluding the first element which is the correct answer.
94 | for (let j = 1; j < answersCopy.length; j += 1) {
95 | const rand = Math.floor(Math.random() * (index - 1)) + 1;
96 | index -= 1;
97 |
98 | const swapTemp1 = answersCopy[index];
99 | answersCopy[index] = answersCopy[rand];
100 | answersCopy[rand] = swapTemp1;
101 | }
102 |
103 | // Swap the correct answer into the target location
104 | for (let i = 0; i < ANSWER_COUNT; i += 1) {
105 | answers[i] = answersCopy[i];
106 | }
107 | const swapTemp2 = answers[0];
108 | answers[0] = answers[correctAnswerTargetLocation];
109 | answers[correctAnswerTargetLocation] = swapTemp2;
110 | return answers;
111 | }
112 |
113 | function isAnswerSlotValid(intent) {
114 | const answerSlotFilled = intent
115 | && intent.slots
116 | && intent.slots.Answer
117 | && intent.slots.Answer.value;
118 | const answerSlotIsInt = answerSlotFilled
119 | && !Number.isNaN(parseInt(intent.slots.Answer.value, 10));
120 | return answerSlotIsInt
121 | && parseInt(intent.slots.Answer.value, 10) < (ANSWER_COUNT + 1)
122 | && parseInt(intent.slots.Answer.value, 10) > 0;
123 | }
124 |
125 | function handleUserGuess(userGaveUp, handlerInput) {
126 | const { requestEnvelope, attributesManager, responseBuilder } = handlerInput;
127 | const { intent } = requestEnvelope.request;
128 |
129 | const answerSlotValid = isAnswerSlotValid(intent);
130 |
131 | let speechOutput = '';
132 | let speechOutputAnalysis = '';
133 | let aplFirstPageSpeechOutput = '';
134 | let aplSecondPageSpeechOutput = '';
135 | const sessionAttributes = attributesManager.getSessionAttributes();
136 | const gameQuestions = sessionAttributes.questions;
137 | let correctAnswerIndex = parseInt(sessionAttributes.correctAnswerIndex, 10);
138 | let currentScore = parseInt(sessionAttributes.score, 10);
139 | let currentQuestionIndex = parseInt(sessionAttributes.currentQuestionIndex, 10);
140 | const { correctAnswerText } = sessionAttributes;
141 | const requestAttributes = attributesManager.getRequestAttributes();
142 | const translatedQuestions = requestAttributes.t('QUESTIONS');
143 |
144 |
145 | if (answerSlotValid
146 | && parseInt(intent.slots.Answer.value, 10) === sessionAttributes.correctAnswerIndex) {
147 | currentScore += 1;
148 | speechOutputAnalysis = requestAttributes.t('ANSWER_CORRECT_MESSAGE');
149 | } else {
150 | if (!userGaveUp) {
151 | speechOutputAnalysis = requestAttributes.t('ANSWER_WRONG_MESSAGE');
152 | }
153 |
154 | speechOutputAnalysis += requestAttributes.t(
155 | 'CORRECT_ANSWER_MESSAGE',
156 | correctAnswerIndex,
157 | correctAnswerText
158 | );
159 | }
160 |
161 | // Check if we can exit the game session after GAME_LENGTH questions (zero-indexed)
162 | if (sessionAttributes.currentQuestionIndex === GAME_LENGTH - 1) {
163 | aplFirstPageSpeechOutput = speechOutput + speechOutputAnalysis;
164 | aplSecondPageSpeechOutput = requestAttributes.t(
165 | 'GAME_OVER_MESSAGE',
166 | currentScore.toString(),
167 | GAME_LENGTH.toString()
168 | );
169 | speechOutput = userGaveUp ? '' : requestAttributes.t('ANSWER_IS_MESSAGE');
170 | speechOutput += speechOutputAnalysis + requestAttributes.t(
171 | 'GAME_OVER_MESSAGE',
172 | currentScore.toString(),
173 | GAME_LENGTH.toString()
174 | );
175 |
176 | if (supportsDisplay(handlerInput)) {
177 | let payload = {
178 | "phrase": makePage(aplFirstPageSpeechOutput,"",`${aplFirstPageSpeechOutput}`,firstTransformerList),
179 | "nextPhrase": makePage(aplSecondPageSpeechOutput,"",`${aplSecondPageSpeechOutput}`,secondTransformerList)
180 | };
181 | speechOutput = "";
182 |
183 | handlerInput.responseBuilder
184 | .addDirective(
185 | {
186 | type: 'Alexa.Presentation.APL.RenderDocument',
187 | version: '1.1',
188 | document : APL_DOC ,
189 | datasources : payload,
190 | token : TOKEN_ID ,
191 | })
192 | .addDirective (
193 | {
194 | type: 'Alexa.Presentation.APL.ExecuteCommands',
195 | token : TOKEN_ID ,
196 | commands :
197 | [
198 | TWO_PAGER_COMMANDS
199 | ]
200 | });
201 | }
202 |
203 | return responseBuilder
204 | .speak(speechOutput)
205 | .getResponse();
206 | }
207 | currentQuestionIndex += 1;
208 | correctAnswerIndex = Math.floor(Math.random() * (ANSWER_COUNT));
209 | const spokenQuestion = Object.keys(translatedQuestions[gameQuestions[currentQuestionIndex]])[0];
210 | const roundAnswers = populateRoundAnswers(
211 | gameQuestions,
212 | currentQuestionIndex,
213 | correctAnswerIndex,
214 | translatedQuestions
215 | );
216 | const questionIndexForSpeech = currentQuestionIndex + 1;
217 | let repromptText = requestAttributes.t(
218 | 'TELL_QUESTION_MESSAGE',
219 | questionIndexForSpeech.toString(),
220 | spokenQuestion
221 | );
222 |
223 | for (let i = 0; i < ANSWER_COUNT; i += 1) {
224 | repromptText += `${i + 1}. ${roundAnswers[i]}. `;
225 | }
226 |
227 | speechOutput += userGaveUp ? '' : requestAttributes.t('ANSWER_IS_MESSAGE');
228 | aplFirstPageSpeechOutput = speechOutput + speechOutputAnalysis + requestAttributes.t('SCORE_IS_MESSAGE', currentScore.toString());
229 | aplSecondPageSpeechOutput = repromptText;
230 | speechOutput += speechOutputAnalysis
231 | + requestAttributes.t('SCORE_IS_MESSAGE', currentScore.toString())
232 | + repromptText;
233 |
234 |
235 | const translatedQuestion = translatedQuestions[gameQuestions[currentQuestionIndex]];
236 |
237 | Object.assign(sessionAttributes, {
238 | speechOutput: repromptText,
239 | repromptText,
240 | currentQuestionIndex,
241 | correctAnswerIndex: correctAnswerIndex + 1,
242 | questions: gameQuestions,
243 | score: currentScore,
244 | correctAnswerText: translatedQuestion[Object.keys(translatedQuestion)[0]][0]
245 | });
246 |
247 | if (supportsDisplay(handlerInput)) {
248 | let payload = {
249 | "phrase": makePage(aplFirstPageSpeechOutput,"",`${aplFirstPageSpeechOutput}`,firstTransformerList),
250 | "nextPhrase": makePage(aplSecondPageSpeechOutput,"",`${aplSecondPageSpeechOutput}`,secondTransformerList)};
251 | speechOutput = "";
252 |
253 | handlerInput.responseBuilder
254 | .addDirective(
255 | {
256 | type: 'Alexa.Presentation.APL.RenderDocument',
257 | version: '1.1',
258 | document : APL_DOC ,
259 | datasources : payload ,
260 | token : TOKEN_ID ,
261 | })
262 | .addDirective (
263 | {
264 | type: 'Alexa.Presentation.APL.ExecuteCommands',
265 | token : TOKEN_ID ,
266 | commands :
267 | [
268 | TWO_PAGER_COMMANDS
269 | ]
270 | });
271 | }
272 |
273 | return responseBuilder.speak(speechOutput)
274 | .reprompt(repromptText)
275 | .withSimpleCard(requestAttributes.t('GAME_NAME'), repromptText)
276 | .getResponse();
277 | }
278 |
279 | function startGame(newGame, handlerInput) {
280 | const requestAttributes = handlerInput.attributesManager.getRequestAttributes();
281 | let speechOutput = newGame
282 | ? requestAttributes.t('NEW_GAME_MESSAGE', requestAttributes.t('GAME_NAME'))
283 | + requestAttributes.t('WELCOME_MESSAGE', GAME_LENGTH.toString())
284 | : '';
285 | let aplFirstPageSpeechOutput = speechOutput;
286 | const translatedQuestions = requestAttributes.t('QUESTIONS');
287 | const gameQuestions = populateGameQuestions(translatedQuestions);
288 | const correctAnswerIndex = Math.floor(Math.random() * (ANSWER_COUNT));
289 |
290 | const roundAnswers = populateRoundAnswers(
291 | gameQuestions,
292 | 0,
293 | correctAnswerIndex,
294 | translatedQuestions
295 | );
296 | const currentQuestionIndex = 0;
297 | const spokenQuestion = Object.keys(translatedQuestions[gameQuestions[currentQuestionIndex]])[0];
298 | let repromptText = requestAttributes.t('TELL_QUESTION_MESSAGE', '1', spokenQuestion);
299 |
300 | for (let i = 0; i < ANSWER_COUNT; i += 1) {
301 | repromptText += `${i + 1}. ${roundAnswers[i]}. `;
302 | }
303 |
304 | speechOutput += repromptText;
305 | const sessionAttributes = {};
306 |
307 | const translatedQuestion = translatedQuestions[gameQuestions[currentQuestionIndex]];
308 |
309 | Object.assign(sessionAttributes, {
310 | speechOutput: repromptText,
311 | repromptText,
312 | currentQuestionIndex,
313 | correctAnswerIndex: correctAnswerIndex + 1,
314 | questions: gameQuestions,
315 | score: 0,
316 | correctAnswerText: translatedQuestion[Object.keys(translatedQuestion)[0]][0]
317 | });
318 |
319 | handlerInput.attributesManager.setSessionAttributes(sessionAttributes);
320 |
321 | if (supportsDisplay(handlerInput)) {
322 | let payload = {
323 | "phrase": makePage(aplFirstPageSpeechOutput,"",`${aplFirstPageSpeechOutput}`,firstTransformerList),
324 | "nextPhrase": makePage(repromptText,"",`${repromptText}`,secondTransformerList)};
325 | speechOutput = "";
326 | handlerInput.responseBuilder
327 | .addDirective(
328 | {
329 | type: 'Alexa.Presentation.APL.RenderDocument',
330 | version: '1.1',
331 | document : APL_DOC ,
332 | datasources : payload ,
333 | token : TOKEN_ID ,
334 | })
335 | .addDirective (
336 | {
337 | type: 'Alexa.Presentation.APL.ExecuteCommands',
338 | token : TOKEN_ID ,
339 | commands :
340 | [
341 | TWO_PAGER_COMMANDS
342 | ]
343 | });
344 | }
345 |
346 | return handlerInput.responseBuilder
347 | .speak(speechOutput)
348 | .reprompt(repromptText)
349 | .withSimpleCard(requestAttributes.t('GAME_NAME'), repromptText)
350 | .getResponse();
351 | }
352 |
353 | function helpTheUser(newGame, handlerInput) {
354 | const requestAttributes = handlerInput.attributesManager.getRequestAttributes();
355 | const askMessage = newGame
356 | ? requestAttributes.t('ASK_MESSAGE_START')
357 | : requestAttributes.t('REPEAT_QUESTION_MESSAGE') + requestAttributes.t('STOP_MESSAGE');
358 | let speechOutput = requestAttributes.t('HELP_MESSAGE', GAME_LENGTH) + askMessage;
359 | const repromptText = requestAttributes.t('HELP_REPROMPT') + askMessage;
360 |
361 | if (supportsDisplay(handlerInput)) {
362 | let payload = {
363 | "phrase": makePage(speechOutput,repromptText,`${speechOutput}`,firstTransformerList),
364 | "nextPhrase": makePage("none","","",secondTransformerList)
365 | };
366 | speechOutput = "";
367 |
368 | handlerInput.responseBuilder
369 | .addDirective(
370 | {
371 | type: 'Alexa.Presentation.APL.RenderDocument',
372 | version: '1.1',
373 | document : APL_DOC ,
374 | datasources : payload ,
375 | token : TOKEN_ID ,
376 | })
377 | .addDirective (
378 | {
379 | type: 'Alexa.Presentation.APL.ExecuteCommands',
380 | token : TOKEN_ID ,
381 | commands :
382 | [
383 | ONE_PAGER_COMMANDS
384 | ]
385 | });
386 | }
387 |
388 | return handlerInput.responseBuilder.speak(speechOutput).reprompt(repromptText).getResponse();
389 | }
390 |
391 | /* jshint -W101 */
392 | const languageString = {
393 | en: {
394 | translation: {
395 | QUESTIONS: questions.QUESTIONS_EN_US,
396 | GAME_NAME: 'Reindeer Trivia',
397 | HELP_MESSAGE: 'I will ask you %s multiple choice questions. Respond with the number of the answer. For example, say one, two, three, or four. To start a new game at any time, say, start game. ',
398 | REPEAT_QUESTION_MESSAGE: 'To repeat the last question, say, repeat. ',
399 | ASK_MESSAGE_START: 'Would you like to start playing?',
400 | HELP_REPROMPT: 'To give an answer to a question, respond with the number of the answer. ',
401 | STOP_MESSAGE: 'Would you like to keep playing?',
402 | QUIT_MESSAGE: 'Good bye.',
403 | CANCEL_MESSAGE: 'Ok, let\'s play again soon.',
404 | NO_MESSAGE: 'Ok, we\'ll play another time. Goodbye!',
405 | TRIVIA_UNHANDLED: 'Try saying a number between 1 and %s',
406 | HELP_UNHANDLED: 'Say yes to continue, or no to end the game.',
407 | START_UNHANDLED: 'Say start to start a new game.',
408 | NEW_GAME_MESSAGE: 'Welcome to %s. ',
409 | WELCOME_MESSAGE: 'I will ask you %s questions, try to get as many right as you can. Just say the number of the answer. Let\'s begin. ',
410 | ANSWER_CORRECT_MESSAGE: 'correct. ',
411 | ANSWER_WRONG_MESSAGE: 'wrong. ',
412 | CORRECT_ANSWER_MESSAGE: 'The correct answer is %s: %s. ',
413 | ANSWER_IS_MESSAGE: 'That answer is ',
414 | TELL_QUESTION_MESSAGE: 'Question %s. %s ',
415 | GAME_OVER_MESSAGE: 'You got %s out of %s questions correct. Thank you for playing!',
416 | SCORE_IS_MESSAGE: 'Your score is %s. '
417 | },
418 | },
419 | 'en-US': {
420 | translation: {
421 | QUESTIONS: questions.QUESTIONS_EN_US,
422 | GAME_NAME: 'American Reindeer Trivia'
423 | },
424 | },
425 | 'en-GB': {
426 | translation: {
427 | QUESTIONS: questions.QUESTIONS_EN_GB,
428 | GAME_NAME: 'British Reindeer Trivia'
429 | },
430 | },
431 | de: {
432 | translation: {
433 | QUESTIONS: questions.QUESTIONS_DE_DE,
434 | GAME_NAME: 'Wissenswertes über Rentiere in Deutsch',
435 | HELP_MESSAGE: 'Ich stelle dir %s Multiple-Choice-Fragen. Antworte mit der Zahl, die zur richtigen Antwort gehört. Sage beispielsweise eins, zwei, drei oder vier. Du kannst jederzeit ein neues Spiel beginnen, sage einfach „Spiel starten“. ',
436 | REPEAT_QUESTION_MESSAGE: 'Wenn die letzte Frage wiederholt werden soll, sage „Wiederholen“ ',
437 | ASK_MESSAGE_START: 'Möchten Sie beginnen?',
438 | HELP_REPROMPT: 'Wenn du eine Frage beantworten willst, antworte mit der Zahl, die zur richtigen Antwort gehört. ',
439 | STOP_MESSAGE: 'Möchtest du weiterspielen?',
440 | QUIT_MESSAGE: 'Auf Wiedersehen.',
441 | CANCEL_MESSAGE: 'OK, dann lass uns bald mal wieder spielen.',
442 | NO_MESSAGE: 'OK, spielen wir ein andermal. Auf Wiedersehen!',
443 | TRIVIA_UNHANDLED: 'Sagt eine Zahl beispielsweise zwischen 1 und %s',
444 | HELP_UNHANDLED: 'Sage ja, um fortzufahren, oder nein, um das Spiel zu beenden.',
445 | START_UNHANDLED: 'Du kannst jederzeit ein neues Spiel beginnen, sage einfach „Spiel starten“.',
446 | NEW_GAME_MESSAGE: 'Willkommen bei %s. ',
447 | WELCOME_MESSAGE: 'Ich stelle dir %s Fragen und du versuchst, so viele wie möglich richtig zu beantworten. Sage einfach die Zahl, die zur richtigen Antwort passt. Fangen wir an. ',
448 | ANSWER_CORRECT_MESSAGE: 'Richtig. ',
449 | ANSWER_WRONG_MESSAGE: 'Falsch. ',
450 | CORRECT_ANSWER_MESSAGE: 'Die richtige Antwort ist %s: %s. ',
451 | ANSWER_IS_MESSAGE: 'Diese Antwort ist ',
452 | TELL_QUESTION_MESSAGE: 'Frage %s. %s ',
453 | GAME_OVER_MESSAGE: 'Du hast %s von %s richtig beantwortet. Danke fürs Mitspielen!',
454 | SCORE_IS_MESSAGE: 'Dein Ergebnis ist %s. '
455 | },
456 | },
457 | };
458 |
459 |
460 | const LocalizationInterceptor = {
461 | process(handlerInput) {
462 | const localizationClient = i18n.use(sprintf).init({
463 | lng: handlerInput.requestEnvelope.request.locale,
464 | overloadTranslationOptionHandler: sprintf.overloadTranslationOptionHandler,
465 | resources: languageString,
466 | returnObjects: true
467 | });
468 |
469 | const attributes = handlerInput.attributesManager.getRequestAttributes();
470 | attributes.t = function (...args) {
471 | return localizationClient.t(...args);
472 | };
473 | },
474 | };
475 |
476 | const LaunchRequest = {
477 | canHandle(handlerInput) {
478 | const { request } = handlerInput.requestEnvelope;
479 |
480 | return request.type === 'LaunchRequest'
481 | || (request.type === 'IntentRequest'
482 | && request.intent.name === 'AMAZON.StartOverIntent');
483 | },
484 | handle(handlerInput) {
485 | return startGame(true, handlerInput);
486 | },
487 | };
488 |
489 |
490 | const HelpIntent = {
491 | canHandle(handlerInput) {
492 | const { request } = handlerInput.requestEnvelope;
493 |
494 | return request.type === 'IntentRequest' && request.intent.name === 'AMAZON.HelpIntent';
495 | },
496 | handle(handlerInput) {
497 | const sessionAttributes = handlerInput.attributesManager.getSessionAttributes();
498 |
499 | const newGame = !(sessionAttributes.questions);
500 | return helpTheUser(newGame, handlerInput);
501 | },
502 | };
503 |
504 | const FallbackHandler = {
505 |
506 | // 2018-May-01: AMAZON.FallackIntent is only currently available in en-US locale.
507 |
508 | // This handler will not be triggered except in that locale, so it can be
509 |
510 | // safely deployed for any locale.
511 |
512 | canHandle(handlerInput) {
513 |
514 | const request = handlerInput.requestEnvelope.request;
515 |
516 | return request.type === 'IntentRequest'
517 |
518 | && request.intent.name === 'AMAZON.FallbackIntent';
519 |
520 | },
521 |
522 | handle(handlerInput) {
523 |
524 | return handlerInput.responseBuilder
525 |
526 | .speak(FALLBACK_MESSAGE)
527 |
528 | .reprompt(FALLBACK_REPROMPT)
529 |
530 | .getResponse();
531 |
532 | },
533 |
534 | };
535 |
536 | const UnhandledIntent = {
537 | canHandle() {
538 | return true;
539 | },
540 | handle(handlerInput) {
541 | const sessionAttributes = handlerInput.attributesManager.getSessionAttributes();
542 | const requestAttributes = handlerInput.attributesManager.getRequestAttributes();
543 | if (Object.keys(sessionAttributes).length === 0) {
544 | let speechOutput = requestAttributes.t('START_UNHANDLED');
545 | let repromptText = speechOutput;
546 | if (supportsDisplay(handlerInput)) {
547 | let payload = {
548 | "phrase": makePage(speechOutput,speechOutput,`${speechOutput}`,firstTransformerList),
549 | "nextPhrase": makePage("none","","",secondTransformerList)
550 | };
551 | speechOutput = "";
552 |
553 | handlerInput.responseBuilder
554 | .addDirective(
555 | {
556 | type: 'Alexa.Presentation.APL.RenderDocument',
557 | version: '1.1',
558 | document : APL_DOC ,
559 | datasources : payload ,
560 | token : TOKEN_ID ,
561 | })
562 | .addDirective (
563 | {
564 | type: 'Alexa.Presentation.APL.ExecuteCommands',
565 | token : TOKEN_ID ,
566 | commands :
567 | [
568 | ONE_PAGER_COMMANDS
569 | ]
570 | });
571 | }
572 | return handlerInput.attributesManager
573 | .speak(speechOutput)
574 | .reprompt(repromptText)
575 | .getResponse();
576 | } else if (sessionAttributes.questions) {
577 | const speechOutput = requestAttributes.t('TRIVIA_UNHANDLED', ANSWER_COUNT.toString());
578 | const repromptText = speechOutput;
579 | if (supportsDisplay(handlerInput)) {
580 | let payload = {
581 | "phrase": makePage(speechOutput,speechOutput,`${speechOutput}`,firstTransformerList),
582 | "nextPhrase": makePage("none","","",secondTransformerList)
583 | };
584 | speechOutput = "";
585 |
586 | handlerInput.responseBuilder
587 | .addDirective(
588 | {
589 | type: 'Alexa.Presentation.APL.RenderDocument',
590 | version: '1.1',
591 | document : APL_DOC ,
592 | datasources : payload ,
593 | token : TOKEN_ID ,
594 | })
595 | .addDirective (
596 | {
597 | type: 'Alexa.Presentation.APL.ExecuteCommands',
598 | token : TOKEN_ID ,
599 | commands :
600 | [
601 | ONE_PAGER_COMMANDS
602 | ]
603 | });
604 | }
605 | return handlerInput.responseBuilder
606 | .speak(speechOutput)
607 | .reprompt(repromptText)
608 | .getResponse();
609 | }
610 | let speechOutput = requestAttributes.t('HELP_UNHANDLED');
611 | const repromptText = speechOutput;
612 | if (supportsDisplay(handlerInput)) {
613 | let payload = {
614 | "phrase": makePage(speechOutput,speechOutput,`${speechOutput}`,firstTransformerList),
615 | "nextPhrase": makePage("none","","",secondTransformerList)
616 | };
617 | speechOutput = "";
618 | handlerInput.responseBuilder
619 | .addDirective(
620 | {
621 | type: 'Alexa.Presentation.APL.RenderDocument',
622 | version: '1.1',
623 | document : APL_DOC ,
624 | datasources : payload ,
625 | token : TOKEN_ID ,
626 | })
627 | .addDirective (
628 | {
629 | type: 'Alexa.Presentation.APL.ExecuteCommands',
630 | token : TOKEN_ID ,
631 | commands :
632 | [
633 | ONE_PAGER_COMMANDS
634 | ]
635 | });
636 | }
637 | return handlerInput.responseBuilder.speak(speechOutput).reprompt(repromptText).getResponse();
638 | },
639 | };
640 |
641 | const SessionEndedRequest = {
642 | canHandle(handlerInput) {
643 | return handlerInput.requestEnvelope.request.type === 'SessionEndedRequest';
644 | },
645 | handle(handlerInput) {
646 | console.log(`Session ended with reason: ${handlerInput.requestEnvelope.request.reason}`);
647 |
648 | return handlerInput.responseBuilder.getResponse();
649 | },
650 | };
651 |
652 | const AnswerIntent = {
653 | canHandle(handlerInput) {
654 | return handlerInput.requestEnvelope.request.type === 'IntentRequest'
655 | && (handlerInput.requestEnvelope.request.intent.name === 'AnswerIntent'
656 | || handlerInput.requestEnvelope.request.intent.name === 'DontKnowIntent');
657 | },
658 | handle(handlerInput) {
659 | if (handlerInput.requestEnvelope.request.intent.name === 'AnswerIntent') {
660 | return handleUserGuess(false, handlerInput);
661 | }
662 | return handleUserGuess(true, handlerInput);
663 | },
664 | };
665 |
666 | const RepeatIntent = {
667 | canHandle(handlerInput) {
668 | return handlerInput.requestEnvelope.request.type === 'IntentRequest'
669 | && handlerInput.requestEnvelope.request.intent.name === 'AMAZON.RepeatIntent';
670 | },
671 | handle(handlerInput) {
672 | const sessionAttributes = handlerInput.attributesManager.getSessionAttributes();
673 | let speechOutput = sessionAttributes.speechOutput;
674 | let repromptText = sessionAttributes.repromptText;
675 | if (supportsDisplay(handlerInput)) {
676 | let payload = {
677 | "phrase": makePage(speechOutput,repromptText,`${speechOutput}`,firstTransformerList),
678 | "nextPhrase": makePage("none","","",secondTransformerList)
679 | };
680 | speechOutput = "";
681 |
682 | handlerInput.responseBuilder
683 | .addDirective(
684 | {
685 | type: 'Alexa.Presentation.APL.RenderDocument',
686 | version: '1.1',
687 | document : APL_DOC ,
688 | datasources : payload ,
689 | token : TOKEN_ID ,
690 | })
691 | .addDirective (
692 | {
693 | type: 'Alexa.Presentation.APL.ExecuteCommands',
694 | token : TOKEN_ID ,
695 | commands :
696 | [
697 | ONE_PAGER_COMMANDS
698 | ]
699 | });
700 | }
701 |
702 | return handlerInput.responseBuilder.speak(speechOutput)
703 | .reprompt(repromptText)
704 | .getResponse();
705 | },
706 | };
707 |
708 | const YesIntent = {
709 | canHandle(handlerInput) {
710 | return handlerInput.requestEnvelope.request.type === 'IntentRequest'
711 | && handlerInput.requestEnvelope.request.intent.name === 'AMAZON.YesIntent';
712 | },
713 | handle(handlerInput) {
714 | const sessionAttributes = handlerInput.attributesManager.getSessionAttributes();
715 | let speechOutput = sessionAttributes.speechOutput;
716 | let repromptText = sessionAttributes.repromptText;
717 | if (sessionAttributes.questions) {
718 | if (supportsDisplay(handlerInput)) {
719 | let payload = {
720 | "phrase": makePage(speechOutput,repromptText,`${speechOutput}`,firstTransformerList),
721 | "nextPhrase": makePage("none","","",secondTransformerList)
722 | };
723 | speechOutput = "";
724 |
725 | handlerInput.responseBuilder
726 | .addDirective(
727 | {
728 | type: 'Alexa.Presentation.APL.RenderDocument',
729 | version: '1.1',
730 | document : APL_DOC ,
731 | datasources : payload ,
732 | token : TOKEN_ID ,
733 | })
734 | .addDirective (
735 | {
736 | type: 'Alexa.Presentation.APL.ExecuteCommands',
737 | token : TOKEN_ID ,
738 | commands :
739 | [
740 | ONE_PAGER_COMMANDS
741 | ]
742 | });
743 | }
744 |
745 | return handlerInput.responseBuilder.speak(speechOutput)
746 | .reprompt(repromptText)
747 | .getResponse();
748 | }
749 | return startGame(false, handlerInput);
750 | },
751 | };
752 |
753 |
754 | const StopIntent = {
755 | canHandle(handlerInput) {
756 | return handlerInput.requestEnvelope.request.type === 'IntentRequest'
757 | && handlerInput.requestEnvelope.request.intent.name === 'AMAZON.StopIntent';
758 | },
759 | handle(handlerInput) {
760 | const requestAttributes = handlerInput.attributesManager.getRequestAttributes();
761 | let speechOutput = requestAttributes.t('QUIT_MESSAGE');
762 | if (supportsDisplay(handlerInput)) {
763 | let payload = {
764 | "phrase": makePage(speechOutput,speechOutput,`${speechOutput}`,firstTransformerList),
765 | "nextPhrase": makePage("none","","",secondTransformerList)
766 | };
767 | speechOutput = "";
768 |
769 | handlerInput.responseBuilder
770 | .addDirective(
771 | {
772 | type: 'Alexa.Presentation.APL.RenderDocument',
773 | version: '1.1',
774 | document : APL_DOC ,
775 | datasources : payload ,
776 | token : TOKEN_ID ,
777 | })
778 | .addDirective (
779 | {
780 | type: 'Alexa.Presentation.APL.ExecuteCommands',
781 | token : TOKEN_ID ,
782 | commands :
783 | [
784 | ONE_PAGER_COMMANDS
785 | ]
786 | });
787 | }
788 | return handlerInput.responseBuilder.speak(speechOutput)
789 | .withShouldEndSession(true)
790 | .getResponse();
791 | },
792 | };
793 |
794 | const CancelIntent = {
795 | canHandle(handlerInput) {
796 | return handlerInput.requestEnvelope.request.type === 'IntentRequest'
797 | && handlerInput.requestEnvelope.request.intent.name === 'AMAZON.CancelIntent';
798 | },
799 | handle(handlerInput) {
800 | const requestAttributes = handlerInput.attributesManager.getRequestAttributes();
801 | let speechOutput = requestAttributes.t('CANCEL_MESSAGE');
802 | if (supportsDisplay(handlerInput)) {
803 | let payload = {
804 | "phrase": makePage(speechOutput,speechOutput,`${speechOutput}`,firstTransformerList),
805 | "nextPhrase": makePage("none","","",secondTransformerList)
806 | };
807 | speechOutput = "";
808 | handlerInput.responseBuilder
809 | .addDirective(
810 | {
811 | type: 'Alexa.Presentation.APL.RenderDocument',
812 | version: '1.1',
813 | document : APL_DOC ,
814 | datasources : payload ,
815 | token : TOKEN_ID ,
816 | })
817 | .addDirective (
818 | {
819 | type: 'Alexa.Presentation.APL.ExecuteCommands',
820 | token : TOKEN_ID ,
821 | commands :
822 | [
823 | ONE_PAGER_COMMANDS
824 | ]
825 | });
826 | }
827 | return handlerInput.responseBuilder.speak(speechOutput)
828 | .getResponse();
829 | },
830 | };
831 |
832 | const NoIntent = {
833 | canHandle(handlerInput) {
834 | return handlerInput.requestEnvelope.request.type === 'IntentRequest'
835 | && handlerInput.requestEnvelope.request.intent.name === 'AMAZON.NoIntent';
836 | },
837 | handle(handlerInput) {
838 | const requestAttributes = handlerInput.attributesManager.getRequestAttributes();
839 | let speechOutput = requestAttributes.t('NO_MESSAGE');
840 | if (supportsDisplay(handlerInput)) {
841 | let payload = {
842 | "phrase": makePage(speechOutput,"",`${speechOutput}`,firstTransformerList),
843 | "nextPhrase": makePage("none","","",secondTransformerList)
844 | };
845 | speechOutput = "";
846 | handlerInput.responseBuilder
847 | .addDirective(
848 | {
849 | type: 'Alexa.Presentation.APL.RenderDocument',
850 | version: '1.1',
851 | document : APL_DOC ,
852 | datasources : payload ,
853 | token : TOKEN_ID ,
854 | })
855 | .addDirective (
856 | {
857 | type: 'Alexa.Presentation.APL.ExecuteCommands',
858 | token : TOKEN_ID ,
859 | commands :
860 | [
861 | ONE_PAGER_COMMANDS
862 | ]
863 | });
864 | }
865 | return handlerInput.responseBuilder.speak(speechOutput).getResponse();
866 | },
867 | };
868 |
869 | const ErrorHandler = {
870 | canHandle() {
871 | return true;
872 | },
873 | handle(handlerInput, error) {
874 | console.log(`Error handled: ${error.message}`);
875 | let speechOutput = 'Sorry, I can\'t understand the command. Please say again.';
876 | const repromptText = speechOutput;
877 | if (supportsDisplay(handlerInput)) {
878 | let payload = {
879 | "phrase": makePage(speechOutput,speechOutput,`${speechOutput}`,firstTransformerList),
880 | "nextPhrase": makePage("none","","",secondTransformerList)
881 | };
882 | speechOutput = "";
883 | handlerInput.responseBuilder
884 | .addDirective(
885 | {
886 | type: 'Alexa.Presentation.APL.RenderDocument',
887 | version: '1.1',
888 | document : APL_DOC ,
889 | datasources : payload ,
890 | token : TOKEN_ID ,
891 | })
892 | .addDirective (
893 | {
894 | type: 'Alexa.Presentation.APL.ExecuteCommands',
895 | token : TOKEN_ID ,
896 | commands :
897 | [
898 | TWO_PAGER_COMMANDS
899 | ]
900 | });
901 | }
902 | return handlerInput.responseBuilder
903 | .speak(speechOutput)
904 | .reprompt(repromptText)
905 | .getResponse();
906 | },
907 | };
908 |
909 | const skillBuilder = Alexa.SkillBuilders.custom();
910 | exports.handler = skillBuilder
911 | .addRequestHandlers(
912 | LaunchRequest,
913 | HelpIntent,
914 | AnswerIntent,
915 | RepeatIntent,
916 | YesIntent,
917 | StopIntent,
918 | CancelIntent,
919 | NoIntent,
920 | SessionEndedRequest,
921 | FallbackHandler,
922 | UnhandledIntent
923 | )
924 | .addRequestInterceptors(LocalizationInterceptor)
925 | .addErrorHandlers(ErrorHandler)
926 | .lambda();
927 |
--------------------------------------------------------------------------------
/lambda/custom/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "trivia",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "ask-sdk-core": "^2.0.0",
13 | "ask-sdk-model": "^1.0.0",
14 | "i18next": "^10.6.0",
15 | "i18next-sprintf-postprocessor": "^0.2.2"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/lambda/custom/questions.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | /**
3 | * When editing your questions pay attention to your punctuation.
4 | * Make sure you use question marks.
5 | * Make sure the first answer is the correct one.
6 | * Set at least ANSWER_COUNT answers, any extras will be shuffled in.
7 | */
8 | QUESTIONS_EN_GB: [
9 | {
10 | 'Reindeer have very thick coats, how many hairs per square inch do they have?': [
11 | '13,000',
12 | '1,200',
13 | '5,000',
14 | '700',
15 | '1,000',
16 | '120,000',
17 | ],
18 | },
19 | {
20 | 'The 1964 classic Rudolph The Red Nosed Reindeer was filmed in? ': [
21 | 'Japan',
22 | 'United States',
23 | 'Finland',
24 | 'Germany',
25 | 'Canada',
26 | 'Norway',
27 | 'France',
28 | ],
29 | },
30 | {
31 | 'Santas reindeer are cared for by one of the Christmas elves, what is his name?': [
32 | 'Wunorse Openslae',
33 | 'Alabaster Snowball',
34 | 'Bushy Evergreen',
35 | 'Pepper Minstix',
36 | ],
37 | },
38 | {
39 | 'If all of Santas reindeer had antlers while pulling his Christmas sleigh, they would all be? ': [
40 | 'Girls',
41 | 'Boys',
42 | 'Girls and boys',
43 | 'No way to tell',
44 | ],
45 | },
46 | {
47 | 'What do Reindeer eat?': [
48 | 'Lichen',
49 | 'Grasses',
50 | 'Leaves',
51 | 'Berries',
52 | ],
53 | },
54 | {
55 | 'What of the following is not true?': [
56 | 'Caribou live on all continents',
57 | 'Both reindeer and Caribou are the same species',
58 | 'Caribou are bigger than reindeer',
59 | 'Reindeer live in Scandinavia and Russia',
60 | ],
61 | },
62 | {
63 | 'In what year did Rudolph make his television debut?': [
64 | '1964',
65 | '1979',
66 | '2000',
67 | '1956',
68 | ],
69 | },
70 | {
71 | 'Who was the voice of Rudolph in the 1964 classic?': [
72 | 'Billie Mae Richards',
73 | 'Burl Ives',
74 | 'Paul Soles',
75 | 'Lady Gaga',
76 | ],
77 | },
78 | {
79 | 'In 1939 what retailer used the story of Rudolph the Red Nose Reindeer?': [
80 | 'Montgomery Ward',
81 | 'Sears',
82 | 'Macys',
83 | 'Kmart',
84 | ],
85 | },
86 | {
87 | 'Santa\'s reindeer named Donner was originally named what?': [
88 | 'Dunder',
89 | 'Donny',
90 | 'Dweedle',
91 | 'Dreamy',
92 | ],
93 | },
94 | {
95 | 'Who invented the story of Rudolph?': [
96 | 'Robert May',
97 | 'Johnny Marks',
98 | 'Santa',
99 | 'J K Rowling',
100 | ],
101 | },
102 | {
103 | 'In what location will you not find reindeer?': [
104 | 'North Pole',
105 | 'Lapland',
106 | 'Korvatunturi mountain',
107 | 'Finland',
108 | ],
109 | },
110 | {
111 | 'What Makes Santa\'s Reindeer Fly?': [
112 | 'Magical Reindeer Dust',
113 | 'Fusion',
114 | 'Amanita muscaria',
115 | 'Elves',
116 | ],
117 | },
118 | {
119 | 'Including Rudolph, how many reindeer hooves are there?': [
120 | '36',
121 | '24',
122 | '16',
123 | '8',
124 | ],
125 | },
126 | {
127 | 'Santa only has one female reindeer, Which one is it?': [
128 | 'Vixen',
129 | 'Clarice',
130 | 'Cupid',
131 | 'Cupid',
132 | ],
133 | },
134 | {
135 | 'In the 1964 classic Rudolph The Red Nosed Reindeer, what was the snowman narrators name?': [
136 | 'Sam',
137 | 'Frosty',
138 | 'Burl',
139 | 'Snowy',
140 | ],
141 | },
142 | {
143 | 'What was Rudolph\'s father\'s name?': [
144 | 'Donner',
145 | 'Dasher',
146 | 'Blixen',
147 | 'Comet',
148 | ],
149 | },
150 | {
151 | 'In the 1964 movie, What was the name of the coach of the Reindeer Games?': [
152 | 'Comet',
153 | 'Blixen',
154 | 'Donner',
155 | 'Dasher',
156 | ],
157 | },
158 | {
159 | 'In the 1964 movie, what is the name of the deer that Rudolph befriends at the reindeer games?': [
160 | 'Fireball',
161 | 'Clarice',
162 | 'Jumper',
163 | 'Vixen',
164 | ],
165 | },
166 | {
167 | 'In the 1964 movie, How did Donner, Rudolph\'s father, try to hide Rudolph\'s nose?': [
168 | 'Black mud',
169 | 'Bag',
170 | 'Pillow case',
171 | 'Sock',
172 | ],
173 | },
174 | {
175 | 'In the 1964 movie, what does the Misfit Elf want to be instead of a Santa Elf?': [
176 | 'Dentist',
177 | 'Reindeer',
178 | 'Toy maker',
179 | 'Candlestick maker',
180 | ],
181 | },
182 | {
183 | 'In the 1964 movie,what was the Bumble\'s one weakness?': [
184 | 'Could not swim',
185 | 'Always hungry',
186 | 'Candy canes',
187 | 'Cross eyed',
188 | ],
189 | },
190 | {
191 | 'In the 1964 movie, what is Yukon Cornelius really in search of?': [
192 | 'Peppermint',
193 | 'Gold',
194 | 'India',
195 | 'Polar Bears',
196 | ],
197 | },
198 | {
199 | 'In the 1964 movie, why is the train on the Island of Misfit Toys?': [
200 | 'Square wheels',
201 | 'No Engine',
202 | 'Paint does not match',
203 | 'It does not toot',
204 | ],
205 | },
206 | {
207 | 'In the 1964 movie, what is the name of the Jack in the Box?': [
208 | 'Charlie',
209 | 'Sam',
210 | 'Billy',
211 | 'Jack',
212 | ],
213 | },
214 | {
215 | 'In the 1964 movie, why did Santa Claus almost cancel Christmas?': [
216 | 'Storm',
217 | 'No snow',
218 | 'No toys',
219 | 'The Reindeer were sick',
220 | ],
221 | },
222 | {
223 | 'In the 1964 movie, what animal noise did the elf make to distract the Bumble?': [
224 | 'Oink',
225 | 'Growl',
226 | 'Bark',
227 | 'Meow',
228 | ],
229 | },
230 | {
231 | 'In the 1964 movie, what is the name of the prospector?': [
232 | 'Yukon Cornelius',
233 | 'Slider Sam',
234 | 'Bumble',
235 | 'Jack',
236 | ],
237 | },
238 | {
239 | 'How far do reindeer travel when they migrate?': [
240 | '3000 miles',
241 | '700 miles',
242 | '500 miles',
243 | '0 miles',
244 | ],
245 | },
246 | {
247 | 'How fast can a reindeer run?': [
248 | '48 miles per hour',
249 | '17 miles per hour',
250 | '19 miles per hour',
251 | '14 miles per hour',
252 | '52 miles per hour',
253 | '41 miles per hour',
254 | ],
255 | },
256 | ],
257 | QUESTIONS_EN_US: [
258 | {
259 | 'Reindeer have very thick coats, how many hairs per square inch do they have?': [
260 | '13,000',
261 | '1,200',
262 | '5,000',
263 | '700',
264 | '1,000',
265 | '120,000',
266 | ],
267 | },
268 | {
269 | 'The 1964 classic Rudolph The Red Nosed Reindeer was filmed in? ': [
270 | 'Japan',
271 | 'United States',
272 | 'Finland',
273 | 'Germany',
274 | 'Canada',
275 | 'Norway',
276 | 'France',
277 | ],
278 | },
279 | {
280 | 'Santas reindeer are cared for by one of the Christmas elves, what is his name?': [
281 | 'Wunorse Openslae',
282 | 'Alabaster Snowball',
283 | 'Bushy Evergreen',
284 | 'Pepper Minstix',
285 | ],
286 | },
287 | {
288 | 'If all of Santas reindeer had antlers while pulling his Christmas sleigh, they would all be': [
289 | 'Girls',
290 | 'Boys',
291 | 'Girls and boys',
292 | 'No way to tell',
293 | ],
294 | },
295 | {
296 | 'What do Reindeer eat?': [
297 | 'Lichen',
298 | 'Grasses',
299 | 'Leaves',
300 | 'Berries',
301 | ],
302 | },
303 | {
304 | 'What of the following is not true?': [
305 | 'Caribou live on all continents',
306 | 'Both reindeer and Caribou are the same species',
307 | 'Caribou are bigger than reindeer',
308 | 'Reindeer live in Scandinavia and Russia',
309 | ],
310 | },
311 | {
312 | 'In what year did Rudolph make his television debut?': [
313 | '1964',
314 | '1979',
315 | '2000',
316 | '1956',
317 | ],
318 | },
319 | {
320 | 'Who was the voice of Rudolph in the 1964 classic?': [
321 | 'Billie Mae Richards',
322 | 'Burl Ives',
323 | 'Paul Soles',
324 | 'Lady Gaga',
325 | ],
326 | },
327 | {
328 | 'In 1939 what retailer used the story of Rudolph the Red Nose Reindeer?': [
329 | 'Montgomery Ward',
330 | 'Sears',
331 | 'Macys',
332 | 'Kmart',
333 | ],
334 | },
335 | {
336 | 'Santa\'s reindeer named Donner was originally named what?': [
337 | 'Dunder',
338 | 'Donny',
339 | 'Dweedle',
340 | 'Dreamy',
341 | ],
342 | },
343 | {
344 | 'Who invented the story of Rudolph?': [
345 | 'Robert May',
346 | 'Johnny Marks',
347 | 'Santa',
348 | 'J K Rowling',
349 | ],
350 | },
351 | {
352 | 'In what location will you not find reindeer?': [
353 | 'North Pole',
354 | 'Lapland',
355 | 'Korvatunturi mountain',
356 | 'Finland',
357 | ],
358 | },
359 | {
360 | 'What Makes Santa\'s Reindeer Fly?': [
361 | 'Magical Reindeer Dust',
362 | 'Fusion',
363 | 'Amanita muscaria',
364 | 'Elves',
365 | ],
366 | },
367 | {
368 | 'Including Rudolph, how many reindeer hooves are there?': [
369 | '36',
370 | '24',
371 | '16',
372 | '8',
373 | ],
374 | },
375 | {
376 | 'Santa only has one female reindeer, Which one is it?': [
377 | 'Vixen',
378 | 'Clarice',
379 | 'Cupid',
380 | 'Cupid',
381 | ],
382 | },
383 | {
384 | 'In the 1964 classic Rudolph The Red Nosed Reindeer, what was the snowman narrators name?': [
385 | 'Sam',
386 | 'Frosty',
387 | 'Burl',
388 | 'Snowy',
389 | ],
390 | },
391 | {
392 | 'What was Rudolph\'s father\'s name?': [
393 | 'Donner',
394 | 'Dasher',
395 | 'Blixen',
396 | 'Comet',
397 | ],
398 | },
399 | {
400 | 'In the 1964 movie, What was the name of the coach of the Reindeer Games?': [
401 | 'Comet',
402 | 'Blixen',
403 | 'Donner',
404 | 'Dasher',
405 | ],
406 | },
407 | {
408 | 'In the 1964 movie, what is the name of the deer that Rudolph befriends at the reindeer games?': [
409 | 'Fireball',
410 | 'Clarice',
411 | 'Jumper',
412 | 'Vixen',
413 | ],
414 | },
415 | {
416 | 'In the 1964 movie, How did Donner, Rudolph\'s father, try to hide Rudolph\'s nose?': [
417 | 'Black mud',
418 | 'Bag',
419 | 'Pillow case',
420 | 'Sock',
421 | ],
422 | },
423 | {
424 | 'In the 1964 movie, what does the Misfit Elf want to be instead of a Santa Elf?': [
425 | 'Dentist',
426 | 'Reindeer',
427 | 'Toy maker',
428 | 'Candlestick maker',
429 | ],
430 | },
431 | {
432 | 'In the 1964 movie,what was the Bumble\'s one weakness?': [
433 | 'Could not swim',
434 | 'Always hungry',
435 | 'Candy canes',
436 | 'Cross eyed',
437 | ],
438 | },
439 | {
440 | 'In the 1964 movie, what is Yukon Cornelius really in search of?': [
441 | 'Peppermint',
442 | 'Gold',
443 | 'India',
444 | 'Polar Bears',
445 | ],
446 | },
447 | {
448 | 'In the 1964 movie, why is the train on the Island of Misfit Toys?': [
449 | 'Square wheels',
450 | 'No Engine',
451 | 'Paint does not match',
452 | 'It does not toot',
453 | ],
454 | },
455 | {
456 | 'In the 1964 movie, what is the name of the Jack in the Box?': [
457 | 'Charlie',
458 | 'Sam',
459 | 'Billy',
460 | 'Jack',
461 | ],
462 | },
463 | {
464 | 'In the 1964 movie, why did Santa Claus almost cancel Christmas?': [
465 | 'Storm',
466 | 'No snow',
467 | 'No toys',
468 | 'The Reindeer were sick',
469 | ],
470 | },
471 | {
472 | 'In the 1964 movie, what animal noise did the elf make to distract the Bumble?': [
473 | 'Oink',
474 | 'Growl',
475 | 'Bark',
476 | 'Meow',
477 | ],
478 | },
479 | {
480 | 'In the 1964 movie, what is the name of the prospector?': [
481 | 'Yukon Cornelius',
482 | 'Slider Sam',
483 | 'Bumble',
484 | 'Jack',
485 | ],
486 | },
487 | {
488 | 'How far do reindeer travel when they migrate?': [
489 | '3000 miles',
490 | '700 miles',
491 | '500 miles',
492 | '0 miles',
493 | ],
494 | },
495 | {
496 | 'How fast can a reindeer run?': [
497 | '48 miles per hour',
498 | '17 miles per hour',
499 | '19 miles per hour',
500 | '14 miles per hour',
501 | '52 miles per hour',
502 | '41 miles per hour',
503 | ],
504 | },
505 | ],
506 | QUESTIONS_DE_DE: [
507 | {
508 | 'Rentiere haben ein sehr dickes Fell, Wie viele Haare pro Quadratzentimeter haben sie?': [
509 | '13,000',
510 | '1,200',
511 | '5,000',
512 | '700',
513 | '1,000',
514 | '120,000',
515 | ],
516 | },
517 | {
518 | 'Der Klassiker aus dem Jahr 1964, Rudolph mit der roten Nase, wurde gedreht in? ': [
519 | 'Japan',
520 | 'USA',
521 | 'Finnland',
522 | 'Deutschland',
523 | 'Kanada',
524 | 'Norwegen',
525 | 'Frankreich',
526 | ],
527 | },
528 | {
529 | 'Um die Rentiere des Weihnachtsmanns kümmert sich eine der Weihnachtselfen, Wie heißt sie?': [
530 | 'Wunorse Openslae',
531 | 'Alabaster Snowball',
532 | 'Bushy Evergreen',
533 | 'Pfeffer Minstix',
534 | ],
535 | },
536 | {
537 | 'Wenn alle Rentiere des Weihnachtsmanns Geweihe hätten, während sie seinen Weihnachtsschlitten ziehen, wären sie alle ': [
538 | 'Weiblich',
539 | 'Männlich',
540 | 'Weiblich und männlich',
541 | 'Kann man nicht sagen',
542 | ],
543 | },
544 | {
545 | 'Was essen Rentiere?': [
546 | 'Flechten',
547 | 'Gras',
548 | 'Blätter',
549 | 'Beeren',
550 | ],
551 | },
552 | {
553 | 'Welche Aussage ist nicht richtig?': [
554 | 'Karibus leben auf allen Kontinenten',
555 | 'Karibus und Rentiere gehören derselben Gattung an ',
556 | 'Karibus sind größer als Rentiere',
557 | 'Rentiere leben in Skandinavien und Russland',
558 | ],
559 | },
560 | {
561 | 'In welchem Jahr kam Rudolph ins Fernsehen?': [
562 | '1964',
563 | '1979',
564 | '2000',
565 | '1956',
566 | ],
567 | },
568 | {
569 | 'Wer war der Sprecher für Rudolph im klassischen Film aus dem Jahr 1964?': [
570 | 'Billie Mae Richards',
571 | 'Burl Ives',
572 | 'Paul Soles',
573 | 'Lady Gaga',
574 | ],
575 | },
576 | {
577 | 'Welche Handelskette verwendete 1939 die Geschichte von Rudolph mit der roten Nase?': [
578 | 'Montgomery Ward',
579 | 'Sears',
580 | 'Macys',
581 | 'Kmart',
582 | ],
583 | },
584 | {
585 | 'Wie hieß das Rentier des Weihnachtsmanns namens Donner ursprünglich?': [
586 | 'Dunder',
587 | 'Donny',
588 | 'Dweedle',
589 | 'Dreamy',
590 | ],
591 | },
592 | {
593 | 'Wer hat die Geschichte von Rudolph erfunden?': [
594 | 'Robert May',
595 | 'Johnny Marks',
596 | 'Santa',
597 | 'J K Rowling',
598 | ],
599 | },
600 | {
601 | 'Wo findest du keine Rentiere?': [
602 | 'Nordpol',
603 | 'Lappland',
604 | 'Korvatunturi Berge',
605 | 'Finnland',
606 | ],
607 | },
608 | {
609 | 'Warum können die Rentiere des Weihnachtsmanns fliegen?': [
610 | 'Magischer Staub der Rentiere',
611 | 'Fusion',
612 | 'Amanita muscaria',
613 | 'Elfen',
614 | ],
615 | },
616 | {
617 | 'Wieviele Rentierhufe gibt es hier einschließlich Rudolph?': [
618 | '36',
619 | '24',
620 | '16',
621 | '8',
622 | ],
623 | },
624 | {
625 | 'Der Weihnachtsmann hat nur ein weibliches Rentier, Wie heißt es?': [
626 | 'Blitzen',
627 | 'Clarice',
628 | 'Cupid',
629 | 'Cupid',
630 | ],
631 | },
632 | {
633 | 'Wie war der Name des erzählenden Schneemanns im klassischen Film Rudolph mit der roten Nase aus dem Jahr 1964?': [
634 | 'Sam',
635 | 'Frosty',
636 | 'Burl',
637 | 'Snowy',
638 | ],
639 | },
640 | {
641 | 'Wie hieß der Vater von Rudolph?': [
642 | 'Donner',
643 | 'Dasher',
644 | 'Blixen',
645 | 'Comet',
646 | ],
647 | },
648 | {
649 | 'Wie war der Name des Trainers der Rentierspiele im klassischen Film aus dem Jahr 1964?': [
650 | 'Comet',
651 | 'Blixen',
652 | 'Donner',
653 | 'Dasher',
654 | ],
655 | },
656 | {
657 | 'Wie war im klassichen Film aus 1964 der Name des Hirsches, mit dem sich Rudolph befreundete?': [
658 | 'Fireball',
659 | 'Clarice',
660 | 'Jumper',
661 | 'Vixen',
662 | ],
663 | },
664 | {
665 | 'Wie hat der Vater von Rudolph, Donner, im Film aus dem Jahr 1964 versucht, die Nase von Rudolph zu verbergen?': [
666 | 'Schwarzer Schlamm',
667 | 'Sack',
668 | 'Kissenbezug',
669 | 'Socke',
670 | ],
671 | },
672 | {
673 | 'Was möchte die Misfit Elfe im Film aus dem Jahr 1964 werden anstatt eine Elfe für den Weihnachtsmann?': [
674 | 'Zahnarzt',
675 | 'Rentier',
676 | 'Spielzeugmacher',
677 | 'Kerzenmacher',
678 | ],
679 | },
680 | {
681 | 'Was war die einzige Schwäche von Bumble im Film aus dem Jahr 1964?': [
682 | 'Konnte nicht schwimmen',
683 | 'War immer hungrig',
684 | 'Zuckerstangen',
685 | 'Schielte',
686 | ],
687 | },
688 | {
689 | 'Was sucht Yukon Cornelius in Wirklichkeit im Film aus dem Jahr 1964?': [
690 | 'Pfefferminz',
691 | 'Gold',
692 | 'Indien',
693 | 'Polarbären',
694 | ],
695 | },
696 | {
697 | 'Warum befindet sich der Zug im Film aus dem Jahr 1964 auf der Insel des fehlerhaften Spielzeugs?': [
698 | 'Viereckige Räder',
699 | 'Keine Dampfmaschine',
700 | 'Farbe stimmt nicht',
701 | 'Pfeift nicht',
702 | ],
703 | },
704 | {
705 | 'Wie lautet der Name des Schachtelmännchens im Film aus dem Jahr 1964?': [
706 | 'Charlie',
707 | 'Sam',
708 | 'Billy',
709 | 'Jack',
710 | ],
711 | },
712 | {
713 | 'Warum hat der Weihnachtsmann im Film aus dem Jahr 1964 Weihnachten beinahe abgesagt?': [
714 | 'Sturm',
715 | 'Kein Schnee',
716 | 'Kein Spielzeug',
717 | 'Die Rentiere waren krank',
718 | ],
719 | },
720 | {
721 | 'Welches tierische Geräusch machte die Elfe im Film aus dem Jahr 1964, um den Bumble abzulenken?': [
722 | 'Oink',
723 | 'Knurr',
724 | 'Wauwau',
725 | 'Miau',
726 | ],
727 | },
728 | {
729 | 'Wie lautet der Name des Goldsuchers im Film aus dem Jahr 1964?': [
730 | 'Yukon Cornelius',
731 | 'Slider Sam',
732 | 'Bumble',
733 | 'Jack',
734 | ],
735 | },
736 | {
737 | 'Wie weit ziehen Rentiere auf ihren Wanderungen?': [
738 | '4800 km',
739 | '1100 km',
740 | '800 km',
741 | '0 km',
742 | ],
743 | },
744 | {
745 | 'Wie schnell läuft ein Rentier?': [
746 | '77 km pro Stunde',
747 | '27 km pro Stunde',
748 | '30 km pro Stunde',
749 | '22 km pro Stunde',
750 | '83 km pro Stunde',
751 | '65 km pro Stunde',
752 | ],
753 | },
754 | ],
755 | };
756 |
--------------------------------------------------------------------------------
/models/de-DE.json:
--------------------------------------------------------------------------------
1 | {
2 | "interactionModel": {
3 | "languageModel": {
4 | "invocationName": "spiel",
5 | "intents": [
6 | {
7 | "name": "AnswerIntent",
8 | "slots": [
9 | {
10 | "name": "Answer",
11 | "type": "AMAZON.NUMBER"
12 | }
13 | ],
14 | "samples": [
15 | "die Antwort ist {Answer}",
16 | "meine Antwort ist {Answer}",
17 | "ist die Antwort {Answer}",
18 | "{Answer} ist meine Antwort",
19 | "{Answer}"
20 | ]
21 | },
22 | {
23 | "name": "DontKnowIntent",
24 | "samples": [
25 | "weiß ich nicht",
26 | "weiß nicht",
27 | "überspringen",
28 | "das weiß ich nicht",
29 | "wer weiß",
30 | "diese Frage weiß ich nicht",
31 | "die weiß ich nicht",
32 | "keine Ahnung"
33 | ]
34 | },
35 | {
36 | "name": "AMAZON.StartOverIntent",
37 | "samples": [
38 | "Spiel starten",
39 | "neues Spiel",
40 | "starten",
41 | "neues Spiel starten"
42 | ]
43 | },
44 | {
45 | "name": "AMAZON.RepeatIntent"
46 | },
47 | {
48 | "name": "AMAZON.HelpIntent"
49 | },
50 | {
51 | "name": "AMAZON.YesIntent"
52 | },
53 | {
54 | "name": "AMAZON.NoIntent"
55 | },
56 | {
57 | "name": "AMAZON.StopIntent"
58 | },
59 | {
60 | "name": "AMAZON.CancelIntent"
61 | }
62 | ]
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/models/en-GB.json:
--------------------------------------------------------------------------------
1 | {
2 | "interactionModel": {
3 | "languageModel": {
4 | "invocationName": "game",
5 | "intents": [
6 | {
7 | "name": "AnswerIntent",
8 | "slots": [
9 | {
10 | "name": "Answer",
11 | "type": "AMAZON.NUMBER"
12 | }
13 | ],
14 | "samples": [
15 | "the answer is {Answer}",
16 | "my answer is {Answer}",
17 | "is it {Answer}",
18 | "{Answer} is my answer",
19 | "{Answer}"
20 | ]
21 | },
22 | {
23 | "name": "DontKnowIntent",
24 | "samples": [
25 | "i don't know",
26 | "don't know",
27 | "skip",
28 | "i don't know that",
29 | "who knows",
30 | "i don't know this question",
31 | "i don't know that one",
32 | "dunno"
33 | ]
34 | },
35 | {
36 | "name": "AMAZON.StartOverIntent",
37 | "samples": [
38 | "start game",
39 | "new game",
40 | "start",
41 | "start new game"
42 | ]
43 | },
44 | {
45 | "name": "AMAZON.RepeatIntent"
46 | },
47 | {
48 | "name": "AMAZON.HelpIntent"
49 | },
50 | {
51 | "name": "AMAZON.YesIntent"
52 | },
53 | {
54 | "name": "AMAZON.NoIntent"
55 | },
56 | {
57 | "name": "AMAZON.StopIntent"
58 | },
59 | {
60 | "name": "AMAZON.CancelIntent"
61 | }
62 | ]
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/models/en-US.json:
--------------------------------------------------------------------------------
1 | {
2 | "interactionModel": {
3 | "languageModel": {
4 | "invocationName": "reindeer trivia",
5 | "intents": [
6 | {
7 | "name": "AMAZON.FallbackIntent",
8 | "samples": []
9 | },
10 | {
11 | "name": "AMAZON.CancelIntent",
12 | "samples": []
13 | },
14 | {
15 | "name": "AMAZON.HelpIntent",
16 | "samples": []
17 | },
18 | {
19 | "name": "AMAZON.StopIntent",
20 | "samples": []
21 | },
22 | {
23 | "name": "AnswerIntent",
24 | "samples": [
25 | "the answer is {Answer}",
26 | "my answer is {Answer}",
27 | "is it {Answer}",
28 | "{Answer} is my answer",
29 | "{Answer}"
30 | ],
31 | "slots": [
32 | {
33 | "name": "Answer",
34 | "type": "AMAZON.NUMBER",
35 | "samples": []
36 | }
37 | ]
38 | },
39 | {
40 | "name": "DontKnowIntent",
41 | "samples": [
42 | "i don't know",
43 | "don't know",
44 | "i don't know that one",
45 | "dunno",
46 | "skip",
47 | "i don't know that",
48 | "who knows",
49 | "i don't know this question"
50 | ],
51 | "slots": []
52 | },
53 | {
54 | "name": "AMAZON.StartOverIntent",
55 | "samples": [
56 | "start game",
57 | "new game",
58 | "start",
59 | "start new game"
60 | ]
61 | },
62 | {
63 | "name": "AMAZON.RepeatIntent"
64 | },
65 | {
66 | "name": "AMAZON.YesIntent"
67 | },
68 | {
69 | "name": "AMAZON.NoIntent"
70 | }
71 | ]
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/skill.json:
--------------------------------------------------------------------------------
1 | {
2 | "skillManifest": {
3 | "publishingInformation": {
4 | "locales": {
5 | "en-US": {
6 | "summary": "Sample Short Description",
7 | "examplePhrases": [
8 | "Alexa open reindeer trivia",
9 | "Alexa tell reindeer trivia to start a game",
10 | "Alexa tell reindeer trivia I want to play"
11 | ],
12 | "name": "reindeer trivia",
13 | "description": "Sample Full Description"
14 | }
15 | },
16 | "isAvailableWorldwide": true,
17 | "testingInstructions": "Sample Testing Instructions.",
18 | "distributionCountries": []
19 | },
20 | "apis": {
21 | "custom": {
22 | "endpoint": {
23 | "sourceDir": "lambda/custom",
24 | "uri": "ask-custom-trivia-default"
25 | }
26 | }
27 | },
28 | "manifestVersion": "1.0"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------