Implementing Login Functionality in SUSI Web Chat

SUSI Web Chat is fully equipped with all the accounting features which are being provided by the SUSI.AI API. This blog discloses all the API features one needs to know to embed the Login functionality in SUSI Web Chat.

  1. To embed the Login feature, first we create a form using material-ui.com components with the followng fields
    1. Email
    2. Password
    3. Note: We can also chose a Custom Server while logging in, here I have used the Standard Server ie. http://api.susi.ai to make the user Login

The form can be made with the help of the following fields

  • TextField for Email, props to be passed
    • Name – email
    • Value – this.state.email which gets the value of the current email
    • floatingLabelText is Email,
    • errorText is the message which we want to show when the email does not match the regex or its empty.

Code Snippet –

<TextField name="email" value={this.state.email} onChange={this.handleChange} errorText={this.emailErrorMessage}    floatingLabelText="Email" />
  • PasswordField for Password
    • Name – password
    • Value – this.state.password which gets the value of the current email
    • floatingLabelText is Password,
    • errorText is the message which we want to show when the password is not filled.

Code Snippet-

<PasswordField name='password' value={this.state.password} onChange={this.handleChange} errorText={this.passwordErrorMessage}   floatingLabelText='Password' />
  • The next elements are RadioButton groups taken from material-ui.com. This ensures the user signs into a standard server or even to a custom server. This is not compulsory as of now.
  • And lastly we need a submit button, which is disabled until all the fields are filled.

Code Snippet –

<RaisedButton label="Login" type="submit" labelColor="#fff" disable={!this.state.validForm} />

For the full form, check out this file at Login.react.js

  1. A Sample UI could be as shown in the image
  2. Next after creating the Login Screen, we make the onSubmit prop which is to be hooked up with another function called handleSubmit. An example code snippet from Login.react.js
 handleSubmit = (e) => {
        e.preventDefault();
        // Get the trimmed values from the fields
        var email = this.state.email.trim();
        var password = this.state.password.trim();
        // Set the default server to login
        let BASE_URL = defaults.Server;
            // handle all the details of the chosen server
        let serverUrl = this.state.serverUrl;
        if(serverUrl.slice(-1) === '/'){
            serverUrl = serverUrl.slice(0,-1);
        }
        if(serverUrl !== ''){
            BASE_URL = serverUrl;
        }
// if email and password is filled return true
        if (!email || !password) { return this.state.isFilled; }
// Check the regex of email
        let validEmail = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(email); 
// Pass the parameters to the loginEndPoint
        let loginEndPoint =
            BASE_URL+'/aaa/login.json?type=access-token&login=' +
            this.state.email + '&password=' + this.state.password;
        // If email and password is filled and valid call AJAX
        if (email && validEmail) {
            // AJAX Calls
        }
    }
    1. Then we make the Ajax Calls and store the created token from hitting the URL at http://api.susi.ai/aaa/login.json?type=access-token&login=EMAIL&password=PASSWORD. We store the cookie in browser and generate a session for the user using a package ‘universal-cookies’.
$.ajax({
    url: loginEndPoint,
    dataType: 'jsonp',
    jsonpCallback: 'p',
    jsonp: 'callback',
    crossDomain: true,
    success: function (response) {
        cookies.set('serverUrl', BASE_URL, { path: '/' });
        let accessToken = response.access_token;
        let state = this.state;// Adding the current State
        let time = response.valid_seconds; // Get the valid time of the cookie
        state.isFilled = true; // Set isFilled to true
        state.accessToken = accessToken; // Get the token
        state.success = true; // Set Success to true
        state.msg = response.message; // Get the server message
        state.time = time; // Get the time in the state
        this.setState(state); // Set the  state with the values
/* Pass the token to the binding function handleOnSubmit passing the arguments - token and the valid time */
        this.handleOnSubmit(accessToken, time);
    }.bind(this),
    error: function (errorThrown) {
        let msg = 'Login Failed. Try Again';
        let state = this.state;
        state.msg = msg;
        this.setState(state);
    }.bind(this)
});

 

    1. We then fire up the handleOnSubmit(accessToken, time) which saves the token for the given expiration time from the server.

