Skip to content

Commit 78c1dad

Browse files
committed
Initial commit
0 parents  commit 78c1dad

16 files changed

+523
-0
lines changed

.github/NEW_ITEM_TEMPLATE.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Item Template
2+
3+
If you'd like to add support for new fruits and vegetables, make sure you provide the following:
4+
5+
- [ ] update `src/instructions.js` to add the storage instructions for the new Item
6+
- [ ] run `npm test` to make sure it works
7+
- [ ] include a reference to your source of information in the pull request
8+
9+
This will be used to ensure that we give correct information to users.

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

.travis.yml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
language: node_js
2+
node_js:
3+
- "4.3"
4+
before_install:
5+
- npm i -g xo ava

LICENSE

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Copyright 2016 Chris Nguyen
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.

README.md

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# "Alexa, ask Fruit Stand, how do I store (fruit | vegetable)..."
2+
3+
Fruit Stand is an Alexa Skill that responds with information
4+
regarding how to store particular fruits or vegetables.
5+
6+
## Getting Started
7+
8+
- `alexa-skill.js` comes directly from the Amazon Alexa Skills Kit
9+
- `index.js` contains the core Alexa skill
10+
- `instructions.js` contains the responses for each item
11+
- `speechAssets` contains the Intent schema and slot metadata used to configure the skill
12+
13+
## Contributions
14+
15+
Contributions are welcome. If you'd like to add support for new fruits and vegetables,
16+
please create an issue before you submit a PR using the [new item template](.github/NEW_ITEM_TEMPLATE.md).
17+
18+
## Credits
19+
20+
- Based on examples from the [Alexa Skills Kit](https://github.com/amzn/alexa-skills-kit-js)
21+
- Information comes from [UC Davis Postharvest Technology](http://ucce.ucdavis.edu/files/datastore/234-1920.pdf)
22+
- Idea from the mind of @street_pizza
23+
24+
## License
25+
26+
Apache 2.0

icons/fruit-108x108.png

9.6 KB
Loading

icons/fruit-512x512.png

121 KB
Loading

package.json

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"name": "alexa-fruit-stand",
3+
"version": "1.0.0",
4+
"description": "Alexa Fruit Stand Skill",
5+
"main": "index.js",
6+
"scripts": {
7+
"items": "node speechAssets/items.js",
8+
"test": "xo && ava -v"
9+
},
10+
"keywords": [
11+
"Alexa Skill",
12+
"Fruit Stand"
13+
],
14+
"author": "Chris Nguyen",
15+
"license": "MIT",
16+
"xo": {
17+
"space": 2,
18+
"semicolon": false,
19+
"ignores": [
20+
"src/alexa-skill.js"
21+
]
22+
},
23+
"devDependencies": {
24+
"ava": "^0.16.0",
25+
"xo": "^0.16.0"
26+
}
27+
}

speechAssets/IntentSchema.json

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"intents": [
3+
{
4+
"intent": "FruitStandIntent",
5+
"slots": [{
6+
"name": "Item",
7+
"type": "LIST_OF_ITEMS"
8+
}]
9+
}, {
10+
"intent": "AMAZON.HelpIntent"
11+
}, {
12+
"intent": "AMAZON.StopIntent"
13+
}, {
14+
"intent": "AMAZON.CancelIntent"
15+
}]
16+
}

speechAssets/README.md

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Alexa Speech Assets
2+
3+
This folder contains metadata used for configuring the Alexa skill.
4+
5+
## IntentSchema.json
6+
7+
This file defines the Intent format. Fruit Stand has one action and
8+
therefore, one intent. Each fruit/vegetable is stored as a custom slot
9+
type called Item.
10+
11+
## items.js
12+
13+
This file imports the instructions and prints out a list of the items, which should
14+
be added to the customSlotTypes as a `LIST_OF_ITEMS`.
15+
16+
`npm run items` will generate this list from the instructions module.
17+
18+
## SampleUtterances.txt
19+
20+
This file defines the phrases that can be used to invoke Fruit Stand.

