Introduction

In this series, I’ll explain how to create a chatbot that is capable of detecting sentiment, analyzing images, and finally having the basis of an evolving personality. This is part 1 of that series.

The Pieces

Ruby Sinatra Google Cloud APIs Line (a chat client)

Since I live in Japan:

I’ll be using the popular chat service Line as our client. For sentiment detection, we will be using Google Cloud Natural Language API. And the language of choice will be Ruby (because, why not), and the micro framework Sinatra as our server. Ok, let’s get this going!

Setting Up The Chat Client

Line is an extremely popular chat service here; however, you don’t need to actually live here to sign up. So you should be able to follow along with no issues.

Once you have downloaded the app and made an account, you can sign up as a developer here: Line Developers Page.

We’ll need to create a new “Provider”:

and a Messaging API “Channel”:

Now we have to give our channel a name (which will be our bot’s display name), and app icon (display picture). Since this is a sentiment detection bot, let’s go with the apt: “Sentiment Bot”

Just a bit creepy…

Upon creation take note of the following values:

channel secret channel access token

Also, make the following changes to the settings:

Use webhooks: enabled Auto-reply messages: disabled Greeting messages: disabled

Finally, we have to set our “Webhook URL”: this is the entry point to bot and client communication. Whenever a message is sent to this channel (our bot), it will be relayed to whatever endpoint we designate in this field. Since we don’t have that yet, our next step is to create one.

Setting Up The Sever

The server is the key element in our bot example. For all intents and purposes, it is the “bot”. Since we are using a 3rd party chat client (Line) as our main communication channel, we need to define an endpoint or webhook, for data transmission.

A webhook, in this context, is an API endpoint that the chat client will post to on receipt of a message. Then it’s up to you (your bot) to parse the message and extract the necessary parts for processing. Once processed, we send this information back to our chat client via their messaging API, for eventual receipt by the end user (i.e. the person chatting with your soon to be bot).

In this example, we’ll be using Ruby along with the micro-framework Sinatra.

Let’s go ahead and create our app:

mkdir sentiment_bot && cd $_ bundle init touch main.rb

Please note that these file and directory names are completely arbitrary, and are chosen for simplicity and consistency’s sake.

Alright, let’s go ahead and install Sinatra (our web framework), by adding the following to the Gemfile.

gem 'sinatra'

As a sanity check, let's create a barebones endpoint that returns one response when we hit it. As a take on “Hello World”, this is going to be our “こんにちは world”. Ok, let’s get going, add the following method to main.rb.

Fire up the server:

ruby main.rb

and visit localhost:4567/hello . We should see our greeting coming through loud and clear. All is right in the world. Now, lets set up the endpoint that will be used as the communication layer between our chat client, and the bot. Per Line’s requirements, and as a good practice, this route will be a “Post”, and as for a name: “callback” is as good as any.

Add the following to main.rb:

It’s fine to leave this as an empty route for now. Back in Line, our webhook needs to be a publicly accessible https URL. However, our server is running locally. One way we can do this is to push our code to a PaaS such as Heroku, but that’s a bit orthogonal the scope of this tutorial. For now, let’s just use the amazing service Ngrok, for HTTP tunneling. After you have installed ngrok and fired up your web server, you can run the following command to get a public URL to our local server:

ngrok http 4567

This tells the ngrok service to create a URL for the local port 4567 (which is Sinatra’s default port). Upon running this, we should see two URLs printed to the console, one http, and the other https. We will be using the https URL. It should be something similar to:

Copy it, and enter it as your bots webhook url, as:

The additional path “callback” refers to the “post” method we just added in main.rb.

Once you’ve entered the URL, you should see a button to “verify”. Upon clicking, we should see a hit to our local server, and on Line, some confirmation of success.

Upon Successful Verification

The next step is to add our bot as a friend on Line, and try to talk to it. We haven’t given it any functionality, so our goal here is simply to see if everything is communicating correctly: i.e. when a message is sent to our bot, our callback url is actually triggered.

Scan the QR code provided for your bot using your Line mobile client. Once you have added your bot, send it a message. You should again see a hit to our server.

Sure, go ahead and add my bot.

We have verified everything is all connected, but a chatbot is pretty boring if it doesn’t actually talk. Now off to the fun part.

Setting up Line SDK

Of course, we can write our own Line API tools using their docs, but this is time-consuming and beyond the scope of this tutorial. Also, Line just happens to have an official SDK.

Add the following to your Gemfile and run bundle install:

gem 'line-bot-api'

Now that the gem is installed, we need to set up our credentials (which we can get from our dev console in Line).

Add the following import to main.rb

require 'line/bot'

And the following as well:

This method will allow us to initiate authenticated requests to our bot/channel. Each bot you make will have a unique secret and access token — you should not make this information public, or check it into your version control system.

Let’s go ahead and set the environment variables we received from Line:

export LINE_CHANNEL_SECRET="you_channel_secret"

export LINE_CHANNEL_ACCESS_TOKEN="you_access_token"

Now, let’s change our ‘callback’ function to the following (taken from Line’s sdk docs):

Now, our bot should act as an echo server, let’s test it out.

Rude…

Ok, everything is looking good! We’ve named our bot “SentimentBot”, so it should probably be able to detect sentiment. Sentiment, in the context of natural language processing, measures whether a given input is negative or positive in relation to human emotion (i.e. bad or good). An input of “I love you!” would be regarded as positive, while “I hate you!” would be considered negative.

Setting Up Google Natural Language

If this is your first time using Google Cloud and thus, Google’s latest authentication system, then you can check out their detailed documentation here: https://cloud.google.com/natural-language/docs/quickstart-client-libraries.

Once you have completed your project setup and have your auth all sorted, we can go ahead and add the ruby client to our Gemfile and of course run bundle install:

gem 'google-cloud-language'

If you have set up your service account correctly and installed the client SDK, then copy the sample code from the docs and run it. You should something similar to the following output if all is well:

Overall document sentiment: (0.30000001192092896)

Sentence level sentiment:

Hello world: (0.30000001192092896)

Once this is all working, let’s integrate it into our bot server code. Currently, our bot only mimics any text or image that is sent to it, but now with the power of Google on our side, let’s make it a bit fancier. Our next steps will be the following:

Read any text sent to the bot Send text to google for sentiment analysis Return the sentiment score to the user via our bot

First, let’s make a function that detects and returns the sentiment of its input. We can do that with the following methods:

These methods are quite straightforward. “google_language_client” simply instantiates the client, and “get_sentiment” uses said client and returns the sentiment analysis of any viable text input.

Let's change our “/post” route to the following:

That settles it…

Given all of your external services are set properly, you should be able to chat with your bot, and it returns the sentiment score of your text. Let’s try it out:

Just returning a sentiment score is pretty boring for anyone unfortunate enough to interact with such a bot. Let’s give it a bit of personality.

Let’s modify our main.rb file to the following:

We made a few changes here. First, we added some constants to hold our text responses, and we also added a new method “get_sentiment_response” which checks the sentiment score and returns an appropriate reply. Let’s try it out:

And there we have it! Our bot can detect sentiment in a message, albeit with a limited vocabulary, and respond accordingly.

In the next post in this series, we will give our bot the ability to understand the images we send it, by utilizing Google Cloud Vision API.