Hands on

Creating a location-aware chatbot with HERE & Twilio

By Dylan Babbs | 04 December 2017

Chatbots are all the hype these days. You can use chatbots to stay updated with current events, order a ride sharing vehicle, or even schedule an appointment. But have you ever considered building your own chatbot?

 

In this guide, I'll teach you how to create a location-aware chatbot with HERE Location Services and Twilio using Node.js. The chatbot will enable users to search for places near a location. For example, a user could search for "Sandwiches near Central Park New York City" or "Subway near 701 Pike Street Seattle." That's both places and addresses you can search for!

To accomplish this, we're going to be using a few different APIs:

This tutorial requires basic knowledge of JavaScript or Node.js apps. You'll need both HERE Developer and Twilio accounts, so if you don't already have those now is a good time to sign up and create a new project on each. For Twilio, you'll also need to sign up for a free phone number. Make sure to register your own phone number with your Twilio account to ensure you can send and receive messages.

If you get lost during the Twilio setup, give this helpful guide a read.

Part 1: Starter Code & Configuration

To get started, you'll need a few npm modules installed:

To install these modules, run npm install package-name in the command line. (Alternatively, give this package.json file a try.)

We're also going to need to install ngrok to run a tunnel providing an externally available URL to our server.

Now we can start coding! Open up your preferred text editor and create a new JavaScript file called server.js. This file will enable us to send and receive messages. Paste the following code:

Don't forget to paste your HERE and Twilio API credentials into their respective fields.

We'll want to configure our server to reply to messages sent to our Twilio phone number.

Once Twilio is configured correctly, the above code will enable our bot to reply with 'Hello, there!' anytime you text your Twilio phone number.

To get the server up and running, you're going to want to run node server.js in the command line. In order to make your server publicly accessible, you'll want to run the command ngrok http 1337 (on macOS a quick way to do this is to run these two commands on different tabs). Port 1337 is now exposed to the public internet.

Copy the forwarding URL (highlighted in the below screenshot) provided by the ngrok console.  

Take the copied URL and configure it as a webhook for your phone number. Under the Messaging header, paste this URL followed by /sms in the message comes in field.

Once you've got that configured, try sending a message to your Twilio phone number. You should get a friendly reply saying 'Hello, there!' 


Part 2: Integrating HERE Location Services 

Now that you've got a functional SMS messaging service, let's make this chatbot location-aware by equipping it with HERE Location Services.

We want our bot to perform the following way:

  • User texts the chatbot with two parameters: a search query and a locationFor example: Pizza near 701 Pike Street Seattle
  • Chatbot geocodes the search query from a POI or an address to coordinates (latitude and longitude)
  • Chatbot searches for places based on the search query near the geocoded location
  • Chatbot replies with three relevant places and gives the option to learn more about a place
  • The user replies to learn more about a certain place
  • Chatbot replies with address of the requested place

Let's change the contents of the app.post block to look like this:

Let's break down the above code.

  • The variable incoming is the plain text sent by the user to the chatbot. We can split this variable into two parts by using incoming.split(' near '). This by no means is the best way to parse text, but we'll do it this way for simplicity's sake.
    • searchQuery: the query we'll search for with the Places API
    • locationString: the string of the location (address or POI) we'll geocode into coordinates
  • We'll pass our searchQuery, hereID, hereCode into a variable geocodeURL to create a request URL to the HERE Places API
  • request.get constructs the request and gives us back parsed JSON containing our results

Once we've received our reply for the API, we can extract the latitude and longitude from the response. Be sure to place the remaining code examples all within the request.get() block.

Now that we've transformed our location string into coordinates, we can start searching for places that fit the constraint of the search query and location. To do so, we're going to construct a HERE Places API search (within the geocode request).

We provided the geocoding request the following parameters:

  • at: latitude and longitude of where to search
  • q: the query to search for. I've added .replace(/  /g, '+') to replace the spaces with plus signs to make a more friendly URL
  • tf: text format of response
  • app_id & app_code: access credentials for the API

I'd like to return 3 results to the user each time, but sometimes there aren't always 3 results available for a particular query, so I created the variable resultAmount to show the appropriate amount of available results.

Let's start processing the results from our API response and begin preparing our reply to the user.

responseMessage sets up the first line of our reply message to the user: Here are the 3 closest Mexican restaurants to 701 Pike Street Seattle.

We loop through the amount of appropriate results (determined with the resultAmount variable) to do the following tasks:

  • Add a place's name, category, and address into a dictionary. We'll be using this dictionary later to reference information about a place
  • Append additional text onto the reply to the user. We add:
    • A number the user can reply with to learn more about a place
    • The name of the place

Sometimes the Places API returns subcategories of the search query, not actual places. To avoid and filter out subcategory results, we can add a simple conditional blocking subcategory results. In the event we do come across a subcategory instead of a place, we increment resultAmount to ensure we return the appropriate amount of results (usually 3).

Now that we've created both our dictionary of places and our text reply to the user, let's go ahead and send something via SMS.

Voila! The user is now sent a list of results relevant to their search query and location! Give it a try with "Sushi near Pike Place Seattle"

Part 3: Additional Information About the Place

We've written code to receive messages, geocode locations, search for places, and send messages. At this point, the user will now receive a message with something along the lines of:

Here are the 3 closest Hamburgers places to you: 

(1) Kidd Valley Hamburgers

(2) McDonald's

(3) Eureka!

Reply with # to learn more information

Our service encourages the user to reply with a number to learn more about a particular place. To enable this feature, we're going to want to add some conditionals within our app.get() block. Modify your code to fit this structure:

  • The if (incoming.length > 1) is designed to accept the user's first message. The initial message to begin the process must contain a search query, the word 'near', and a location string. This will be longer than one character.
  • The else if (places.length > 0 && incoming.length == 1) is designed to accept the user's second message. We check to make sure that the places dictionary is empty and that their incoming message is only one digit in length (the second message is supposed to be an integer between 1 and 3). 

There are plenty of additional ways to check this case, but we'll stick with these conditions.

Within the else if statement, let's insert the following code: 

We're now able to send the address to the user about the requested place.

Part 4: Error Handling & Advanced Functionality

To ensure messages that don't follow the strict 'near' format don't crash our service, let's add some error handling.

Right below the if (incoming.length > 1) statement, let's add:

This ensures the user's first message contains a 'near' so we're able to extract the search query and location string.

Additionally, let's add this if statement right after we create our geocodeJson variable in the geocoding request:

In the event no places are returned from the Places API query, we send a message informing the user to try again.

Congratulations, you've created a functioning location-aware chatbot! You can check out the full source code here

There's no need to stop here! We've created just a simple version of a location-aware chatbot. What additional features could you bring to this chatbot using HERE APIs? Try enhancing this project by giving our Traffic, Routing, Transit, Weather, and Positioning services a shot.

Want to chat in person about HERE Location Services? You can find me at the Turkish Airlines Travel Hackathon on December 22-24 in Istanbul, Turkey!