Teaching Susi

In this blog post, I’ll explain how you can add a skill to SUSI.

Skills to be added in this tutorial:

  1. Ask SUSI for conversion of decimal into Binary .
  2. Ask SUSI to tell a quote.
  3. Skill development in SUSI is very interesting and easy. A comprehensive guide for skill development can be found here.

We have a Susi Skill development environment based on an Etherpad. Are you unaware what an Etherpad is? It is a blank web page where you can just put in your text and everyone can collaborate.

Here is a screenshot of what etherpad looks like:

  • open http://dream.susi.ai
  • name a dream (just pick a name for your tests in lower case letters)
  • the etherpad is filled with a welcome message, just delete the content completely

Ask SUSI for conversion of decimal into Binary

“*” here represents any decimal number number.Suppose we enter a decimal number and want susi to return it’s binary equivalent. So to make our skill, first of all we should form a general query.

Query: Convert * into binary or * in binary

After defining our query we want susi to reply with relevant answer.

For taking out the conversion from decimal to binary we can use JavaScript.

We define Javascript syntax in etherpad as follows :

!javascript:Binary for $1$ = $!$
(+$1$).toString(2);
eol

Explanation :

!javascript” allows us to print like javascript console. We can add JavaScript code by using this and do mathematical calculations to convert our decimal into binary.

“Binary for $1$ = $!$”  represents output format where $1$ stores the value in “*” in query given by user to susi. $!$ will print the result of javascript code below.

“(+$1$).toString(2);” This is a single line javascript code while converts value in “$1$” to binary, It’s output is reflected in “$!$”

“eol” represents end of line, which signifies our code for skill is finished.

In etherpad our skill would look like :

“#” – used for commenting out lines in skill

#The following code returns binary equivalent of a decimal number given by user

convert * into binary || binary of *
!javascript:Binary for $1$ = $!$
(+$1$).toString(2);
eol

Screenshot:

Ask SUSI to tell a quote

We can use external API’s for providing answer to user’s query. The external API used for telling the quote is Quotes Rest API created by They Said So. It offers a very good quotes platform and also the quotes are not repeated when several requests are made continuously.

We need a query for our skill.

Query: Tell me a quote.

Now let’s say that we use this JSON response for fetching quote data.

Our JSON object looks like:

{
 success: {
  total: 1
 },
contents: {
quotes: [
{
quote: "Let our advance worrying become advance thinking and planning.",
length: "62",
author: "Winston Churchill",
tags: [
"anxiety",
"inspire",
"planning",
"time-management"
],
category: "inspire",
date: "2017-05-31",
permalink: "https://theysaidso.com/quote/o3aMOSUwOPqUnJv9YyfYHweF/winston-churchill-let-our-advance-worrying-become-advance-thinking-and-planning",
title: "Inspiring Quote of the day",
background: "https://theysaidso.com/img/bgs/man_on_the_mountain.jpg",
id: "o3aMOSUwOPqUnJv9YyfYHweF"
}
],
copyright: "2017-19 theysaidso.com"
}
}

Now we are interested in getting value corresponding to  quotes key, which takes the path:  “path”:”$.contents.quotes“.

We make output query as follows:

!console:$quote$
     {
        "url" : "http://quotes.rest/qod.json",
        "path":"$.contents.quotes"
      }
eol

Explanation :

“!console” prints the output and this is returned by SUSI.AI.

$quote$” is the key whose value will be printed from parsed JSON.It contains our quote and this is a random quote. This is the string which will be responded by SUSI.AI

“url” generated JSON response from external API.

“path” is parsing path of JSON object which we follow for getting correct response.

Our skill will look like:

tell me a quote
!console:$quote$
     {
        "url" : "http://quotes.rest/qod.json",
        "path":"$.contents.quotes"
      }
eol

Screenshot :

Resources:

Continue Reading

Detecting password strength in SUSI.AI Web Chat SignUp

Every SignUp page contains a field to enter a password, but it should not be just a dumb component that takes input and saves it on server. A password field on a SignUp page should tell how weak or strong the password is. We decided to implement this in our SUSI.AI Web Chat SignUp Page.

Our SignUp page look like this:

After entering a valid email, user needs to enter the password. It shows that minimum 6 character are required:

We have the following div for our Password Field :

<PasswordField
  name="password"
  style={fieldStyle}
  value={this.state.passwordValue}
  onChange={this.handleChange}
  errorText={this.passwordErrorMessage}
  floatingLabelText="Password" />

In our OnChange Method we need to check the strength of password once the six character limit is crossed and display the strength visually.

We have used Dropbox’s zxcvbn library for the purpose of getting the strength of password.

