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 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

  1. 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
  1. 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();
    };
  1. 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
  1. 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
  1. 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