Creating a React Based Conversational Chatbot Client

Built using Oracle Intelligent Bots version 18.2.3

Introduction

Oracle Intelligent Bots is an integrated feature of Oracle Autonomous Mobile Cloud Enterprise (AMCe) which allows you to develop Intelligent Chatbots. A Chatbot or Bot is a computer program designed to simulate a conversation with human users, especially over the Internet. End users can easily connect to Chatbots through many of the popular messaging apps or a pop up on your site, without having to download and install a new app from an App store.

By using Artificial Intelligence (AI) and Natural Language Processing (NLP) powered by Neural Networks and Machine Learning, Oracle Intelligent Bots detects what the user is trying to achieve (their intent) and respond appropriately with information or results of transactions from API connections to any of your back-end enterprise applications and information sources.

Oracle Intelligent Bots gives customers an improved experience by helping them to resolve their questions quickly in a conversational manner which in turn can help to reduce costs and pressure on customer services.

To read background on Oracle Intelligent Bots please visit: https://www.oracle.com/solutions/mobile/bots.html#overview

 

The concepts, scripts and information presented in this article are for educational purposes only. They are not supported by Oracle Development or Support, and come with no guarantee or warrant for functionality in any environment other than the test system used to prepare this article. Before applying any changes presented in this article to your environment, you should thoroughly test to assess functionality and performance implications.

Creating a React Based Conversational Chatbot Client

Your Oracle Intelligent Bots instance comes with a collection of sample applications. These samples show you how to build various chat client applications using Oracle Jet, HTML5 and JS. This article will show you how to create a sample React client that allows a user to talk to the provided example bot called FinancialBot, but you can use this client to talk to any other Chatbot.

React is a declarative, efficient, and flexible JavaScript library for building user interfaces. React has a concept of Components which allow the developer to split the UI into independent, reusable pieces. We will create a React component that encapsulates the Chatbot UI and can be reused throughout any React based application. Due to the separation of concerns (focusing on UI components only) it is quick to pick up.

Before You Begin

To complete this exercise, make sure you have the following:

  • Oracle Intelligent Bots instance with sample applications up and running.
  • Node.js and npm downloaded and installed on your machine. Links below.
  • Basic knowledge of JavaScript.

We will assume the client will run on localhost for this article. In a real world situation this could be running in a Docker container within the Oracle Container Cloud Service.

Architecture

The bot we will be using for this exercise, Financial Bot, allows end users to find balances in their banking accounts, transfer money between banking accounts and send money to different people and accounts. The Financial Bot runs inside Oracle Intelligent Bots and is accessible via a WebHook.

As mentioned above the Oracle Intelligent Bots comes with a collection of preinstalled example clients. Some of the examples make use of a JavaScript based application called the ChatServer. This application will sit in between your React Client and your Oracle Intelligent Bots. It will allow you to configure and save WebHook details between your Oracle Intelligent Bots and ChatServer application quickly via the administration tooling.

Your React client will create a WebSocket connection with the ChatServer. Your client is what your users can see, where they enter their messages to the Chatbot, and where the responses are displayed.

In summary, the client will communicate to the ChatServer over a WebSocket and the ChatServer  to the Bots Service with a WebHook.

What’s the difference between a WebSocket and a WebHook?

A WebHook is commonly used for server to server communication. It is an HTTP callback (HTTP POST) that occurs when something happens. A web application implementing WebHooks will POST a message to a URL when an event happens. WebHooks do not have a long-lived open connection.

WebSockets are often used in real time messaging apps and can be used for server to browser communication. The server hosts a WebSocket server, and clients can open a connection to that server.  Unlike HTTP, the socket that is connected to the server stays open for communication, pushing messages to the client/browser in real time.

High Level Flow

High Level Flow

For the exercise, your client can run locally, but it could easily run in a Docker container on Oracle Container Cloud Service.

As an extra step in the exercise you can install one of the out of the box sample application on your local system (or Oracle Container Cloud Service) this will also make use of the ChatServer application. This is covered in the below.

