Nikolay BeliovskyBenjamin
Published © GPL3+

Treats for Chores

Simple system built to motivate family members to complete their chores.

IntermediateFull instructions provided5 hours1,042

Things used in this project

Hardware components

Mindstorms EV3 Programming Brick / Kit
LEGO Mindstorms EV3 Programming Brick / Kit
×1
Echo Dot
Amazon Alexa Echo Dot
×1

Software apps and online services

Microsoft Visual Studio Code
Amazon Alexa ASK SDK for Node.js

Story

Read more

Schematics

Building instructions for the robot

Here are instructions to assemble the "treats for chores" robot

BOM for the model

here is csv file, exported from the studio

Model for the treats for chores

It is a built model of our solution

Code

Python code for the EV3

Python
This is code, which runs on the EV3 and reacts to different payloads being sent from the Alexa
#!/usr/bin/env python3
# Copyright 2019 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
# 
# You may not use this file except in compliance with the terms and conditions 
# set forth in the accompanying LICENSE.TXT file.
#
# THESE MATERIALS ARE PROVIDED ON AN "AS IS" BASIS. AMAZON SPECIFICALLY DISCLAIMS, WITH 
# RESPECT TO THESE MATERIALS, ALL WARRANTIES, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING 
# THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.

import os
import sys
import time
import logging
import json
import random
import threading
import ast

from enum import Enum
from agt import AlexaGadget

from ev3dev2.led import Leds
from ev3dev2.sound import Sound
from ev3dev2.motor import LargeMotor, OUTPUT_A, OUTPUT_B, OUTPUT_C, SpeedPercent 

# Set the logging level to INFO to see messages from AlexaGadget
logging.basicConfig(level=logging.INFO, stream=sys.stdout, format='%(message)s')
logging.getLogger().addHandler(logging.StreamHandler(sys.stderr))
logger = logging.getLogger(__name__)

class MindstormsGadget(AlexaGadget):
    """
    A Mindstorms gadget that performs movement based on voice commands.
    Two types of commands are supported, directional movement and preset.
    """

    def __init__(self):
        """
        Performs Alexa Gadget initialization routines and ev3dev resource allocation.
        """
        super().__init__()

        # Gadget state
        self.patrol_mode = False

        # Ev3dev initialization
        self.leds = Leds()
        self.sound = Sound()
        self.motorA = LargeMotor(OUTPUT_A)
        self.motorB = LargeMotor(OUTPUT_B)
        self.motorC = LargeMotor(OUTPUT_C)
        # Start threads
        logger.info("set upev3dev")

    def on_connected(self, device_addr):
        """
        Gadget connected to the paired Echo device.
        :param device_addr: the address of the device we connected to
        """
        self.leds.set_color("LEFT", "GREEN")
        self.leds.set_color("RIGHT", "GREEN")
        logger.info("{} connected to Echo device".format(self.friendly_name))

    def on_disconnected(self, device_addr):
        """
        Gadget disconnected from the paired Echo device.
        :param device_addr: the address of the device we disconnected from
        """
        self.leds.set_color("LEFT", "BLACK")
        self.leds.set_color("RIGHT", "BLACK")
        logger.info("{} disconnected from Echo device".format(self.friendly_name))

    def on_custom_mindstorms_gadget_control(self, directive):
        """
        Handles the Custom.Mindstorms.Gadget control directive.
        :param directive: the custom directive with the matching namespace and name
        """
        try:
            payload = json.loads(directive.payload.decode("utf-8"))
            print("Control payload: {}".format(payload), file=sys.stderr)
            control_type = payload["type"]
            if control_type == "move":
                self._move(payload["name"])
            if control_type == "setup":
                nameA = payload["nameA"]
                nameB = payload["nameB"]
                nameC = payload["nameC"]
                logger.info("got names: {}, {}, {}".format(nameA, nameB, nameC))
                namesDict = {'nameA':nameA, 'nameB':nameB, 'nameC':nameC}
                with open('names.ini', 'w') as f:
                    print(namesDict, file=f)
                f.close()


        except KeyError:
            print("Missing expected parameters: {}".format(directive), file=sys.stderr)

    def _move(self, value):
        """
        Handles move commands from the directive.
        Picks right motor from directive to dump the candies into chosen hopper
        """

        print("Move command: ({})".format(value), file=sys.stderr)
        with open('names.ini', 'r') as f:
            readNamesDict = ast.literal_eval(f.readline()) #getting names dictionary from the file
            logger.info ("type of readNamesDict is {} and the value is {}".format(type(readNamesDict), readNamesDict))
        f.close()
        

        if value in readNamesDict.values():
            logger.info("{} with type {}".format(readNamesDict,type(readNamesDict)))
            for k, v in readNamesDict.items():
                if v == value:
                    motorSelect = k
            
            logger.info ("we need to open bay for {}".format(motorSelect))
        if motorSelect == "nameA":
            self.motorA.on_for_degrees(SpeedPercent(75),-90, brake=True, block=True)
            time.sleep(0.1)
            self.motorA.on_for_degrees(SpeedPercent(75), 90, brake=True, block=True)
        elif motorSelect == "nameB":
            self.motorB.on_for_degrees(SpeedPercent(75),-90, brake=True, block=True)
            time.sleep(0.1)
            self.motorB.on_for_degrees(SpeedPercent(75), 90, brake=True, block=True)
        else :
            self.motorC.on_for_degrees(SpeedPercent(75),-90, brake=True, block=True)
            time.sleep(0.1)
            self.motorC.on_for_degrees(SpeedPercent(75), 90, brake=True, block=True)
        


    def _activate(self, command, speed=50):
        """
        Handles preset commands.
        :param command: the preset command
        :param speed: the speed if applicable
        """
        print("Activate command: ({}, {})".format(command, speed), file=sys.stderr)
        if command in Command.MOVE_CIRCLE.value:
            self.drive.on_for_seconds(SpeedPercent(int(speed)), SpeedPercent(5), 12)

        if command in Command.MOVE_SQUARE.value:
            for i in range(4):
                self._move("right", 2, speed, is_blocking=True)

        if command in Command.PATROL.value:
            # Set patrol mode to resume patrol thread processing
            self.patrol_mode = True

        if command in Command.FIRE_ONE.value:
            self.weapon.on_for_rotations(SpeedPercent(100), 3)

        if command in Command.FIRE_ALL.value:
            self.weapon.on_for_rotations(SpeedPercent(100), 10)

    
   


