1 | ![Alexia](alexia-logo.png "Alexia")
|
2 |
|
3 | A Framework for creating Amazon Echo (Alexa) skills using Node.js
|
4 |
|
5 | [![NPM Version][npm-image]][npm-url]
|
6 | [![Build Status][travis-image]][travis-url]
|
7 | [![Coverage Status][coveralls-image]][coveralls-url]
|
8 |
|
9 | ```javascript
|
10 | const alexia = require('alexia');
|
11 | const app = alexia.createApp('HelloWorldApp');
|
12 |
|
13 | app.intent('HelloIntent', 'Hello', () => {
|
14 | return 'Hello from Alexia app';
|
15 | });
|
16 | ```
|
17 |
|
18 | ## Installation
|
19 |
|
20 | `npm install alexia --save`
|
21 |
|
22 | ## Overview
|
23 |
|
24 | Alexia helps you to write Amazon Echo skills using Node.js. This framework handles Amazon Echo requests and automatically calls intents in your application. See the [Features and Samples](#features-and-samples)
|
25 |
|
26 | ## Terminology
|
27 |
|
28 | Creating new skills for Amazon Echo using alexia requires you to understand some basic terms. This part should clarify the most of them.
|
29 |
|
30 | - **Skill** - Alexa app
|
31 | - **Intent** - Invoked if one of intent `utterances` is recognized
|
32 | - **Utterance** - Voice input example
|
33 | - **Slot** - Variable part of utterance
|
34 | - **Session Attributes** - data persisted through the session
|
35 | - **Cards** - visual output displayed in [Alexa app](http://alexa.amazon.com/)
|
36 |
|
37 | ## Features and Samples
|
38 |
|
39 | ### Create App
|
40 |
|
41 | To create new app simply call `alexia.createApp()`
|
42 |
|
43 | ```javascript
|
44 | const alexia = require('alexia');
|
45 | const app = alexia.createApp('MyApp')
|
46 | ```
|
47 |
|
48 | ### Create Intents
|
49 |
|
50 | You have multiple options for creating intents. You can create named intents, intents with automatically generated name or intents with multiple sample utterances.
|
51 |
|
52 | ```javascript
|
53 | // Named intent
|
54 | app.intent('MyIntent', 'Hello Alexa my name is Michael', () => 'Hi Michael');
|
55 |
|
56 | // Generated intent name
|
57 | app.intent(null, 'Hello Alexa what is in my calendar for today', () => 'Your calendar is empty. Enjoy');
|
58 |
|
59 | // Intent with more utterances
|
60 | app.intent('AnotherIntent', ['Hello', 'Hi', 'Whats up'], () => 'Hello yourself');
|
61 | ```
|
62 |
|
63 | ### Built-in Intents
|
64 |
|
65 | Amazon Alexa Skills Kit provides a collection of built-in intents. These are intents for very common actions. Alexia provides convenient methods for their reusing and extending.
|
66 |
|
67 | List of built-in intents: `cancel`, `help`, `next`, `no`, `pause`, `previous`, `repeat`, `resume`, `startOver`, `stop`, `yes`.
|
68 |
|
69 | See official Amazon docs: [Available Built-in Intents](https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/implementing-the-built-in-intents#Available Built-in Intents)
|
70 |
|
71 | ```javascript
|
72 | // Use default built-in utterances
|
73 | app.builtInIntent('stop', () => 'Stopping now');
|
74 |
|
75 | // Extend built-in utterances
|
76 | app.builtInIntent('stop', 'Stop now', () => 'Stopping now');
|
77 | app.builtInIntent('stop', ['Stop now', 'Please stop'], () => 'Stopping now');
|
78 | ```
|
79 |
|
80 | ### Slots
|
81 |
|
82 | As mentioned in [Terminology](#terminology) section - slots represent variable part of user input in utterances. To make their creation bit easier our utterances contain slot name with type. These samples are converted into common utterances recognized by Alexa and slots are included in intentSchema.
|
83 |
|
84 | ```javascript
|
85 | app.intent('SlotIntent', 'My number is {num:Number}', (slots) => {
|
86 | return `Your number is ${slots.num}`;
|
87 | });
|
88 | ```
|
89 |
|
90 | ### Custom Slots
|
91 |
|
92 | Alexia helps you to create custom slots by specifying its `name` and `utterances`
|
93 |
|
94 | ```javascript
|
95 | app.customSlot('Name', ['Arnold', 'Otto', 'Walda', 'Pete']);
|
96 |
|
97 | app.intent('CustomSlotIntent', 'My name is {name:Name}', (slots) => {
|
98 | return `Hi ${slots.name}`;
|
99 | });
|
100 | ```
|
101 |
|
102 | ### Session Attributes
|
103 |
|
104 | Intent can be resolved using simple string (a text response) or more complex `responseObject`. Its attribute `attrs` will override current sessionAttributes. If you wish to extend current session attributes you can use for example `Object.assign` method. Make sure you set `end` attribute to `false` to keep the session open (default: `true`). See [Session Attributes example](examples/session-attributes.js)
|
105 |
|
106 | ```javascript
|
107 | app.intent('AttrsIntent', 'session attributes test', (slots, attrs) => {
|
108 | return {
|
109 | text: 'Alexa response text here',
|
110 | attrs: {
|
111 | attr1: 'Whatever to be remebered in this session'
|
112 | },
|
113 | end: false
|
114 | };
|
115 | });
|
116 | ```
|
117 |
|
118 | ### Cards
|
119 |
|
120 | To display card in Alexa app add configuration to responseObject `card` property
|
121 |
|
122 | ```javascript
|
123 | app.intent('CardsIntent', 'Whats in shopping cart', () => {
|
124 | return {
|
125 | text: 'Your shopping card contains Amazon Echo Device and 2 more items. To see the full list check out your Alexa app',
|
126 | card: {
|
127 | title: 'Shopping cart',
|
128 | content: 'You shopping cart contains: Amazon Echo, Amazon Tap, Echo Dot'
|
129 | }
|
130 | };
|
131 | });
|
132 | ```
|
133 |
|
134 | ### Reprompt
|
135 |
|
136 | To add reprompt text to your response add `reprompt` string value to responseObject
|
137 |
|
138 | ```javascript
|
139 | app.intent('RepromptIntent', 'Send emai to Mom', () => {
|
140 | return {
|
141 | text: 'What is the text of your message',
|
142 | reprompt: 'Sorry I did not catch it. What is the text of your message'
|
143 | };
|
144 | });
|
145 | ```
|
146 |
|
147 | ### SSML
|
148 |
|
149 | Use SSML to create more complex text responses. Just set the `ssml` parameter of responseObject to `true` and enter `SSML` into `text` property. See official Amazon docs: [Speech Synthesis Markup Language](https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/speech-synthesis-markup-language-ssml-reference)
|
150 |
|
151 | ```javascript
|
152 | app.intent('SSMLIntent', 'what are the digits of number {num:Number}', (slots) => {
|
153 | return `<say-as interpret-as="digits">${number}</say-as>`
|
154 | });
|
155 | ```
|
156 |
|
157 | ### Asynch Intent Handling
|
158 |
|
159 | For asynchronous intent handling add third parameter to your handler callback and call it when your response is ready. The response structure is identical to responseObject
|
160 |
|
161 | ```javascript
|
162 | app.intent('AsyncIntent', 'Search for something in database', (slots, attrs, done) => {
|
163 | setTimeout(() => {
|
164 | done('Work complete');
|
165 | }, 120);
|
166 | });
|
167 | ```
|
168 |
|
169 | ### Generate Speech Assets
|
170 |
|
171 | To minimize manual work needed while deploying your Alexa skills you can use our speechAssets generator. This helps you to create `intentSchema`, `sampleUtterances` and `customSlots` for your apps.
|
172 |
|
173 | Speech assets consists of:
|
174 | - **intentSchema** - array of intents with slots
|
175 | - **utterances** - phrases that are used to invoke intents
|
176 | - **customSlots** - custom slot types with samples
|
177 |
|
178 | For more information see [interaction model reference](https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/alexa-skills-kit-interaction-model-reference)
|
179 |
|
180 | ```javascript
|
181 | const speechAssets = app.speechAssets(); // object
|
182 | console.log(speechAssets.toString()); // stringified version - f.e. copy paste from console
|
183 | ```
|
184 |
|
185 | ### Handling Amazon Requests
|
186 |
|
187 | To handle Amazon requests you need to create HTTP server with POST route. See below example with [Hapi](http://hapijs.com/) server
|
188 |
|
189 | ```javascript
|
190 | const Hapi = require('hapi');
|
191 | const server = new Hapi.Server();
|
192 | const app = require('./app'); // Your app
|
193 |
|
194 | server.connection({
|
195 | port: process.env.PORT || 8888
|
196 | });
|
197 |
|
198 | server.route({
|
199 | path: '/',
|
200 | method: 'POST',
|
201 | handler: (request, response) => {
|
202 | app.handle(request.payload, (data) => {
|
203 | response(data);
|
204 | });
|
205 | }
|
206 | });
|
207 |
|
208 | server.start((err) => {
|
209 | if (err) throw err;
|
210 | console.log('Server running at:', server.info.uri);
|
211 |
|
212 | const speechAssets = app.speechAssets();
|
213 | console.log(speechAssets.toString());
|
214 | });
|
215 | ```
|
216 |
|
217 | ### Actions
|
218 |
|
219 | Feature of Alexia that helps you to control flow of the intents. To understand it easier see the code below.
|
220 |
|
221 | By defining the action you enable transition from one intent to another. When no actions are specified, every intent transition is allowed.
|
222 |
|
223 | Each action could have condition to check whether the transition should be handled or the fail method should be invoked. If no fail method is defined `app.defaultActionFail()` is invoked when condition of handling is not met or the action (transition) is not defined.
|
224 |
|
225 | ```javascript
|
226 | // Allow transition from any intent to `intent1`.
|
227 | app.action({
|
228 | from: '*',
|
229 | to: 'intent1'
|
230 | });
|
231 |
|
232 | // Allow transition from start intent to `intent2`.
|
233 | app.action({
|
234 | from: '@start',
|
235 | to: 'intent2'
|
236 | });
|
237 |
|
238 | // Allow transition from `intent1` to `intent2` if condition is met using custom fail handler
|
239 | app.action({
|
240 | from: 'intent1',
|
241 | to: 'intent2',
|
242 | if: (slots, attrs) => slots.pin === 1234,
|
243 | fail: (slots, attrs) => 'Sorry, your pin is invalid'
|
244 | });
|
245 |
|
246 | // Set default fail handler
|
247 | app.defaultActionFail(() => 'Sorry, your request is invalid');
|
248 | ```
|
249 |
|
250 | ## Testing
|
251 |
|
252 | ### Deploy
|
253 |
|
254 | - Implement server handler on POST endpoint. See [Handling Amazon Requests](#handling-amazon-requests)
|
255 | - Deploy application on public secured endpoint. For example:
|
256 | - [Heroku](https://www.heroku.com)
|
257 | - [AWS](https://aws.amazon.com)
|
258 |
|
259 | ### Create skill
|
260 |
|
261 | - Login to your [Amazon developer account](https://developer.amazon.com)
|
262 | - Select Apps & Services
|
263 | - Select Alexa
|
264 | - Select Alexa Skills Kit
|
265 | - Add a new Skill
|
266 | - Set skill info required to run app:
|
267 |
|
268 | **Skill Information**
|
269 | - Name: Name of your app, can be whatever
|
270 | - Invocation Name: Short phrase or abbreviation of your app name. Will be used to start your app by saying: `Alexa, start MyApp` if your invocation name is `MyApp`
|
271 |
|
272 | **Interaction model**
|
273 | - Use our generator `assets = app.generateSpeechAssets()` to generate speech assets
|
274 | - Custom Slot Types: Click `Add Slot Type`
|
275 | - Type: name of custom slot type
|
276 | - Values: contents assets.customSlots.myCustomSlot or enter custom slot samples manually
|
277 | - Do this for each custom slot
|
278 | - Intent Schema: enter value of `assets.intentSchema`
|
279 | - Sample Utterances: enter value of `assets.sampleUtterances`
|
280 |
|
281 | **Configuration**
|
282 | - Endpoint: select HTTPS and enter url or your publicly accesible server
|
283 |
|
284 | **SSL Certificate**
|
285 | - Select what applies to your SSL certificate
|
286 | - Could remain unselected when no certificate is required
|
287 |
|
288 | **Test**
|
289 | - Enable skill testing on this account
|
290 | - Enter one of your utterances and click `Ask MyApp`
|
291 |
|
292 | ### Device Testing
|
293 |
|
294 | - Connect to your Amazon Echo device using the same developer account where you created skill
|
295 | - Enable application for testing
|
296 | - Say `Alexa, start <myApp>`
|
297 |
|
298 | ### Echoism.io (Online Simulator)
|
299 |
|
300 | - Open [Echoism.io](https://echosim.io/)
|
301 | - Login with your Amazon developer account
|
302 | - Interact with Alexa simulator
|
303 |
|
304 | ### Unit Testing
|
305 |
|
306 | Each application should be unit-tested. We are exposing simple API helping you to create sample Alexa requests for testing and debugging
|
307 |
|
308 | ```javascript
|
309 | const app = require('./path-to-your-app');
|
310 |
|
311 | // Create sample requests
|
312 | const launchRequest = alexia.createLaunchRequest();
|
313 | const sessionEndedRequest = alexia.createSessionEndedRequest();
|
314 | const intentRequest = alexia.createIntentRequest('MyIntent');
|
315 |
|
316 | // Simulate request handling
|
317 | app.handle(launchRequest, (response) => {
|
318 |
|
319 | // Test the response
|
320 | expect(response).to.be.defined;
|
321 | });
|
322 | ```
|
323 |
|
324 | ## Next Plan
|
325 |
|
326 | - Generate API documentation
|
327 | - Add API to save speechAssets to file
|
328 | - Add more cards options (images etc.)
|
329 | - Merge session attributes automatically
|
330 | - Advanced error handling
|
331 | - Logging
|
332 | - Add more sophisticated request creator for unit testing
|
333 |
|
334 | ## Scripts
|
335 |
|
336 | - `npm test` - run unit tests
|
337 | - `npm test:dev` - run unit tests in development mode using nodemon as watcher
|
338 | - `npm run lint` - run eslint
|
339 | - `npm run lint:fix` - run eslint and automatically fix problems
|
340 |
|
341 | ## Contributing
|
342 |
|
343 | Alexia is an open source project and we encourage contributions. Please make sure to cover your code with unit tests
|
344 |
|
345 | For more information refer to general guide [Contributing to Open Source](https://guides.github.com/activities/contributing-to-open-source/)
|
346 |
|
347 | ## License
|
348 |
|
349 | [MIT](LICENSE)
|
350 |
|
351 | [npm-image]: https://img.shields.io/npm/v/alexia.svg
|
352 | [npm-url]: https://npmjs.org/package/alexia
|
353 | [travis-image]: https://img.shields.io/travis/Accenture/alexia/master.svg
|
354 | [travis-url]: https://travis-ci.org/Accenture/alexia
|
355 | [coveralls-image]: https://coveralls.io/repos/github/Accenture/alexia/badge.svg?branch=master
|
356 | [coveralls-url]: https://coveralls.io/github/Accenture/alexia?branch=master
|