Callbacks

This feature will allow you to integrate eddi with a backend server to monitor the messages with a chatbot.

The callback can be invoked by multiple actions that you define in the package , you will receive in the post body a conversationMemorySnapshot which is the model that has all information about the current conversation that invoked this callback, we will go through a step by step example to show you how callbacks work.

In order to enbale and configure callbacks in abot you will have to add this into one of the packages used by the chatbot:

callback package extension
   {
    "type": "eddi://ai.labs.callback",
    "config": {
      "callbackUri": "String",
      "action": "String",
      "callOnActions":"String",
      "timeoutInMillis": Long
      }
    }

Description :

typeMust be eddi://ai.labs.callback to activate a callback.
config.callbackUri

(String) this is the URI that will be invoked; a POST request will be sent to that URI alongside conversationMemorySnapshot in the request body.

config.action(String) if you have one action that will invoke the callback use this property.
config.callOnActions(String) if you have multiple actions that will invoke the callback use this property, it should coma separated values. e.g("action1,action2,...").
config.timeoutInMillis

(Long) a duration of time in millisecond before timeout occurs.

Here is the model for conversationMemorySnapshot :

conversationMemorySnapshot structure
  "conversationMemorySnapshot": {
    "id": "String",
    "botId": "String",
    "botVersion": Integer,
    "environment": "String",
    "conversationState": "String",
    "conversationSteps": [array of conversationSteps],
    "redoCache": []
  }

Description :

id(String) id of the conversation
botId(String) id of the bot
botVersion(String) version of the chatbot
environment(String) bot environment e.g: restricted, unrestricted
conversationState

(String) enumeration values :

READY,
IN_PROGRESS
ENDED
EXECUTION_INTERRUPTED
ERROR

conversationSteps(Array of conversationStep) History of the conversation

Important note

Callbacks does not have a store like the other extensions e.g : http calls, behaviorSet, regularDictionaries,etc..

Step by step example :

We will do a step by step example from scratch (chatbot creation to a simple conversation that uses a callback)

For the sake of simplicity we will use a simple nodejs http server to intercept the callback and get the conversation snapshot.

1 - Create regularDictionnary 

More about regular dictionaries can be found  here .

Creating the regular dictionary
Request URL
	POST	http://localhost:7070/regulardictionarystore/regulardictionaries

Request Body

{
  "language" : "en",
  "words" : [
    {
      "word" : "callback",
      "exp" : "callback(*)",
      "frequency" : 0
    }
  ],
  "phrases" : [
    {
      "phrase" : "callback",
      "exp" : "callback"
    }
    
  ]
}

Response Body
	no content

Response Code
	201

Response Headers
{
  "access-control-allow-origin": "*",
  "date": "Sun, 13 May 2018 16:40:58 GMT",
  "access-control-allow-headers": "authorization, Content-Type",
  "content-length": "0",
  "location": "eddi://ai.labs.regulardictionary/regulardictionarystore/regulardictionaries/5af86a9aba31c023bcb9ef2b?version=1",
  "access-control-allow-methods": "GET, PUT, POST, DELETE, PATCH, OPTIONS",
  "access-control-expose-headers": "location",
  "content-type": null
}

2 - Create the behaviorSet

More about behaviorSets can be found here.

Creating the behaviorSet
Request URL
	POST	http://localhost:7070/behaviorstore/behaviorsets
Response Body
	no content
Response Code
	201

Request Body

{
  "behaviorGroups": [
    {
      "name": "Smalltalk",
      "behaviorRules": [
        {
          "name": "callback",
          "actions": [
            "callback"
          ],
          "children": [
            {
              "type": "inputmatcher",
              "values": {
                "expressions": "callback"
              }
            }
          ]
        }
      ]
    }
  ]
}

Response Headers
{
  "access-control-allow-origin": "*",
  "date": "Sun, 13 May 2018 16:45:52 GMT",
  "access-control-allow-headers": "authorization, Content-Type",
  "content-length": "0",
  "location": "eddi://ai.labs.behavior/behaviorstore/behaviorsets/5af86bc0ba31c023bcb9ef2c?version=1",
  "access-control-allow-methods": "GET, PUT, POST, DELETE, PATCH, OPTIONS",
  "access-control-expose-headers": "location",
  "content-type": null
}

3 - Create the outputSet

More about outputSet can be found here.

Creating the outputSet
Request URL
	POST	http://localhost:7070/outputstore/outputsets

Request Body
{
  "outputSet": [
    {
      "action": "callback",
      "timesOccurred": 0,
      "outputs": [
        {
          "type": "text",
          "valueAlternatives": [
            "callback is done please check you nodejs server log"
          ]
        }
      ]
    }
  ]
}

Response Body
	no content

Response Code
	201