if __name__ == '__main__':

    gadget = MindstormsGadget()

    # Set LCD font and turn off blinking LEDs
    os.system('setfont Lat7-Terminus12x6')
    gadget.leds.set_color("LEFT", "BLACK")
    gadget.leds.set_color("RIGHT", "BLACK")

    # Startup sequence
    gadget.sound.play_song((('C4', 'e'), ('D4', 'e'), ('E5', 'q')))
    gadget.leds.set_color("LEFT", "GREEN")
    gadget.leds.set_color("RIGHT", "GREEN")

    # Gadget main entry point
    gadget.main()

    # Shutdown sequence
    gadget.sound.play_song((('E5', 'e'), ('C4', 'e')))
    gadget.leds.set_color("LEFT", "BLACK")
    gadget.leds.set_color("RIGHT", "BLACK")

index.js of the custom skill

JavaScript
This file contains backend logic of the "treats for chores" project
const Alexa = require('ask-sdk-core');
const Util = require('./util');
const Common = require('./common');

const listIsEmpty = '#list_is_empty#';

const welcomeOutput = 'Welcome. You can say, top todo';
const welcomeReprompt = 'You can say, top todo';
const helpOutput = 'You can say top todo or cancel top todo.';
const helpReprompt = 'Say top todo or cancel top todo.';
const NAMESPACE = 'Custom.Mindstorms.Gadget';
const NAME_CONTROL = 'control';

const listStatuses = {
  ACTIVE: 'active',
  COMPLETED: 'completed',
};

// handlers

const LaunchRequestHandler = {
    canHandle(handlerInput) {
        return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest';
    },
    handle: async function(handlerInput) {

        let request = handlerInput.requestEnvelope;
        let { apiEndpoint, apiAccessToken } = request.context.System;
        let apiResponse = await Util.getConnectedEndpoints(apiEndpoint, apiAccessToken);
        if ((apiResponse.endpoints || []).length === 0) {
            return handlerInput.responseBuilder
            .speak(`I couldn't find an EV3 Brick connected to this Echo device. Please check to make sure your EV3 Brick is connected, and try again.`)
            .getResponse();
        }

        // Store the gadget endpointId to be used in this skill session
        let endpointId = apiResponse.endpoints[0].endpointId || [];
        Util.putSessionAttribute(handlerInput, 'endpointId', endpointId);

        return handlerInput.responseBuilder
            .speak("Welcome, you can start working with treats for chores, start by creating 3 lists, or you can check top to do items for each user")
            .reprompt("Awaiting commands")
            .getResponse();
    }
};

const TopToDoHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest' && request.intent.name === 'TopToDoIntent';
  },
  async handle(handlerInput) {
    const responseBuilder = handlerInput.responseBuilder;
    var name = handlerInput.requestEnvelope.request.intent.slots.name.value;
    const attributesManager = handlerInput.attributesManager;
    const endpointId = attributesManager.getSessionAttributes().endpointId || [];
    let speechOutput;
    console.log('Starting top todo handler');
    const itemName = await getTopToDoItem(handlerInput);
    //thats where function called, we either get the name of the item, or 
    //listIsEmpty
    if (!itemName) {
      speechOutput = 'Alexa List permissions are missing. You can grant permissions within the Alexa app.';
      const permissions = ['read::alexa:household:list'];
      return responseBuilder
        .speak(speechOutput)
        .withAskForPermissionsConsentCard(permissions)
        .getResponse();
    } else if (itemName === listIsEmpty) {
        //Here is our call to action, 
        //we form directive with 'move' type with the name of the user whose list is
        //empty
      speechOutput = 'Your todo list is empty, everything is complete, please collect your treat!';
      const directive = Util.build(endpointId, NAMESPACE, NAME_CONTROL,
            {
                type: 'move',
                name: name
            });
      return responseBuilder
        .speak(speechOutput)
        .addDirective(directive)
        .getResponse();
    }
    speechOutput = `Your top to do for ${name} is ${itemName}.  To mark it as complete, say complete ${name} to do.`;
    const speechReprompt = 'Say complete my to do to mark it complete.';
    return responseBuilder
      .speak(speechOutput)
      .reprompt(speechReprompt)
      .getResponse();
  },
};

const CreateListHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest' && request.intent.name === 'CreateListIntent';
  },
  async handle(handlerInput) {
    var name = handlerInput.requestEnvelope.request.intent.slots.name.value;
    const responseBuilder = handlerInput.responseBuilder;
    const listClient = handlerInput.serviceClientFactory.getListManagementServiceClient();
    let speechOutput;
    console.log('Starting CreateListIntent handler');
    var listObject = {
            'name': name + " list",
            "state": "active"
        }
    listClient.createList(listObject);    
    
    
    speechOutput = `Your custom list for ${name} have been created`;
    const speechReprompt = 'Now you can populate it';
    return responseBuilder
      .speak(speechOutput)
      .reprompt(speechReprompt)
      .getResponse();
  },
};

const CreateTripleListHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest' && request.intent.name === 'CreateTripleListIntent';
  },
  async handle(handlerInput) {
    //getting list names from slots
    var nameA = handlerInput.requestEnvelope.request.intent.slots.nameA.value;
    var nameB = handlerInput.requestEnvelope.request.intent.slots.nameB.value;
    var nameC = handlerInput.requestEnvelope.request.intent.slots.nameC.value;
    // here we set up attributesManager to get endpointId later
    const attributesManager = handlerInput.attributesManager;
    //setting up endpointId to send the info on created lists to gadget
    const endpointId = attributesManager.getSessionAttributes().endpointId || []; 
    const responseBuilder = handlerInput.responseBuilder;
    const listClient = handlerInput.serviceClientFactory.getListManagementServiceClient(); //setting up ListManagementServiceClient for list creation
    let speechOutput;
    console.log('Starting CreateListIntent handler');
    //Creating list objects with names from slots, and active statuses, meaning they are not archived
    var listObjectA = {
            'name': nameA + " list",
            "state": "active"
        }
    //leveraging createlist method for each of the custom lists
    listClient.createList(listObjectA);
    var listObjectB = {
            'name': nameB + " list",
            "state": "active"
        }
    listClient.createList(listObjectB);
    var listObjectC = {
            'name': nameC + " list",
            "state": "active"
        }
    listClient.createList(listObjectC); 
    
    
    speechOutput = `Your custom lists for ${nameA}, ${nameB} and ${nameC} have been created`;
    const speechReprompt = 'Now you can populate it';
    //building directive to send to the EV3, here we use "setup type of the payload"
    const directive = Util.build(endpointId, NAMESPACE, NAME_CONTROL,
            {
                type: 'setup',
                nameA: nameA,
                nameB: nameB,
                nameC: nameC
            });
    return responseBuilder
      .speak(speechOutput)
      .reprompt(speechReprompt)
      .addDirective(directive)
      .getResponse();
  },
};

const NamedTopToDoHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest' && request.intent.name === 'NamedTopToDoIntent';
  },
  async handle(handlerInput) {
    const responseBuilder = handlerInput.responseBuilder;
    const attributesManager = handlerInput.attributesManager;
    const endpointId = attributesManager.getSessionAttributes().endpointId || [];
    let speechOutput;
    console.log('Starting named top to do handler');
    const itemName = await getNamedToDoItem(handlerInput);
    //thats where function called, we either get the name of the item, or 
    //listIsEmpty
    if (!itemName) {
      speechOutput = 'Alexa List permissions are missing. You can grant permissions within the Alexa app.';
      const permissions = ['read::alexa:household:list'];
      return responseBuilder
        .speak(speechOutput)
        .withAskForPermissionsConsentCard(permissions)
        .getResponse();
    } else if (itemName === listIsEmpty) {
      speechOutput = 'Your to do list is empty.';
      //Here is our call to action, 
      //we form directive with 'move' type with the name of the user whose list is
      //empty
      const directive = Util.build(endpointId, NAMESPACE, NAME_CONTROL,
            {
                type: 'move',
                name: name
            });
      return responseBuilder
        .speak(speechOutput)
        .addDirective(directive)
        .getResponse();
    }
    speechOutput = `Your top named to do is ${itemName}.  To mark it as complete, say complete my to do.`;
    const speechReprompt = 'Say complete my to do to mark it complete.';
    return responseBuilder
      .speak(speechOutput)
      .reprompt(speechReprompt)
      .getResponse();
  },
};

const CompleteTopToDoHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest' && request.intent.name === 'CompleteTopToDoIntent';
    
  },
  async handle(handlerInput) {
    const responseBuilder = handlerInput.responseBuilder;
    var name = handlerInput.requestEnvelope.request.intent.slots.name.value;
    const attributesManager = handlerInput.attributesManager;
    const endpointId = attributesManager.getSessionAttributes().endpointId || [];
    let speechOutput;
    console.info('Starting complete top to do handler');
   // try {
      const result = await completeTopToDoAction(handlerInput);
      if (!result) {
        speechOutput = 'Alexa List permissions are missing. You can grant permissions within the Alexa app.';
        const permissions = ['write::alexa:household:list'];
        return responseBuilder
          .speak(speechOutput)
          .withAskForPermissionsConsentCard(permissions)
          .getResponse();
      } else if (result === listIsEmpty) {
        speechOutput = 'I could not complete your top to do. Your to do list is empty, please collect your treat.';
        const directive = Util.build(endpointId, NAMESPACE, NAME_CONTROL,
            {
                type: 'move',
                name: name
            });
        return responseBuilder
        .speak(speechOutput)
        .addDirective(directive)
        .getResponse();
      } else {
        console.log(result.id);
        const listClient = handlerInput.serviceClientFactory.getListManagementServiceClient();
        const listId = await getToDoListId(handlerInput);
        const list = await listClient.getList(listId, listStatuses.ACTIVE);
        console.log(list.items.length);
        if (list.items.length > 1){
        speechOutput = `I successfully completed ${result.value} task for ${name} top to do.  Bye for now!`;
        } else {
            speechOutput = `I successfully completed ${result.value} task for ${name} top to do.  Thats your last task, go get your treat`;
            const directive = Util.build(endpointId, NAMESPACE, NAME_CONTROL,
            {
                type: 'move',
                name: name
            });
            return responseBuilder
            .speak(speechOutput)
            .addDirective(directive)
            .getResponse();
            }
      }
    //} catch (err) {
        console.log(speechOutput);
      speechOutput = 'I could not complete the to do.  Please try again later';
    //}
    return responseBuilder
      .speak(speechOutput)
      .getResponse();
  },
};

const AmazonHelpHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest' && request.intent.name === 'AMAZON.HelpIntent';
  },
  handle(handlerInput) {
    const responseBuilder = handlerInput.responseBuilder;
    return responseBuilder
      .speak(helpOutput)
      .reprompt(helpReprompt)
      .getResponse();
  },
};

const AmazonCancelStopHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest' &&
      (request.intent.name === 'AMAZON.CancelIntent' || request.intent.name === 'AMAZON.StopIntent');
  },
  handle(handlerInput) {
    const responseBuilder = handlerInput.responseBuilder;
    const speechOutput = 'Okay, talk to you later! ';

    return responseBuilder
      .speak(speechOutput)
      .withShouldEndSession(true)
      .getResponse();
  },
};

const SessionEndedHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'SessionEndedRequest';
  },
  handle(handlerInput) {
    console.log(`Session ended with reason: ${handlerInput.requestEnvelope.request.reason}`);
    return handlerInput.responseBuilder.getResponse();
  },
};

const ErrorHandler = {
  canHandle() {
    return true;
  },
  handle(handlerInput, error) {
    const request = handlerInput.requestEnvelope.request;

    console.log(`Original Request was: ${JSON.stringify(request, null, 2)}`);
    console.log(`Error handled: ${error}`);

    return handlerInput.responseBuilder
      .speak('Sorry, I had trouble doing what you asked.  Please ask for it again.')
      .reprompt('Sorry, I had trouble doing what you asked.  Please ask for it again.')
      .getResponse();
  },
};

// helpers

/**
* List API to retrieve the customer to-do list.
*/
async function getToDoListId(handlerInput) {
  // check session attributes to see if it has already been fetched
  const attributesManager = handlerInput.attributesManager;
  const sessionAttributes = attributesManager.getSessionAttributes();
  const name = handlerInput.requestEnvelope.request.intent.slots.name.value;
  let listId;
  console.log(`Name of the list should contain: ${name}`)

  if (!sessionAttributes.todoListId) {
    // lookup the id for the 'to do' list
    const listClient = handlerInput.serviceClientFactory.getListManagementServiceClient();
    const listOfLists = await listClient.getListsMetadata();
    if (!listOfLists) {
      console.log('permissions are not defined');
      return null;
    }
    for (let i = 0; i < listOfLists.lists.length; i += 1) {
      console.log(`found ${listOfLists.lists[i].name} with id ${listOfLists.lists[i].listId}`);
      const decodedListId = Buffer.from(listOfLists.lists[i].listId, 'base64').toString('utf8');
      console.log(`decoded listId: ${decodedListId}`);
      // The default lists (To-Do and Shopping List) list_id values are base-64 encoded strings with these formats:
      //  <Internal_identifier>-TASK for the to-do list
      //  <Internal_identifier>-SHOPPING_LIST for the shopping list
      // Developers can base64 decode the list_id value and look for the specified string at the end. This string is constant and agnostic to localization.
      if (listOfLists.lists[i].name.includes(name)) {
        // since we're looking for the default to do list, it's always present and always active
        listId = listOfLists.lists[i].listId;
        break;
      }
    }
  }
  attributesManager.setSessionAttributes(sessionAttributes);
  console.log(JSON.stringify(handlerInput));
  return listId;
}

/**
* Helper function to retrieve the top to-do item.
*/
async function getTopToDoItem(handlerInput) {
  const listClient = handlerInput.serviceClientFactory.getListManagementServiceClient();
  const listId = await getToDoListId(handlerInput);
  console.log(`listid: ${listId}`);
  const list = await listClient.getList(listId, listStatuses.ACTIVE);
  if (!list) {
    console.log('null list');
    return null;
  } else if (!list.items || list.items.length === 0) {
    console.log('empty list');
    return listIsEmpty;
  }
  console.log(`list item found: ${list.items[0].value} with id: ${list.items[0].id}`);
  return list.items[0].value;
}

async function getNamedToDoItem(handlerInput) {
  const listClient = handlerInput.serviceClientFactory.getListManagementServiceClient();
  const listId = await getToDoListId(handlerInput);
  console.log(`named listid: ${listId}`);
  const list = await listClient.getList(listId, listStatuses.ACTIVE);
  if (!list) {
    console.log('null list');
    return null;
  } else if (!list.items || list.items.length === 0) {
    console.log('empty list');
    return listIsEmpty;
  }
  console.log(` named list item found: ${list.items[0].value} with id: ${list.items[0].id}`);
  for (let i = 0; i < lists.items.length; i += 1){
      console.log(`items in named list: ${list.items[i].value} with i: ${i}`)
      if (list.items[i].value.startsWith("Mark")){
          return list.items[i].value
          break
      }
  }
  
  return list.items[0].value;
}