Here’s the sample code

handleOnSubmit = (loggedIn, time) => {
        let state = this.state;
        if (state.success) {
            cookies.set('loggedIn', loggedIn, { path: '/', maxAge: time }); // set the cookie in the browser to maintain the loggedIn state
            this.props.history.push('/', { showLogin: false });
            window.location.reload();// reload after the loggedIn cookie creation
        }
        else {
            this.setState({
                error: true,
                accessToken: '',
                success: false
            });
        }
    }
  1. We then check the access token and redirect him based on his login state. This is handled in MessageSection.react.js
import Cookies from 'universal-cookie';
const cookies = new Cookies();
if (cookies.get('loggedIn')) {
    //Show all functionalities of loggedIn state
}
else {
//Redirect user to login page
}

 

To have a look at the full project, visit https://github.com/fossasia/chat.susi.ai and feel free to contribute. To test the project visit http://chat.susi.ai

Resources

Continue ReadingImplementing Login Functionality in SUSI Web Chat

Creating and Maintaining User Sessions Using Universal-Cookies in SUSI Web Chat

If you login to SUSI Web Chat, and come back again after some days, you find that you didn’t have to login and all your previous sent messages are in there in the message pane. To achieve this, SUSI Web Chat uses cookies stored in your browser which is featured in this blog.  

In ReactJS, it’s highly misleading and extensive to use the conventional Javascript methodology of saving tokens and deleting them. However, universal-cookie, a node package allows you to store and get cookies with the least possible confusion. In the following examples, I have made use of the get, set and remove functions of the universal-cookie package which have documentations easily available at this link. The basic problem one finds while setting cookies and maintaining sessions is the time through which it should be valid and to secure the routes. We shall look at the steps below to figure out how was it implemented in SUSI Web Chat.

1. The first step is to install the packages by using the following command in your project’s root-

npm install universal-cookie --save

2. Import the Cookies Class, where-ever you want to create a Cookie object in your repository.

import Cookies from 'universal-cookie';

Create a Cookie object at the same time in the file you want to use it,

const cookies = new Cookies();

3. We make use of the set function of the package first, where we try to set the cookie while the User is trying to login to the account.

Note – The cookie value can be set to any value one wants, however, here I am setting it to the access token which is generated by the server so that I can access it throughout the application.

$.ajax({ options: options,
        success: function (response) {
//Get the response token generated from the server
                let accessToken = response.access_token;                       // store the current state
                 let state = this.state;
// set the time for which the session needs to be valid
            let time = response.valid_seconds;
//set the access token in the state
             state.accessToken = accessToken;
// set the time in the state
             state.time = time;           
// Pass the accessToken and the time through the binded function
             this.handleOnSubmit(accessToken, time);
            }.bind(this),
        error: function ( jqXHR, textStatus, errorThrown) {
                   // Handle errors
                   }
        });

Function –  handleOnSubmit()

// Receive the accessToken and the time for which it needs to be valid
handleOnSubmit = (loggedIn, time) => {
        let state = this.state;
        if (state.success) {
              // set the cookie of with the value of the access token at path ‘/’ and set the time using the parameter ‘maxAge’
            cookies.set('loggedIn', loggedIn, { path: '/', maxAge: time });
// Redirect the user to logged in state and reload
            this.props.history.push('/', { showLogin: false });
            window.location.reload();
        }
        else {
        // Handle errors
    }
}

4.  To access the value set to the cookie, we make use of the get function. To check the logged in state of the User we check if get method is returning a null value or an undefined value, this helps in maintaining the User behaviour at every point in the application.

if(cookies.get('loggedIn')===null||
    cookies.get('loggedIn')===undefined) {
    // Handle User behaviours do not send chat queries with access token if the cookie is null
    url = BASE_URL+'/susi/chat.json?q='+
          createdMessage.text+
          '&language='+locale;
  }
  else{
   //  Send the messages with User’s access token
    url = BASE_URL+'/susi/chat.json?q='
          +createdMessage.text+'&language='
          +locale+'&access_token='
          +cookies.get('loggedIn');
  }