To build this example we will follow the below steps:

  • Create a WebHook in the bots administration tooling and configure the ChatServer
  • Create a basic React application using the react client
  • Add a reconnecting WebSocket library
  • Configure the client and test

Create a WebHook

To set up the WebHook between the ChatServer and Oracle Intelligent Bots we need to add configuration in two locations.

Firstly create a WebHook channel inside your Oracle Intelligent Bots administration tool, sometimes referred to as “BotsUI”. For this example we are using the FinancialBot. Inside the BotsUI and inside the FinancialBot, click the settings icon on the left menu bar and click the green ‘add Channel’ button.

create_react_chatbot_create_channel

Create a Webhook Channel

Popup window to create channel

Name: <Anything you like>

Channel Type: Webhook

Platform Version: 1.1 (Conversation Model)

Outgoing Webhook URIhttps://bots-samples-nodejs:8889/ext/apps/chat/bots/  ( this is the ChatServer)

Channel Enabled: True

Click ‘Create’.

Next add the bot ID to the end of the outgoing WebHook URI. At the end of the URI add the long unique identifier from the end of the WebHook URL along with “/messages”. So your outgoing WebHook URI will look like this:

Outgoing Webhook URIhttps://bots-samples-nodejs:8889/ext/apps/chat/bots/<LONG BOT UNIQUE IDENTIFIER HERE>/messages

create_react_chatbot_view_channel

View WebHook Channel

Note the secret key and the WebHook URI as these will be used in the next step.

The second configuration required is connection between the ChatServer and to the Oracle Intelligent Bots WebHook we just created. The ChatServer administration UI can be found here: http://localhost:8888/ext/apps/chat/admin. Click “New Channel” and enter the fields.

Create a New Channel

Create a New Channel

Enter the secret key and WebHook URI found in the previous BotsUI configuration. Click Save.

Extra Step:

If you would like to test the out of the box sample clients you can follow these steps:

Within your Intelligent Bots Cloud Service navigate to the Developer Resources at http://<server>:<port>/ext/dev-resources/. Select under the heading “Web-based Chat Widget”, “Sample Web Chat Widget”. This is a JS based widget that allows you to host your bot on any website. The look and feel of this widget can be customised.

Download the widget by clicking “Download original code”. Unzip the file locally. Navigate into the chat directory and type:

#cd chatwidget_web

#npm install

#npm run build

#npm run serve

Navigate to http://localhost:8089/dist/Blank/index.html

If you find this is not working, “add node ./” to the package.json file

"serve": "node ./node_modules/grunt/bin/grunt",
"build": "node ./node_modules/grunt/bin/grunt build",

Run npm run serve to start the development server and then navigate to the Blank example.

#npm run serve

create_react_chatbot_samples_1

ChatBot Samples Application Launch Page

If you see the above you have successfully started the service. Now we will configure it to point to the FinancialBot.

Inside the directory /chatwidget_web/dist/Blank/settings.js

create_react_chatbot_samples_2

Change URI, channel, chatTitle, and miniTitle with your settings.

chatTitle: FinancialBot
miniTitle: Lets Chat

Save and refresh your browser (there is no need to restart). Click the ‘Let’s chat’ to open the chat window.

create_react_chatbot_samples_3

ChatBot Sample Application Running

You have successfully set up the samples JavaScript web client.

Create the foundation React Application

First create and start a barebones application using the npm/React commands below.

#npm install -g create-react-app

#create-react-app chatbot-client

#cd chatbot-client

#npm start

Your browser should be launched and navigated to http://localhost:3000/. You should see the below.

React Hello World

React Welcome Page

Create the new Chat React Component (Chat.jsx) inside the src directory. JSX is a syntax extension to JavaScript which is used by React for templating instead of normal JavaScript. It allows you to write HTML/XML-like structures in the same file as you write JavaScript code. Further reading in the links below.

Inside App.js, replace the contents of the render method to include your new component.

<div>
 <Chat/>
</div>

Add the Component to the imports:

