The idea of having a bot, who listens, understands and responds to your commands, is very intriguing. How about creating one yourself? It might sound daunting at first but it’s not that difficult in reality.
In this post we will create a bot for Google Assistant which powers Google Home
, Google Now
and probably some other google products. To keep this post really short and easy to follow, I will not plug the NLP piece in our bot, which you might have to in case you decide to build a really intelligent bot. Our bot will do a simple thing, when asked for a movie suggestion, it will suggest a movie.
Prerequisites
Since we are building a bot for Google Assistant
, you need a gmail account and you might also have to enable Voice and Audio Activity
control for that account. In order to do that, head over to your My Activity control page and you will see an option for it.
Next thing you need is to have Node.JS
installed in your system, since we will use Node.JS
to build the bot.
In order to test our bot locally, we need a tunneling utility which makes our local server reachable from public internet. ngrock is my favorite but you can also use localtunnel or something else you like. In case you have a dedicated server and you are planning to test your bot directly in the server then you can skip this.
With that covered let’s setup the project directory and dependencies.
Setup
Create a directory with whatever name you like, I have named mine movie-suggester
, yeah that’s how imaginative I am :). Next add package.json
in it which looks like as shown below:
{
"name": "movie-suggester",
"version": "1.0.0",
"description": "a bot talking about movies",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "nishant",
"license": "ISC",
"dependencies": {
"actions-on-google": "^1.0.8",
"body-parser": "^1.17.1",
"express": "^4.15.2"
}
}
You can also generate this file for you simply by running npm init
command.
As you can see we have actions-on-google
as dependency, which is Node.JS
sdk from Google to develop for Google Actions. The other two dependencies express
and body-parser
are to run the actual bot server. Simply run npm install
from project’s root directory and it will bring all the dependencies to your system.
Next, go ahead and download gactions, this is a standalone CLI utility which you will need to run and test the bot. After download copy this executable to the root directory of your project. You might also have to change the file mode using chmod +x ./gactions
depending upon the development environment you are using.
Creating the bot
Finally after everything is in place we can write the code for the bot. Create index.js
file in the root directory of your project and copy paste following code.
const express = require('express');
const bodyParser = require('body-parser');
const googleActions = require('actions-on-google');
let ActionsSdkAssistant = googleActions.ActionsSdkAssistant;
//create an express app
const app = express();
//setup bodyparser middleware to handle JSON and urlencoded post requests
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
//this endpoint is really not needed, this is just to test if our server is accessible
app.get('/', (request, response) => {
response.send(':)');
});
//this endpoint is where 'Google Assistant' is going to post messages whenever users interact with it.
app.post('/', (request, response) => {
const assistant = new ActionsSdkAssistant({ request, response });
const actionsMap = new Map();
actionsMap.set(assistant.StandardIntents.MAIN, mainHandler);
actionsMap.set(assistant.StandardIntents.TEXT, rawInput);
assistant.handleRequest(actionsMap);
});
//start the server to listen on port 3300
app.listen(3300, () => {
console.log('app started listening on port', 3300);
});
//this is the trigger handler which will be called when a user asks google assistant 'talk to movie teller'
let mainHandler = function (assistant) {
let inputPrompt = assistant.buildInputPrompt(false, `Welcome, what can I do for you?`, ['say something']);
assistant.ask(inputPrompt);
}
//this handler get's called for all the subsequent interactions with google assistant after user is connected to the bot
//this is where we can place all the logic to make the bot respond to user queries
let rawInput = function (assistant) {
let rawInput = assistant.getRawInput();
if (rawInput === 'bye') {
assistant.tell('GoodBye')
} else if (rawInput.toLowerCase().trim() === 'suggest me a movie') {
let movies = ['Logan', 'Split', 'John Wick Chapter 2', 'Rogue One A Star Wars Story'];
let inputPrompt = assistant.buildInputPrompt(false, `sure, go ahead and watch the movie titled ${movies[Math.floor(4 * Math.random())]}, it's fantastic. Enjoy`);
assistant.ask(inputPrompt);
} else {
let inputPrompt = assistant.buildInputPrompt(false, `you said ${rawInput}`);
assistant.ask(inputPrompt);
}
}
above code is mostly self explanatory, the only part which requires a bit further discussion is POST
request handler. We create an instance of ActionsSdkAssistant
passing request
and response
as option parameters and then we call it’s handleRequest
method passing it a map of ‘intents’ vs ‘handlers’.
Intents in general represent the intension of a user interaction, for example when a user says ‘talk to movie suggester’, our bot is notified with assistant.StandardIntents.MAIN
intent and we can choose to respond the way we like. After the user is connected to the bot, Google Assistant notifies our bot with assistant.StandardIntents.TEXT
intent for all subsequent user interanctions.
Once inside an intent handler, we can get the raw speech of the user by assistant.getRawInput()
which gives us the transcript of the users speech. At this point we can decide how the bot should repond.
Google Actions provides SSML xml like markup language to facilitate speech construction. It’s pretty extensive, do check it out.
Start the server using node index.js
command. At this point you should have the server running on port 3300. Test it by simply hitting the http://localhost:3300
url. You should see a “:)”.
Action Package
In order to connect our bot to Google Assistant, we need to create action package, which is a file named action.json
. Being inside the project’s root directory, run ./gactions init
command this will create the action package file for you. Now change the file content as shown below:
{
"versionLabel": "0.0.1",
"agentInfo": {
"languageCode": "en-US",
"projectId": "<INSERT YOUR PROJECT ID HERE>",
"voiceName": "male_1"
},
"actions": [
{
"description": "Launch intent",
"initialTrigger": {
"intent": "assistant.intent.action.MAIN"
},
"httpExecution": {
"url": "<ngrock url or your server url>"
}
}
]
}
the one setting you definitely need to change in the action.json file is httpExecution url. Since our express server is running locally on port 3300 run ngrock http 3300
command which will give you one time public urls for http and https both. Copy the https version of the url and update the action.json file with it.
we are all set to run the bot now, at this point following is how my project directory structure looks like:
├── action.json
├── index.js
├── gactions
├── package.json
Run the bot
You can start the bot using following command:
gactions preview --action_package=action.json --invocation_name="movie suggester"
running the above command will present you with a one time url and prompt you to enter the authorization code. Navigate to the url and finish oauth steps, you will receive a authorization code in your browser window, copy the code and pass it to the prompt. If everything went well so far, then you are ready to test the bot.
Test the bot
There are two ways you can test the bot, either via command line using gactions simulate
or via Actions Web Simulator. I will test it using web simulator because that’s fun, so start by typing or speaking ‘talk to movie suggester’, after you get the welcome message, you can ask ‘suggest me a movie’, and the bot should suggest you a movie as shown below.
That’s it, there you have it, a bot which talks to you.