5. To delete the cookies, we make use of the remove function, which deletes that cookie. This function is called while logging the user out of the application.

cookies.remove('loggedIn');
this.props.history.push('/');
window.location.reload();

Here’s the full code in the repository. Feel free to contribute:https://github.com/fossasia/chat.susi.ai

Resources

Continue ReadingCreating and Maintaining User Sessions Using Universal-Cookies in SUSI Web Chat

Using react-url-query in SUSI Chat

For SUSI Web Chat, I needed a query parameter which can be passed to the components directly to activate the SUSI dreams in my textarea using just the URL which is not easy when one is using react-router. React URL Query is a package for managing state through query parameters in the URL in React. It integrates well with React Router and Redux and provides additional tools specifically targeted at serializing and deserializing state in URL query parameters. So for example, if one wants to pass some parameters to populate in your component directly through the URL, you can use react-url-query. Eg. http://chat.susi.ai/?dream=fossasia will populate fossasia in our textarea section without actually typing the term textarea.

So this in the URL,
Screenshot from 2017-06-29 09.46.33

Will produce this in the textarea,

To achieve this. the following steps are required:

  1. First we proceed with installing the packages (Dependencies  – history)
npm install history --save
npm install react-url-query --save
  1.   We then instantiate a history in our component where we want to listen to the parameters like the following code. Our class ChatApp is where we want to pass the params.

ChatApp.react.js

import history from '../history'; 
//Import the history object from the History package.
    
 // force an update if the URL changes inside the componentDidMount function
  componentDidMount() {
      history.listen(() => this.forceUpdate());
   }
  1.  Next, we define the props of the parameters in our Message Section. For that we need the following props-
  • urlPropsQueryConfig – this is where we define our URLConfig
  • Static proptypes – the query param to which we want to pass the value, so for me it’s dream.
  • The defaultProps when no such value is being passed to our param should be left a blank.
  • And then we finally assign the props.
  • This is then passed to the Message Composer Section from where we receive the value passed.

MessageSection.react.js

// Adding the UrlConfig
const urlPropsQueryConfig = {
  dream: { type: UrlQueryParamTypes.string }
};

 // Defining the query param inside our ClassName
  static propTypes = {
    dream: PropTypes.string
  }
// Setting the default param

  static defaultProps = {     
dream: ''
  }

 //Assigning the props inside the render() function
    const {
      dream
    } = this.props;
 //Passing the dream to the MessageComposer Section

                  <MessageComposer
                    threadID={this.state.thread.id}
                    theme={this.state.darkTheme}
                    dream={dream} />                
//Exporting our Class

export default addUrlProps({ urlPropsQueryConfig })(ClassName);
  1. Next we update the Message Composer section by the props we had passed. For this we first check if the props are null, we don’t populate it in our textarea if it is, otherwise we populate the textarea with the value ‘dream + props.dream’ so the value passed in the URL will be prepend by a word dream to enable the ‘dream value’ in our textarea.

The full file is available at MessageComposer.js

 //Add Check to the constructor
 constructor(props) {
    super(props);
    this.state = {text: ''};
    if(props.dream!==''){   //Setting the text as received ‘dream dreamPassed’
      this.state= {text: 'dream '+ props.dream}
    }
  }
// Populate the textarea
        <textarea
          name="message"
          value={this.state.text}
          onChange={this._onChange.bind(this)}
          onKeyDown={this._onKeyDown.bind(this)}
          ref={(textarea)=> { this.nameInput = textarea; }}
          placeholder="Type a message..."
        />
// Add props to the component
MessageComposer.propTypes = {
  /* other props */,
  dream: PropTypes.string //Setting Proptypes to receive the prop from the MessageSection
};

Now we have the full code working for querying any dream. Head over to chat.susi.ai?dream=fossasia Change fossasia to see the text change.

Resources

Continue ReadingUsing react-url-query in SUSI Chat

Using SUSI as your dictionary