speechAssets/SampleUtterances.txt

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
FruitStandIntent how do I store {Item}
2+
FruitStandIntent how do I store some {Item}
3+
FruitStandIntent how do I store these {Item}
4+
FruitStandIntent how do I store the {Item}
5+
FruitStandIntent how do I store this {Item}
6+
FruitStandIntent how do you store {Item}
7+
FruitStandIntent how do you store some {Item}
8+
FruitStandIntent how do you store these {Item}
9+
FruitStandIntent how do you store the {Item}
10+
FruitStandIntent how do you store this {Item}
11+
FruitStandIntent how to store {Item}
12+
FruitStandIntent how to store some {Item}
13+
FruitStandIntent how to store these {Item}
14+
FruitStandIntent how to store the {Item}
15+
FruitStandIntent how to store this {Item}
16+
FruitStandIntent how should I store {Item}
17+
FruitStandIntent how should I store some {Item}
18+
FruitStandIntent how should I store these {Item}
19+
FruitStandIntent how should I store the {Item}
20+
FruitStandIntent how should I store this {Item}

speechAssets/items.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const instructions = require('../src/instructions')
2+
3+
for (var key in instructions) {
4+
if (key) {
5+
console.log(key)
6+
}
7+
}

src/alexa-skill.js

+197
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
/**
2+
Copyright 2014-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with the License. A copy of the License is located at
5+
6+
http://aws.amazon.com/apache2.0/
7+
8+
or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
9+
*/
10+
11+
'use strict';
12+
13+
function AlexaSkill(appId) {
14+
this._appId = appId;
15+
}
16+
17+
AlexaSkill.speechOutputType = {
18+
PLAIN_TEXT: 'PlainText',
19+
SSML: 'SSML'
20+
}
21+
22+
AlexaSkill.prototype.requestHandlers = {
23+
LaunchRequest: function (event, context, response) {
24+
this.eventHandlers.onLaunch.call(this, event.request, event.session, response);
25+
},
26+
27+
IntentRequest: function (event, context, response) {
28+
this.eventHandlers.onIntent.call(this, event.request, event.session, response);
29+
},
30+
31+
SessionEndedRequest: function (event, context) {
32+
this.eventHandlers.onSessionEnded(event.request, event.session);
33+
context.succeed();
34+
}
35+
};
36+
37+
/**
38+
* Override any of the eventHandlers as needed
39+
*/
40+
AlexaSkill.prototype.eventHandlers = {
41+
/**
42+
* Called when the session starts.
43+
* Subclasses could have overriden this function to open any necessary resources.
44+
*/
45+
onSessionStarted: function (sessionStartedRequest, session) {
46+
},
47+
48+
/**
49+
* Called when the user invokes the skill without specifying what they want.
50+
* The subclass must override this function and provide feedback to the user.
51+
*/
52+
onLaunch: function (launchRequest, session, response) {
53+
throw "onLaunch should be overriden by subclass";
54+
},
55+
56+
/**
57+
* Called when the user specifies an intent.
58+
*/
59+
onIntent: function (intentRequest, session, response) {
60+
var intent = intentRequest.intent,
61+
intentName = intentRequest.intent.name,
62+
intentHandler = this.intentHandlers[intentName];
63+
if (intentHandler) {
64+
console.log('dispatch intent = ' + intentName);
65+
intentHandler.call(this, intent, session, response);
66+
} else {
67+
throw 'Unsupported intent = ' + intentName;
68+
}
69+
},
70+
71+
/**
72+
* Called when the user ends the session.
73+
* Subclasses could have overriden this function to close any open resources.
74+
*/
75+
onSessionEnded: function (sessionEndedRequest, session) {
76+
}
77+
};
78+
79+
/**
80+
* Subclasses should override the intentHandlers with the functions to handle specific intents.
81+
*/
82+
AlexaSkill.prototype.intentHandlers = {};
83+
84+
AlexaSkill.prototype.execute = function (event, context) {
85+
try {
86+
console.log("session applicationId: " + event.session.application.applicationId);
87+
88+
// Validate that this request originated from authorized source.
89+
if (this._appId && event.session.application.applicationId !== this._appId) {
90+
console.log("The applicationIds don't match : " + event.session.application.applicationId + " and "
91+
+ this._appId);
92+
throw "Invalid applicationId";
93+
}
94+
95+
if (!event.session.attributes) {
96+
event.session.attributes = {};
97+
}
98+
99+
if (event.session.new) {
100+
this.eventHandlers.onSessionStarted(event.request, event.session);
101+
}
102+
103+
// Route the request to the proper handler which may have been overriden.
104+
var requestHandler = this.requestHandlers[event.request.type];
105+
requestHandler.call(this, event, context, new Response(context, event.session));
106+
} catch (e) {
107+
console.log("Unexpected exception " + e);
108+
context.fail(e);
109+
}
110+
};
111+
112+
var Response = function (context, session) {
113+
this._context = context;
114+
this._session = session;
115+
};
116+
117+
function createSpeechObject(optionsParam) {
118+
if (optionsParam && optionsParam.type === 'SSML') {
119+
return {
120+
type: optionsParam.type,
121+
ssml: optionsParam.speech
122+
};
123+
} else {
124+
return {
125+
type: optionsParam.type || 'PlainText',
126+
text: optionsParam.speech || optionsParam
127+
}
128+
}
129+
}
130+
131+
Response.prototype = (function () {
132+
var buildSpeechletResponse = function (options) {
133+
var alexaResponse = {
134+
outputSpeech: createSpeechObject(options.output),
135+
shouldEndSession: options.shouldEndSession
136+
};
137+
if (options.reprompt) {
138+
alexaResponse.reprompt = {
139+
outputSpeech: createSpeechObject(options.reprompt)
140+
};
141+
}
142+
if (options.cardTitle && options.cardContent) {
143+
alexaResponse.card = {
144+
type: "Simple",
145+
title: options.cardTitle,
146+
content: options.cardContent
147+
};
148+
}
149+
var returnResult = {
150+
version: '1.0',
151+
response: alexaResponse
152+
};
153+
if (options.session && options.session.attributes) {
154+
returnResult.sessionAttributes = options.session.attributes;
155+
}
156+
return returnResult;
157+
};
158+
159+
return {
160+
tell: function (speechOutput) {
161+
this._context.succeed(buildSpeechletResponse({
162+
session: this._session,
163+
output: speechOutput,
164+
shouldEndSession: true
165+
}));
166+
},
167+
tellWithCard: function (speechOutput, cardTitle, cardContent) {
168+
this._context.succeed(buildSpeechletResponse({
169+
session: this._session,
170+
output: speechOutput,
171+
cardTitle: cardTitle,
172+
cardContent: cardContent,
173+
shouldEndSession: true
174+
}));
175+
},
176+
ask: function (speechOutput, repromptSpeech) {
177+
this._context.succeed(buildSpeechletResponse({
178+
session: this._session,
179+
output: speechOutput,
180+
reprompt: repromptSpeech,
181+
shouldEndSession: false
182+
}));
183+
},
184+
askWithCard: function (speechOutput, repromptSpeech, cardTitle, cardContent) {
185+
this._context.succeed(buildSpeechletResponse({
186+
session: this._session,
187+
output: speechOutput,
188+
reprompt: repromptSpeech,
189+
cardTitle: cardTitle,
190+
cardContent: cardContent,
191+
shouldEndSession: false
192+
}));
193+
}
194+
};
195+
})();
196+
197+
module.exports = AlexaSkill;

0 commit comments

Comments
 (0)