Back to search

Build a chat bot using Ember.js and Dialogflow

  • Christian Nwamba
June 21st, 2018
You will need Node and npm installed on your machine.

Introduction

Truth be told, technology is changing the way customers interact with businesses generally, irrespective of the company’s size, workforce and products. The expectation is that your brand ought to be reachable anytime and anywhere. Demand ranges from making enquiries about products, asking for support, to placing orders or requesting for additional services.

Believe me, keeping up with all these activities in a personal cost efficient manner can be a daunting task. This is where a tool like Dialogflow really shines. With it, you can easily build an end to end conversational experience for your customers and have it integrated on your website.

In this article, we’ll dive into a simple example of how to build a chat bot using Dialogflow and Ember.js. This bot will engage in a simple conversation ( small talk ) and respond based on the context of the message from a user. In order to get responses in realtime, we’ll use Pusher to update the client, this amongst other things, will enhance the flow of conversation.

A quick look at what we’ll build:

emberjs-chatbot-demo

Prerequisites

It is important that you have Node.js and npm installed on your machine. Learn how to install Node.js and npm here. A quick run-down of the core technologies we will be using include:

  • Ember.js: an open source JavaScript web framework for creating scalable single-page web applications.
  • Pusher: a Node.js client to interact with the Pusher REST API
  • Express: Node utility for handling HTTP requests via routes
  • Axios: a promise-based HTTP client that works both in the browser and in a Node.js environment.
  • Body Parser: attaches the request payload on Express’s req, hence req.body stores this payload for each request.
  • Dialogflow: an engine for building conversational experiences. It leverages Google’s machine learning and natural language processing technology, thereby giving developers the ability to utilize a user friendly interface to build chat bots and deploy them to any platform.

Getting started

The most convenient and recommended way of getting an Ember app up and running with a single command is by using the Ember CLI tool. You can install it with npm, open your terminal and type this command:

     npm install -g ember-cli

The Ember CLI will give us access to the ember command that will be used to set up our project easily.

Creating the application

To create our application we’ll use the ember new command. Open up the terminal on your machine and run a command that will create an application named chat-bot-ember in your project directory:

     ember new chat-bot-ember

Next, change directory into the newly created project and start the development server:

     // change directory
     cd chat-bot-ember

     // start the development server
     ember serve

This will start the development server on http://localhost:4200. Open your favorite browser and navigate to that URL, you should see a default welcome page by Ember.js as shown below:

ember-start-page

Install server dependencies

Run the following command to install the dependencies required for this project using:

    npm install --save axios pusher pusher-js
    npm install --save body-parser cors dotenv express 
    ember install ember-browserify

Create your Dialogflow account

As pointed out earlier, Dialogflow will help us create a conversational flow for our chat bot, in order to achieve this, we’ll need to create an account and later proceed to create and configure a Dialogflow agent. Head over to their official website and create a free account.

emberjs-chatbot-dialogflow-signin

Create your first Dialogflow agent

A Dialogflow agent is essentially the chat bot and its most fundamental purpose is to detect the intent that comes from a user and respond appropriately. For instance, if a user sends a message such as “Who are you?”, if the agent has been trained to recognize such a phrase, it will detect the intent and respond to the user based on a configured response.

Once you are done setting up an account, click on the Create Agent button to create an agent:

emberjs-chatbot-dialogflow-create-agent-1

Give your agent a name that suits your purpose, I have named mine Ember-chat-bot and finally click on the CREATE button to complete the process

emberjs-chatbot-dialogflow-create-agent-2

Creating small talk

For a quick start, Dialogflow comes with an optional feature called Small Talk. This can easily be customized to give our bot a basic level of interactivity with the users. By default, there are responses with predefined phrases within the small talk panel. Go ahead and customize the response as you deem fit. For now, we are going to keep it simple and respond to few questions:

💡 Note: ensure that you enable the small talk by clicking on the switch as indicated by the red box in the image below:

emberjs-chatbot-dialogflow-smalltalk

You can now use the test console at the right hand side corner to try out a sentence. As in the image below:

emberjs-chatbot-dialogflow-smalltalk-demo

A basic chat agent is now ready to be integrated into our application. We’ll make use of this in a bit.

Pusher account setup

Head over to Pusher and sign up for a free account.