SUSI can be taught to give responses from APIs as well. I made use of an API called Datamuse which is a premier search engine for English words, indexing 10 million unique words and phrases in more than 1000 dictionaries and glossaries.

1. First, we head towards creating our dream pad for creating rules for the skill. To do this we need to create a dream at dream.susi.ai and give it a name, say dictionary.

2. After that one needs to go to the API and check the response generated.

3. Going through the docs of the API, one can create various queries to produce informative responses as follows –

  • Word with a similar meaning.

define *| Meaning of *| one word for *

!console: $word$
{
"url":"https://api.datamuse.com/words?ml=$1$",
"path":"$.[0]"
}
eol
  • Word related to something that start with a given letter.

word related to * that start with the letter *

!console: $word$
{
"url":"https://api.datamuse.com/words?ml=$1$&sp=$2$*",
"path":"$.[0]"
}
eol

  • Word that sound like a given word..

word that sound like *|sounding like *

!console: $word$
{
"url":"https://api.datamuse.com/words?sl=$1$",
"path":"$.[0]"
}
eol

  • Words that are spelled similarly to a given word.

words that are spelled similarly to *| similar spelling to *| spelling of *

!console: $word$
{
"url":"https://api.datamuse.com/words?sp=$1$",
"path":"$.[0]"
}
eol

  • Word that rhyme with a given word.

rhyme *| word rhyming with *

!console: $word$
{
"url":"https://api.datamuse.com/words?rel_rhy=$1$",
"path":"$.[0]"
}
eol

  • Adjectives that are often used to describe a given word.

adjective to describe *|show adjective for *|adjective for *

!console: $word$
{
"url":"https://api.datamuse.com/words?rel_jjb=$1$",
"path":"$.[0]"
}
eol

  • Suggestions for a given word.

suggestions for *| show words like *| similar words to * | words like *

!console: $word$
{
"url":"https://api.datamuse.com/sug?s=$1$",
"path":"$.[0]"
}
eol

This is a sample query response for define *

To create more dictionary skills go to http://dream.susi.ai/p/dictionary and add skills from the API. To contribute by adding more skills, send a pull request to the susi_skill_data.  To test the skills, you can go to chat.susi.ai

Continue ReadingUsing SUSI as your dictionary

20 Amazing Things SUSI can do for You

SUSI.AI has a collection of varied skills in numerous fields such as knowledge, entertainment, problem solving, small-talk, assistants etc. Here’s a list of top skills which SUSI possesses.

Knowledge Based

  1. Ask SUSI to describe anything.

Sample Queries describe *

  1. Ask SUSI the distance between any two cities.

Sample queries – distance between * and *|What is distance between * and * ?| What is distance between * and *         

  1. Ask SUSI about your site’s rank.

Sample Query – site rank of *                

  1. Ask SUSI to know the location of any place.

Sample Queries – where is *

        

  1. Ask SUSI the time in any city.

 Sample Query – current time in *

        

  1. Ask SUSI the weather information of any city.

Sample Queries – temperature in * , hashtags * *, mentions * *, weather in *, Tell me about humidity in *|What is humidity in *|Humidity in *|* Humidity, Tell me tomorrow’s weather in *|Weather forecast of *

        

  1. Ask SUSI to wiki about anything.

Sample Query – wiki *

            

  1. Ask SUSI about any word, words etc.

Sample Queries – define *| Meaning of *| one word for *, word related to * that start with the letter *, word that sound like *|sounding like *, words that are spelled similarly to *| similar spelling to *| spelling of *, rhyme *| word rhyming with *, adjective to describe *|show adjective for *|adjective for *, suggestions for *| show words like *| similar words to * | words like *

  1. Ask SUSI about a day in the calendar.

Sample Queries – Date * ?, Day * ?, Day on year * month * date *?

        

  1. Ask to convert a currency to USD for you. 

Sample Queries –  convert * to USD

        

Problem Solving Based

  1. Ask SUSI to solve a problem for you in Mathematics.

  Sample Queries – compute *| Compute *| Calculate *| calculate *

        