Response Headers
{
  "access-control-allow-origin": "*",
  "date": "Sun, 13 May 2018 16:48:37 GMT",
  "access-control-allow-headers": "authorization, Content-Type",
  "content-length": "0",
  "location": "eddi://ai.labs.output/outputstore/outputsets/5af86c65ba31c023bcb9ef2d?version=1",
  "access-control-allow-methods": "GET, PUT, POST, DELETE, PATCH, OPTIONS",
  "access-control-expose-headers": "location",
  "content-type": null
}

4 - Create a nodejs test server 

at this step we will create a simple nodejs http server to intercept the callback.

Copy this code into a file named app.js and then run the command : node app.js

You should get as output in the console : Server running at http://127.0.0.1:3333/ if you successfully ran the file.

app.js
var http = require('http');
var qs = require('querystring');

http.createServer(function (request, response) {

	console.log(request.method);
	console.log(request.url);

	 if (request.method == 'POST') {
        var body = '';

        request.on('data', function (data) {
            body += data;

            // Too much POST data, kill the connection!
            // 1e6 === 1 * Math.pow(10, 6) === 1 * 1000000 ~~~ 1MB
            if (body.length > 1e6)
                request.connection.destroy();
        });

        request.on('end', function () {
            var postData = qs.parse(body);
            console.log(postData);
            // use post['blah'], etc.
        });
    }

  response.writeHead(200, {'Content-Type': 'text/plain'});
  response.end('Hello World\n');

}).listen(3333, '127.0.0.1');
console.log('Server running at http://127.0.0.1:3333/');


5 - Creating the package

More about packages can be found here.

Creating the package
Request URL
	POST	http://localhost:7070/packagestore/packages

Request Body
{
  "packageExtensions": [
    {
      "type": "eddi://ai.labs.parser",
      "extensions": {
        "dictionaries": [
          {
            "type": "eddi://ai.labs.parser.dictionaries.integer"
          },
          {
            "type": "eddi://ai.labs.parser.dictionaries.decimal"
          },
          {
            "type": "eddi://ai.labs.parser.dictionaries.punctuation"
          },
          {
            "type": "eddi://ai.labs.parser.dictionaries.email"
          },
          {
            "type": "eddi://ai.labs.parser.dictionaries.time"
          },
          {
            "type": "eddi://ai.labs.parser.dictionaries.ordinalNumber"
          },
          {
            "type": "eddi://ai.labs.parser.dictionaries.regular",
            "config": {
              "uri": "eddi://ai.labs.regulardictionary/regulardictionarystore/regulardictionaries/{{dictionary_id}}?version=1"
            }
          }
        ],
        "corrections": [
          {
            "type": "eddi://ai.labs.parser.corrections.stemming",
            "config": {
              "language": "english",
              "lookupIfKnown": "false"
            }
          },
          {
            "type": "eddi://ai.labs.parser.corrections.levenshtein",
            "config": {
              "distance": "2"
            }
          },
          {
            "type": "eddi://ai.labs.parser.corrections.mergedTerms"
          }
        ]
      },
      "config": {}
    },
    {
      "type": "eddi://ai.labs.behavior",
      "config": {
        "uri": "eddi://ai.labs.behavior/behaviorstore/behaviorsets/{{behaviourset_id}}?version=1"
      }
    },
    {
      "type": "eddi://ai.labs.output",
      "config": {
        "uri": "eddi://ai.labs.output/outputstore/outputsets/{{outputset_id}}?version=1"
      }
    },
    {
    "type": "eddi://ai.labs.callback",
    "config": {
      "callbackUri": "http://127.0.0.1:3333/",
      "action": "callback",
      "callOnActions":"",
      "timeoutInMillis": 10000
      }
    }
  
  ]
}

Response Body
	no content

Response Code
	201

Response Headers
{
  "access-control-allow-origin": "*",
  "date": "Sun, 13 May 2018 19:26:36 GMT",
  "access-control-allow-headers": "authorization, Content-Type",
  "content-length": "0",
  "location": "eddi://ai.labs.package/packagestore/packages/5af8916cba31c023bcb9ef2f?version=1",
  "access-control-allow-methods": "GET, PUT, POST, DELETE, PATCH, OPTIONS",
  "access-control-expose-headers": "location",
  "content-type": null
}

6 - Creating the bot

Creating the chatbot
Request URL
	POST	http://localhost:7070/botstore/bots

Request Body
{
  "packages" : [
    "eddi://ai.labs.package/packagestore/packages/{{package_id}}?version=1"
  ],    "channels" : []
}

Response Body
	no content

Response Code
	201

Response Headers
{
  "access-control-allow-origin": "*",
  "date": "Sun, 13 May 2018 21:18:16 GMT",
  "access-control-allow-headers": "authorization, Content-Type",
  "content-length": "0",
  "location": "eddi://ai.labs.bot/botstore/bots/5af8ab98ba31c023bcb9ef32?version=1",
  "access-control-allow-methods": "GET, PUT, POST, DELETE, PATCH, OPTIONS",
  "access-control-expose-headers": "location",
  "content-type": null
}

