Giving Facebook Chatbot intelligence with RiveScript, NodeJS server running in AWS Lambda serverless architecture
This is a long Blog describes how I build my Chatbot (named I’m Simon Chatbot) to demonstrate below features:
- The Chatbot talks with human via Facebook Messenger
- Chatbot server app running NodeJS (with ExpressJS framework)
- Giving an A.I. brain to the Chatbot with RiveScript
- The Chatbot server App hosts in AWS Lambda (comply with serverless architecture)
- User state management persistent via AWS DynamoDB
- Use Serverless framework for easy App deployment
1. Create a Facebook Page
I want my Chatbot could be interfaced with my Facebook friends via Facebook Messenger. First of all, I need to create a Facebook page required by Messenger Platform. I make a funny banner picture and avatar to the Facebook Page as below:
2. Create an Facebook App and configure the Messenger Platform
To accomplish chatting in Messenger, Facebook requires a Facebook App to define the configuration of the Chatbot web service. I create the App from the Facebook Developer website. As Facebook developer documentation mentioned, I add “Messenger” product as below screenshot:
Obtain the “Page Access Token” and record it:
Select the messenger events which will be handled:
Now the setup is done. I can start programming the Chatbot…
3. Build the Chatbot in NodeJS
$ node -v && express --version
Below is the initial Node-express server for local development (it depends on external modules. The full source-codes in this Github repo:
You can download & install the full source codes as follows:
$ git clone https://github.com/simonho288/rivescript-chatbot-lambda
$ cd rivescript-chatbot-lambda
$ npm install
$ touch aws.config.json
IMPORTANT: You’ll need to edit the aws.config.json file and put your AWS ACCESS KEY ID & ACCESS KEY SECRET in the JSON properties, like:
"accessKeyId": "<YOUR ACCESS_KEY_ID>",
"secretAccessKey": "<YOUR ACCESS_KEY_SECRET>",
"region": "<YOUR REGION>"
To obtain AWS Key ID & Key Secret, you can create a new IAM user. Please refer to this instruction.
4. Setup the Facebook App Webhook
Webhook is the entry point of my Chatbot server App when Messenger receives messages from users. To setup the Facebook App webhook. Follow the below steps:
1. Run the local express server in the project root directory:
$ node server
Server listening on port 3000
2. Make a secure HTTP tunnel (HTTPS) between the local server and the external Internet to allow Messenger RESTful calls. I’m using amazing Ngrok to setup the tunnel. You can download it for free & run it:
$ ngrok http 3000
You’ll see the below similar screen:
Login to Facebook developer and create a new App. After the App has been created, go to webhook section:
If anything setup properly, it should no error and the subscription dialog disappears. That’s mean verification success.
5. Install RiveScript with brain files
RiveScript is a simple scripting language for giving intelligence to software for handling Human natural languages. After I used it in several projects, I feel it is not only simple but also powerful. Especially it supports asynchronous programming model that perfectly matches with NodeJS’s asynchronize non-blocking model. NodeJS non-blocking programming model leads up PHP at least two times faster, 20% faster than Java and 10% faster than ASP.Net
To install RiveScript to our server App (locate in project root):
$ npm install -S rivescript
I create a module rivescript.js to handle RiveScript:
Furthermore, to leverage the benefits of RiveScript NLP, I program several RiveScript brain files in /rsBrainFiles directory that are to make the Chatbot more human-like:
6. First talk to my Chatbot
I can’t wait to try chatting with my Chatbot. I open the Facebook Page and click the “send message button”:
Facebook Messenger provides a full-screen view which a better experience, I open it as below screen:
Type below messages to test the Chatbot:
The above answers are programmed in one of brain files /rsBrainFiles/myself.rive. Full scripts are:
To demonstrate the RiveScript asynchronous operation, I add a command for real-time stock price querying. It is sub-routine getStockPrice in /rsBrainFiles/stockprice.rive file:
! version = 2.0
+ [*] stock price [of] *
- stock price of <star1> is <call>getStockPrice <star1></call>
+ * stock price
- <call>getStockPrice <star1></call>
There have two processes inside the sub-routine getStockPrice when receiving stock query message: 1. Lookup the global stock symbol by company name, 2. Get the current stock price by stock symbol. All rely on external Yahoo Finance APIs. Which is programmed in /libs/external.js module:
Consequently, the Chatbot performs below stock messages and answers:
You can also be chatting with my Chatbot. Go to this Messenger Page and select “send message test button”, or search “Im Simon Chatbot” from Messenger mobile App. Feel free to chat with it. It does NOT store either your contact info or the messages you entered. (The privacy statement is declared to Facebook here)
7. AWS Lambda preparation and Install Serverless Framework for deployment
After the Chatbot test successfully, I need a server to host the NodeJS server app. I have three options:
My final decision is Lambda due to below reasons:
- Low maintenance (zero server to administrate)
- Really cheap (no charges if the code not running)
- Autoscale and high availability
- Easy to deploy provided via serverless framework
Serverless is a hot topic in the software architecture world. I’ve been using Serverless framework for several months, I so agree with that:
To install the serverless framework, in the project root directory, type:
$ npm install serverless -g
$ aws configure
$ sls create --template aws-nodejs --path hello
Above commands install the serverless framework, setup AWS user access key ID & access key secret, create a serverless function and store the configuration to file serverless.yml
I modify the serverless.yml as below:
8. Handling user state with AWS DynamoDB
User state persistence is another important feature of RiveScript. It provides best user experience and makes chatbot more intelligent. For example:
In webhook.js, the sequence of message processing when integrates state management becomes important:
As you can see, it loads the user state (calls SDB.loadUserRecord()) before process the message. At the end of processing, it saves the user state (calls SDB.saveUserRecord()) after the reply sent back to the user.
9. Final Deployment
When everything is done, I deploy it to Lambda using serverless. In project root I type:
$ sls deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service .zip file to S3 (8.04 MB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
Serverless: Stack update finished...
GET - https://xw8oub6nsd.execute-api.ap-southeast-1.amazonaws.com/prod/webhookfb
POST - https://xw8oub6nsd.execute-api.ap-southeast-1.amazonaws.com/prod/webhookfb
Just a single command, serverless do the rest until it returns the result URLs.
I copy the URL to Facebook App webhook subscription to change the server location from local to Lambda:
Now I can stop the local server, chat with the chatbot in my mobile Messenger App. The video captured as:
Just a quick recap, highlights of above procedures:
- Created a Facebook page.
- Created a Facebook App.
- Created a Chatbot server App.
- Created an AWS IAM user.
- Setup Messenger webhook.
- Tested in the local server.
- Gave a brain to the Chatbot.
- Non-block calling Yahoo Finance API to get real-time stock price.
- User state persistent thru AWS DynamoDB.
- Deployed the Chatbot server App to AWS Lamba in serverless architecture.
The full source code is saved in this Github repo.