Entertainment Based

  1. Ask SUSI to draw a card for you.

Sample Query – draw a card

        

  1. Ask SUSI to toss a coin for you.

Sample Query – flip a coin

        

  1. Ask SUSI to tell you a Big Bang Theory Joke.

Sample Query – * big bang theory| tell me about big bang theory|geek jokes|geek joke|big bang theory *

  1. Ask SUSI to generate a meme for you.

 Sample Query – get me a meme

        

        

  1. Ask SUSI to give you a recipe. 

Sample Queries – * cook *, cook *|how to cook *|recipe for

 

  1. Ask SUSI to tell you a random joke.

Sample Queries – tell me a joke|recite me a joke|entertain me

  1. Ask SUSI to give you a random gif.

Sample Query – random gif

        

Assistants

  1. Ask SUSI to translate something for you

Sample Queries – What is * in french|french for * , What is * in german|german for *, What is * in spanish|spanish for *,  What is * in hindi|hindi for *

  1. Ask SUSI to search anything for you.

Sample Queries – search *|query *|duckduckgo *

        

To contribute to the above skills you can follow the tutorial here. To test or chat with SUSI you can go to chat.susi.ai

Continue Reading20 Amazing Things SUSI can do for You

Using Flux to embed SUSI’s API Service in a Chat System.

To embed SUSI’s API Service in a chat-like system, I needed a view which could populate the content dynamically and maintain the state of the Application at the same time. Flux follows a unidirectional data flow path and I used this feature to the advantage of the Chat Application to maintain the real time state of the Chat View.

A Flowchart model of Flux looks like

flux flowchart

 

src: https://github.com/facebook/flux

Flux uses a dispatcher service to render its views, thus making the data flow in a unidirectional path. When a user reacts with a React view (here through the TextArea in the chat system), the view propagates an action through the dispatcher service, to the various stores that hold the application’s data and finally update the views that are affected. Here’s another flowchart model from the website which helps one understand the model in a better way.

flux flow

For the current Chat Application, I used a single Message Store which contained all the event listeners to detect any change in the view. For example, when I send a “Hey” to SUSI, an action is called to Dispatch this message to the Message Store with an ActionType  “CREATE_MESSAGE”. This store then renders the message in the Message Section View.

Here is an example snippet from the Actions.js file which performs an action of type CREATE_MESSAGE and dispatches the messages to the MessageStore.js.

export function createMessage(text, currentThreadID) {
let message = ChatMessageUtils.getCreatedMessageData(text, currentThreadID);
ChatAppDispatcher.dispatch({
type: ActionTypes.CREATE_MESSAGE,
message
});
ChatWebAPIUtils.createMessage(message);
};

The response from the message is generated as soon as another ActionType named

“CREATE_SUSI_MESSAGE” is dispatched to the store, thereby rendering the SUSI’s response generated in the view.

The file ChatConstants.js which declares all the ActionTypes.

import keyMirror from 'keymirror';

export default {

  ActionTypes: keyMirror({
    CREATE_MESSAGE: null,
    RECEIVE_RAW_CREATED_MESSAGE: null,
    CREATE_SUSI_MESSAGE: null,
    RECEIVE_SUSI_MESSAGE: null,
    RECEIVE_RAW_MESSAGES: null
  })

};

To get the message up on the view, I have used the following utils to call the API, render the messages to the view and call the different actions. Here’s a code snippet from ChatMessageUtils.js

export function createMessage(message) {
  ChatExampleDataServer.postMessage(message, createdMessage => {
    Actions.receiveCreatedMessage(createdMessage, message.id);
  });
  ChatExampleDataServer.postSUSIMessage(message, createdMessage => {
    Actions.createSUSIMessage(createdMessage, message.threadID);
  });
};

To know more about the project join us on Gitter at gitter.im/fossasia/susi_webchat, or to contribute go to https://github.com/fossasia/chat.susi.ai/.

A demo application can be found running at http://chat.susi.ai.

Resources –

To know more about Flux you can visit the following websites.

Continue ReadingUsing Flux to embed SUSI’s API Service in a Chat System.