Skip to content
This repository has been archived by the owner on Feb 21, 2023. It is now read-only.

Commit

Permalink
First commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
Jamison committed Aug 1, 2016
0 parents commit 39e692b
Show file tree
Hide file tree
Showing 80 changed files with 6,627 additions and 0 deletions.
53 changes: 53 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# OS generated files
.DS_Store*
ehthumbs.db
Icon?
Thumbs.db
.idea

# Logs and databases
*.log

# ignore compiled files
dest/
*.com
*.class
*.dll
*.exe
*.o
*.so

# ignore packaged files
*.crx
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip

# Media Files
*.avi
*.swf
*.flv
*.mpg
*.mpe
*.mpeg
*.m4v
*.mp4
*.mp3
*.mov
*.webm
*.ogg
*.ogv

# Dependancies
dist/
docs/
report/
node_modules/
jspm_packages/
bower_components/
.tmp/
37 changes: 37 additions & 0 deletions Config
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# -*-perl-*-

package.ADXDT-Alexa-Skill-Decision-Tree-Editor = {
interfaces = (1.0);

deploy = {
generic = true;
};

build-environment = {
chroot = basic;
network-access = blocked;
};

# Use NoOpBuild. See https://w.amazon.com/index.php/BrazilBuildSystem/NoOpBuild
build-system = no-op;
build-tools = {
1.0 = {
NoOpBuild = 1.0;
};
};

# Use runtime-dependencies for when you want to bring in additional
# packages when deploying.
# Use dependencies instead if you intend for these dependencies to
# be exported to other packages that build against you.
dependencies = {
1.0 = {
};
};

runtime-dependencies = {
1.0 = {
};
};

};
1 change: 1 addition & 0 deletions Procfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
web: node index.js
118 changes: 118 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Interactive Adventure Game Tool

This tool provides an easy to use front-end that allows developers to instantly deploy code for your story, or use the generated code as a starting point for more complex projects. It was written in Node.js by Thomas Yuill, a designer and engineer in the Amazon Advertising team.

