How to build "Compost Helper Alexa Skill"
Using Software apps and online services: Step by step build "Alexa skill" I wanted to build a very simple skill that tells a user if an item can be added to compost. My hope is that a skill like this encourages others to do more composting (and reduce what is added to landfills). The skill is ...
Using Software apps and online services:
Step by step build "Alexa skill" I wanted to build a very simple skill that tells a user if an item can be added to compost. My hope is that a skill like this encourages others to do more composting (and reduce what is added to landfills). The skill is straight-forward: a user can ask about a specific item or for information about items in general (which prompt the skill to send a website link to the user).
"Alexa, ask Compost Helper can I compost newspaper?" "Alexa, ask Compost Helper can I compost rice?" "Alexa, ask Compost Helper what can I compost?"
Logic
The skill was written using the Fact Skill as a template, with the following key changes:
- I created a custom slot called "LIST_OF_ITEMS". This slot contains 100+ household items that a user might inquire about
- I created a JSON list of the items, with the following attributes: Item (oranges), Answer (yes), AddOn (" you add them in small amounts and you open split the fruit").
- I use the Fuse.js library to do "fizzy matching" against the JSON list to find the best match (e.g. napkins = paper napkins = used napkins)
- The JSON attributes are used to construct the reply: "Yes, you can compost oranges if you add them in small amounts and you split open the fruit"
User Interaction
The user interaction is straight-forward. A user asks if an item can be added to compost, and Alexa replies yes or no.
User: "Alexa, ask Compost Helper can I compost milk?" Alexa: "No, you cannot compost milk. "
If the user does not indicate an item, Alexa asks the user to provide an item to validate:
User: "Alexa, ask Compost Helper can I compost?" Alexa: "I did not hear the name of the item that you want me to validate. Can you tell me the item you are asking about? " User: "Coffee" Alexa: "Yes, you can compost coffee grounds."
Finally, Alexa provides a website with more information if the user wants to know what s/he can compost.
User: "Alexa, ask Compost Helper what can I compost?" Alexa: "There are a large number of items you can compost. I've sent a website to the Alexa app. Check out the site for a list of items you can compost."
CODE
- List of Items (JSON)
[ { "item": "water", "answer": "Yes", "addOn": "" }, { "item": "fruit", "answer": "Yes", "addOn": "" }, { "item": "vegetables", "answer": "Yes", "addOn": "" }, { "item": "fruit scraps", "answer": "Yes", "addOn": "" }, { "item": "vegetable scraps", "answer": "Yes", "addOn": "you crush them first" }, { "item": "egg shells", "answer": "Yes", "addOn": "" }, { "item": "coffee grounds", "answer": "Yes", "addOn": "" }, { "item": "coffee filters", "answer": "Yes", "addOn": "" }, { "item": "tea bags", "answer": "Yes", "addOn": "they are made of natural materials. If in doubt, just compost the team leaves" }, { "item": "loose leaf tea", "answer": "Yes", "addOn": "" }, { "item": "tea leaves", "answer": "Yes", "addOn": "" }, { "item": "tea", "answer": "Yes", "addOn": "" }, { "item": "soy milk", "answer": "Yes", "addOn": "it only if it is spoiled" }, { "item": "rice milk", "answer": "Yes", "addOn": "it only if it is spoiled" }, { "item": "almond milk", "answer": "Yes", "addOn": "it only if it is spoiled" }, { "item": "coconut milk", "answer": "Yes", "addOn": "it only if it is spoiled" }, { "item": "paper napkins", "answer": "Yes", "addOn": "it is not dirty from oil, grease, or chemicals." }, { "item": "paper towels", "answer": "Yes", "addOn": "it is not dirty from oil, grease, or chemicals." }, { "item": "paper plates", "answer": "Yes", "addOn": "it is not waxy and not dirty from oil, grease, or chemicals." }, { "item": "pizza boxes", "answer": "Yes", "addOn": "it is unwaxed, and cut into small pieces" }, { "item": "paper bags", "answer": "Yes", "addOn": "it shredded" }, { "item": "Paper towel rolls", "answer": "Yes", "addOn": "it shredded" }, { "item": "Paper towel dowels", "answer": "Yes", "addOn": "it shredded" }, { "item": "crackers", "answer": "Yes", "addOn": "it is stale" }, { "item": "cereal", "answer": "Yes", "addOn": "it is stale" }, { "item": "nut shells", "answer": "Yes", "addOn": "they are not walnut shells" }, { "item": "tofu", "answer": "Yes", "addOn": "it is stale" }, { "item": "tempeh", "answer": "Yes", "addOn": "it is stale" }, { "item": "seaweed", "answer": "Yes", "addOn": "" }, { "item": "kelp", "answer": "Yes", "addOn": "" }, { "item": "nori", "answer": "Yes", "addOn": "" }, { "item": "popcorn kernels", "answer": "Yes", "addOn": "they are burnt or unpopped" }, { "item": "spices", "answer": "Yes", "addOn": "" }, { "item": "herbs", "answer": "Yes", "addOn": "" }, { "item": "pretzels", "answer": "Yes", "addOn": "they are stale" }, { "item": "candy", "answer": "Yes", "addOn": "it is stale and crushed or chopped" }, { "item": "protein bars", "answer": "Yes", "addOn": "they are stale" }, { "item": "energy bars", "answer": "Yes", "addOn": "they are stale" }, { "item": "pizza crusts", "answer": "Yes", "addOn": "" }, { "item": "oatmeal", "answer": "Yes", "addOn": "" }, { "item": "peanut shells", "answer": "Yes", "addOn": "" }, { "item": "egg cartons", "answer": "Yes", "addOn": "they are cardboard and are cut up" }, { "item": "pumpkin seeds", "answer": "Yes", "addOn": "they are cut up so they can't sprout" }, { "item": "sunflower seeds", "answer": "Yes", "addOn": "they are cut up so they can't sprout" }, { "item": "sesame seeds", "answer": "Yes", "addOn": "they are cut up so they can't sprout" }, { "item": "avocado pits", "answer": "Yes", "addOn": "they are cut up so they can't sprout" }, { "item": "wine corks", "answer": "Yes", "addOn": "they are chopped up" }, { "item": "jelly", "answer": "Yes", "addOn": "" }, { "item": "jam", "answer": "Yes", "addOn": "" }, { "item": "preserves", "answer": "Yes", "addOn": "" }, { "item": "beer", "answer": "Yes", "addOn": "" }, { "item": "wine", "answer": "Yes", "addOn": "" }, { "item": "pumpkin seeds", "answer": "Yes", "addOn": "you break the shell into smaller pieces" }, { "item": "pumpkins", "answer": "Yes", "addOn": "" }, { "item": "avocados", "answer": "Yes", "addOn": "" }, { "item": "avocado pits", "answer": "Yes", "addOn": "they are cut up so they can't sprout" }, { "item": "tomatoes", "answer": "Yes", "addOn": "" }, { "item": "oranges", "answer": "Yes", "addOn": "you have a small amout and you split open the fruit" }, { "item": "lemons", "answer": "Yes", "addOn": "you have a small amout and you split open the fruit" }, { "item": "limes", "answer": "Yes", "addOn": "you have a small amout and you split open the fruit" }, { "item": "grapefruits", "answer": "Yes", "addOn": "" }, { "item": "grapes", "answer": "Yes", "addOn": "" }, { "item": "melon", "answer": "Yes", "addOn": "you split open the fruit" }, { "item": "apples", "answer": "Yes", "addOn": "" }, { "item": "pears", "answer": "Yes", "addOn": "" }, { "item": "strawberries", "answer": "Yes", "addOn": "" }, { "item": "bananas", "answer": "Yes", "addOn": "" }, { "item": "mangoes", "answer": "Yes", "addOn": "you remove the mango stone" }, { "item": "pineapples", "answer": "Yes", "addOn": "you cut up the skin and crown" }, { "item": "potatoes", "answer": "Yes", "addOn": "you cut them into pieces to they don't sprout" }, { "item": "onions", "answer": "Yes", "addOn": "you cut them into pieces to they don't sprout" }, { "item": "broccoli", "answer": "Yes", "addOn": "" }, { "item": "carrots", "answer": "Yes", "addOn": "" }, { "item": "kale", "answer": "Yes", "addOn": "" }, { "item": "lettuce", "answer": "Yes", "addOn": "" }, { "item": "cucumbers", "answer": "Yes", "addOn": "" }, { "item": "parsnips", "answer": "Yes", "addOn": "you cut them into pieces" }, { "item": "olives", "answer": "Yes", "addOn": "you remove the pits and they are not covered in oil" }, { "item": "cauliflower", "answer": "Yes", "addOn": "" }, { "item": "peppers", "answer": "Yes", "addOn": "" }, { "item": "beans", "answer": "Yes", "addOn": "" }, { "item": "mushrooms", "answer": "Yes", "addOn": "" }, { "item": "corn", "answer": "Yes", "addOn": "" }, { "item": "corn on the cob", "answer": "Yes", "addOn": "you cut the cob into pieces" }, { "item": "corn cobs", "answer": "Yes", "addOn": "you cut the cob into pieces" }, { "item": "corn husks", "answer": "Yes", "addOn": "" }, { "item": "garlic", "answer": "Yes", "addOn": "you cut them into pieces to they don't sprout" }, { "item": "leeks", "answer": "Yes", "addOn": "" }, { "item": "spinach", "answer": "Yes", "addOn": "" }, { "item": "newspaper", "answer": "Yes", "addOn": "the newspaper is wet and you mix with other materials" }, { "item": "cardboard", "answer": "Yes", "addOn": "the cardboard is not shiny, which indcates it has a plastic coating" }, { "item": "shredded paper", "answer": "Yes", "addOn": "" }, { "item": "brown paper", "answer": "Yes", "addOn": "" }, { "item": "cut flowers", "answer": "Yes", "addOn": "" }, { "item": "toilet roll tubes", "answer": "Yes", "addOn": "" }, { "item": "flour", "answer": "Yes", "addOn": "you disperse it evenly in your compost pile" }, { "item": "oil", "answer": "No", "addOn": "" }, { "item": "motor oil", "answer": "No", "addOn": "" }, { "item": "olive oil", "answer": "No", "addOn": "" }, { "item": "milk", "answer": "No", "addOn": "" }, { "item": "cheese", "answer": "No", "addOn": "" }, { "item": "yogurt", "answer": "No", "addOn": "" }, { "item": "tampons", "answer": "No", "addOn": "" }, { "item": "condoms", "answer": "No", "addOn": "" }, { "item": "shampoo", "answer": "No", "addOn": "" }, { "item": "magazines", "answer": "No", "addOn": "" }, { "item": "take out menus", "answer": "No", "addOn": "" }, { "item": "diapers", "answer": "No", "addOn": "" }, { "item": "catalogs", "answer": "No", "addOn": "" }, { "item": "cream", "answer": "No", "addOn": "" }, { "item": "plums", "answer": "No", "addOn": "" }, { "item": "meat", "answer": "No", "addOn": "" }, { "item": "butter", "answer": "No", "addOn": "" }, { "item": "shortening", "answer": "No", "addOn": "" }, { "item": "cooking oil", "answer": "No", "addOn": "" }, { "item": "vegetable oil", "answer": "No", "addOn": "" }, { "item": "pasta", "answer": "No", "addOn": "" }, { "item": "rice", "answer": "No", "addOn": "" }, { "item": "cooked pasta", "answer": "No", "addOn": "" }, { "item": "cooked rice", "answer": "No", "addOn": "" }, { "item": "bread", "answer": "No", "addOn": "" }, { "item": "pitas", "answer": "No", "addOn": "" }, { "item": "tortillas", "answer": "No", "addOn": "" }, { "item": "potato chips", "answer": "No", "addOn": "" }, { "item": "tortilla chips", "answer": "No", "addOn": "" }, { "item": "fish", "answer": "No", "addOn": "" }, { "item": "seafood", "answer": "No", "addOn": "" }, { "item": "chicken", "answer": "No", "addOn": "" }, { "item": "poultry", "answer": "No", "addOn": "" }, { "item": "beef", "answer": "No", "addOn": "" }, { "item": "pork", "answer": "No", "addOn": "" }, { "item": "cakes", "answer": "No", "addOn": "" }, { "item": "pies", "answer": "No", "addOn": "" }, { "item": "desserts", "answer": "No", "addOn": "" }, { "item": "bakes beans", "answer": "No", "addOn": "" }, { "item": "face pads", "answer": "No", "addOn": "" }, { "item": "face wipes", "answer": "No", "addOn": "" }, { "item": "dog waste", "answer": "No", "addOn": "" }, { "item": "human waste", "answer": "No", "addOn": "" }, { "item": "wrapping paper", "answer": "No", "addOn": "" }, { "item": "gift paper", "answer": "No", "addOn": "" }, { "item": "wall paper", "answer": "No", "addOn": "" }, { "item": "pet waste", "answer": "No", "addOn": "" }, { "item": "cat waste", "answer": "No", "addOn": "" }, { "item": "cat litter", "answer": "No", "addOn": "" } ] CREDITS
- Index.js
/** * Compost helper Alexa skill * Darian Johnson @darianbjohnson (Twitter) **/ 'use strict'; const Alexa = require('alexa-sdk'); const APP_ID = undefined; // TODO replace with your app ID (OPTIONAL). var list = require('./list_of_items.json'); var Fuse = require('fuse.js'); const handlers = { 'LaunchRequest': function () { this.emit('AMAZON.HelpIntent'); }, 'GetCompostAnswer': function () { var intentObj = this.event.request.intent; if (!intentObj.slots.Items.value){ var message = "You did not tell me the name of an item to validate. Can you tell me the item you are asking about?"; var reprompt = "Tell me the item you are asking about." this.emit(':ask', message, reprompt); }else{ console.log(intentObj.slots.Items.value); if(intentObj.slots.Items.value == "?" ){ var message = "I did not understand the name of the item that you want me to validate. Can you tell me again?"; var reprompt = "Tell me the item you are asking about." this.emit(':ask', message, reprompt); } else if (intentObj.slots.Items.value == "post"){ var message = "I did not hear the name of the item that you want me to validate. Can you tell me the item you are asking about?"; var reprompt = "Tell me the item you are asking about." this.emit(':ask', message, reprompt); } else{ var options = { shouldSort: true, threshold: 0.2, location: 0, distance: 10, maxPatternLength: 10, minMatchCharLength: 2, keys: [ "item" ] }; var fuse = new Fuse(list, options); // "list" is the item array var result = fuse.search(intentObj.slots.Items.value); var message = "" if (result.length < 1){ this.emit(':tell', "I'm sorry, I didn't understand the item you are asking about. It might not be in my database."); }else{ var can=", you can compost "; if (result[0].answer == "No" ){can = ", you cannot compost " }; var message = result[0].answer + can + result[0].item if (result[0].addOn.length >0){ message = message + " if " + result[0].addOn }; message = message + "."; this.emit(':tell', message); } } } }, 'AMAZON.HelpIntent': function () { const speechOutput = "The Compost Helper will tell you if a household item can be added to your compost. To get started, tell me the item you want to ask about." const reprompt = "What item do you want to inquire about?" this.emit(':ask', speechOutput, reprompt); }, 'WhatCanICompost': function () { var cardTitle = 'What Can I Compost?'; var cardContent = 'Check out this link for a list of items to compost: http://www.compostthis.co.uk'; const speechOutput = "There are a large number of items you can compost. I've sent a website to the Alexa app. Check out the site for a list of items you can compost." this.emit(':tellWithCard', speechOutput, cardTitle, cardContent, null); }, 'AMAZON.CancelIntent': function () { this.emit(':tell', "OK."); }, 'AMAZON.StopIntent': function () { this.emit(':tell', "OK."); }, }; exports.handler = function (event, context) { const alexa = Alexa.handler(event, context); alexa.APP_ID = APP_ID; // To enable string internationalization (i18n) features, set a resources object. //alexa.resources = languageStrings; alexa.registerHandlers(handlers); alexa.execute(); };
- Sample Utterances (Plain text)
GetCompostAnswer {Items} GetCompostAnswer can i compost {Items} GetCompostAnswer could i compost {Items} GetCompostAnswer should i compost {Items} GetCompostAnswer is {Items} compostable GetCompostAnswer can I add {Items} to the compost GetCompostAnswer can I put {Items} in the compost WhatCanICompost what can I compost WhatCanICompost what should I compost WhatCanICompost give me a list of what I can compost
- List of Items (Custom Slot values)
fruit vegetables fruit scraps vegetable scraps egg shells coffee grounds coffee filters tea bags loose leaf tea tea leaves tea soy milk rice milk almond milk coconut milk paper napkins paper towels paper plates pizza boxes paper bags Paper towel rolls Paper towel dowels crackers cereal nut shells tofu tempeh seaweed kelp nori popcorn kernels spices herbs pretzels candy protein bars energy bars pizza crusts oatmeal peanut shells egg cartons sunflower seeds sesame seeds avocado pits wine corks jelly jam preserves beer wine pumpkin seeds pumpkins avocados tomatoes oranges lemons limes grapefruits grapes melon apples pears strawberries bananas mangos pineapples potatoes onions broccoli carrots kale lettuce cucumbers parsnips olives cauliflower peppers beans mushrooms corn corn on the cob corn cobs corn husks garlic leeks spinach newspaper cardboard shredded paper brown paper cut flowers toilet roll tubes flour oil motor oil olive oil milk cheese yogurt tampons condoms shampoo magazines take out menus diapers catalogs cream plums meat butter shortening cooking oil vegetable oil pasta rice cooked pasta cooked rice bread pitas tortillas potato chips tortilla chips fish seafood chicken poultry cakes pies desserts bakes beans face pads face wipes dog waste human waste wrapping paper gift paper wall paper pet waste cat waste cat litter water beef pork
- Intent Schema
{ "intents": [ { "slots": [ { "name": "Items", "type": "LIST_OF_ITEMS" } ], "intent": "GetCompostAnswer" }, { "intent": "AMAZON.HelpIntent" }, { "intent": "AMAZON.CancelIntent" }, { "intent": "AMAZON.StopIntent" }, { "intent": "WhatCanICompost" } ] }
Sourse : https://www.hackster.io