In my last post, I summarized how I created a Natural Language Processor around which I am building a Home Automation solution. I want my smart home to be able to more than just turn things on an off, so I have been adding pieces of functionality that will automate more than that. The first piece of functionality I added was the ability to create and manage items on a TODO list.
Add the Tokens
If you'll recall from my last post, the language processor contains several Token classes that know how to parse out and tokenize words or phrases. These classes are the building blocks which are used to define the system's vocabulary. For the TODO list functionality, we need to define Token classes for the following:
- "list", "get", "show"
- "for", "on"
- dates and times
The language processor will parse the command we specify into a list of tokens that will be compared to the parameter lists of our command methods. When a match is found, that method is called. We need to define our command methods, next.
Create the Command Methods
In the end, we are wrapping little more than CRUD operations for a TODO list table in the database. One example of a command method is below.
- public static void CreateNewToDoItem(ConversationContext cContext, TokenCreate create, TokenToDo todo, TokenQuotedPhrase phrase)
- var repos = new ToDoRepository();
- var newTodo = repos.CreateNewTodo((string)phrase.Value, null, cContext.ConversationUser.UserId);
- cContext.Say("Added ToDo \"" + phrase.Value + "\"", newTodo);
This method takes a token for "create", one for "todo" and another for a quoted phrase which is any phrase found between quotes. So an example of a command that might result in this method's being called would be
create a new todo "Call the hardware store about paint"
You can see that when the method is executed, a new record is created for the todo item. The first parameter is the conversation context. This context contains information such as what channel the communication is on (IM, email, etc.), the user being conversed with and a list of incoming and outgoing messages in this conversation. This is important in some cases. Consider when the user wants to delete a todo item. We could allow them to specify the item by its text, but that could be error prone and a lot of typing. It'd be better if they could specify only a number. So, in my implementation, the user requests a list of their items and what is returned is a numbered list. The user can then say, "delete 2" to remove the second item.
How does the system know which item was number 2? When the list is generated, it's stored in the context such that 2 corresponds to a particular item. From that point on, it doesn't matter what else happens to the records in the database because 2 doesn't just mean the second item, but the item that was second in that list at that point in time. This is possible because of the context.
The reply to the user gets sent to the right user through the right channel because of the context. In this implementation, we don't have to worry about these details in the command method, the context keeps it sorted out for us.
By repeating the process of creating the necessary tokens to build up our vocabulary and then creating rules to match, functionality is layered onto the system to allow the user to associate a due date and time with the item,
create new todo "call the insurance man" for tomorrow 1:30