Examples of chatbots

Using Postback

Postback is a mechanism whereby if a user clicks a button, the response is stored in a "payload" which can be read by an item further on in the flow. This can be used to branch the chatbot's flow depending on user response.

The following shows a chatbot example that asks the user whether or not they have an account, and if so, asks for the account number.

Example using Postback

Although there is no direct link between Account Query and the two boxes Account Confirmation and No Account Confirmation, there is a logical link that has been created using a Postback button type with a payload.

In the Account Query box, there are two buttons defined: one labelled Yes and one No. In each case the Button Type is Postback. The payload for these buttons is defined as account_yes and account_no respectively. This is why the two boxes labelled Yes and No appear and are linked to the Account Query box. The user will be presented with two buttons, one labelled Yes and No, to click in response to the question "Do you have an account?" Depending on the user response, the payload is set to either account_yes or account_no.

The Account Confirmation box has account_yes in the box When the User Says, while the No Account Confirmation box has account_no in the box When the User Says. Therefore only one of these boxes will be processed, depending upon the payload set in the Account Query box, and the chatbot flow branches.

Using Conditions

When the user responds to a question, that response can be written to a variable, which can later be tested in a condition to determine what happens next.

The following example achieves the same end as the Postback example above, but using conditions instead of Postback. The only difference is that the user must type their response to the question Do you have an account? (yes or no) rather than clicking a button.

Example using conditions

In the Account Query box, under Answers, a variable name of account_status is specified to store the user's response (which should be yes or no). The box Act on Account Status has the following conditions under Settings:

Condition settings for the Act box

The first condition says that if account_status = yes, then continue with the box called Account Confirmation.

The second condition says that if account_status = no, then continue with the box called No Account Confirmation.

Using the REST Action: example of extracting data

This example shows the use of an Action interaction in a chatbot to extract data via a REST API. This chatbot is designed to provide the user with the latest New York Times bestseller (out of three categories) and provide a link for them to order it on Amazon. It is configured as follows:

Example using REST action

The flow throughout this chatbot is described below.

Start and Choose List

The chatbot displays a welcome message, then asks the user which book list they would like to view. There are three possible options: Hardcover Graphic Books, Paperback Graphic Books and Manga. These options are displayed as buttons, and a variable called list_name is set to one of the following according to the user's choice:

  • hardcover-graphic-books
  • paperback-graphic-books
  • manga

This is achieved by the three boxes to the right of Choose List.

Get List

The next step is the Action called Get List. This uses a REST API and is configured with the following Details and Settings (nothing is set under Advanced so this tab is not shown):

Get List action

The ACTION TYPE is set to REST, indicating that this action is to interact with a REST API.

The Settings are as follows:

  • ENDPOINT: This is the endpoint of the REST API that is to be accessed. In this case the Endpoint is https://api.nytimes.com/svc/books/v3/lists.json?api-key=1F94qJVdY2PkappNhfTM6myHAXJKqVbp&list={list_name}. The variable list_name, that was populated earlier, is provided as part of the endpoint name; this tells the API from which list to choose the bestseller.
  • METHOD: Can be GET, POST, PUT or DELETE, depending on how you want to use the API. In this example, GET is used, since data is required from the API.
  • AUTHORIZATION: Used to pass the Authorization header, if required. In this example, it is left blank.
  • CONTENT-TYPE: Used to pass the Content-Type header, if required. In this example, it is left blank.
  • HEADERS: Used to specify the name and value of any Header, if required. In this example, it is left blank.
  • VARIABLE NAME: The variable to which the data extracted from the API will be written. In this example, the variable is bestseller. Note that an array of data may be returned, such as context.bestseller.results[0].display_name and context.bestseller.results[0].book_details[0].title.
  • TIME TO LIVE: The number of minutes for which the information obtained from the REST API call stays in the cache. If this is blank or set to zero, no data is cached (as in this example).
  • SET DATA FROM RESPONSE: Specifies the data to hold the response from the REST API call. In this example, the field is blank because the response data is returned to the variable specified under VARIABLE NAME.
  • SET ERROR IF RESPONSE: If the response from the REST API call contains or does not contain (depending on the dropdown in the first box) the data in the second box, an error is raised. In this example, the error boxes are not used.
  • Test: This button is provided so that you can test the response from the API. However, if you include a variable name in the ENDPOINT parameter (as in this example), you cannot test the response; you must preview the chatbot instead.