ember-pusher-signup

Create a new app by selecting Channels apps on the sidebar and clicking Create Channels app button on the bottom of the sidebar:

ember-pusher-create-app

Configure an app by providing basic information requested in the form presented. You can also choose the environment you intend to integrate Pusher with to be provided with some boilerplate code:

ember-pusher-config-app

You can retrieve your keys from the App Keys tab:

ember-pusher-app-keys

Integrating the chatbot agent into our application

We’ll be making an API call to Dialogflow API to develop a conversational interface for our application. To execute this, we will need a developer access token generated for our newly created agent from the dashboard. Copy the developer access token and save it as we will use it for the API call.

emberjs-chatbot-dialogflow-key

Setting the environment variables

Create a .env file in the root directory of your application and add your application credentials as obtained from your Pusher dashboard and also the DEVELOPER_ACCESS_TOKEN from the Dialogflow agent dashboard as follows:

      PUSHER_APP_ID=YOUR_APP_ID
      PUSHER_APP_KEY=YOUR_APP_KEY
      PUSHER_APP_SECRET=YOUR_APP_SECRET_KEY
      PUSHER_APP_CLUSTER=CLUSTER

      DEVELOPER_ACCESS_TOKEN=YOUR_DEVELOPER_ACCESS_TOKEN

We will make use of the variables specified in the above snippet later in our project. And do ensure that you replace YOUR_APP_ID, YOUR_APP_KEY, YOUR_APP_SECRET_KEY, CLUSTER and YOUR_DEVELOPER_ACCESS_TOKEN placeholders with the appropriate credentials.

Setting up the server

When a user interacts with the chat bot from our application, the user’s message will be processed and sent to Dialogflow API which will further pass it as a query request to Dialogflow. We will use Express and Node to set up a simple server for this process.

Since the Ember application that we configured earlier is running on a different domain, we’ll enable CORS in order to ensure communication between the Express server and Ember.

Create an app.js file in the root directory of your application and add the following code snippet to it to set up the server:

    // app.js

      const express = require('express');
      const bodyParser = require('body-parser');
      const cors = require('cors');
      const Pusher = require('pusher');
      const axios = require('axios');
      require('dotenv').config();

      const app = express();

      app.use(cors());
      app.use(bodyParser.urlencoded({extended: false}));
      app.use(bodyParser.json());

      // Ensure that your pusher credential are properly set in the .env file  
      const pusher = new Pusher({
          appId: process.env.PUSHER_APP_ID,
          key: process.env.PUSHER_APP_KEY,
          secret: process.env.PUSHER_APP_SECRET,
          cluster: process.env.PUSHER_APP_CLUSTER,
          encrypted: true
      });

      const dialogFlowURL = "https://api.dialogflow.com/v1/query?v=20150910";
      const token = process.env.DEVELOPER_ACCESS_TOKEN;

      app.set('port', process.env.PORT || 3000);
      app.post('/dialogue', (req, res) => {
          const data = {
              query: req.body.text,
              lang: 'en',
              sessionId: '1234567890!@#$%^&*()'
          }    

          axios.post(`${dialogFlowURL}`, data, {headers: { Authorization: `Bearer ${token}` }})
          .then( response => {
              const responseData = {
                  query: data.query,
                   speech: response.data.result.fulfillment.speech
              };
              pusher.trigger('bot', 'bot-response', responseData);
          })
      })

      app.listen(app.get('port'), () => {
          console.log("Listening on " + app.get('port'));
      })

First, we loaded all the necessary middlewares for the Express server and then configured Pusher using the credentials we added to our environment variables earlier.

In addition, we created the /dialogue endpoint that will receive and process the message of a user when having conversation with our chat bot. Furthermore, we created a new data object containing the message posted by user, default language, and a unique sessionId.

We then proceeded to use Axios to make an API call to Dialogflow API, passing the data object and an authorization header with the token. Finally, we triggered an event named bot-response through a bot channel.

Open another terminal and run the command below to start the server on http://localhost:3000:

    node app.js

This will log a message to the console as shown by the image below:

ember-chat-node-running

Generating the UI components

Since ember supports the usage and sharing of UI elements on multiple pages, we will leverage this and generate the bot-app component for our application.

