Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

Build a foodie bot with JavaScript

Save for later
  • 7 min read
  • 03 May 2018

article-image

Today, we are going to build a chatbot that can search for restaurants based on user goals and preferences. Let us begin by building Node.js modules to get data from Zomato based on user preferences. Create a file called zomato.js. Add a request module to the Node.js libraries using the following command in the console:

This tutorial has been taken from Hands-On Chatbots and Conversational UI Development.

> npm install request --save


In zomato.js, add the following code to begin with:

var request = require('request');

var baseURL = 'https://developers.zomato.com/api/v2.1/';

var apiKey = 'YOUR_API_KEY';

var catergories = null;

var cuisines = null;

getCategories();

getCuisines(76);


Replace YOUR_API_KEY with your Zomato key. Let's build functions to get the list of categories and cuisines at startup. These queries need not be run when the user asks for a restaurant search because this information is pretty much static:

function getCuisines(cityId){
var options = {
uri: baseURL + 'cuisines',
headers: {
'user-key': apiKey
},
qs: {'city_id':cityId},
method: 'GET'
}
var callback = function(error, response, body) {
if (error) {
console.log('Error sending messages: ', error)
} else if (response.body.error) {
console.log('Error: ', response.body.error)
} else {
console.log(body);
cuisines = JSON.parse(body).cuisines;
}
}
request(options,callback);
}


The preceding code will fetch a list of cuisines available in a particular city (identified by a Zomato city ID). Let us add the code for identifying the list of categories:

function getCategories(){
var options = {
uri: baseURL + 'categories',
headers: {
'user-key': apiKey
},
qs: {},
method: 'GET'
}
var callback = function(error, response, body) {
if (error) {
console.log('Error sending messages: ', error)
} else if (response.body.error) {
console.log('Error: ', response.body.error)
} else {
categories = JSON.parse(body).categories;
}
}
request(options,callback);
}


Now that we have the basic functions out of our way, let us code in the restaurant search code:

function getRestaurant(cuisine, location, category){
var cuisineId = getCuisineId(cuisine);
var categoryId = getCategoryId(category);
var options = {
uri: baseURL + 'locations',
headers: {
'user-key': apiKey
},
qs: {'query':location},
method: 'GET'
}
var callback = function(error, response, body) {
if (error) {
console.log('Error sending messages: ', error)
} else if (response.body.error) {
console.log('Error: ', response.body.error)
} else {
console.log(body);
locationInfo = JSON.parse(body).location_suggestions;
search(locationInfo[0], cuisineId, categoryId);
}
}
request(options,callback);
}
function search(location, cuisineId, categoryId){
var options = {
uri: baseURL + 'search',
headers: {
'user-key': apiKey
},
qs: {'entity_id': location.entity_id,
'entity_type': location.entity_type,
'cuisines': [cuisineId],
'categories': [categoryId]},
method: 'GET'
}
var callback = function(error, response, body) {
if (error) {
console.log('Error sending messages: ', error)
} else if (response.body.error) {
console.log('Error: ', response.body.error)
} else {
console.log('Found restaurants:')
var results = JSON.parse(body).restaurants;
console.log(results);
}
}
request(options,callback);
}


The preceding code will look for restaurants in a given location, cuisine, and category. For instance, you can search for a list of Indian restaurants in Newington, Edinburgh that do delivery. We now need to integrate this with the chatbot code. Let us create a separate file called index.js. Let us begin with the basics:

var restify = require('restify');
var builder = require('botbuilder');
var request = require('request');
var baseURL = 'https://developers.zomato.com/api/v2.1/';
var apiKey = 'YOUR_API_KEY';
var catergories = null;
var cuisines = null;
Chapter 6
[ 247 ]
getCategories();
//setTimeout(function(){getCategoryId('Delivery')}, 10000);
getCuisines(76);
//setTimeout(function(){getCuisineId('European')}, 10000);
// Setup Restify Server
var server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, function () {
console.log('%s listening to %s', server.name, server.url);
});
// Create chat connector for communicating with
// the Bot Framework Service
var connector = new builder.ChatConnector({
appId: process.env.MICROSOFT_APP_ID,
appPassword: process.env.MICROSOFT_APP_PASSWORD
});
// Listen for messages from users
server.post('/foodiebot', connector.listen());


Add the bot dialog code to carry out the restaurant search. Let us design the bot to ask for cuisine, category, and location before proceeding to the restaurant search:

