0

I'm creating some kind of a "personal assistant" application which is basically a web service that receives a message and then does something according to it.

For example I send "what time is it?" and I get the current time as answer. Other examples:

  • "tell me a joke" -> queries and sends some joke from an public api
  • "I have to [X] -> sets [X] to todo list
  • "What do I have to do?" -> sends todo list
  • "Start my pc" -> Starts PC via Wake On Lan

or what ever else comes to my mind.

My first prototype just uses an if else statment which looks something like

if message.contains("foo"):
  # do foo stuff
elif message.contains("bar"):
  # do bar stuff

Of course this will be a total mess after adding several commands so I'm thinking about what would be a good concept to structure such a huge conditional statement.

(I'm using Python with the web.py framework)

One idea is to use some list / map to create a mapping between key words and associated functions and split functionality in different classes (like a todo list module and so on).

There are applications like WolframAlpha or Siri which have just a single input method but several hundred or thousand different functions in the brackground. Of course those are on a totally different level but in general, how do you create a nice and clean branching from a single input to a big number of different functions?

  • 1
    @gnat: That's not a dupe, but I swear I've seen this question before. – Robert Harvey Mar 2 '16 at 15:27
  • 1
    You are delving into the realm of NLP. You are either going to have to have a bajillion branching conditions and a hand coded parser of enormous complexity (and there's no way around that or making it look pretty), or go down the path of graduate level research in natural language programming. – user40980 Mar 2 '16 at 15:29
  • 1
  • 3
    @gnat: None of those are duplicates. The "huge conditional statement" thing is a red herring; large if statements are not how personal assistants work. – Robert Harvey Mar 2 '16 at 15:32
  • 1
    If you're going to go up against a graduate-level problem like this, I think your best bet is to combine a voice recognition system like Sphinx with a search engine like Apache Lucene. – Robert Harvey Mar 2 '16 at 15:36
1

The usual approach to mapping strings to functions is to use a dictionary or hashtable. Here is what it would look like in C#:

var commands = new Dictionary<string, Action<string>>();

This creates a hash table with a string key and a method delegate taking one parameter (in this case a string. You can use the parameter however you want).

You can create the commands at compile time:

var commands = new Dictionary<string, Action<string>>
{
    { "Tell me a joke", TellJoke }, 
    { "I have to",  IHaveTo }
};

or at runtime:

commands.add("Tell me a joke", TellJoke);

Where TellJoke is some method that takes one parameter and returns nothing. After a bit of pre-processing of the search string, the mapped function would then be called thusly:

Commands[searchKey](searchString);

or more robustly:

bool ExecuteCommand(string key, string search)
{
    if (commands.Contains(key))
    {
        Commands[searchKey](search);
        return true;
    }
    return false;
}

Of course, a real personal assistant wouldn't work this way. You would have some sort of engine that can be modified at runtime, not compile time, so that it can learn.

  • If the key is parameterized (such as with "I have to {0}" - you're likely going to be walking all the indexes if you don't find an exact match anyways. This is not likely to be efficient. A Trie based system with wildcards might be a better choice for the underlying data structure. – user40980 Mar 2 '16 at 16:01
  • @MichaelT: Fixed. This arrangement would likely pass an arbitrary string parameter to every method anyway (i.e. the original search term). As I already hopefully made clear, the approach is naive. – Robert Harvey Mar 2 '16 at 16:02
  • Of course naive dictionary lookup wouldn't be compatible with place holders. I'd probably use a dictionary fixed prefixes and pattern matching/regexes to disambiguate if necessary. – CodesInChaos Mar 2 '16 at 16:02
  • @CodesInChaos I don't disagree with you at all on that, though {"prefix" => {"validation regex1" => fp1, "validation regex2" => fp2, "default" => fp3}, "prefix", ...} is going to get hairy too once you start trying to handle it all. And I dread trying to test the data structure. – user40980 Mar 2 '16 at 16:12
  • @MichaelT I'd produce both the prefix and the regex programmatically from the original pattern (which might either be a regex or a simpler language). I'd use some kind of dictionary for the prefix and a flat list for the regex+action. In the first version I'd start with a simple linear search through a list, only adding the prefix dictionary as an optimization later on. – CodesInChaos Mar 2 '16 at 16:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.