Major reasons of choosing this library are :

  • Flexibility : It allows different passwords as long as certain level of complexity is matched.
  • Usability : It is very easy use and gives instant feedback. This helps user towards less guessable passwords.

For installing this library :

 npm -S install zxcvbn

For importing this:

import zxcvbn from 'zxcvbn';

Now in our OnChange Method:

handleChange = (event) => {
        let email;
        let password;
        let confirmPassword;
        let serverUrl;
        let state = this.state
      // Checking if event is password
        if (event.target.name === 'password') {
            password = event.target.value;
            let validPassword = password.length >= 6;
            state.passwordValue=password;
            state.passwordError = !(password && validPassword);
            if(validPassword) {
              //getting strength of password from zxcvbn
              let result = zxcvbn(password);
              state.passwordScore=result.score;
              let strength = [
                'Worst',
                'Bad',
                'Weak',
                'Good',
                'Strong'
              ];
              state.passwordStrength=strength[result.score];
            }
            else {
              state.passwordStrength='';
              state.passwordScore=-1;
            }
        }

Explanation:

In the above method result variable gets the strength of password and result.score gives us the score of password in terms of an integer and according to which we have made an array to get result in remarks corresponding to score. We have remarks like Good, Strong, etc.

Initially we have set the score to -1 to know that user has not entered the password yet. Once user has entered password the score changes.
Then we made a wrapper class to help css format the color of remark and display a meter (determining password strength) with corresponding length and color. We have used template strings to make our wrapper class. This helps us in having different names of wrapper class according to the score of the password.

// using Template Strings(look at resources for more info)
const PasswordClass=[`is-strength-${this.state.passwordScore}`];

Then we wrapped our Password field in div with className = “PasswordClass”.

<div className={PasswordClass.join(' ')}>
        <PasswordField
            name="password"
            style={fieldStyle}
            value={this.state.passwordValue}
            onChange={this.handleChange}
            errorText={this.passwordErrorMessage}
            floatingLabelText="Password" />
            <div className="ReactPasswordStrength-strength-bar" />
<div>

All that was left to was add css code corresponding to every score. For example for score=3, the following css was made:

.is-strength-3 { color: #57B8FF; }

.ReactPasswordStrength-strength-bar {
  box-sizing: border-box;
  height: 2px;
  position: relative; top: 1px; right: 1px;
  transition: width 300ms ease-out;
}

.is-strength--1 .ReactPasswordStrength-strength-bar {
  background: #D1462F;
  display: none;
}
// if strength = -1 then setting display of block equals to none
.is-strength--1 .ReactPasswordStrength-strength-bar {
  background: #D1462F;
  display: none;
}

.is-strength-3 .ReactPasswordStrength-strength-bar {
  background: #57B8FF; //Changing color according to password’s strength
  width: 192px; //Changing width according to password’s strength
  display: block;
}

After successfully implementing all these features, We had following SignUP page:

Resources:

1)Dropbox’s library(ZXVBN): https://github.com/dropbox/zxcvbn

2)Template Strings(Used here for making wrapping class of Password Field): https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Template_literals

Test Link:

This can be tested here.

Continue Reading

Adding Emoji Support in SUSI Web Chat

SUSI.AI web chat sometimes, renders responses which contains emojis. We cannot rely on browser’s capability to render these emojis. The Problem is, that the default support for emojis of browsers does not offer a great variety of emojis to be rendered. The solution we implemented in the SUSI.AI web chat is to make use of a npm package to support our need for displaying emojis.

There were many options to choose from. For example :

Comparison between emoji packages :

Property Twemoji React-easy-emoji React-twemoji React-emojione
Built by Twitter Appfigures ZxMYS Pladaria
Usage Can be used as an object with function parse: twemoji.parse() Can be used as function: emoji() It is a simple wrapper for Twemoji.Can be used as component: <Twemoji> Can be used as function: emojify() or component: <Emojify>
Conversion compatibility Provides standard Unicode emoji support across all platforms Parse only basic emojis.Doesn’t parse emoji names like 🙂 and emoticons like 🙂 Convert emoji characters to Twemoji images Converts shortnames, unicode and ASCII smileys into renderable emojis
Dependencies None loot-web-kit lodash, prop-types, twemoji None

After detailed analysis of the above mentioned packages, we decided to go with React-emojione.

The major reasons are :

  • It is very easy to use.
  • It has no dependencies.
  • It can convert shortnames, unicode and ASCII symbols properly.
  • It can be used as both function and component, which diversifies its usage.

Installation:

npm install -S react-emojione

Basic usage (as function)

import {emojify} from 'react-emojione';
 
ReactDOM.render(
    <div>
        {emojify(':p')}
    </div>,
    document.body
);

Basic usage (as component)

