ask-gib v0.12.6
ask-gib
This lib allows you to create Alexa Skills using TypeScript and an (IMO) easier approach to request/response architecture.
Use in combination with...
- ask-gib-api
- Broad coverage of Alexa AWS JSON reference, including type definitions and string literal constants.
- lex-gib
- i18n and synonym-like dynamic speech composition for more expressive Alexa speech.
- ssml-gib
- Factory functions for SSML tags supported by Alexa
- SpeechCons
- English (US)
- English (UK)
- German (DE)
- Use auto-completion for any and every SpeechCon currently supported!
- helper-gib
- Logging, other utils.
- Useful with Cloudwatch logs.
Installation
Install with npm:
npm install --save ask-gib
Import ES6 style:
import * as ask from 'ask-gib';
let h = new ask.Helper(); // If you want to use the helperUsage Overview
- Implement
FuncyAlexaSkillclass. - Flesh out functions to handle requests.
- Hook up the skill in the handler in index.ts.
Usage
Inherit from
FuncyAlexaSkill. In ctor, map each intent to an array of transforms that will be executed in order. Be sure to initialize the launch request handler as well.export interface FooStore extends ask.BaseSkillStore { foo: string; } export class FooSkill extends ask.FuncyAlexaSkill<FooStore> { constructor(appId: string, dynamoDbTableName: string) { super(appId, dynamoDbTableName, lexData); // see lex-gib for lexData info // Creates first-non-null-wins request handling pipelines // I personally name these `transform___` but not necessary. t.transformsByName = { "FooIntent": [t.transformFooBar, t.transformFooBaz, t.transformHelpDefault], "AMAZON.HelpIntent": [t.transformHelpBar, t.transformHelpDefault], "AMAZON.FallbackIntent": [t.transformHelpDefault], "AMAZON.RepeatIntent": [t.transformRepeat], "AMAZON.CancelIntent": [t.transformGoodbye], "AMAZON.StopIntent": [t.transformGoodbye] } // Launch is special. Define pipeline for it here. t.transformsByName[t.getLaunchRequestName()] = [t.transformWelcome]; } ... }Inside each transform, check the state, most often in the
_storeproperty. Check to see if you want your transform to handle the incoming stimulus. If yes, return the nextSkillState. If no (i.e. the transform doesn't apply), returnnull.transformFooBar: ask.SkillTransform = ( stimulus: ask.Stimulus, history: ask.SkillState[] ): ask.SkillState => { // Can also use Promise<ask.SkillState> // Check to see if this transform applies, if not return null. if (!this._store || this._store.foo !== "bar") { return null; } // Create your speech, mixing plain text, ssml, with ssml helpers. // lex provides powerful i18n, 'hi' -> hello, howdy, Guten Tag, etc. // But here is also shown hard-coded text. let hi = this.lex._('hi'); let output = ask.SpeechBuilder.with() .ssml(hi.ssml) .text("Build some speech with plain text...") .ssml(`<p>${Ssml.emphasis("Emphasize", "strong")} with some ssml.</p>`) .text("Would you like to foo?") .outputSpeech(); let reprompt = ask.SpeechBuilder.with() .text("Maybe you didn't hear me...") .existing(output) // reuses existing speech output .outputSpeech(); // Create interaction object, which represents the entire request // & response. The JSON response object sent back to Alexa will // be built automatically from this. let interaction: ask.Interaction = { stimulus: stimulus, type: "ask", output: output, reprompt: reprompt, // If you include `cardTitle/Content`, it will automatically // incorporate this into your response with a simple card, // e.g. `TellWithCard`, `AskWithCard`. cardTitle: "My Title", cardContent: output.text, } // The final bit of plumbing let nextSkillState: ask.SkillState = { id: h.generateUUID(), interaction: interaction, location: "a1" } // Optionally store some global state for this user. // Anything that is stored in the _store object is persisted across // sessions, and you can extend `BaseStore` for type-safety. this._store.foo = "baz"; return nextSkillState; }Put this in your handler in your
index.tsfile.// Create the handler that responds to the Alexa Request. export var handler = async function ( event: ask.RequestBody, context: ask.Context, callback: (error: any, response: ask.ResponseBody) => void ) { try { // Create an instance of the skill. var skill = new FooSkill(APP_ID, DB_NAME); // I await execute, which is not necessary WRT the callback. // Async execute is convenient to write, and the callback // actually is called just before the await will return. await skill.execute(event, context, callback); h.logFuncComplete(lc); } catch (errExec) { h.logError(`errExec`, errExec, lc); } }
Highlights
FuncyAlexaSkill- Easier workflow for handling incoming requests without function decorators.
- Plumbing is handled for you.
SpeechBuilder- Helper class that builds up
OutputSpeechobjects with a fluent manner. - See ssml-gib for details.
- Helper class that builds up
DynamoDBHelper- Simplistic, promise-based helper class that saves and retrieves a user's
DynamoRecordbased on user id and db table name. - Assumes that you have separately created the table in DynamoDB with the given table name.
- Simplistic, promise-based helper class that saves and retrieves a user's
DevOps
I also wanted to mention that you can create a nice workflow for DevOps.
With a single keystroke chord ctrl+shift+B, vscode executes the default build task, which is npm run build.
This...
- Compiles the TypeScript with
tsc. - Builds and copies my TS output to the
binfolder. - Copies over the node_modules folder fresh.
- Deletes old zip and zips up bin into new zip. (Note: You need to create the first bin.zip file manually. Need to correct the npm bash task.)
- Uses aws cli to push the
bin.zipto the Lambda function (which uses aliases for production so I can't harm any live skills).
I also update my models and check status via npm scripts as well,
which can get/update models and more. ctrl+~ brings up the vscode bash shell which
makes this a breeze.
I highly recommend using the npm scripts + aws and ask CLIs. (Needs updated to task version 2.0.0)
Here is the relevant code:
.vscode/tasks.json:
{
"version": "0.1.0",
"tasks": [
{
"taskName": "tsc",
"isBuildCommand": true,
"isShellCommand": true,
"command": "npm",
"args": [ "run", "build" ],
"showOutput": "silent",
"problemMatcher": "$tsc"
},
{
"taskName": "mochatest",
"isShellCommand": true,
"command": "npm",
"args": [ "run", "test" ],
"showOutput": "always"
}
]
}package.json:
{
...
"scripts": {
"build": "npm run build:ts",
"build:ts": "tsc -p .",
"postbuild": "npm run do-node-modules && npm run zip:bin && npm run aws-push",
"zip:bin": "cd bin && pwd && rm bin.zip && zip -r bin.zip * && cd .. && pwd",
"do-node-modules": "rm -rf bin/node_modules && cp -r node_modules bin/node_modules",
"aws-push": "aws lambda update-function-code --function-name skillGibA --zip-file fileb://bin/bin.zip --profile alexa",
"aws-push-eu": "aws lambda update-function-code --function-name skillGibA_EU --zip-file fileb://bin/bin.zip --profile alexa-eu",
"ask-get-models": "ask api get-model -s $SKILL_SID -l en-US > models_tmp/en-US.json --profile alexa && ask api get-model -s $SKILL_SID -l en-IN > models_tmp/en-IN.json --profile alexa && ask api get-model -s $SKILL_SID -l en-CA > models_tmp/en-CA.json --profile alexa && ask api get-model -s $SKILL_SID -l en-GB > models_tmp/en-GB.json --profile alexa && ask api get-model -s $SKILL_SID -l en-AU > models_tmp/en-AU.json --profile alexa",
"ask-update-models": "ask api update-model -s $SKILL_SID -l en-US --file models/en-US.json --profile alexa && ask api update-model -s $SKILL_SID -l en-IN --file models/en-IN.json --profile alexa && ask api update-model -s $SKILL_SID -l en-CA --file models/en-CA.json --profile alexa && ask api update-model -s $SKILL_SID -l en-GB --file models/en-GB.json --profile alexa && ask api update-model -s $SKILL_SID -l en-AU --file models/en-AU.json --profile alexa",
"ask-get-model-statuses": "ask api get-model-status -s $SKILL_SID -l en-US --profile alexa && ask api get-model-status -s $SKILL_SID -l en-IN --profile alexa && ask api get-model-status -s $SKILL_SID -l en-CA --profile alexa && ask api get-model-status -s $SKILL_SID -l en-GB --profile alexa && ask api get-model-status -s $SKILL_SID -l en-AU --profile alexa"
},
...
}Thanks
- Amazon for creating such good documentation and a good product.
- The official Alexa Skills Kit SDK for Node.js
- This is where I got the idea for the simple DynamoDB table persistence.
- Up.
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
10 years ago
10 years ago