Get Bestseller Details

This is another Action. Its purpose is to extract the data returned from the REST API call into variables that are used later in the chat.

The ACTION TYPE is Set Variable, and the Settings tab has the following piece of Java code:

1 context.bestseller_list = context.bestseller.results[0].display_name;
2 context.bestseller_current = context.bestseller.results[0].book_details[0].title;
3 context.bestseller_desc = context.bestseller.results[0].book_details[0].description;
4 context.bestseller_link = context.bestseller.results[0].amazon_product_url;

Four variables are set to data returned from the REST API call, comprising the name, title, description and Amazon URL for the bestseller.

Note:
You must set all required variables in a single Action connected to the Action that calls the API. You cannot set any variables from the API call later in the chat.
Note:
There is no one-to-many relationship between the Set Variable Action and other interactions; so there may be cases in other chats where the API must be called multiple times.

Display Bestseller

This Message interaction displays the title of the bestseller in the chosen category, in the following format:

This week's bestseller in {bestseller_list} is {bestseller_current}.

Where bestseller_list is the variable holding the list and bestseller_current is the variable holding the title of the bestseller.

Learn more

This is a Question interaction that asks the user whether they want to know more about the title just mentioned, or whether they want to choose another category.

Book description

This Message interaction displays the book description in the following format:

From the back cover:

{bestseller_desc}

Where bestseller_desc is the variable holding the description.

Link to book

This Message interaction displays the Amazon link to order the book, in the following format:

Here's an Amazon link to the book. Sorry, I can't format it or present it in a neat button:

{bestseller_link}

Using the REST Action: Example of sending SMS

In this example, the REST Action is used to send an SMS. The whole chatbot is not shown, just the configuration of the Action to send an email.

Obtaining the mobile number

Firstly, you should determine the mobile number to which the SMS should be sent. If you need to get this number from the user, use a Question interaction in the chatbot.

Mobile Numbers must conform to E.164 standards. This format is designed to include all of the necessary information to successfully route any call or SMS. The E.164 numbering plan works as follows:

  • A telephone number can have a maximum of 15 digits.
  • The first part of the number is the country code (one to three digits) and is preceded by a '+' sign.
  • The second part is the national destination code (NDC).
  • The last part is the subscriber number (SN).
  • The NDC and SN together are collectively called the national (significant) number.

For example, a UK mobile number of 07702852283 in E.164 format would be +447702852283:

  • Country code: +44
  • National destination code: 7702
  • Subscriber number: 852283
  • The result: +447702852283

Note the following:

  • In the international E.164 notation, a leading '0' is removed.
  • In the E.164 notation, all spaces, dashes ['-'] and parentheses [ '(' and ')'] are removed, and except for the leading '+' sign, all characters should be numeric.

There are two methods by which you can obtain the mobile number from a Question interaction:

First method:

  • Set the Answer Type to Accept any answer.
  • Set the Variable Name to something meaningful.

The advantage of this method is simplicity, but the disadvantage is that there is no validation on the format of the mobile number; it relies on the user to enter it correctly in E.164 format.

Second method:

  • Set the Answer Type to Set up Regular Expression Answer.
  • Set Variable Name to something meaningful.

This method enables validation on the mobile number, but is more complex.

The following is an example of a regular expression that can be used to validate the format of a mobile number. It checks for E.164 compliance but also makes sure that the country code is valid:

(\+|00)(297|93|244|1264|358|355|376|971|54|374|1684|
1268|61|43|994|257|32|229|226|880|359|973|1242|387|
590|375|501|1441|591|55|1246|673|975|267|236|1|61|41|
56|86|225|237|243|242|682|57|269|238|506|53|5999|61|
1345|357|420|49|253|1767|45|1809|1829|1849|213|593|
20|291|212|34|372|251|358|679|500|33|298|691|241|44|
995|44|233|350|224|590|220|245|240|30|1473|299|502|
594|1671|592|852|504|385|509|36|62|44|91|246|353|98|
964|354|972|39|1876|44|962|81|76|77|254|996|855|686|
1869|82|383|965|856|961|231|218|1758|423|94|266|370|
352|371|853|590|212|377|373|261|960|52|692|389|223|
356|95|382|976|1670|258|222|1664|596|230|265|60|262|
264|687|227|672|234|505|683|31|47|977|674|64|968|92|
507|64|51|63|680|675|48|1787|1939|850|351|595|970|
689|974|262|40|7|250|966|249|221|65|500|4779|677|
232|503|378|252|508|381|211|239|597|421|386|46|268|
1721|248|963|1649|235|228|66|992|690|993|670|676|
1868|216|90|688|886|255|256|380|598|1|998|3906698|
379|1784|58|1284|1340|84|678|681|685|967|27|260|
263)(9[976]\d|8[987530]\d|6[987]\d|5[90]\d|42\d|3[
875]\d|2[98654321]\d|9[8543210]|8[6421]|6[6543210]|
5[87654321]|4[987654310]|3[9643210]|2[70]|7|1)\d{4,20}$

Authentication token

Secondly, you should request an authentication token, using an Action interaction with an Action Type of REST. The other parameters of this interaction should be as follows:

  • Endpoint: https://usersapi.communicate.engageone.co/authenticate
  • Method: POST
  • Body: set this to the following:
{
"client_id": "xxxxxx.yyyyyyyyyyyy@communicate.engageone.co",
"secret": "zzzzzzzzzzzzz",
"customer_id": "xxxxxx"
}

Replace the default entries shown above with the actual credentials for your Team.

This API call returns the token you need when sending the email.

Sending the SMS

The Action interacton for sending the email should be configured as follows:

Send SMS action

The Action Type is set to REST, indicating that this action is to interact with a REST API.

The Settings are as follows:

  • Endpoint: Set to:

    https://api.region.communicate.engageone.co/campaigns/campaignname/transactional

    where region = the AWS region in which your Team resides.

    (For the EU this is typically eu-west-1 or eu-west-2 while for USA it is us-east-1 or us-east-2. APAC will be something different again). Replace bold italic items with actual values.

  • Method. Set this to POST.#
  • Authorization. Set this to Bearer {token}, where {token} is the authentication token you requested above.
  • Content-Type. Set this to application/json.
  • Headers. Set to PB-Customer-Id and customer_id respectively.
  • Body. Set to the following:
    {
    "communication": "communication_name",
    "dataset": [
    {"mobile": "{{mobile_fieldname}}"}
    ],
    "phone_number_json_path": "$[*].mobile.fieldname",
    "sender": "sendername",
    "sender_name": "sendername",
    "ignore_missing_fields": true,
    "project": "project_name"
    } 
    Note:
    Replace the bold italic entries shown in the example above with those for your EMAIL Communication.

The remaining fields are optional.

Using the REST Action: Example of sending email

In this example, the REST Action is used to send an email. The whole chatbot is not shown, just the configuration of the Action to send an email.

Email address

Firstly, you should determine the email address to which the email should be sent. If you need to get this address from the user, use a Question interaction in the chatbot.

Authentication token

Secondly, you should request an authentication token, using an Action interaction with an Action Type of REST. The other parameters of this interaction should be as follows:

  • Endpoint: https://usersapi.communicate.engageone.co/authenticate
  • Method: POST
  • Body: set this to the following:
{
"client_id": "xxxxxx.yyyyyyyyyyyy@communicate.engageone.co",
"secret": "zzzzzzzzzzzzz",
"customer_id": "xxxxxx"
}

Replace the default entries shown above with the actual credentials for your Team.

This API call returns the token you need when sending the email.

Sending the email

The Action interacton for sending the email should be configured as follows:

Email action

The Action Type is set to REST, indicating that this action is to interact with a REST API.

