node-red-contrib-ecolect is a wrapper around the Ecolect natural language matching library. Whilst it was developed as a complementary module for node-red-contrib-google-action to process speech input, it can process text messages received from anywhere.
This node takes a plain text string and tries to match it to one of the configured topics using fuzzy pattern matching of training phrases. The node can also extract values from the string such as numbers, dates, times, and sub-strings. The value extraction is quite powerful and will interpret values like 'next Friday', 'in 15 minutes', '2.4 million'.
Messages for each topic are sent on separate outputs so that they can be processed by a flow specific to that topic. The last output is always for messages that the processor could not recognise.
The output message contains the matched topic and the extracted values. All other message properties are passed through unchanged.
The Ecolect library works by comparing each word in the input with the corresponding word in each training phrase to calculate the edit distance. It then returns the topic for the phrase with the lowest total edit distance. This is not as powerful as the approach used by cloud based systems such as Google Assistant which use Bayesian techniques to calculate the probability that an input phrase matches a topic based of the frequency of word combinations in the training phrases. The Bayesian approach is good for handling a large variety of topics from a large population of speakers but requires a lot of training. Ecolect doesn't require as much training but isn't good at matching on input that is only vaguely similar to the training phrases.
Here is a simple example application:
I have a SonoffTH sensor running Tasmota on each of the three levels of my house which feed temperature and humidity information to Node Red via MQTT. From these readings the comfort level is calculated for each area and all of the information is recorded in the global context.
This flow allows me to query the current temperature, humidity or comfort level for each area using Google Assistant

Action Request is the Google Action request listener. Intent is a switch node that directs the flow according to whether the conversation is initiating, processing, or closing. An incoming message for the query "what is the temperature upstairs?" from Google Action looks like:
{"conversationId":"1514954494935",
"intent":"actions.intent.TEXT",
"dialogState":{},
"closeConversation":true,
"userId":"151298",
"payload":"what is the temperature upstairs",
"_msgid":"56de9922.33bec8"}
Ecolect is the Natural Language Matching node that interprets the incoming text. In this example it only has one topic configured that looks like:

The topic has two values defined - room and reading. Using enumerations improves the accuracy of the matching. The phrases specify what the topic will be matched by and include the locations of the values.
If the topic is matched, the message is sent out of the first output, otherwise it will be sent out of the last output. After processing by Ecolect it looks like:
{"topic":"climate",
"conversationId":"1514954494935",
"intent":"actions.intent.TEXT",
"dialogState":{},
"closeConversation":true,
"userId":"151298",
"payload":"what is the temperature upstairs",
"_msgid":"56de9922.33bec8",
"values":{
"reading":"temperature",
"room":"upstairs"},
"score":1}
The message is passed to the Answer Climate Query node. This is a simple change node which uses the following Jsonata to respond to the query by pulling the reading from the global context.
($room := (values.room = "upstairs" ) ? $globalContext("climate.upper") : (
(values.room = "downstairs") ? $globalContext("climate.lower") :
$globalContext("climate.middle"));
$reading := (values.reading = "temperature") ? $room.temperature : (
(values.reading = "humidity") ? $room.humidity : $room.comfort);
$unit := (values.reading = "temperature") ? "degrees" : (
(values.reading = "humidity") ? "percent" : "");
"The " & values.room & " " & values.reading & " is " & $reading & " " & $unit)
After processing by the response node, it looks like:
{"topic":"climate",
"conversationId":"1514954494935",
"intent":"actions.intent.TEXT",
"dialogState":{},
"closeConversation":false,
"userId":"1512980920890",
"payload":"The upstairs temperature is 30.6 degrees",
"_msgid":"56de9922.33bec8",
"values":{
"reading":"temperature",
"room":"upstairs"},
"score":1}
This is sent back to Google and my Google home announces "The upstairs temperature is 30.6 degrees".
dialogState is an object that is passed back and forwards with Google for the life of the conversation. If I stored this queries values in there then I can add contextual awareness to my app. For instance, if I asked 'what is the temperature upstairs?' and then ask "what is it downstairs?" the app could understand that I was still talking about temperature.
Enjoy,
Dean