import Chat from "./Chat";

Inside Chat.js, add the basic Component layout and your divs to prepare for formatting and outputting of your messages:

import React from 'react';
import React, { Component } from 'react'

class Chat extends Component {
 constructor(props) {
	super(props);
 }
 render() {
 return (
   <div className="Chat-container">
      <div className="Chat-row">
        <div className="Chat-column">
          <div className="Chat-card">
            <div className="Chat-body">
                  <div className="Chat-title">Financial React Based Chatbot</div>
                  <div className="Chat-messages"> Message output div </div>
            </div>
            <div className="Chat-footer"> Submit button div  </div>
          </div>
        </div>
      </div>
   </div>
  );
 }
}

export default Chat;

Create a css file, Chat.css file to add styling. Import it within your Chat.js file.

import './Chat.css';

Inside Chat.css add your formatting.

.Chat-container{
  width: 24%;
  position: absolute;
  border: 1px solid #0084ff;
  height: 400px;
  right: 15px;
  bottom: 15px;
  text-align: center;
}
.Chat-row{
  height: 50px;
}
.Chat-column{
  height: 50px;
}
.Chat-body{
  padding-top: 20px;
  height: 200px;
}
.Chat-title{
  height: 40px;
}
.Chat-messages{
  border: 1px solid #0084ff;
  overflow: auto;
  height: 290px;
  position : relative;
  bottom:0;
}
.Chat-footer{
  position: absolute;
  width: 100%;
  bottom: 10px;
}
.Chat-bubble-left{
  padding: 5px 10px 5px 10px;
  text-align: left;
  border-radius: 10px;
  background: #F0F0F0;
  position : relative;
  bottom:0;
}
.Chat-bubble-right{
  text-align: right;
  padding: 5px 10px 5px 10px;
  background: #cce6ff;
  border-radius: 10px;
}

Save the files and refresh the browser. You should not need to restart npm.

Inside the Chat.jsx render method, locate the div called ”Chat-footer” and add the input field and submit button with in a form by replacing the text with:

<form >
<input type="text" size= "40" placeholder="Message" className="Chat-input" value={this.state.message} onChange={ev => this.setState({message: ev.target.value})}/>
<button onClick={this.sendMessage} className="Chat-submit">Summit</button>
</form>

And add properties to the constructor under the line which calls super(props)

 this.state = {
  message: '',
  messages: []
 }

If you refresh your browser you will see a submit button and input field.

Making a Conversation with the FinancialBot

To connect your React client to the ChatServer we will make use of a library called the ‘Reconnecting WebSocket’. This small wrapper will automatically reconnect if the WebSocket connection is closed. We will also create a helper js file to separate the connection logic out of the ReactComponent. This will be called bots-websocket.js. It is best practise to minimise the business logic inside your React component.

To add the Reconnecting WebSocket library to your package.json so it is included in the build dependencies add the following:

"reconnecting-websocket": "^3.2.2"

To pick up the new library run:

#npm install

Inside the bots-websocket.js enter the logic for managing the connection and messages.

import ReconnectingWebSocket from 'reconnecting-websocket'

class BotsWebsocket {
    constructor(addMessageCallback) {
        debug('constructor: ')
        this.addMessageCallback = addMessageCallback
        this.channel = 'CHANNEL-ID-HERE'
        this.userId = "1"
        this.websocketConnectionUrl = 'ws://localhost:8888/ext/apps/chat/ws'
        this.connect()
    }

    connect() {
        let self = this
        let connection = this.websocketConnectionUrl + '?user=' + this.userId
        debug('initWebSocketIfNeeded: connection ' + connection)
        this.ws = new ReconnectingWebSocket(connection)

        this.ws.onmessage = function(evt) {
            debug('Message received: ' + evt.data)
            let response = JSON.parse(evt.data)
            if (response.body && response.body.messagePayload) {
                const messagePayload = response.body.messagePayload

                // ES6 Note the use of Backquotes
                debug(`messagePayload is ${messagePayload.text}`)

                var test = messagePayload.text
                let messageReceived = ''

                // check if its an array or not
                if (test.indexOf('textposition') !== -1) {
                    messageReceived = JSON.parse(test)
                } else {
                    messageReceived = JSON.stringify(messagePayload.text)
                }

                self.addMessageCallback(messageReceived)
            } else if (response.error) {
                debug('FAIL:' + response.error.message)
                self.addMessageCallback(response.error.message)
            }
        }
    }

