AdventureBot is an Amazon Alexa Skill for powering voice-based adventures on Alexa-enabled devices. AdventureBot includes a game library, an AWS lambda function, a command line utility, and an Alexa Skill definition to get you going as quickly as possible.
The following tools and accounts are required to complete these instructions.
- Install .NET Core 2.1
- Install AWS CLI
- Sign-up for an AWS account
- Sign-up for an Amazon developer account
- Setup LambdaSharp Tool
- Clone or download the GitHub repository:
https://github.com/LambdaSharp/Alexa-AdventureBot-Challenge
- Change folder to the command line project:
cd Alexa-AdventureBot-Challenge/AdventureBot.Cli
- Run app with a sample file:
dotnet run ../assets/adventures/my-demo-adventure.yml
NOTE:
type
quit
to exit
Set AWS Profile and λ# Tool
-
If you haven't already done so, configure your AWS profile using:
aws configure
NOTE:
AWS Lambda functions for Alexa Skills must be deployed in
us-east-1
-
Verify your λ# tool setup by listing the deployed modules:
lash list --tier Demo
NOTE:
With the the
LAMBDASHARPTIER
environment variable you can omit the--tier
command line option.
The following text should appear (or similar):
$ lash list --tier Demo
MindTouch LambdaSharp Tool (v0.2) - List LambdaSharp modules
MODULE STATUS DATE
LambdaSharp [UPDATE_COMPLETE] 2018-08-06 05:18:40
LambdaSharpS3PackageLoader [UPDATE_COMPLETE] 2018-08-06 23:23:55
Found 2 modules for deployment tier 'Demo'
Deploy AdventureBot
The AdventureBot code is packaged as a λ# module, which streamlines the creating, configuring, and uploading of assets for serverless applications.
- Switch to the git checkout folder
- Run the λ# tool to deploy AdventureBot:
lash deploy --tier Demo
Once complete, the λ# tool will have taken care of the following steps for you:
- Create the AdventureBot Lambda function (
AdventureBot.Alexa
) - Configure the Lambda function to use
my-demo-adventure.yml
- Create the S3 Bucket to hold the adventure and sound files (
AdventureBucket
) - Upload the adventure and sound files to the S3 Bucket
- Create a public access policy for the sound files (required by sound playback) (
SoundFilesPolicy
) - Create the DynamoDB table to hold the player state (
PlayerTable
) - Create the AdventureBot End-of-Adventure SNS Topic (
AdventureFinishedTopic
)
Test Lambda Function
- Open the AWS Console.
- Go to the deployed Lambda function.
- Click on the
Test
button and the top right corner. - Add the following test event:
{ "session": { "new": true, "sessionId": "amzn1.echo-api.session.123", "attributes": {}, "user": { "userId": "amzn1.ask.account.123" }, "application": { "applicationId": "amzn1.ask.skill.123" } }, "version": "1.0", "request": { "locale": "en-US", "timestamp": "2016-10-27T18:21:44Z", "type": "LaunchRequest", "requestId": "amzn1.echo-api.request.123" }, "context": { "AudioPlayer": { "playerActivity": "IDLE" }, "System": { "device": { "supportedInterfaces": { "AudioPlayer": {} } }, "application": { "applicationId": "amzn1.ask.skill.123" }, "user": { "userId": "amzn1.ask.account.123" } } } }
- Click Save.
- Click Test.
- After a few seconds you should see the following log output:
START RequestId: 68ae2de4-9f22-11e8-af75-9dfa5dec067f Version: $LATEST *** INFO: function age: 00:00:00.2227575 [00:00:00.0032438] *** INFO: function invocation counter: 1 [00:00:00.0601929] *** INFO: start function initialization [00:00:00.0602282] *** INFO: TIER = test [00:00:00.1021029] *** INFO: MODULE = AdventureBot [00:00:00.1399067] *** INFO: DEADLETTERQUEUE = https://sqs.us-east-1.amazonaws.com/123456789012/Demo-LambdaSharp-DeadLetterQueue-CLS0Z58PDNF7 [00:00:00.1399346] *** INFO: LOGGINGTOPIC = arn:aws:sns:us-east-1:123456789012:Demo-LambdaSharp-LoggingTopic-HRHBCQ2CIG5I [00:00:00.1399503] *** INFO: GITSHA = 016eb793458915e09e37aa98831696919803b946 [00:00:00.1401559] *** INFO: ROLLBAR = DISABLED [00:00:03.1799579] *** INFO: ADVENTURE_FILE = s3://demo-adventurebot-adventurebucket-7lvk4gdds7ei/Adventures/my-demo-adventure.yml [00:00:03.3615716] *** INFO: SOUND_FILES = https://demo-adventurebot-adventurebucket-7lvk4gdds7ei.s3.amazonaws.com/Sounds/ [00:00:03.3799610] *** INFO: end function initialization [00:00:03.3800065] *** INFO: no previous state found in player table [00:00:14.2404703] *** INFO: new player session started [00:00:14.2598708] *** INFO: player status: New [00:00:14.2602678] *** INFO: launch [00:00:14.2602949] *** INFO: storing state in player table {"RecordId":"resume-38ed755cbe3288b2c875a0413d51b683","CurrentPlaceId":"start","Status":1,"Start":"2018-08-13T17:58:13.1550708Z","End":null,"AdventureAttempts":1,"CommandsIssued":2} [00:00:15.0230883] *** INFO: invocation completed [00:00:15.4424319] END RequestId: 68ae2de4-9f22-11e8-af75-9dfa5dec067f REPORT RequestId: 68ae2de4-9f22-11e8-af75-9dfa5dec067f Duration: 15942.98 ms Billed Duration: 16000 ms Memory Size: 128 MB Max Memory Used: 42 MB
The following steps set up the Alexa Skill with an invocation name, a predefined set of voice commands, and associates it with the AdventureBot lambda function.
Setup Alexa Skill
- Sign-up for an Amazon developer account
- Log into the Amazon Developer Console
- Click on the
Alexa
logo - Click on
Alexa Skill Kit
under Add Capabilities to Alexa - Click on
Start a Skill
- Click on
Create Skill
- Enter the skill name:
AdventureBot
- Click on
Create Skill
- Interaction Model
- Click on
JSON Editor
in the left navigation - Upload
assets/alexa-skill.json
file - Click
Save Model
- Click
Build Model
(this will take a minutes)
- Click on
- Endpoint
- Select
AWS Lambda ARN
option - Under
Default Region
paste the Lambda ARN:arn:aws:lambda:us-east-1:******:function:Demo-AdventureBot-Alexa
NOTE:
the Lambda ARN can be found on the top right corner of the AWS Console after selecting the Lambda function
- Click
Save Endpoints
- Select
- Test
- Click on
Test
in the top banner - Enable
Test is enabled for this skill
- Click on
- Congratulations!! Your Alexa Skill is now available on all your registered Alexa-devices and Alexa-enabled apps.
- For Alexa devices, say:
Alexa, open Adventure Bot
- For the Amazon Alexa app, click the microphone icon, and say:
open Adventure Bot
- For the Alexa Developer Console, type in
open adventure bot
- Then say,
describe
,hint
,yes
, or any other custom and built-in intents. - Say
quit
to exit the skill.
- For Alexa devices, say:
This part is left as an exercise to the reader.
Modify AdventureBot so that it sends out a SNS message when a player completes an adventure. Track how long it took for the player to complete, how many place where visited, and any other statistics you think would be insightful to understand your players.
This part is left as an exercise to the reader.
AdventureBot uses Alexa session state to track players through their exploration. However, when the session ends, the player state is lost. Add code to AdventureBot to store the player's state in DynamoDB. Detect at the beginning of a new session if the player has an unfinished adventure and offer to resume or restart instead.
This part is left as an exercise to the reader.
Create your own adventure and showcase it!
Hint
- Take a look at the
asserts/adventures/my-demo-adventure.yml
file - If you change the name of the file, make sure to update the
AdventureFile
parameter in theDeploy.yml
file
The AdventureBot uses a simple JSON file to define places. Each place has a description and a list of choices that are available to the player.
The main object has only one field called places
.
places:
PlaceDefinition
- places
-
Map of place IDs to place objects. This map must contain a place called start.
Required: Yes
Type: Map of Place Definitions
The place object has multiple fields.
name:
description: String
instructions: String
choices:
ChoiceDefinition
- description
-
Text describing the place/situation the player is in. This text is automatically read when the player first enters a place and can be repeated with the built-in *describe* command.
Required: Yes
Type: String
- instructions
-
Text describing the actions the player can provide. This text is automatically read when the player first enters a place and can be repeated with the built-in *help* command.
Required: Yes
Type: String
- finished
-
Boolean indicating that the place marks the end of an adventure. The value is false by default.
Required: No
Type: Boolean
- choices
-
Map of choices to actions the player can make.
Required: Yes
Type: Map of Choice Definitions
The choice object associates a command with zero or more actions. The field name must be one of the recognized commands:
"one"
through"nine"
"yes"
and"no"
"help"
"hint"
"restart"
"quit"
yes:
- ActionDefinition
no:
- ActionDefinition
The action object associates an action with an argument. The field name must be one of the recognized actions:
"say"
: Says one or more sentences"pause"
: Pause the output for a while"play"
: Play an MP3 file"goto"
: Go to place
The say action converts text into speech.
say: You open the door.
The pause action is delays further speech for the specified duration in seconds.
pause: 0.5
The play action plays back an MP3 file. Note the MP3 file must satisfy certain conditions (see APPENDIX B - Sound File Format).
play: door-close.mp3
The goto action changes the place a player is in. The new place is described at the end of the commands.
goto: name-of-place
The MP3 file must satisfy the following conditions:
- The MP3 must be hosted at an Internet-accessible HTTPS endpoint. HTTPS is required, and the domain hosting the MP3 file must present a valid, trusted SSL certificate. Self-signed certificates cannot be used.
- The MP3 must not contain any customer-specific or other sensitive information.
- The MP3 must be a valid MP3 file (MPEG version 2).
- The audio file cannot be longer than ninety (90) seconds.
- The bit rate must be 48 kbps. Note that this bit rate gives a good result when used with spoken content, but is generally not a high enough quality for music.
- The MP3 sample rate must be 16000 Hz.
A good source of free samples can be found at SoundEffects+.
Alexa compatible MP3 can be produced with the ffmpeg
utility:
ffmpeg -i <source-file> -ac 2 -codec:a libmp3lame -b:a 48k -ar 16000 <destination-file>
This challenge was made possible by the excellent of Tim Heuer who wrote the outstanding Alexa.NET library!
- Copyright (c) 2018 MindTouch, Inc.
- Apache 2.0