The Ember component generally consists of two parts: a JavaScript component file that defines behavior and a Handlebars template that defines the markup for the component’s UI.

Bot app component

Run the command below to generate the bot-app component:

     ember generate component bot-app

Bot app component file

Add the following content to ./app/components/bot-app.js:

    // ./app/components/bot-app.js

      import Component from '@ember/component';
      import axios from 'npm:axios';
      import Pusher from 'npm:pusher-js';

      export default Component.extend({
          chats: null,
          init() {
              this._super(...arguments);
              this.set('chats', []);
              let pusher = new Pusher('YOUR_APP_KEY', { // update your APP_KEY
                  cluster: 'CLUSTER',
                  encrypted: true
              });
              const channel = pusher.subscribe('bot');
              channel.bind('bot-response', data => {
                  const response = {
                      speech: data.speech,
                      query: data.query
                  }
                  this.get('chats').pushObject(response);
              });
          },
          actions: {
              sendChat() {
                  const text = this.get('message');
                  axios.post('http://localhost:3000/dialogue', { text });
                  this.set('message', '');
              }
          }
      });

First, we imported the required modules for this component and we initialize Pusher with the APP_KEY and CLUSTER as obtained from our Pusher account dashboard and then proceeded to use the subscribe() method from Pusher to subscribe to the created bot channel.

Finally, the sendChat() action basically receives the message submitted by a user and POST it to the server. This action will be triggered once a user press the enter key after typing a message.

Don’t forget to replace the YOUR_APP_KEY and CLUSTER placeholder with the appropriate details from your Pusher account dashboard.

Bot app component template

