Pubnub coupled with IBM Watson can enable developers and business owners to streamline their frontlines by creating smart assistants which answers the simple questions forĀ you.
Chatbots, whether they be customer service agents or shopping assistants in an online store, have become commonplace amongst the way we interact with businesses. Intelligent bots and assistants serve to be the frontline for many businesses and now is a better time than any to build a smart approach to solving problems.
You might be wondering if itās possible to create an intelligent assistant of your own. The short answer is yes, and thatās exactly what weāll walk through today, using ChatEngine and IBM Watson Assistant. Our bot will answer basic questions for people looking to learn more information about PubNub, but your bot can be trained and customized however you wish. Weāll show you how to do this too.
The full project GitHub repo is available here.
Youāll also need to sign up for Pubnub!
How It WorksĀ š©āš»
Before we get into the code, letās map out the logic in terms of how our user will interact with our assistant.
At first, the user asks a question via ChatEngine to send a message to out our chatbot assistant. The reason we have two ChatEngine connections is to make sure that our bot can handle multiple connections at once. In our specific case weāll make our chatbot on the same client but in an ideal situation, it would be a good idea to have the chatbot running on a separate client.
Once the bot receives the message via ChatEngine it sends the message to PubNub Functions. The goal behind this is to reduce the amount of backend code we have and just focus on the things that matterāāāthe experience. Functions is how we connect our messaging application to the IBM Watson Assistant service.
In our BLOCKS Catalog, there is an IBM Assistant BLOCK which needs a bit of configuration, and once thatās done it will be connected to IBM Watson. The function will query Watson and get a reply back, which it will then send to our customer.
Getting Started with ChatEngine andĀ Watson
Configuring ChatEngine š
Building the chat interface and backend for a chatbot can be challenging and time-consuming. Weāll mitigate that using ChatEngine, our PubNub-powered framework that makes building cross-platform a breeze.
Youāll first have to configure a new ChatEngine application in PubNub. You can do this in our ChatEngine quickstart, and it will provide you your pub/sub keys as well as configuring your keyset for ChatEngine.
Watson + BLOCKSĀ š«
Once we have ChatEngine configured, we can start building our assistant.
First, create a new Function within our ChatEngine Module. We can call this function āAssistantā, have an event of āOn Requestā and make our channel name be āassistantā. After adding our new Function we can go ahead and add the code for it to connect to IBM Assistant.
This is actually a version of the code available in the IBM Assistant BLOCK but slightly changed so that we could fit it with our interaction model. In particular, if we look at lines 55ā65 weāll that the way we handle our response and the method we get data from our client has changed.
Youāll notice that in the Function code above that weāre using the vault to get access to certain keys available to our module. Weāll need to add three more keys to our vault which can be found when setting up Watson.
Watson Configuration š¤ø
Head over to Watson to get your keys. If you havenāt already, feel free to set up a Watson instance on your Bluemix console. Youāll see that with your new Watson resource youāll have a username and password. View those and insert them into the vault in the Assistant Function we just created. The next key we need is the workspaceID, we can go to the launch tool in the Bluemix console and create a workspace.
In here, we can either create a workspace from scratch or use a sample. For this example, letās go with the customer service example. Once weāre in the workspace we can open the hamburger menu on the side and go to the improve tab. Near the top of the page, we should see a credentials button, and by clicking that we can get our workspaceID.
So, now that we have our keys, our vault should look something like this.
At this point, we have the cogs of our application working. We created the structure that will receive messages from our bot and send that data to our assistant and also have our assistant wired up so that those messages can get a meaningful response.
Letās start developing our client and its interface.
Me, My Bot, and IĀ š¤
Looking at the client, there are two things that weāre going to make. The first being the input for where the user can submit their message and the second being the bot that can send that data to our function. Ideally, weād separate these two components but for simplicity, weāll have them both running on the same client.
To begin, letās create a basic React project which we can do by using the create-react-app tool.
$ npx create-react-app Watson-Assistan
If your version of npm is less than 5.2 feel free to use npm
instead of npx
. The difference between the two is based on the scope of the installation and whether the command is a one-off or not. If you need more information read about it in npmās blogpost.
The folder should now be set up so letās navigate into it.
cd Watson-Assistant/
Great! Our project tree should look something like this.
|-- Watson-Assistant|-- .gitignore|-- README.md|-- package-lock.json|-- package.json|-- public| |-- favicon.ico| |-- index.html| |-- manifest.json|-- src|-- App.css|-- App.js|-- App.test.js|-- index.css|-- index.js|-- logo.svg|-- registerServiceWorker.js
In here weāre going to take out some of the boilerplate that the create-react-app tool as graciously left for us.
We can take out logo.svg
and registerServiceWorker.js
. Thereās no particular reason other than to clean up our project, but if you feel that you the need to look more into why the service worker file is there have a look at this issue on the master GitHub repo.
After cleaning up our directory our structure should look something like this.
|-- Watson-Assistant|-- .gitignore|-- package-lock.json|-- package.json|-- public| |-- favicon.ico| |-- index.html| |-- manifest.json|-- src|-- index.css|-- index.js
Now letās look at the file where the majority of our app is going to sit: index.js.
Weāll start by looking at the lifecycle and what weāre going to render in our browser. First, ensure we have ChatEngine in our package.
$ npm i chat-engine
At this point, Iād also recommend checking out my package.json file on GitHub. Here you can follow along completely without breaking your code. Iāll try to make sure that I explain each package I use so that you get a better understanding of how everything fits in.
So now that we have the packages, letās start coding.
To create our client we need to give our ChatEngine client the keys to the ChatEngine app we made earlier. Choosing our app on the PubNub Admin Dashboard then choosing our keyset we can get the publish and subscribe keys. We can then create our client object like this.
const ChatClient = ChatEngineCore.create({publishKey: 'pub-c-e1295433-4475-476d-9e37-4bdb84dacba0', subscribeKey: 'sub-c-890a0b26-6451-11e8-90b6-8e3ee2a92f04'},{globalChannel: 'watson-assistant'});
Since we are creating the ChatClient and ChatBot on the same client weāre going to duplicate this but change the name to ChatBot.
Itās also nice to have a username for every connection we make so letās make a template for usernames, something like this:
const now = new Date().getTime(); const username = ['user', now].join('-');
Connect our user and chatbot to our ChatEngine.
ChatClient.connect(username, { signedOnTime: now }); ChatBot.connect(`${now}bot`, { signedOnTime: now });
Create our chat class and look at the different lifecycle methods.
The constructor is a good place to begin, and in here weāre going to assign our variables with our chat instances. We can also initialize all the variables we want to store in the state.
Personally, I want to use this react-clippy package that will act as our assistant. We can use different animated characters to show our message and animate them. For Clippy we need to have an animation that plays so Iāll define that in my state. We also need the input the user gives and the response we get from our function.
Note: this post has no relation to Microsoft and they had nothing to do with this
In the end, our constructor looks like this.
constructor() { super(); this.chat = new ChatClient.Chat(`${now}chat`);this.bot = new ChatBot.Chat(`${now}chat`);this.state = {reply: 'Ask Me Something!',chatInput: '',animation: 'Congratulate' };}
Before going further, itās a good idea to formulate a bit more about the render function. We know that weāre going to be accepting input so weāll need some sort of input box. As well, weāll be displaying a response and Iāll be adding the wonderful Clippy.
render() {return (<div style={container}><div style={{height:100, width:100}}><p> {this.state.reply} </p>
<Clippy
actor={ 'Clippy' }
animation={ this.state.animation } />
<input
id = "chat-input"
type = "text"
name = ""
value = { this.state.chatInput }
onChange = { this.setChatInput }
onKeyPress = { this.handleKeyPress } />
<input
type = "button"
onClick = { this.sendChat }
value = "Send Chat" />
</div>
</div> ); }
There are a couple other functions that complete some functionality in the chat class such as pressing enter to send the message but Iāll leave that up to you to explore. What weāll look at now is the sending message part. There are two functions and they directly relate to how the flow of our project works.
sendChat = () => {if (this.state.chatInput) {this.chat.emit('message', {text: this.state.chatInput,channel: `${now}chat`});this.setState({ chatInput: '' })this.setState({ animation: 'Processing', reply: '' }); }}componentDidMount() {this.bot.on('message', (payload) => { axios.get(`https://pubsub.pubnub.com/v1/blocks/sub-key/sub-c-890a0b26-6451-11e8-90b6-8e3ee2a92f04/chat? question=${payload.data.text}`) .then(response => { this.setState({ animation: 'Writing', reply: response.data }); });});}
The sendChat function lets the user send their message to the bot. Notice how weāre emitting the message and weāre defining the channel by the time. This allows making each chat in its own private session so that we donāt interrupt conversations other customers may be having at the same time.
We also need to ensure our bot listen for messages coming in. So that when the Chat component has mounted we need to make sure that our bot sends that message to our function and then updates our component with the message. For doing the request Iām using the axios package and you read more about here.
One last step. We need to make sure that once our ChatEngine connection is established we render our chat component. We can do that by adding this to the bottom of our file.
ChatClient.on('$.ready', () => {ChatBot.on('$.ready', () => {ReactDOM.render( <Chat /> , document.getElementById('root') ); });});
Our Chatbot is Up-and-Running! šā
This is a great starting point for building something more unique. It would definitely be a good idea to explore the documentation for IBM Assistant to train our bot to be clever and have more depth in their responses. ChatEngine can do a lot of cool things to connect instantly with people and services. I would love to see what you build next š.
Follow me on Twitter / Instagram! @nxsyed
Originally published at www.pubnub.com.