The Settings are as follows:

  • Endpoint: Set to:

    https://api.region.communicate.engageone.co/campaigns/campaignname/transactional

    where region = the AWS region in which your Team resides.

    (For the EU this is typically eu-west-1 or eu-west-2 while for USA it is us-east-1 or us-east-2. APAC will be something different again). Replace bold italic items with actual values.

  • Method. Set this to POST.
  • Authorization. Set this to Bearer {token}, where {token} is the authentication token you requested above.
  • Content-Type. Set this to application/json.
  • Headers. Set to PB-Customer-Id and customer_id respectively.
  • Body. Set to the following:
    {
     "communication": "email_communication_name",
     "dataset": [
     {
     "firstname": "{{yourName}}",
     "lastname": "{{yourlastname}}",
     "title": "{{yourtitle}}",
     "email": "{{email}}"
     }
     ],
     "email_json_path": "$[*].email",
     "sender": "joe.bloggs@mycompany.com",
     "subject": "Your Insurance Quote",
     "ignore_missing_fields": true,
     "project": "Acquisitions"
    }
    Note:
    Replace the bold italic entries shown in the example above with those for your EMAIL Communication.

The remaining fields are optional.

Using the REST Action: Example of asking EVA a question

If you want your Communicate chatbot to ask a question of an EVA (Electroinic Virtual Assistant) bot, this section shows an example of how to do it.

Determine the question

Firstly, you should determine the question to be asked of EVA. To do this, create a Question interaction with Answer Type set to Accept any answer and Variable Name set to variable_name.

Ask the question

The Action interaction for asking the question should be configured as follows:

EVA Question action

The Action Type is set to POST, indicating that this action is to interact with a REST API.

The Settings are as follows:

  • Endpoint: Set to:

    https://api.chat2check.com/v3/chatbot/messageAndDocuments

  • Method. Set this to POST.
  • Authorization. Leave this blank.
  • Content-Type. Leave this blank.
  • Headers. Set to x-lang and en respectively.
  • Body. Set to the following:
    {
     "query": "{{variable_name}}",
     "botId": "bot-id",
     "threshold": "0.3",
     "doStemming": "false",
     "doTypos": "false",
     "doLevenshtein": "true"
    }

    Replace the bot-id shown in the example above with that of your EVA bot.

  • Variable Name. Set to eva_reply.
  • If you want to keep count of the number of times you call EVA, use an Action to initialize a variable. For example, context.evaCount = 0 Then use an Action to increment that variable. For example, context.evaCount ++.

Evaluate the response

The Action interaction for evaluating the response to the question asked of an EVA bot should be configured as follows:

EVA Response action

The Action Type is set to Set Variable.

Under Code, paste in the following javascript code:

var text = "";
context.goto = null;
context.question = context.lastSentText
context.requestId = new Date().getTime();
try{
var sent = false;
var disamb = context.disamb != null ? context.disamb : [];
if (!toDisamb()) {
 try {
 context.answers.messages = reorder(context.answers.messages);
 //Se la risposta viene da python o da serpapi, non mostro correggi
 if(context.answers.layer == "Python" || context.answers.layer == "SerpApi"){
 context.buttons = context.buttonProd; 
 }else{
 if (context.isDev) {
 context.buttons = context.buttonDev;
 }
 else {
 context.buttons = context.buttonProd;
 }
 }
 for (var i = 0; i < context.answers.messages.length; i++) {
 if(context.answers.messages[i].score > 0 || 
context.answers.messages[i].semanticScore > 6){
 //Gestione del goto
 if (context.answers.messages[i].responseId.indexOf('goto_') > -1) {
 var goto = context.answers.messages[i].responseId.split
("goto_")[1].split("_")[0];
 context.fadId = null;
 try{
 if(goto == "fad"){
 context.fadId = context.answers.messages[i].responseId.split
("goto_")[1].split("_")[1];
 context.fadId = context.fadId.trim() != "" ? context.fadId : null;
 }
 }catch(e){}
 context.goto = goto;
 break;
 }
 if (context.answers.messages[i].message.indexOf("\ufffd") > -1) {
 context.answers.messages[i].message = "<p>" + 
context.answers.messages[i].message.split("\ufffd")[1];
 }
 //Formattazione dei risultati
 var index = i + 1;
 if (context.answers.messages[i].message.indexOf("§") > -1)
 context.answers.messages[i].message = 
context.answers.messages[i].message.split("§")[1];
 text = index + ")<br>" +
 "Response Id: " + context.answers.messages[i].responseId +
 "<br>" + context.answers.messages[i].message;
 if (!context.isDev)
 text = context.answers.messages[i].message;
 system.sendToUser(text);
 sent = true;
 //Se la differenza tra score corrente e score del
 messaggio successivo è 3, non mando i successivi
 if (i + 1 != context.answers.messages.length) {
 if ((context.answers.messages[i].semanticScore 
- context.answers.messages[i + 1].semanticScore) 
>= 3 || !context.isDev)
 break;
 }
 }
 }
 } catch (e) {
 /*
 if(context.answers.searchOnWeb){
 context.goto = "serpapi"
 }else{
 system.sendToUser(context.lang["nonHoRisposta"]
[context.currentLang]);
 }
 */ 
 }
 if(user.apiOptions && user.apiOptions.documents 
&& context.goto == null){
 try{
 var documents = JSON.parse(context.answers.jsonDocuments);
 if(documents.result1 && documents.result1.indexOf
("Score: 0") == -1){
 system.sendToUser(context.lang["documenti"][context.currentLang])
 if(context.isDev){
 system.sendToUser(documents.result1)
 }else{ 
 context.goto = "documents";
 context.documentCards = []; 
 context.documentCards.push({
 "title": documents.result1_title,
 "subtitle": '<img src="https://cdn3.iconfinder.com/
data/icons/adobe-creative-suite-file-extensions-v3/
1024/pdf-01-512.png" style="width: 100px;margin: 0 auto;">' ,
 "buttons": [ 
 {"type": "web_url", "title":"Open", "url": documents.result1_linkRelevant}
 ]
 })
 }
 sent = true;
 }
 if(documents.result2 && documents.result2.indexOf("Score: 0") == -1){
 if(context.isDev){
 system.sendToUser(documents.result2)
 }else{
 context.documentCards.push({
 "title": documents.result2_title,
 "subtitle": '<img src="https://cdn3.iconfinder.com/
data/icons/adobe-creative-suite-file-extensions-v3/
1024/pdf-01-512.png" style="width: 100px;margin: 0 auto;">' ,
 "buttons": [ 
 {"type": "web_url", "title":"Open", "url": documents.result2_linkRelevant}
 ]
 })
 }
 }
 }catch(e){}
 }else{
 if (context.answers.messages.length == 0 || 
context.answers.messages[0].score == 0){
 if(context.answers.searchOnWeb){
 context.goto = "serpapi"
 }else{
 system.sendToUser(context.lang["nonHoRisposta"][context.currentLang]);
 }
 }
 }
 if(!sent){
 if(context.answers.searchOnWeb){
 context.goto = "serpapi"
 }else if(context.answers.generateText) {
 context.goto = "python"
 }
 else{
 system.sendToUser(context.lang["nonHoRisposta"][context.currentLang]);
 }
 }
}
function sortBy(property) {
 var sortOrder = -1;
 return function (a, b) {
 var result = (a[property] < b[property]) ? -1 : 
(a[property] > b[property]) ? 1 : 0;
 return result * sortOrder;
 }
}
function reorder(array) {
 var nearMatch = [];
 var prevScore = array[0].semanticScore;
 for (var i = 0; i < array.length; i++) {
 if (Math.abs(array[i].semanticScore - prevScore) < 1)
 nearMatch.push(array[i]);
 }
 return nearMatch.sort(sortBy("score"));
}
function toDisamb() {
 for (var j = 0; j < disamb.length; j++) {
 var testoPulsanti = [];
 for (var g = 0; g < disamb[j].testoPulsanti.length; g++) {
 testoPulsanti.push(disamb[j].testoPulsanti[g].payload);
 }
 for (var g = 0; g < disamb[j].paroleCheFannoScattare.length; g++) {
 if (checkParoleInAnd(disamb[j].paroleCheFannoScattare[g], 
context.question) && notContains(disamb[j].
paroleCheEvitanoCheScatti, context.question) 
&& notContains(testoPulsanti, context.question)) {
 context.goto = "disamb";
 context.domandaDisambiguata = disamb[j].domandaCheFaIlBot;
 context.pulsantiDisambiguazione = disamb[j].testoPulsanti;
 return true;
 }
 }
 }
 return false;
}
function checkParoleInAnd(arrayDiParole, frase) {
 if (arrayDiParole) {
 for (var i = 0; i < arrayDiParole.length; i++) {
 var regex = new RegExp("(?:^|[^a-zA-Z0-9]+)" + 
arrayDiParole[i].toLowerCase().normalize('NFD').
replace(/[\u0300-\u036f]/g, "") + "[^a-zA-Z0-9]*");
 if (!regex.test(frase.toLowerCase().normalize('NFD').
replace(/[\u0300-\u036f]/g, "")))
 return false;
 }
 }
 return true;
}
function notContains(arrayDiParole, frase) {
 if (arrayDiParole) {
 for (var i = 0; i < arrayDiParole.length; i++) {
 var regex = new RegExp("(?:^|[^a-zA-Z0-9]+)" + 
arrayDiParole[i].toLowerCase().normalize('NFD').
replace(/[\u0300-\u036f]/g, "") + "[^a-zA-Z0-9]*");
 if (regex.test(frase.toLowerCase().normalize('NFD').
replace(/[\u0300-\u036f]/g, "")))
 return false;
 }
 }
 return true;
}
var Base64 = { _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz0123456789+/=", encode: 
function (e) { var t = ""; var n, r, i, s, o, u, a; 
var f = 0; e = Base64._utf8_encode(e); while 
(f < e.length) { n = e.charCodeAt(f++); 
r = e.charCodeAt(f++); i = e.charCodeAt(f++); 
s = n >> 2; o = (n & 3) << 4 | r >> 4; u = 
(r & 15) << 2 | i >> 6; a = i & 63; if (isNaN(r)) 
{ u = a = 64 } else if (isNaN(i)) { a = 64 } t = 
t + this._keyStr.charAt(s) + this._keyStr.charAt(o)
 + this._keyStr.charAt(u) + this._keyStr.charAt(a) }
 return t }, decode: function (e) 
{ var t = ""; var n, r, i; var s, o, u, a; 
var f = 0; e = e.replace(/++[++^A-Za-z0-9+/=]/g, "");
 while (f < e.length) { s = this._keyStr.
indexOf(e.charAt(f++)); o = this._keyStr.
indexOf(e.charAt(f++)); u = this._keyStr.
indexOf(e.charAt(f++)); a = this._keyStr.
indexOf(e.charAt(f++)); n = s << 2 | o >> 4; 
r = (o & 15) << 4 | u >> 2; i = (u & 3) << 6 | a;
 t = t + String.fromCharCode(n); if (u != 64) 
{ t = t + String.fromCharCode(r) } if (a != 64) 
{ t = t + String.fromCharCode(i) } } t = 
Base64._utf8_decode(t); return t }, _utf8_encode: 
function (e) { e = e.replace(/\r\n/g, "n"); 
var t = ""; for (var n = 0; n < e.length; n++) 
{ var r = e.charCodeAt(n); if (r < 128) 
{ t += String.fromCharCode(r) } else if 
(r > 127 && r < 2048) { t += String.fromCharCode
(r >> 6 | 192); t += String.fromCharCode(r & 63 | 128) }
 else { t += String.fromCharCode(r >> 12 | 224);
 t += String.fromCharCode(r >> 6 & 63 | 128); 
t += String.fromCharCode(r & 63 | 128) } } return t },
 _utf8_decode: function (e) { var t = ""; var n = 0;
 var r = c1 = c2 = 0; while (n < e.length) 
{ r = e.charCodeAt(n); if (r < 128) 
{ t += String.fromCharCode(r); n++ } else if 
(r > 191 && r < 224) { c2 = e.charCodeAt(n + 1);
 t += String.fromCharCode((r & 31) << 6 | 
c2 & 63); n += 2 } else { c2 = e.charCodeAt(n + 1);
 c3 = e.charCodeAt(n + 2); t += String.fromCharCode
((r & 15) << 12 | (c2 & 63) << 6 | c3 & 63); n += 3 } } return t } }
context.answersbase64 = Base64.encode(JSON.stringify(context.answers))
}catch(e){
system.sendToUser(context.lang["nonHoRisposta"][context.currentLang]);
}