var bot = new builder.UniversalBot(connector, [
function (session) {
session.send("Hi there! Hungry? Looking for a restaurant?");
session.send("Say 'search restaurant' to start searching.");
session.endDialog();
}
]);
// Search for a restaurant
bot.dialog('searchRestaurant', [
function (session) {
session.send('Ok. Searching for a restaurant!');
builder.Prompts.text(session, 'Where?');
},
function (session, results) {
session.conversationData.searchLocation = results.response;
builder.Prompts.text(session, 'Cuisine? Indian,
Italian, or anything else?');
},
function (session, results) {
session.conversationData.searchCuisine = results.response;
	builder.Prompts.text(session, 'Delivery or Dine-in?');
},
function (session, results) {
session.conversationData.searchCategory = results.response;
session.send('Ok. Looking for restaurants..');
getRestaurant(session.conversationData.searchCuisine,
session.conversationData.searchLocation,
session.conversationData.searchCategory,
session);
}
])
.triggerAction({
matches: /^search restaurant$/i,
confirmPrompt: 'Your restaurant search task will be abandoned.
Are you sure?'
});


Notice that we are calling the getRestaurant() function with four parameters. Three of these are ones that we have already defined: cuisine, location, and category. To these, we have to add another: session. This passes the session pointer that can be used to send messages to the emulator when the data is ready. Notice how this changes the getRestaurant() and search() functions:

Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at $19.99/month. Cancel anytime
function getRestaurant(cuisine, location, category, session){
var cuisineId = getCuisineId(cuisine);
var categoryId = getCategoryId(category);
var options = {
uri: baseURL + 'locations',
headers: {
'user-key': apiKey
},
qs: {'query':location},
method: 'GET'
}
var callback = function(error, response, body) {
if (error) {
console.log('Error sending messages: ', error)
} else if (response.body.error) {
console.log('Error: ', response.body.error)
} else {
console.log(body);
locationInfo = JSON.parse(body).location_suggestions;
search(locationInfo[0], cuisineId,
categoryId, session);
}
}
request(options,callback);
}
function search(location, cuisineId, categoryId, session){
var options = {
uri: baseURL + 'search',
headers: {
'user-key': apiKey
},
qs: {'entity_id': location.entity_id,
'entity_type': location.entity_type,
'cuisines': [cuisineId],
'category': categoryId},
method: 'GET'
}
var callback = function(error, response, body) {
if (error) {
console.log('Error sending messages: ', error)
} else if (response.body.error) {
console.log('Error: ', response.body.error)
} else {
console.log('Found restaurants:')
console.log(body);
//var results = JSON.parse(body).restaurants;
//console.log(results);
var resultsCount = JSON.parse(body).results_found;
console.log('Found:' + resultsCount);
session.send('I have found ' + resultsCount +
' restaurants for you!');
session.endDialog();
}
}
request(options,callback);
}


Once the results are obtained, the bot responds using session.send() and ends the dialog:

build-a-foodie-bot-with-javascript-img-0

build-a-foodie-bot-with-javascript-img-1

Now that we have the results, let's present them in a more visually appealing way using cards. To do this, we need a function that can take the results of the search and turn them into an array of cards:

function presentInCards(session, results){
var msg = new builder.Message(session);
msg.attachmentLayout(builder.AttachmentLayout.carousel)
var heroCardArray = [];
var l = results.length;
if (results.length > 10){
l = 10;
}
for (var i = 0; i < l; i++){
var r = results[i].restaurant;
var herocard = new builder.HeroCard(session)
.title(r.name)
.subtitle(r.location.address)
.text(r.user_rating.aggregate_rating)
.images([builder.CardImage.create(session, r.thumb)])
.buttons([
builder.CardAction.imBack(session,
"book_table:" + r.id,
"Book a table")
]);
heroCardArray.push(herocard);
}
msg.attachments(heroCardArray);
return msg;
}


And we call this function from the search() function:

function search(location, cuisineId, categoryId, session){
var options = {
uri: baseURL + 'search',
headers: {
'user-key': apiKey
},
qs: {'entity_id': location.entity_id,
'entity_type': location.entity_type,
'cuisines': [cuisineId],
'category': categoryId},
method: 'GET'
}
var callback = function(error, response, body) {
if (error) {
console.log('Error sending messages: ', error)
} else if (response.body.error) {
console.log('Error: ', response.body.error)
} else {
console.log('Found restaurants:')
console.log(body);
var results = JSON.parse(body).restaurants;
var msg = presentInCards(session, results);
session.send(msg);
session.endDialog();
}
}
request(options,callback);
}


Here is how it looks:

build-a-foodie-bot-with-javascript-img-2

We saw how to build a restaurant search bot, that gives you restaurant suggestions as per your preference.

If you found our post useful check out Chatbots and Conversational UI Development.

Top 4 chatbot development frameworks for developers

How to create a conversational assistant using Python

My friend, the robot: Artificial Intelligence needs Emotional Intelligence