import Emojify from 'react-emojione';
 
ReactDOM.render(
    <Emojify>
        <span>:p</span>
    </Emojify>,
    document.body
);

Some notes about the <Emojify> component:

  • If it has a single child, it won’t be wrapped
  • Otherwise it will be wrapped with a <span>

Difference between component and function?

Functional Stateless Components are just a ‘dumb’ function that takes props as an input. They do not have any state or methods. Just (props) => { return <span>content</span>; }

Class components can have state, variables, methods etc.

Now we needed our react app to render emojis. Our component named MessageListItem.react renders all the text and images of response.

There is a function called imageParse in this component. We use this function to parse our emojis.

Screenshot of SUSI Web Chat

Emoji’s like (:p) are now rendered properly

The implementation is as follows :

function imageParse(stringWithLinks){
  let replacePattern = new RegExp([
                      '((?:https?:\\/\\/)(?:[a-zA-Z]{1}',
                      '(?:[\\w-]+\\.)+(?:[\\w]{2,5}))',
                      '(?::[\\d]{1,5})?\\/(?:[^\\s/]+\\/)',
                      '*(?:[^\\s]+\\.(?:jpe?g|gif|png))',
                      '(?:\\?\\w+=\\w+(?:&\\w+=\\w+)*)?)'
                      ].join(''),'gim');
  let splits = stringWithLinks.split(replacePattern);
  let result = [];
  splits.forEach((item,key)=>{
    let checkmatch = item.match(replacePattern);
    if(checkmatch){
      result.push(
        <img key={key} src={checkmatch}
            style={{width:'95%',height:'auto'}} alt=''/>)
    }
    else{
      result.push(<Emojify  key={key}>{item}</Emojify>);
    }
  });
  return result;
}

Here we put {item} inside <Emojify> tag to render all the emoji’s present inside {item}.

This parses all emojis regardless of browser support. This package fulfills all our needs in this case.

Resources:

react-emojione package: https://www.npmjs.com/package/react-emojione

Testing link: SUSI.AI (Web Chat): http://chat.susi.ai/

Continue Reading

Adding Snackbar to undo recent change in theme of SUSI.AI Web Chat

SUSI.AI Web Chat has two primary themes: Light and Dark. The user can switch between these two from settings, but what if the user does not prefer the theme change. He/She has to repeat the entire process of Going to Settings -> Selecting another theme -> saving it. To enable the user to instantly change the theme, we decided to add snackbar on theme change.

What is Snackbar ?

Snackbar contains info regarding the operation just performed and it displays them in a visual format. Snackbar can also have a button like “Undo” to revert the recent operation just made.

It appears at the bottom of screen by default. A simple snackbar looks like this:

Now we needed this to pop-up, whenever the theme is changed. When a user changes theme we run a function named “implementSettings” which checks what the theme is changed to.

The method is:

implementSettings = (values) => {
    this.setState({showSettings: false});
    if(values.theme!==this.state.currTheme){
      this.setState({SnackbarOpen: true});
    }
    this.changeTheme(values.theme);
    this.changeEnterAsSend(values.enterAsSend);
    setTimeout(() => {
       this.setState({
           SnackbarOpen: false
       });
   }, 2500);
  }

The argument values is an object that contains all the change that user has made in settings. Here values.theme contains the value of theme user selected from settings. We first check if the theme is same as the current one if so, we do nothing. If the theme is different from current, then we update the theme by calling this.changeTheme(values.theme) and also initiate snackbar by setting SnackbarOpen to open.

The snackbar component looks like:

<Snackbar
     open={this.state.SnackbarOpen}
     message={'Theme Changed'}
     action="undo"
     autoHideDuration={4000}
     onActionTouchTap={this.handleActionTouchTap}
     onRequestClose={this.handleRequestClose}
/>

This appears on the screen as follows :

Now if a user wants to change the theme instantly he/she can press the undo button. For this undo button, we have a method handleActionTouchTap. In this method, we change the theme back to previous one. The method is implemented in the following manner:

handleActionTouchTap = () => {
    this.setState({
      SnackbarOpen: false,
    });
    switch(this.state.currTheme){
      case 'light': {
          this.changeTheme('dark');
          break;
      }
      case 'dark': {
          this.changeTheme('light');
          break;
      }
      default: {
          // do nothing
      }
    }
  };

The above method is pretty self-explanatory which checks the current theme(“light” or “dark”) and then revert it. We also change the state of SnackbarOpen to “false” so that on clicking “UNDO” button, the theme changes back to previous one and the snackbar closes.Now user is having an option of instantly changing back to previous theme.

Resources:

Testing Link:

http://chat.susi.ai/

Continue Reading
  • 1
  • 2
Close Menu