This template file will be used to loop over each chat and also display the input field for enter a message and start a conversation with our chat bot. Open ./app/templates/components/bot-app.hbs and edit as shown below:

    {{!-- ./app/templates/components/bot-app.hbs --}}

        <div class="panel-body">
          <div class="chats">
               {{#each chats as |chat|}}
            <div class="chat">
              <div class="chat-avatar">
                <a class="avatar avatar-online" data-toggle="tooltip" href="#" data-placement="right" title="" data-original-title="June Lane">
                  <img src="http://res.cloudinary.com/yemiwebby-com-ng/image/upload/v1529185121/user-new_fm7q4a.png" alt="Active user">
                  <i></i>
                </a>
              </div>
              <div class="chat-body">
                <div class="chat-content">
                  <p>
                    {{ chat.query }}
                  </p>
                </div>
              </div>
            </div>
            <div class="chat chat-left">
              <div class="chat-avatar">
                <a class="avatar avatar-online" data-toggle="tooltip" href="#" data-placement="left" title="" data-original-title="Edward Fletcher">
                  <img src="http://res.cloudinary.com/yemiwebby-com-ng/image/upload/v1529185121/bot_gphhi8.png" alt="bot">
                  <i></i>
                </a>
              </div>
              <div class="chat-body">
                <div class="chat-content">
                  <p>{{ chat.speech }}</p>
                </div>
              </div>
            </div>
            {{/each}}
          </div>
        </div>
        <div class="panel-footer">
            <div class="input-group">
                {{input value=message enter="sendChat" class="form-control" placeholder="Enter your message and press enter"}}
            </div>
        </div>        

Update the app template

Update the application template file by adding the bot-app component:

    {{!-- ./app/templates/application.hbs --}}

      <div class="container bootstrap snippets">
      <div class="col-md-7 col-xs-12 col-md-offset-2">
        <div class="panel" id="chat">
          <div class="panel-heading">
            <h3 class="panel-title text-center">
              Realtime Ember Chat Bot
            </h3>
          </div>
           {{#bot-app}}{{/bot-app}}
        </div>
      </div>
      </div>
      {{outlet}}

Stylesheet

To add some minimal styling to the page, open ./app/styles/app.css and paste this code in it:

     // ./app/styles/app.css

      body {
        background:#ddd;
        margin-top:10px;
        }
        .panel {
          margin-top: 40px;
          border: 2px solid #f5f5f5 !important;
        }

        .chat-box {
            height: 100%;
            width: 100%;
            background-color: #fff;
            overflow: hidden
        }

        .chats {
            padding: 30px 15px
        }

        .chat-avatar {
            float: right
        }

        .chat-avatar .avatar {
            width: 30px;
                -webkit-box-shadow: 0 2px 2px 0 rgba(0,0,0,0.2),0 6px 10px 0 rgba(0,0,0,0.3);
            box-shadow: 0 2px 2px 0 rgba(0,0,0,0.2),0 6px 10px 0 rgba(0,0,0,0.3);
        }

        .chat-body {
            display: block;
            margin: 10px 30px 0 0;
            overflow: hidden
        }
        .input-group {
          display: block !important;
        }

        .chat-body:first-child {
            margin-top: 0
        }

        .chat-content {
            position: relative;
            display: block;
            float: right;
            padding: 8px 15px;
            margin: 0 20px 10px 0;
            clear: both;
            color: #fff;
            background-color: #62a8ea;
            border-radius: 4px;
                -webkit-box-shadow: 0 1px 4px 0 rgba(0,0,0,0.37);
            box-shadow: 0 1px 4px 0 rgba(0,0,0,0.37);
        }

        .chat-content:before {
            position: absolute;
            top: 10px;
            right: -10px;
            width: 0;
            height: 0;
            content: '';
            border: 5px solid transparent;
            border-left-color: #62a8ea
        }

        .chat-content>p:last-child {
            margin-bottom: 0
        }

        .chat-content+.chat-content:before {
            border-color: transparent
        }

        .chat-left .chat-avatar {
            float: left
        }

        .chat-left .chat-body {
            margin-right: 0;
            margin-left: 30px
        }

        .chat-left .chat-content {
            float: left;
            margin: 0 0 10px 20px;
            color: #76838f;
            background-color: #dfe9ef
        }

        .chat-left .chat-content:before {
            right: auto;
            left: -10px;
            border-right-color: #dfe9ef;
            border-left-color: transparent
        }

        .chat-left .chat-content+.chat-content:before {
            border-color: transparent
        }

        .panel-footer {
            padding: 0 30px 15px;
            background-color: transparent;
            border-top: 1px solid transparent;
            border-bottom-right-radius: 3px;
            border-bottom-left-radius: 3px;
            overflow: auto;
        }
        .avatar img {
            width: 100%;
            max-width: 100%;
            height: auto;
            border: 0 none;
            border-radius: 1000px;
        }
        .chat-avatar .avatar {
            width: 30px;
        }
        .avatar {
            position: relative;
            display: inline-block;
            width: 40px;
            white-space: nowrap;
            border-radius: 1000px;
            vertical-align: bottom;
        }

Updating the index page

Open the ./app/index.html file and include the CDN file for Bootstrap to enhance the styling and layout of our application. Open up the file and add update as shown below:

     <!-- ./app/index.html -->

      <!DOCTYPE html>
      <html>
        <head>
          <meta charset="utf-8">
          <meta http-equiv="X-UA-Compatible" content="IE=edge">
          <title>ChatBotEmber</title>
          <meta name="description" content="">
          <meta name="viewport" content="width=device-width, initial-scale=1">
          {{content-for "head"}}
          <link integrity="" rel="stylesheet" href="{{rootURL}}assets/vendor.css">
          <link integrity="" rel="stylesheet" href="{{rootURL}}assets/chat-bot-ember.css">
          <!-- add the CDN file -->
          <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">

          {{content-for "head-footer"}}
        </head>
        <body>
          {{content-for "body"}}
          <script src="{{rootURL}}assets/vendor.js"></script>
          <script src="{{rootURL}}assets/chat-bot-ember.js"></script>
          {{content-for "body-footer"}}
        </body>
      </html>

Testing the application

Stop the Ember development server if it is currently running by typing Ctrl + C in the terminal and restart it with ember serve. In addition, don’t forget to also run node app.js from another terminal to start the Express server in case you haven’t done that. Next, open http://localhost:4200 to test the application.

emberjs-chatbot-homepage

Conclusion

Obviously, the chat bot built in this tutorial only engaged a minimal conversation with users. This can be enhanced and tailored to suit the need of your brand in order to keep your customers engaged and welcomed.

Feel free to check out the complete source code here on GitHub and add more awesome features. I hope you found this tutorial helpful.

  • Channels

© 2018 Pusher Ltd. All rights reserved.

Pusher Limited is a company registered in England and Wales (No. 07489873) whose registered office is at 28 Scrutton Street, London EC2A 4RP.