      sendToBot(message) {
          const messageToBot = message ?
              {
                  to: {
                      type: 'bot',
                      id: this.channel
                  },
                  messagePayload: {
                      type: 'text',
                      text: message
                  }
              } :
              {
                  to: {
                      type: 'bot',
                      id: this.channel
                  }
              }
          const ws = this.ws
          // wait for websocket until open
          waitForSocketConnection(this.ws, function() {
              ws.send(JSON.stringify(messageToBot))
              debug('Message sent: ' + JSON.stringify(messageToBot))
          })
      }
}

// debug method
const debug = message => console.log(message)

const waitForSocketConnection = (socket, callback) => {
    setTimeout(function() {
        if (socket.readyState === 1) {
            callback()
        } else {
            debug('waiting for connection...')
            waitForSocketConnection(socket, callback)
        }
    }, 1000) // wait 1 second for the connection...
}

export default BotsWebsocket

Replace the ‘YOUR_CHANNEL_ID’ and ‘YOUR_SERVER’ with your details.

Add calls to the BotsWebsocket in your Chat.jsx in the constructor, under “this.state = { message: ”, messages: []  }”.

        const addMessageCallback = data => {
            console.log('received content - ' + JSON.stringify(data))
            this.setState({
                messages: [...this.state.messages, data]
            })
        }
        this.botsWebsocket = new BotsWebsocket(addMessageCallback)

        this.sendMessage = ev => {
            ev.preventDefault()
            this.setState({
                messages: [...this.state.messages, this.state.message]
            })
            this.botsWebsocket.sendToBot(this.state.message)
            // reset the text input
            this.setState({
                message: ''
            })
        }

And into the Chat-messages div add the output UI logic. For messages to the Chatbot we use the css branding “bubble-left“ and responses are displayed using “bubble-right”.

                          {
                              this.state.messages.map((message,index) => {
                              if(index % 2 === 0){
                                  return (<div className="Chat-bubble-left" key={index} >{message} </div>)
                              }
                              else{
                                  return  <div className="Chat-bubble-right" key={index} >{message}</div>
                              }

                              })
                          }

Refresh the browser if it does not automatically refresh. You should now see the below:

create_react_chatbot_final

Ask the Chatbot a question such as “What is my balance for savings?” You should see the responses in the client.

Troubleshooting tips

  • Verify your message to the Chatbot is working inside the BotsUI test widget.
  • Utilise your browser developer tools the React browser plugin to debug.

Next Steps/Ideas

  • Restructure your application into standard deployment folders for ease of use. Separating styling, components, and js libraries.
  • Improve the styling, add images.
  • Analyse the JSON returned for different response types such as images or lists. Create appropriate views to display these, consider encapsulating this UI in different Components.
create_react_chatbot_chatserver_debug

Browser Debug Showing List Response.

  • Take into account different users using your client by taking userID variable into consideration.
  • Connect to other chatbots provided in the system or create your own Custom Component ( like here http://www.ateam-oracle.com/using-content-and-experience-cloud-with-your-oracle-intelligent-bots-chatbot/ )

Further Reading and Useful Links

Oracle Intelligent Bots video tutorial series
Oracle Intelligent Bots https://www.oracle.com/solutions/mobile/bots.html#overview
React Introduction https://reactjs.org/tutorial/tutorial.html#what-is-react
Node https://nodejs.org
NPM www.npmjs.com
JSX https://reactjs.org/docs/introducing-jsx.html
Reconnecting WebSocket https://github.com/pladaria/reconnecting-websocket

Add Your Comment