Drafts of SUSI Chatbots

While creating a SUSI bot using bot wizard, a user has the option to save a draft of the bot at any step. Then he/she can continue building the bot from there. We can do four operations on a draft: Storing, fetching, editing and deleting.

Storing a draft:

For the storage of drafts, a GET request is made to the storeDraft.json API. The code of chatbot is passed in ‘object’ parameter. This code must be in JSON format. A sample API call looks like this:

https://api.susi.ai/cms/storeDraft.json?object={"test":"123"}

The JSON passed in ‘object’ has the following format:

{
   “group”: /*group_here*/
   “language”: /*language_here*/
   “name”: /*bot_name_here*/
   “buildCode”: /*code_in_build_tab_here*/
   “designCode”: /*code_in_design_tab_here*/
   “configCode”: /*code_in_config_tab_here*/
}

While storing the draft, we can either specify an ID ourselves as a parameter named ‘id’ in the API call url or we can get a randomly generated id from the server itself.
The hex codes in designCode includes ‘#’ which can not be passed in the url. Hence, we remove it while saving a draft and then add it back while editing it.

Fetching a draft:

For fetching drafts, a GET request is made to the readDraft.json API. We can either simply call the API without any other parameters which will return all the chatbots of the user. The API call for this looks like this:

https://api.susi.ai/cms/readDraft.json

We can fetch a particular draft by specifying the ID of draft in the API call like this:

https://api.susi.ai/cms/readDraft.json?id=abcdef12

Editing a draft:

The drafts are displayed on the botbuilder page. From there a user can open a draft simply by clicking on it. This uses the ID of that draft to fetch its details by making a GET request to readDraft.json API as specified above.
For applying the details fetched to bot wizard, we pass the draft ID in url of bot wizard as “/botbuilder/botwizard?draftID=abcdef12”.  Then we fetch this ID using “this.getQueryStringValue(‘draftID’)” and this is followed by fetching all details of bot.
After fetching details of the chatbot, all the details are updated in the state of Botwizard component and hence user can continue making SUSI bot.

Deleting a draft:

For the deletion of drafts, a GET request is made to the deleteDraft.json API. We need to specify the id of the draft that we want to delete in the ‘id’ parameter. So, the API call looks like this:

https://api.susi.ai/cms/deleteDraft.json?id=abcdef12

Resources

Continue ReadingDrafts of SUSI Chatbots

Fetching Bots from SUSI.AI Server

Public skills of SUSI.AI are stored in susi_skill_cms repository. A private skill is different from a public skill. It can be viewed, edited and deleted only by the user of who created it. The purpose of private skill is that this acts as a chatbot. All the information of the bot like design, configuration etc is stored within the private skill itself. In order to show the lists of chatbots a user has created to him/her, we need to fetch these lists from the server. The API for fetching private skills is in ListSkillService.java servlet. This servlet is used for both the purposes for fetching public skills and private skills.

How are bots fetched?

All the private skills are stored in data/chatbot/chatbot.json location in the SUSI server. Hence, we can fetch these skills from here.
The API call to fetch private skills is:

https://api.susi.ai/cms/getSkillList.json?private=1&access_token=accessTokenHere

The API call has two parameters:

  1. private = 1: This parameter tells the servlet that we’re asking for private skills because same API is used for fetching public skills as well.
  2. access_token : We have to pass the access-token in order to authenticate the user and access the chatbots of the specific user because the chatbots are stored according to user id of the users in chatbot.json. To get the user id, we need access-token.

For fetching the chatbots from chatbot.json, we firstly authenticate the user. Then we check if the user has any chatbots or not. If the user has chatbots then we loop through chatbot.json to find the chatbots of user by using user id. After getting chatbots details, we simply present it in json structure. You can easily understand this through the following code snippets. For authenticating:

String userId = null;
String privateSkill = call.get("private", null);
if (call.get("access_token", null) != null) {
    ClientCredential credential = new ClientCredential(ClientCredential.Type.access_token, call.get("access_token", null));
    Authentication authentication = DAO.getAuthentication(credential);
    // check if access_token is valid
    if (authentication.getIdentity() != null) {
        ClientIdentity identity = authentication.getIdentity();
        userId = identity.getUuid();
    }
}