![alt text](https://cloud.githubusercontent.com/assets/7671574/17307374/9d0a7b72-57e9-11e6-917b-d2b1c4f542c2.png "Interactive Adventure Game Tool Screenshot")

## How to Get Started

Setup AWS and the Amazon Developer Console

To get started with the included sample project, you'll need to setup a few pre-requisites:

* The tool generates Node.js code that will be deployed to AWS Lambda to handle requests from users passed to you from the Alexa platform. 
* The skill uses a table in AWS DynamoDB to save the user's progress between sessions.  
* You can then register your skill with Alexa using the Amazon Developer website, linking it to your AWS resources.

You can change the name of these resources to whatever you like later, but for now, setup the following items:

1. Create or login to an AWS account. In the AWS Console:
1. Create an AWS role with full access to Lambda and DynamoDB.
1. Create an AWS Lambda function named MyAlexaSkillLambdaFunction being sure to select the role created above and configuring "Alexa Skills Kit" as the "Event Source".  Take note of the ARN on the upper right, which you'll configure in the Developer Console later.

![alt text](https://cloud.githubusercontent.com/assets/7671574/17307511/66788fda-57ea-11e6-909a-903ef4194b19.png "AWS Lambda Role Screenshot")

![alt text](https://cloud.githubusercontent.com/assets/7671574/17307542/8735226a-57ea-11e6-973a-673aa754ee8a.png "AWS Lambda Event Source Screenshot")

1. Create an AWS DynamoDB table named MyAlexaSkillTable with the case sensitive primary key "userId".

![alt text](https://cloud.githubusercontent.com/assets/7671574/17307587/b80787f2-57ea-11e6-9be2-3df26e8e5947.png "AWS DynamoDB Screenshot")

1. Create or login to an [Amazon Developer account](https://developer.amazon.com).  In the Developer Console:
1. [Create an Alexa Skill](https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/developing-an-alexa-skill-as-a-lambda-function) named MySkill and using the invocation name "my skill" and using the ARN you noted above.

![alt text](https://cloud.githubusercontent.com/assets/7671574/17307653/13500166-57eb-11e6-844d-1083efa3dddb.png "Developer Portal Skill Information Screenshot")

![alt text](https://cloud.githubusercontent.com/assets/7671574/17307655/167433a8-57eb-11e6-9951-822ad2243f11.png "Developer Portal Configuration Screenshot")

## Set up Your Machine

Next, you'll setup your local environment to run the tool.  It's run using Node.js and you access it with a standard web browser.  On OS X:

1. Configure AWS credentials the tool will use to upload code to your Skill.  You do this by creating a file under a ".aws" directory in your home directory.

```
mkdir ~/.aws/
touch ~/.aws/credentials
```
2. The file should have the format, and include keys you retrieve from the AWS console:
```
[default]
aws_access_key_id = [KEY FROM AWS]
aws_secret_access_key = [SECRET KEY FROM AWS]
```
2. Setup NodeJS and NPM:
```
brew install node
```
3. Get the code and install dependencies:
```
git clone https://github.com/alexa/interactive-adventure-game-tool.git
npm install
```
4. Launch:
```
npm start
```
## Using the Tool
Once the tool opens in a browser window, you'll see that a sample project is pre-loaded that shows off the main features of the tool.
On the left, you'll see a tree of nodes, which represents how users will navigate your skill.  Users start at the big blue "Start" node.
The smaller bubbles above each node represents the utterance, a phrase the user will say to reach that node, and Alexa will read these to the user when they reach the parent node unless you override this using "Override Default Prompt" or if the node is hidden (see below).
In the sample skill, an example interaction with Alexa might be:
```
User:  Alexa, launch My Alexa Skill.
Alexa:  Welcome to my Alexa Skill.  To learn how to use this skill, say "Help".  When you are ready, say "Begin".
User:  Begin
Alexa:  You enter a room with three doors, each with a distinct number on it. Which door would you like to open?
```
If you select a node, you can see the Voice and Card elements on the right that Alexa will send/say to the user upon reaching the node.
Under the "Advanced" options, you can change the color of the node to help you organize (colors don't change the behavior of your skill) and you can "hide" nodes, causing Alexa to skip reading their utterance as part of the default prompt of the parent.
If you click on an utterance, you can enter multiple variations of the phrase that will also be accepted by Alexa.  Only the first one will be read to the user in the default prompt.
Lastly, the icons on the upper right allow you to:
* ![alt text](https://cloud.githubusercontent.com/assets/7671574/17307920/48d152f8-57ec-11e6-9bdd-f24c9695ce49.png "Save Icon") Save the Skill code, which will be output to "./src/skill". 
* ![alt text](https://cloud.githubusercontent.com/assets/7671574/17307929/515c27ae-57ec-11e6-8347-3736778f1b41.png "Upload Icon")
Upload the Skill code to the Lambda function you configured earlier.  You can configure the function name by clicking the home icon and changing the values under "AWS Settings".
* ![alt text](https://cloud.githubusercontent.com/assets/7671574/17307932/53fc7e50-57ec-11e6-8019-00fa8054e53e.png "Help Icon") See help content for the tool.
![alt text](https://cloud.githubusercontent.com/assets/7671574/17307977/8888955a-57ec-11e6-90aa-334bf4467119.png "Interactive Adventure Game Tool Main Panel Screenshot")
![alt text](https://cloud.githubusercontent.com/assets/7671574/17307979/8ba30248-57ec-11e6-89ed-ae05c2a934ff.png "Interactive Adventure Game Tool Voice Panel Screenshot")
## Finishing Deployment of Your Skill
Click the "Save" icon (if you haven't already), and the "Upload" icon to send the Skill code up to Lambda.  When you save the Skill, the tool generates some additional configuration inside "./src/skill/models/" that you'll use to tell Alexa how users will interact with you Skill.
You'll need to complete the configuration manually by logging into the [Developer Console](https://developer.amazon.com) and accessing the "My Alexa Skill" you created above.  On the "Interaction Model" tab, copy and paste the Intent Schema from "./src/skill/models/intentSchema.json" and Sample Utterances from "./src/skill/models/utterances.txt".
Click save, and the Skill should now be available on your developer account.  If your Alexa device is associated with the same Amazon account as your Developer Console account, then you can start using the skill immediately.  Or you can use it on the [online simulator](https://echosim.io) by logging in using the same account.
Congrats!  Enjoy and let your imagination run wild, we can't wait to see what you come up with!
5 changes: 5 additions & 0 deletions event.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"key": "value",
"key2": "value2",
"other_key": "other_value"
}
6 changes: 6 additions & 0 deletions gulp-tasks/_default.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
var gulp = require('gulp');
var runSequence = require('run-sequence');

gulp.task('default', function () {
runSequence(['styles','tags'],'serve');
});
151 changes: 151 additions & 0 deletions gulp-tasks/_generate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
var fs = require('fs')
var gulp = require('gulp')
var $ = require('gulp-load-plugins')()

gulp.task('generate', function ( cb ) {

var config = JSON.parse(fs.readFileSync('./src/skill/models/config.json','utf8'))
var scenes = JSON.parse(fs.readFileSync('./src/skill/models/scenes.json','utf8'))
var intentSchema = {}

return new Promise( function ( resolve, reject ) {

var intentNames = new Set()
var functionDefs = {}
var utterances = []

intentSchema.intents = [{ intent: 'UnrecognizedIntent' }]
utterances.push.apply( utterances, [
'UnrecognizedIntent ThisIsPurposlyNonSense',
'UnrecognizedIntent ThisIsPurposlyNonSense ThisIsPurposlyNonSense',
'UnrecognizedIntent ThisIsPurposlyNonSense ThisIsPurposlyNonSense ThisIsPurposlyNonSense',
'UnrecognizedIntent ThisIsPurposlyNonSense ThisIsPurposlyNonSense ThisIsPurposlyNonSense ThisIsPurposlyNonSense',
'UnrecognizedIntent ThisIsPurposlyNonSense ThisIsPurposlyNonSense ThisIsPurposlyNonSense ThisIsPurposlyNonSense ThisIsPurposlyNonSense'
])

// process commands from config.json
Object.keys( config.commands ).forEach( function( intent ) {
functionDefs[ intent ] = createFunctionDefinition( intent, config.commands[ intent ][0] )
config.commands[ intent ].forEach( function ( utterance ) {
utterance = replaceIntegersWithWords( utterance )
utterances.push( intent + ' ' + utterance )
intentNames.add( intent )
})
})

// process scenes from script/.json
scenes.forEach( function( scene ) {
if ( ! scene.options ) return // exit
scene.options.forEach( function( option ) {
var intent = createIntentName(replaceIntegersWithWords( option.utterances[0] ))
functionDefs[ intent ] = createFunctionDefinition( intent, option.utterances[0] )
intentNames.add( intent )
option.utterances.forEach( utterance => {
utterance = replaceIntegersWithWords( utterance )
utterances.push( intent + ' ' + utterance )
})
})
})

// construct intent schema
for ( var name in functionDefs ) {
var intentExists = intentSchema.intents.find( function ( intent ) {
return ( intent.intent === name )
})
if ( ! intentExists ) {
intentSchema.intents.push({ intent: name, })
}
}

// write generated intents
functionDefsWriteStream = fs.createWriteStream('./src/skill/handlers/intentHandlers_generated.js')
functionDefsWriteStream.on('open', function () {
functionDefsWriteStream.write('var processUtterance = require(\'./processUtterance\')\n\n')
functionDefsWriteStream.write('module.exports = {\n')
for ( var name in functionDefs ) {
functionDefsWriteStream.write( '\t"' + name + '": ' + functionDefs[ name ] )
}
functionDefsWriteStream.write('}')
functionDefsWriteStream.end()
})

// write utterance
utterancesWriteStream = fs.createWriteStream('./src/skill/models/utterances.txt')
utterancesWriteStream.on('open', function () {
utterancesWriteStream.write( utterances.join('\n') )
utterancesWriteStream.end()
})

// write intent schema
intentSchemaWriteStream = fs.createWriteStream('./src/skill/models/intentSchema.json')
intentSchemaWriteStream.on('open', function () {
var content = JSON.stringify( intentSchema, null, 2 )
intentSchemaWriteStream.write( content )
intentSchemaWriteStream.end()
})

resolve()

})

})

function createIntentName ( utterance ) {
return utterance.toLowerCase().split(' ').map( function ( word ) {
return word.charAt(0).toUpperCase() + word.slice(1)
}).join('') + 'Intent'
}

function createFunctionDefinition ( intentName, utterance ) {
return 'function ( intent, session, request, response ) {\n'
+ '\t\tprocessUtterance( intent, session, request, response, "' + utterance + '" )\n'
+ '\t},\n'
}

function replaceIntegersWithWords ( utterance ) {
return utterance.split(' ').map( function ( word ) {
if ( Number( word ) ) return word = convertIntegerToWord( Number( word ) )
return word
}).join(' ')
}

function convertIntegerToWord ( it ) {

var units = new Array ("zero","one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen")
var tens = new Array ("twenty","thirty","forty","fifty","sixty","seventy","eighty","ninety")
var theword = ""
var started

if ( it > 999 ) return "Lots"
if ( it == 0 ) return units[0]

for (var i = 9; i >= 1; i--){
if (it>=i*100) {
theword += units[i]
started = 1
theword += " hundred"
if (it!=i*100) theword += " and "
it -= i*100
i=0
}
}

for (var i = 9; i >= 2; i--){
if (it>=i*10) {
theword += (started?tens[i-2].toLowerCase():tens[i-2])
started = 1
if (it!=i*10) theword += "-"
it -= i*10
i=0
}
}

for (var i=1; i < 20; i++) {
if (it==i) {
theword += (started?units[i].toLowerCase():units[i])
}
}

return theword

}
Loading

0 comments on commit 39e692b

Please sign in to comment.