7 - Deploy the bot

Deploying the chatbot
Request URL
	POST	http://localhost:7070/administration/restricted/deploy/<bot_id>?version=1&autoDeploy=true

Response Body
	no content

Response Code
	202

Response Headers
{
  "access-control-allow-origin": "*",
  "date": "Sun, 13 May 2018 21:21:54 GMT",
  "access-control-allow-headers": "authorization, Content-Type",
  "content-length": "0",
  "access-control-allow-methods": "GET, PUT, POST, DELETE, PATCH, OPTIONS",
  "access-control-expose-headers": "location",
  "content-type": null
}

8 - Create the conversation

Creating the conversation
Request URL
	POST	http://localhost:7070/bots/<env>/<bot_id>

Response Body
	no content

Response Code
	201

Response Headers
{
  "access-control-allow-origin": "*",
  "date": "Sun, 13 May 2018 21:30:45 GMT",
  "access-control-allow-headers": "authorization, Content-Type",
  "content-length": "0",
  "location": "eddi://ai.labs.conversation/conversationstore/conversations/5af8ae85ba31c023bcb9ef35",
  "access-control-allow-methods": "GET, PUT, POST, DELETE, PATCH, OPTIONS",
  "access-control-expose-headers": "location",
  "content-type": null
}

9 - Say callback

Creating the conversation
Request URL
	POST	http://localhost:7070/bots/<env>/<bot_id>/<conversation_id>?returnDetailed=false&returnCurrentStepOnly=true

Request Body
	{
		"input":"callback"
	}

Response Body
{
    "botId": "5af8b075ba31c023bcb9ef3b",
    "botVersion": 1,
    "environment": "unrestricted",
    "conversationState": "READY",
    "redoCacheSize": 0,
    "conversationSteps": [
        {
            "conversationStep": [
                {
                    "key": "input:initial",
                    "value": "weather"
                },
                {
                    "key": "actions",
                    "value": [
                        "ask_for_city"
                    ]
                },
                {
                    "key": "output:text:ask_for_city",
                    "value": "Which City would you like to know the weather of?"
                }
            ],
            "timestamp": 1526247548410
        }
    ]
}

Response Code
	200

Response Headers
{
  "access-control-allow-origin": "*",
  "date": "Sun, 13 May 2018 21:35:15 GMT",
  "content-type": "application/json;resteasy-server-has-produces=true",
  "access-control-allow-headers": "authorization, Content-Type",
  "content-length": "325",
  "access-control-allow-methods": "GET, PUT, POST, DELETE, PATCH, OPTIONS",
  "access-control-expose-headers": "location"
}

10 - check the nodejs console

We will find in the nodjs console something similar to this : 

Creating the conversation
{
  "conversationMemorySnapshot": {
    "id": "5b01a9e1ba31c030b4c461ed",
    "botId": "5b01a9d5ba31c030b4c461eb",
    "botVersion": 1,
    "environment": null,
    "conversationState": "IN_PROGRESS",
    "conversationSteps": [
      {
        "packages": [
          {
            "context": "",
            "lifecycleTasks": [
              {
                "key": "behavior_rules:fail",
                "result": [
                  "callback"
                ],
                "possibleResults": [
                  [
                    "callback"
                  ]
                ],
                "timestamp": 1526835681004,
                "public": false
              }
            ]
          }
        ]
      },
      {
        "packages": [
          {
            "context": "",
            "lifecycleTasks": [
              {
                "key": "input:initial",
                "result": "callback",
                "possibleResults": [
                  "callback"
                ],
                "timestamp": 1526835683768,
                "public": true
              },
              {
                "key": "input:formatted",
                "result": "callback",
                "possibleResults": [
                  "callback"
                ],
                "timestamp": 1526835683768,
                "public": false
              },
              {
                "key": "input:normalized",
                "result": "callback",
                "possibleResults": [
                  "callback"
                ],
                "timestamp": 1526835683768,
                "public": false
              },
              {
                "key": "expressions:parsed",
                "result": "callback",
                "possibleResults": [
                  "callback"
                ],
                "timestamp": 1526835683768,
                "public": false
              },
              {
                "key": "behavior_rules:success",
                "result": [
                  "callback"
                ],
                "possibleResults": [
                  [
                    "callback"
                  ]
                ],
                "timestamp": 1526835683768,
                "public": false
              },
              {
                "key": "actions",
                "result": [
                  "callback"
                ],
                "possibleResults": [
                  [
                    "callback"
                  ]
                ],
                "timestamp": 1526835683769,
                "public": true
              },
              {
                "key": "output:text:callback",
                "result": "callback is done please check you nodejs server log",
                "possibleResults": [
                  "callback is done please check you nodejs server log"
                ],
                "timestamp": 1526835683769,
                "public": true
              }
            ]
          }
        ]
      }
    ],
    "redoCache": []
  }
}

Full example :

If you would like to run the full example through postman , you can download and import the collection below.