You can see that the parameter private is stored in privateSkill. We check if privateSkill is not null followed by checking if the user id provided is valid or not. When both the checks are successful, we create a JSON object in which we store all the bots. To do this, we loop through the chatbot.json file to find the user id provided in API call. If the user id doesn’t exist in chatbot.json file then a message “User has no chatbots.” is displayed. If the user id is found then we again loop through all the chatbots and put their name as the value of key “name”,  language as the value of key “language” and group as the value of key “group”. All these key value pairs for the chatbots are pushed in an array and finally that array is added to the JSON object. This JSON is then received as response of the API call. The following code will demonstrate this:

if(privateSkill != null) {
    if(userId != null) {
        JsonTray chatbot = DAO.chatbot;
        JSONObject result = new JSONObject();
        JSONObject userObject = new JSONObject();
        JSONArray botDetailsArray = new JSONArray();
        JSONArray chatbotArray = new JSONArray();
        for(String user_id : chatbot.keys())
        {
            if(user_id.equals(userId)) {
                userObject = chatbot.getJSONObject(user_id);
                Iterator chatbotDetails = userObject.keys();
                List<String> chatbotDetailsKeysList = new ArrayList<String>();
                while(chatbotDetails.hasNext()) {
                    String key = (String) chatbotDetails.next();
                    chatbotDetailsKeysList.add(key);
                }
                for(String chatbot_name : chatbotDetailsKeysList)
                {
                    chatbotArray = userObject.getJSONArray(chatbot_name);
                    for(int i=0; i<chatbotArray.length(); i++) {
                        String name = chatbotArray.getJSONObject(i).get("name").toString();
                        String language = chatbotArray.getJSONObject(i).get("language").toString();
                        String group = chatbotArray.getJSONObject(i).get("group").toString();
                        JSONObject botDetails = new JSONObject();
                        botDetails.put("name", name);
                        botDetails.put("language", language);
                        botDetails.put("group", group);
                        botDetailsArray.put(botDetails);
                        result.put("chatbots", botDetailsArray);
                    }
                }
            }
        }
        if(result.length()==0) {
            result.put("accepted", false);
            result.put("message", "User has no chatbots.");
            return new ServiceResponse(result);
        }
        result.put("accepted", true);
        result.put("message", "All chatbots of user fetched.");
        return new ServiceResponse(result);
    }
}

So, if chatbot.json contains:

{"c9b58e182ce6466e413d5acafae906ad": {"chatbots": [
 {
   "name": "testing111",
   "language": "en",
   "group": "Knowledge"
 },
 {
   "name": "DNS_Bot",
   "language": "en",
   "group": "Knowledge"
 }
]}}

Then, the JSON received at http://api.susi.ai/cms/getSkillList.json?private=1&access_token=JwTlO8gdCJUns569hzC3ujdhzbiF6I is:

{
  "session": {"identity": {
    "type": "email",
    "name": "test@whatever.com",
    "anonymous": false
  }},
  "chatbots": [
    {
      "name": "testing111",
      "language": "en",
      "group": "Knowledge"
    },
    {
      "name": "DNS_Bot",
      "language": "en",
      "group": "Knowledge"
    }
  ],
  "accepted": true,
  "message": "All chatbots of user fetched."
}

References:

Continue ReadingFetching Bots from SUSI.AI Server

Protected Skills for SUSI.AI Bot Wizard

The first version of SUSI AI web bot plugin is working like a protected skill. A SUSI.AI skill can be created by someone with minimum base user role USER, or in other words, anyone who is logged in.  Anyone can see this skill or edit it. This is not the case with a protected skill or bot. If a skill is protected it becomes a personal bot and then it can only be used by the SUSI AI web client (chatbot) created by that user. Also, only the person who created this skill will be able to edit it or delete it. This skill won’t be listed with all the other public skills on skills.susi.ai.

How is a skill made private?

To make a skill private, a new parameter is added to SusiSkill.java file. This is a boolean called protected. If this parameter is true (Yes) then the skill is protected else if the parameter is false (No) then the skill is not protected. To add protected parameter, we add the following code to SusiSkill.java:

private Boolean protectedSkill;
boolean protectedSkill = false;

You can see that protectedSkill is a boolean with initial value false.
We need to read the value of this parameter in skill code. This is done by the following code:

if (line.startsWith("::protected"&& (thenpos = line.indexOf(' ')) > 0) {
  if (line.substring(thenpos+ 1).trim().equalsIgnoreCase("yes")) protectedSkill=true;
  json.put("protected",protectedSkill);
}

As you can see that the value of protected is read from the skill code. If it’s ‘Yes’ then protectedSkill is set as true and if it’s ‘No’ then protectedSkill is set as false.
If no protected parameter is given in the skill code, its value remains false.

How to add only protected skills from bot wizard?

Now that protected parameter has been added to the server, we need to add this parameter in the skill code but it should be ‘Yes’ if the user is creating a bot and ‘No’ if user is creating a skill using skill creator. In order to do this, we simply check if the user is creating a bot wizard. This can be done by passing a props in the CreateSkill.js file when the skill creator is being used to create a protected skill. Next, we can determine whether the user is using bot wizard or not simply by an if else statement. The following code will demonstrate it:

if (this.props.botBuilder) {
 code = '::protected Yes\n' + code;
else {
 code = '::protected No\n' + code;
}

References:

Continue ReadingProtected Skills for SUSI.AI Bot Wizard

Fetching responses from SUSI.AI Server for Botbuilder Build Views

In SUSI.AI, we use skill editor for creating and editing public/private skills. The editor we use is Ace editor. The skill is written in a code format documented here. This works fine for a developer but for a user with little experience in coding, this can be confusing. Hence, for providing more clarity as to what the skill does, I built conversation view and tree view along with code view for the skill editor.

Conversation view shows the skill in form of actual conversation between the user and the bot while tree views shows the same conversation in form of a tree. Earlier these views were implemented by converting the code view into an object containing user queries and SUSI responses.

While this works for simple skills, it obviously won’t work for a complex skill in which the responses are fetched from an API. Hence we needed live responses from SUSI server.

This is done similar to how preview works. We pass the whole skill in an instant parameter in the chat.json API along with the user query. This gives us the response from SUSI in form of a JSON.

API Call:

We send a GET request to the following URL:

https://api.susi.ai/susi/chat.json?q=userQuery&instant=wholeSkill

This contains two parameters:

  • q: The user query is passed in this parameter.
  • instant: The whole skill code (present in the code view) is passed in this parameter.

The response is a JSON providing response from SUSI.

Getting user queries:

We can not rely on user to provide the user queries in conversation view and tree view because the user has already provided it in the code view. Hence, we fetch the user queries from code view. This is simply done by dissecting the code and putting all the lines which don’t start with ::, !, #, {, } and “ in an array. Then we split the entries of this array wherever a vertical bar (|) is found. This provides us an array containing all the user queries. It’ll be clear from the following function:

fetchUserInputs = () => {
  let code = this.state.code;
  let userInputs = [];
  let userQueries = [];
  var lines = code.split('\n');
  for (let i = 0; i < lines.length; i++) {
    let line = lines[i];
    if (
      line &&
      !line.startsWith('::') &&
      !line.startsWith('!') &&
      !line.startsWith('#') &&
      !line.startsWith('{') &&
      !line.startsWith('}') &&
      !line.startsWith('"')
    ) {
      let user_query = line;
      while (true) {
        i++;
        if (i >= lines.length) {
          break;
        }
        line = lines[i];
        if (
          line &&
          !line.startsWith('::') &&
          !line.startsWith('!') &&
          !line.startsWith('#')
        ) {
          break;
        }
      }
      userQueries.push(user_query);
    }
  }
  for (let i = 0; i < userQueries.length; i++) {
    let queries = userQueries[i];
    let queryArray = queries.trim().split('|');
    for (let j = 0; j < queryArray.length; j++) {
      userInputs.push(queryArray[j]);
    }
  }
  this.setState({ userInputs }, () => this.getResponses(0));
};

Getting response to a single query at a time:

Now, we have an array containing all the user queries but we can not simply run a loop through the array and then get responses for each query because the AJAX call that we’re making to fetch response is asynchronous. Hence, this will result in multiple AJAX calls in a very short period of time. This will cause a failure in fetching responses and conversation view won’t work. We definitely don’t want that.

To solve this problem, we get response for a single query at a time and make the next AJAX call only when the response for the current call is received. You can see in the code snippet provided in last section, after updating state of userInputs, we’re calling getResponses as a callback and passing 0. This 0 is the index of array which will be incremented on every successful AJAX call. The following code snippet will demonstrate this:

$.ajax({
  type: 'GET',
  url: url,
  contentType: 'application/json',
  dataType: 'json',
  success: function(data) {
  let answer;
  if (data.answers[0]) {
    // Putting response in an object along with user query
    if (responseNumber + 1 === userInputs.length) { // Stopping when responses are fetched for all user queries.
      this.setState({ loaded: true });
    }
    this.setState({ responseData }, () => // updating the response data
      this.getResponses(++responseNumber),  // Incrementing the index and calling getResnponses again as a callback when response data state is updated.
    );
  }.bind(this),
  error: function(err) {
    console.log(err);
  }.bind(this),
});

The code snippets I provided are used in conversation view. Same algorithm is used in tree view as well.

References:

Continue ReadingFetching responses from SUSI.AI Server for Botbuilder Build Views

Different views for SUSI Skill Creator

SUSI Skill Creator is a service provided to easily create skills for SUSI. The skill can be written in the form of code. The coding syntax is described in SUSI skill tutorial. The problem with this is that we can’t expect everyone to be great coders and be able to understand the document and easily create a skill. Hence, we needed some robust alternatives for people who don’t want to write the code. This is where UI View and Tree View comes in.

What is UI View?

UI View or User Interface View shows the skill in form of chat bubbles. This is useful for demonstrating how the actual chat will look like.

Hello
Hi. I’m SUSI.

The following code will be shown as this in conversation view:

What is Tree View?

Tree view shows the conversation in form of a tree with its branching representing the chats.

Hello|Hi
Hi. I'm SUSI.|Hey there!

The following code will be shown as this in tree view:

How are the views synchronised?

We’re basically not making any API calls or performing any major function in any of the views. The components of different views are solely for their own function. All the API calls are made in a parent component named SkillCreator.

The main reason for creating a parent component is that we need the category, language, name and commit message options to appear on all the three views. Hence, it only makes sense to have a parent component for them and different components for the views.

The default code (that appears in code editor by default) is in a state in SkillCreator. We pass this state to the code view component as a props.

<CodeView
  skillCode={this.state.code}
  sendInfoToProps={this.sendInfoToProps}
/>

Now, we need to get any change made in the code in CodeView and change the code state of SkillCreator accordingly. For that, we have a function named sendInfoToProps which is passed as props to CodeView and is then called from CodeView whenever we make some change. This will be more clear after having a look at the function sendInfoToProps:

sendInfoToProps = value => {
 if (value) {
  this.setState(
   {
     code: value.code ? value.code : this.state.code,
     expertValue: value.expertValue
       ? value.expertValue
       : this.state.expertValue,
     groupValue: value.groupValue
       ? value.groupValue
       : this.state.groupValue,
     languageValue: value.languageValue
       ? value.languageValue
       : this.state.groupValue,
   imagUrl: value.imageUrl ? value.imageUrl : this.state.imageUrl,
   },
   () => this.generateSkillData(),
  );
 }
};

You can see that we update the code in SkillCreator and other states required. Also, you can notice the we’re calling generateSkillData function here. This is done to convert the code to skill data which is sent to Conversation view and Tree view as props.
We’re calling generateSkillData as a callback function because setState is an asynchronous function.
This will demonstrate how this is passed to Conversation view:

<ConversationView
  skillData={this.state.skillData}
  handleDeleteNode={this.handleDeleteNode}
/>

Same is the case for this handleDeleteNode function. We have an option in both Conversation view and Tree view to allow the user to delete a conversation (originally written as skill in code view). On delete, handleDeleteNode is called from the props and the conversation is deleted from the code which is then send to all the views (as props) and the views are updated as well.

References:

Continue ReadingDifferent views for SUSI Skill Creator

Code view and UI View in design tab of bot wizard

Design tab is for designing your SUSI AI chatbot. You can change the background colour, add an image as background color, change colour of user text box, bot text box etc. On SUSI AI bot wizard design tab, we have two views. These views show the same thing but in a different way for different people. The code view is mainly for the developers while the UI (User Interface) view is for a non-developer user because we can not expect them to know how to code even if it is easy.

Code View

The current code view of design tab looks like this:

::bodyBackground #ffffff
::bodyBackgroundImage
::userMessageBoxBackground #0077e5
::userMessageTextColor #ffffff
::botMessageBoxBackground #f8f8f8
::botMessageTextColor #455a64
::botIconColor #000000
::botIconImage

For changing colours, you simply have to change the hex codes and for adding images as background, you need to add the url of image. You can also upload an image but that function is provided in the UI View.

UI View

The current UI view of design tab looks like this:

Here, we have colour picker for user to choose a colour for various components of the chatbot. There’s also a small box with the same colour as specified in hex code for previewing.

Switching and Synchronising between Code view and UI view

We have different components for code view and UI view. In order to synchronise both the views, we need to have the same code in state of both components. To do that, we add the code in state of the parent component i.e. design.js and then pass it to code view and UI view as states.

The following code snippet will demonstrate this:

<CodeView
    design={{
        sendInfoToProps: this.sendInfoToProps,
        updateSettings: this.updateSettings,
        code: this.state.code,
    }}
/>

You can see that we pass a whole object as props.
Using this approach, same code is passed to both the views. This solves the first problem. The next problem is that if we do a change in code view then it should happen in the code state of parent file as well. Same goes for UI view.
To do this, whenever we change the code in code view or UI view, we call a function in the parent file (design.js) which was passed as props and we pass the state of code view or UI view as arguments of this function. This function then updates the state accordingly. The name of the function is sendInfoToProps and it is as follows:

sendInfoToProps = values => {
    this.setState({ ...values });
};

You can see that it simply updates the state value as per the parameters passed to it.
So this is how synchronisation works between different views.

References:

Continue ReadingCode view and UI View in design tab of bot wizard

Skills tab of SUSI AI Admin Panel

The Skills tab in SUSI.AI Admin Panel displays all the skills of SUSI in a tabular form. The table is created using the Table component of Ant Design. It’s preferred because we’re going to handle a lot of data here and that can turn out to be heavy if we use Google’s Material-ui.

Displaying the data:

The data is rendered in the form of a table which has seven columns – Name, Group, Language, Type, Author, Status and Action. The first 5 columns displays basic details of a skill. The “Status” column shows whether the skill has been reviewed by admin or not. All the reviewed skills are either “Approved” or “Not Approved”. The final column “Action” contains all the actions that admin can perform on the skill. Currently, an admin can change the review status of a skill. More actions will be added in future as this is still in beta.

All the column names are stored in a variable in the form of an array. The following code will demonstrate the way of making three columns – Name, Group, Language.

this.columns = [
  {
    title: 'Name',
    dataIndex: 'skill_name',
    sorter: false,
    width: '20%',
  },
  {
    title: 'Group',
    dataIndex: 'group',
    width: '15%',
  },
  {
    title: 'Language',
    dataIndex: 'language',
    width: '10%',
  },
];

All the skills are also stored in an array which is a state variable. These columns and skills are then passed to the Table component as props. The following code will demonstrate that:

<Table
  columns={this.columns}
  rowKey={record => record.registered}
  dataSource={this.state.skillsData}
/>

Fetching all the skills from SUSI Server:

All the public skills can be fetched from ListSkillService API of SUSI Server. We can filter all the skills using various filters. We want to display the skills alphabetically on Skills tab in Admin Panel. Hence, we filter the skills accordingly. To do this, we pass three parameters in the GET request. They are as follows:

  • applyFilter: true
  • filter_name: ascending
  • filter_type: lexicographical

This returns all the skills in an alphabetical order. The API request url looks like this:

https://api.susi.ai/cms/getSkillList.json?applyFilter=true&filter_name=ascending&filter_type=lexicographical

After fetching the skills, we put all the parameters of these skills required for our table in an object which is then pushed into an array. One object is created for each skill.
If the API call fails for some reason then a Google’s Material-ui Snackbar appears with a message that an error occurred.

Changing review status of a skill:

An admin can change the review status of any skill. This is done by making a GET request to ChangeSkillStatusService API. The request contains five parameters. They are as follows:

  1. Model: Model of the skill is passed here (string)
  2. Group: Group of the skill is passed here (string)
  3. Language: Language of the skill is passed here (string)
  4. Reviewed: true is passed is skill has been approved and false if skill is not approved. (boolean)
  5. Access_token: The access token of user is passed here. This is for verifying the user’s BASE ROLE. This is taken from cookies using cookies.get(‘loggedIn’). (string)

The call url looks like this:

https://api.susi.ai/cms/changeSkillStatus.json?model=general&group=Knowledge&language=en&skill=aboutsusi&reviewed=true&access_token=yourAccessTokenHere

If the API call is successful, then the review status of a skill is successfully changed. Otherwise, an error message is thrown.

References:

Continue ReadingSkills tab of SUSI AI Admin Panel

Code view in Configure tab of SUSI.AI Bot Wizard

The purpose of configure tab in SUSI.AI bot wizard is to provide the bot creator various options on how the bot will interact with different websites. It currently provides an option of enabling or disabling the chatbot on different websites.
The configure tab has two parts. One is the code view which allows the users to write websites on which they want to enable/disable the chatbot and a table below it which lists those websites.

The default code in code view is passed in a state in the Configure.js file. The following code demonstrates that:

this.state = {
  code: this.props.code,
};

Fetching data from code view:

After writing the websites on which the user wants the chatbot to be enabled/disabled and pressing on the ‘Save’ button, a functiongenerateConfigData is called.
This function takes the code in code view and stores in inside of a variable. Then it splits the code and makes two arrays:

  • enabledSites: This array contains all the websites that are written in  enabled field.
  • disabledSites: This array contains all the websites that are written in disabled field.

This process can be easily understood from the following code snippet:

let newCode = this.state.code;
let websiteData = newCode
 .split('::sites_enabled')[1]
 .split('::sites_disabled');
let enabledSites = websiteData[0].split(',');
let disabledSites = websiteData[1].split(',');

This data is stored inside an object.

Displaying the data:

The data fetched from the code view now has to be displayed in form of a table. This data is looks like this:

let configData = [
 {
   id: '1',
   name: 'website1.com',
   last: 'Jan 12, 2018 20:08 hrs',
   status: 1,
 },
 {
   id: '2',
   name: 'website2.com',
   last: 'Feb 19, 2018 13:00 hrs',
   status: 1,
 },
 {
   id: '3',
   name: 'website3.com',
   last: 'Mar 14, 2018 10:15 hrs',
   Status: 2,
 }
];

Status is 1 if the website is in enabled column and 2 if the website is in disabled column.
To display this data on the screen, we simply map through the data and display the rows of the table. The following code demonstrates it:

{configData.map((item, index) => {
 if (item.name) {
   return (
    <TableRow key={index}>
      <TableRowColumn style={{ fontSize: '16px' }}>
         {item.name}
     </TableRowColumn>
      <TableRowColumn style={{ fontSize: '16px' }}>
         {item.last}
     </TableRowColumn>
     <TableRowColumn>
       <SelectField
         floatingLabelText="Status"
         fullWidth={true}
         value={item.status}
       >
         <MenuItem value={1} primaryText="Enable" />
         <MenuItem value={2} primaryText="Disable" />
       </SelectField>
     </TableRowColumn>
    </TableRow>
   );
 }
})}

References:

Continue ReadingCode view in Configure tab of SUSI.AI Bot Wizard

How does conversation view of bot wizard work in the SUSI.AI Botbuilder?

 

Earlier, we could view the skills in code view only in SUSI.AI. Code views shows user queries along with bot responses in a simple form. Different types of responses are coded in different ways and there’s a proper documentation for it here. While this works for a developer, it’s not user friendly. The main purpose of a chatbot web plugin is that user should be able to customise it. User should be able to add skills. Hence we need a conversation view to better show the skills of SUSI.

Fetching data from code view and its storage form:

Skill data from code view is fetched and then stored in the following form:

{
   userQueries: [],
   botResponses: [],
}

This is stored in an object called conversationData.
userQueries stores an array of all the user queries. Similarly, botResponses stores the answers to these queries.
For the query at index 0 of the array in userQueries, the response is at index 0 of botResponses. For the query at index 1 of the array in userQueries, the response is at index 1 of botResponses. The queries and responses are stored in this way.

For example:
If the query is: “Hi|Hello” and the response is “Hi. I am SUSI.|Hello!”
Then the object conversationData will look like this:

{
   userQueries: [[‘Hi’, ‘Hello’]],
   botResponses: [[‘Hi. I am SUSI’, ‘Hello!’]],
}

You can see that index 0 of userQueries holds the queries and botResponses holds its responses.
An example of data from code view getting stored in object conversationData.

::name <Skill_name>
::author <author_name>
::author_url <author_url>
::description <description>
::dynamic_content <Yes/No>
::developer_privacy_policy <link>
::image <image_url>
::terms_of_use <link>

Hi|Hello
Hi. I’m a chatbot.

I need help.|Can you help me?
Sure! I’ll help you. What do you want help with?

How do I track my order?|I need to track my order.
Please tell me the order id.

This will be stored in conversationData in the following way:

{
   userQueries: [
      [‘Hi’, ‘Hello’],
      [‘I need help.’, ‘Can you help me?’],
      [‘How do I track my order?’, ‘I need to track my order.’]
   ],
   botResponses: [
      [Hi. I’m a chatbot.],
      [‘Sure! I’ll help you. What do you want help with?’],
      [‘Please tell me the order id.’]
   ],
}

Rendering data in conversation view:

The data collected in conversationData object is passed to conversation view JS file as props. Now this data can be rendered by injecting HTML elements using jQuery but that is not a right approach. So, we use an array to render it. We pass the HTML elements into the array using the push() method.

This will be more clear from the following code snippets.

This is the code for adding user query:

for (let query of user_query) {
   if (query !== ‘’) {
      conversation.push(
            <div className=”user-text-box”>{query}</div>,
      );
   }
}

This is the code for adding bot response:

for (let response of bot_response) {
   if (response !== ‘’) {
      conversation.push(
            <div className=”bot-text-box”>{response}</div>,
      );
   }
}

References:

 

Continue ReadingHow does conversation view of bot wizard work in the SUSI.AI Botbuilder?

How to receive different types of messages from SUSI Line Bot

In this blog, I will explain how to receive different types of messages responses from LINE Bot. This includes text, sticker, video, audio, location etc types of responses. Follow this tutorial to make SUSI AI LINE Bot.

How does LINE Messaging API work?

The messaging API of LINE allows data to be passed between the server of SUSI AI and the LINE Platform. When a user sends a message to SUSI bot, a webhook is triggered and the LINE Platform sends a request to our webhook URL. SUSI Server then sends a request to the LINE Platform to respond to the user. Requests are sent over HTTPS in JSON format.

Different Message types

  1. Image Messages

To send images, we need two things, the URLs of original image and smaller preview image in the message object. The preview image will be displayed in text and full image is displayed when user clicks on the preview image.
The message object for image message has 3 properties –

Property

Type

Description

type

String

image

originalContentUrl

String

Image URL

previewImageUrl

String

Preview image URL

Sample Message object:

{
   "type": "image",
   "originalContentUrl": "https://susi.ai/original.jpg",
   "previewImageUrl": "https://susi.ai/preview.jpg"
}
  1. Video Messages

To send videos, we need two things, the URL of video file and URL of preview image of video in the message object.
The message object for video messages has 3 properties:

Property

Type

Description

type

String

image

originalContentUrl

String

Video file URL

previewImageUrl

String

Preview image URL

Sample Message object for video type responses:

{
   "type": "video",
   "originalContentUrl": "https://susi.ai/original.mp4",
   "previewImageUrl": "https://susi.ai/preview.jpg"
}
  1. Audio Messages

To send an audio message, you have to include the URL to audio file and the duration in the message object.
The message object for audio messages has 3 properties:

Property

Type

Description

type

String

image

originalContentUrl

String

Audio file URL

duration

Number

Length of the Audio file in milliseconds

Sample Message object for audio type responses:

{
   "type": "audio",
   "originalContentUrl": "https://susi.ai/original.m4a",
   "duration": 10000
}
  1. Location Messages

To send location information to users, you need to include title, address, latitude and longitude of the location.
The message object needs to include 5 properties:

Property

Type

Required

Description

type

String

Required

location

title

String

Required

Title

address

String

Required

Address

latitude

Decimal

Required

Latitude

longitude

Decimal

Required

Longitude

Sample Message object for location type responses:

{
   "type": "location",
   "title": "singapore",
   "address": "address",
   "latitude": 1.2896698812440377,
   "longitude": 103.85006683126556
}

How to use these Message objects?

You have to send the response that you got from SUSI server to LINE platform. Now this response is sent in the form of an object. This object tells the LINE platform about the type of this message. So simply sending this object to reply API of LINE sends the message to user.
It looks like this:

return client.replyMessage(event.replyToken, answer);

References:

Continue ReadingHow to receive different types of messages from SUSI Line Bot