A Natural Language Understanding (NLU) toolkit for Flutter.
This is a direct port of https://github.com/kolloldas/EasyNLU
easy_nlu
is a combinatory categorial grammar (CCG) library written in pure Dart. It is capable of transforming natural language utterances such as:
meet Alice Monday night for dinner
into a canonical, structured form like:
{
"task": "meet Alice",
"auxtask": "dinner",
"startTime": {
"dow": 1,
"shift": "night"
}
}
The high level steps to integrating an NLU capability, broadly are the following:
- Define the rules for the parser
- Collect labeled samples and train the parser
- Write a resolver to convert the strcutured form into task specific objects
- Integrate into the mobile app
As a toy example, we can define a task such as turning on and off phone features like Bluetooth, Wifi and GPS.
i.e.:
{"feature": "bluetooth", "action": "enable}
A few sample inputes could be:
- turn off Bluetooth
- bt on
- enable wifi
- kill GPS
We can say that at the top level, we have a command that must have a feature and an action. We can capture this as
Rule r1 = Rule.fromStrings("\$Setting","\$Feature \$Action");
Rule r2 = Rule.fromStrings("\$Setting","\$Action \$Feature");
A rule contains a left hand side (LHS) and right hand side (RHS) at a minimum. By convention, we prepend a "$" to a word to indicate it denotes a category. A category represents a collection of words or other categories. We can capture our target words like "bluetooth", "bt", "wifi", etc as lexical rules, normalized for variations and structured into sub-features:
List<Rule> featureRules = [
Rule.fromStringWithParsedTemplate("\$Feature", "\$Bluetooth", "{\"feature\": \"bluetooth\"}"),
Rule.fromStringWithParsedTemplate("\$Feature", "\$Wifi", "{\"feature\": \"wifi\"}"),
Rule.fromStringWithParsedTemplate("\$Feature", "\$Gps", "{\"feature\": \"gps\"}"),
Rule.fromStrings("\$Bluetooth", "bt"),
Rule.fromStrings("\$Bluetooth", "bluetooth"),
Rule.fromStrings("\$Wifi", "wifi"),
Rule.fromStrings("\$Gps", "gps"),
Rule.fromStrings("\$Gps", "location"),
];
For our actions:
List<Rule> actionRules = [
Rule.fromStringWithParsedTemplate(
"\$Action", "\$EnableDisable", "{\"action\": \"@first\"}"),
Rule.fromStringWithParsedTemplate(
"\$EnableDisable", "?\$Switch \$OnOff", "@last"),
Rule.fromStringWithParsedTemplate(
"\$EnableDisable", "\$Enable", "enable"),
Rule.fromStringWithParsedTemplate(
"\$EnableDisable", "\$Disable", "disable"),
Rule.fromStringWithParsedTemplate("\$OnOff", "on", "enable"),
Rule.fromStringWithParsedTemplate("\$OnOff", "off", "disable"),
Rule.fromStrings("\$Switch", "switch"),
Rule.fromStrings("\$Switch", "turn"),
Rule.fromStrings("\$Enable", "enable"),
Rule.fromStrings("\$Disable", "disable"),
Rule.fromStrings("\$Disable", "kill")
];
The "?" in the third rule means that the category is optional.
To determine if a parse is successful, the parser looks for a special category called the root category. It is denoted as "$ROOT".