Skip to content

The intention

As we began to discuss in previous chapters, to validate a voice rule A.V.A.T.A.R uses intentions and actions, which are simple functions that receive a state and return it with an internal composition:

  • Intention: The function you wish to attach to a sentence.
  • Action: An action function that will be called if the intention is satisfactorily resolved.

We can think of it like this:

graph LR
  A[Sentence]
  A --> B{NLP};
  B --> C[Plugin<br>Intention file];
  C --> F{resolved?};
  F --> |Yes| G[Plugin<br>Action file]; 
  F --> |No| I[Exit]; 
  C --> |access to| H[Plugin<br>Property file<br>];
  G --> J[Plugin<br>Script file];
  G --> |access to| H;
  J --> |access to| H;
  J --> K['action' method];
  I --> O{Next<br>plugin?};
  O --> |Yes| L[Intention file<br>plugin x...];
  L --> F{resolved?};
  O --> |No| P[Exit];
  P --> Q[Message from A.V.A.T.A.R:<br>Start again, I didn't understand]; 

Resolution methods

Resolution methods for validating a rule that can be used in the intention file.

By sentence syntax

helpers.syntax(sentence, terms)

  • sentence string - state.sentence (in english).
  • terms array - Array of rules (in English)

If one of the terms is validated, then the intention is resolved.

import {default as _helpers} from '../../ia/node_modules/ava-ia/helpers/index.js';

export default async function (state, actions) {
    // Exit if the intent is already resolved
    if (state.isIntent) return (0, _helpers.resolve)(state);

    // Loop over array of terms in the `rules` object of the property file
    for (var rule in Config.modules.myFirstPlugin.rules) {   
        // Trys to resolve the intent by the syntax
        var match = (0, _helpers.syntax)(state.sentence, Config.modules.myFirstPlugin.rules[rule]);
        // If verified, then exit
        if (match) break;
    }

    // Is intent resolved?
    if (match) {
        state.isIntent = true;
        state.rule = rule;
        // sends the result to the associated action file
        return (0, _helpers.factoryActions)(state, actions);
    } else 
        // otherwize continues to check next plugin
        return (0, _helpers.resolve)(state);
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
    "modules": { 
        "myFirstPlugin": {
            "version": "1.0",
            "name": "My first plugin",
            "rules": {
                "test": ["test * (command|order)"]
            }
        }
    }
}

By a term in the sentence

helpers.intersect(terms, tokens)

  • terms array - Collection of terms.
  • tokens array - The tokens of the state.sentence sentence.

If one of the tokens is validated, the intention is resolved.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import {default as _helpers} from '../../ia/node_modules/ava-ia/helpers/index.js';

export default async function (state, actions) {
  // Exit if the intent is already resolved
    if (state.isIntent) return (0, _helpers.resolve)(state);

    // Loop over array of tokens in the `rules` object of the property file
    for (var rule in Config.modules.myFirstPlugin.rules) {  
      // Trys to resolve the array of tokens
      var match = (0, _helpers.intersect)(Config.modules.myFirstPlugin.rules[rule], state.tokens); 
      // If verified, then exit
      if (match) break;
    }

    // Is intent resolved?
    if (match) {
        state.isIntent = true;
        state.rule = rule;
        // sends the result to the associated action file
        return (0, _helpers.factoryActions)(state, actions);
    }  else 
        // otherwize continues to check next plugin
        return (0, _helpers.resolve)(state);
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
    "modules": { 
        "myFirstPlugin": {
            "version": "1.0",
            "name": "My first plugin",
            "rules": {
                "test": ["1", "one"]
            }
        }
    }
}
Info

The state.tokens array is composed automatically with the sentence (in English) before the intent call (see previous chapter)

For the sentence “what time is it”, the state.tokens object is :

state.tokens: [ 'what', 'time', 'is', 'it' ]

Simple intention

The validation of the intention proposed by Plugin Studio is a simple resolution by the arrays of the rules object in the plugin properties file. This validation generally covers 90% of requirements.

Personalized intention

The formatting of an intention is not fixed. It's up to you to choose, depending on what you want to make. For example, an object array can link to another object array in the plugin's properties file.

Here's an example of solving a slightly more complex problem for a home automation project.
Suppose we want to retrieve all the information required for an action that can be identical to several devices with the following sentences:

- turn on/off the light (default room = living room)
- turn on/off the light in the living room
- turn on/off the light in the kitchen

We can understand that the device ID is different for each part and so is the value to be passed to the device for the action, which gives:

- Living room ID: 1151500     // device ID
- Kitchen ID: 2664444         // device ID
- value Off: 0                // same value "Off" for both devices
- value On: 100               // same value "On" for both devices

Below are the intention and property files corresponding to an elegant solution of the problem:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import {default as _helpers} from '../../ia/node_modules/ava-ia/helpers/index.js'
import _ from 'underscore';

export default async function (state, actions) {
  var match, command, type, value, periph, answer;

  // The intents object in the property file
  var tbl = Config.modules.myFirstPlugin.intents;

  /** Searches for the room for which the rule is executed
  /* - sentence: turn on the light in the Living room
  /* - return: Living room
  const clientTo = Avatar.clientFromRule(state.rawSentence);

  // for all entries of the "intents" object
  for (var i=0 ; i < tbl.length && !match; i++) {

      // for all entries of the "ruleGroups" object
      for (value in Config.modules.myFirstPlugin.ruleGroups[tbl[i]]) {

          // Only if the entries passe the test
          if (value !== 'command' && value !== 'answer') {

              // Trys to resolve the intent by the syntax
              match = (0, _helpers.syntax)(state.sentence, Config.modules.myFirstPlugin.ruleGroups[tbl[i]][value]);

              // Is intent resolved?
              if (match) {

                  // Keeps the command 
                  command = Config.modules.myFirstPlugin.ruleGroups[tbl[i]].command 
                  ? Config.modules.myFirstPlugin.ruleGroups[tbl[i]].command 
                  : false;

                  // Keeps the answer if exists
                  answer = Config.modules.myFirstPlugin.ruleGroups[tbl[i]].answer 
                  ? Config.modules.myFirstPlugin.ruleGroups[tbl[i]].answer 
                  : false;

                  // Keeps the periph ID in the "clients" object
                  type = tbl[i];
                  _.map(Config.modules.myFirstPlugin.intents[type], num => { 
                    if (Config.modules.myFirstPlugin.clients[clientTo][num]) {
                      periph = Config.modules.myFirstPlugin.clients[clientTo][num];
                    }   
                  })
                  break;
              }
          }
      }
  }

  // Is intent resolved? 
  if (match) {

      // Sets information
      state.isIntent = true;
      state.command = command;
      state.periph = periph ? periph : false;
      state.value = value ? value : false;
      state.answer = answer ? answer : false;

      // sends the result to the associated action file
      return (0, _helpers.factoryActions)(state, actions);
  } else {
      // otherwize continues to check next plugin
      return (0, _helpers.resolve)(state);
  }
}
{
  "modules":{
    "myFirstPlugin":{
      "name":"myFirstPlugin",
      "ruleGroups":{
        "switch":{
          "0":["turn off * light","extins * light"],
          "100":["turn on * light","light * light"],
          "command":"set",
          "answer":"magic!"
        },
        "temperature":{
          "command":"get",
          "get":["give * temperature"]
        },
        "tv":{
          "0":["turn off * tv","off * tv","tv * off"],
          "100":["turn on * tv","turne on * tv"],
          "command":"set"
        }
      },
      "clients":{
        "Living room":{
          "Living room switch":"1151500",
          "Living room temperature":"152764",
          "Living room TV jack":"1982673"
        },
        "Kitchen":{
          "Kitchen switch":"2664444",
          "Kitchen temperature":"5598874"
        },
        "Bedroom":{
          "Bedroom TV jack":"483087"
        }
      },
      "intents":{
        "switch":["Living room switch","Kitchen switch"],
        "temperature":["Living room temperature", "Kitchen temperature"],
        "tv":["Living room TV jack","Bedroom TV jack"]
      }
    }
  }
}

Explanation

  1. Line 13: Finds the client in the sentence (can be a real client or a virtual client), returns the client for which the action is to be performed (see Avatar.clientFromRule() for futher information).

    Warning

    A client name doesn't have to be translated!
    The verification of the client in the sentence is resolved with the current language (state.rawSentence)

  2. Line 16: For all entries in the intents object.

  3. Line 19: For all entries in the ruleGroups object.
  4. Line 25: Checks the sentence by the syntaxe for the ruleGroups[intents[i]][value] array.
  5. Line 28: If checked, retrieves the values of the “command”, “answer” and “periph” keys.
  6. Line 64: Sends information to the associated action file.

What's important to remember?

  1. Be sure to choose the type of intention you want for your plugin. Except in specific cases, the validation by the syntax is the most widely used.
  2. Nothing is set in stone. You can modify the intent.myFirstPlugin.js file as you wish.


Natural Language ProcessingThe action