/**
* List API to delete the top todo item.
*/
async function completeTopToDoAction(handlerInput) {
  const listClient = handlerInput.serviceClientFactory.getListManagementServiceClient();
  // get the list
  const listId = await getToDoListId(handlerInput);
  const list = await listClient.getList(listId, listStatuses.ACTIVE);
  console.log(`List length is ${list.items.length}`)
  // if the list doesn't exist, no permissions or has no items
  if (!list) {
    return null;
  } else if (!list.items || list.items.length === 0) {
    return (listIsEmpty);
  }

  // get first item
  const item = list.items[0];
  const updateRequest = {
    value: item.value,
    status: listStatuses.COMPLETED,
    version: item.version,
  };
  return listClient.updateListItem(listId, item.id, updateRequest);
}

// exports

const skillBuilder = Alexa.SkillBuilders.custom();
exports.handler = skillBuilder
  .addRequestHandlers(
    AmazonCancelStopHandler,
    AmazonHelpHandler,
    LaunchRequestHandler,
    CompleteTopToDoHandler,
    TopToDoHandler,
    NamedTopToDoHandler,
    SessionEndedHandler,
    CreateListHandler,
    CreateTripleListHandler,
  )
  .addErrorHandlers(ErrorHandler)
  .withApiClient(new Alexa.DefaultApiClient())
  .withCustomUserAgent('cookbook/list-access/v1')
  .lambda();

Interaction model for the custom skill

JSON
This JSON file describes an interaction model of the skill
{
    "interactionModel": {
        "languageModel": {
            "invocationName": "treats for chores",
            "intents": [
                {
                    "name": "TopToDoIntent",
                    "slots": [
                        {
                            "name": "name",
                            "type": "AMAZON.FirstName"
                        }
                    ],
                    "samples": [
                        "what is top to do for {name}",
                        "what is {name} top to do",
                        "top to do for {name}",
                        "{name} top todo",
                        "{name} top to do",
                        "stop todo",
                        "stop to do"
                    ]
                },
                {
                    "name": "CompleteTopToDoIntent",
                    "slots": [
                        {
                            "name": "name",
                            "type": "AMAZON.FirstName"
                        }
                    ],
                    "samples": [
                        "top task for {name} is done",
                        "{name} have done the top task",
                        "{name} have completed the top task",
                        "complete top task for {name}",
                        "clear {name} top todo",
                        "clear {name} top to do",
                        "delete {name} top todo",
                        "delete {name} top to do",
                        "delete todo for {name}",
                        "delete {name} to do",
                        "delete to do for {name}",
                        "complete {name} todo",
                        "complete todo for {name}",
                        "complete top todo for {name}"
                    ]
                },
                {
                    "name": "NamedTopToDoIntent",
                    "slots": [],
                    "samples": [
                        "what is my named todo",
                        "what is my named to do",
                        "named todo",
                        "named to do",
                        "my named todo",
                        "my named to do",
                        "stop named todo",
                        "stop named to do"
                    ]
                },
                {
                    "name": "AMAZON.CancelIntent",
                    "samples": []
                },
                {
                    "name": "AMAZON.HelpIntent",
                    "samples": []
                },
                {
                    "name": "AMAZON.StopIntent",
                    "samples": []
                },
                {
                    "name": "AMAZON.NavigateHomeIntent",
                    "samples": []
                },
                {
                    "name": "CreateListIntent",
                    "slots": [
                        {
                            "name": "name",
                            "type": "AMAZON.FirstName"
                        }
                    ],
                    "samples": [
                        "Create list for {name}"
                    ]
                },
                {
                    "name": "CreateTripleListIntent",
                    "slots": [
                        {
                            "name": "nameA",
                            "type": "AMAZON.FirstName"
                        },
                        {
                            "name": "nameB",
                            "type": "AMAZON.FirstName"
                        },
                        {
                            "name": "nameC",
                            "type": "AMAZON.FirstName"
                        }
                    ],
                    "samples": [
                        "Please create three lists one for {nameA} one for {nameB} and one for {nameC}",
                        "Create lists for {nameA} for {nameB} and for {nameC}",
                        "Create lists for {nameA} {nameB} and for {nameC}",
                        "Create list for {nameA}  {nameB} and {nameC}"
                    ]
                }
            ],
            "types": []
        }
    }
}

Credits

Nikolay Beliovsky

Nikolay Beliovsky

1 project • 1 follower
STEM teacher at Moscow Economical School I've been making a lot of different projects since I was 9 years old, when I was introduced to LEGO
Benjamin

Benjamin

0 projects • 0 followers

Comments