The oracle module deals with mapping the input to a parametrized sentence and executing the instructions (the QTL template) upon finding a match. It’s loosely based on AIML and similar constructive approaches to natural language interpretations. Its amazingly simple yet effective, especially in a NodeJS implementation. The speed with which one can alter templates and template interpretation is terribly swift in comparison to, say, Java or Python thanks to JavaScript and JSON’s flexibility.

Let’s start with the most basic example.

{
    "Id": "VtQTrdkSRX",
    "Grab": "Hello $1",
    "Template": {
      "Answer": "Hello you :)"
    },
    "UserId": "Everyone"
  }

This will catch anything that starts with “Hello”, the $1 being a wildcard for anything. The UserId set to Everyone means that it can be used for any user. This allows to have user-specific answers or group-specific answers.

Of course, there are many ways to say hello, but you don’t want to repeat the same answer over and over again. So, you can redirect variations of hello to this template. For example:

{
    "Id": "VtQTrdkS5X",
    "Grab": "Hi",
    "Template": {
      "Answer": {
        "Redirect": "Hello"
      }
    },
    "UserId": "Everyone"
  }

Case sensitivity, quotation marks and such are pre-filtered so you don’t need to catch those.

Input creates knowledge and this gets stored in the semantic network (aka simply the graph):

{
    "Id": "ABI99zzXMr",
    "Grab": "A $1 is a $2",
    "Template": {
      "Answer": {
        "String": "Ok, a $1 is cool."
      },
      "Think": {
        "Create": {
          "Graph": {
            "Nodes": [
              {
                "Title": "$1",
                "DataType": "Thought",
                "Id": 1
              },
              {
                "Title": "$2",
                "DataType": "Thought",
                "Id": 2
              }
            ],
            "Links": [
              {
                "IdSource": "1",
                "IdTarget": "2",
                "Title": "is"
              }
            ]
          }
        }
      }
    },
    "UserId": "Everyone"
  }

The thinking portion here means that the module will execute some stuff besides generating an answer. You can think of these JSON snippets as little programs, codons or thinking genes. In this case an input like “a tree is a plant” or “a car is a vehicle” will create two entities related with an “is” (semantic) relation. The knowledge acquired in this way is re-used by the deduction-module  to infer things. In effect, upon asking “what is a tree” Qwiery will look up the tree entity, search for relationships and tell you eventually that a tree is a plant. This happens to be the exact same answer as what was given initially but this is just a simple example. There are many possibilities here.

Answer variations are realized through random choices. For example, the following template

{
    "Id": "v1Tfis3UbH",
    "Grab": "tell me",
    "Template": {
      "Answer": {
        "Choice": [
          "What do you want to know?",
          "Well, all is fine, what 'bout you?",
          "To be or not to be, that is the Grab.",
          "Nothing specific to tell you at this moment.",
          {
            "Join": [
              "Glad you ask :)",
              {
                "Choice": [
                  "I should analyze a few things!",
                  "Tons of things to do on my backlog."
                ]
              },
              "So, I better move on."
            ]
          }
        ]
      }
    },
    "UserId": "Everyone"
  }

defines a few “Choice” sections which instruct to pick up one of the options. An extension to this could be to link the choice to the emotional module or to the social emotion toward the current user. Here again, things are at the same time easy to extend and fun to experiment with.

The QTL interpretation is very flexible and you can send all sorts of instruction out to the client or out to the Qwiery modules; changing the emotional state, altering the semantic network… The basic implementation in the code assumes the client can deal with various data types. For example

{
    "Id": "rTRTTIO9ti",
    "Grab": "an entity",
    "Template": {
      "Answer": [{
        "Entity": {
          "Title": "Showing you an entity",
          "Description": "Just a demonstration of how an entity can sit in an answer within QTL",
          "DataType": "Thought"
        },
        "DataType": "SingleEntity"
      }]
    },
    "UserId": "Everyone"
  }

this will send a Thought entity and it assumes that the client is capable of recognizing this, render it or whatnot.

The QTL language also allows for more complex processing. For example, a workflow which captures the info to send an email is as follows

 

{
    "Id": "IPCDSE2mUp",
    "Grab": "Send mail",
    "Template": {
      "Answer": "ThinkResult",
      "Think": {
        "CreateReturn": {
          "Workflow": {
            "Name": "Send Mail",
            "Reminder": "An unfinished mail draft is pending with subject '$Subject'",
            "IsActive": false,
            "Variables": {
              "To": "",
              "Subject": "",
              "Body": ""
            },
            "States": [
              {
                "Type": "QA",
                "Name": "Initial state",
                "ActivationResponse": "Sure, let's create a mail.",
                "IsInitial": true
              },
              {
                "Type": "QA",
                "Name": "To state",
                "Variable": "To",
                "ActivationResponse": "What is the mail address to send it to?",
                "RejectResponse": "Sorry, an empty mail address is not valid."
              },
              {
                "Type": "QA",
                "Name": "Subject state",
                "Variable": "Subject",
                "ActivationResponse": "What is the subject?",
                "RejectResponse": "Sorry, an empty subject is not valid."
              },
              {
                "Type": "QA",
                "Name": "Body state",
                "Variable": "Body",
                "ActivationResponse": "What is the content of the mail?",
                "RejectResponse": "Sorry, an empty mail is not valid."
              },
              {
                "Type": "YesNo",
                "Name": "Confirmation state",
                "RejectResponse": "Please just use 'yes', 'no', or 'n' or 'y' or 'yep' or alike. If you tell me to forget about it I will just ignore the info you gave me :)",
                "ActivationResponse": [
                  {
                    "Type": "Summary"
                  },
                  "Do you want to send this mail?"
                ]
              },
              {
                "Type": "QA",
                "Name": "Commit state",
                "IsFinal": true,
                "Execute": "sendMail",
                "ActivationResponse": "The mail was sent."
              },
              {
                "Type": "QA",
                "Name": "Exit state",
                "IsFinal": true,
                "ActivationResponse": "No problem, no mail was sent."
              }
            ],
            "Transitions": [
              {
                "From": "Initial state",
                "To": "To state",
                "Value": true
              },
              {
                "From": "To state",
                "To": "Subject state",
                "Value": true
              },
              {
                "From": "Subject state",
                "To": "Body state",
                "Value": true
              },
              {
                "From": "Body state",
                "To": "Confirmation state",
                "Value": true
              },
              {
                "From": "Confirmation state",
                "To": "Exit state",
                "Value": false
              },
              {
                "From": "Confirmation state",
                "To": "Commit state",
                "Value": true
              }
            ]
          }
        }
      }
    },
    "UserId": "Everyone"
  }

If you are familiar with state-machines you will recognize the typical states and transitions mechanisms. If you have inserted in the config of Qwiery a mail module (the default being the SendGrid service on Azure) this effectively sends an email.

The workflow engine is fun and can easily be extended. It sits in the processing pipeline at the very top because as long as the workflow is active Qwiery will redirect input by to user to the workflow. The user can quit/save the workflow at any moment by using ‘q’ or ‘quit’ or ‘exit’, which will prompt the user for whether the flow needs to be saved or forgotten. If saved, the workflow will be added to the unfinished tasks of the user. Clicking the task will re-initiate the workflow. The cool things about workflows in NodeJS/JSON is that the logic, the state and the data can all sit together in a lightweight JSON snippet. This is a sharp contrast with technologies like .Net or Java where this sort of implementation would engender serious serialization and state management. In this NodeJS implementation one can save the whole workflow in between user sessions as a snippet of JSON.