Building a WhatsApp Recipe Bot with Python, Flask, MongoDB and Twilio

February 21, 2020
Written by
Philip Obosi
Contributor
Opinions expressed by Twilio contributors are their own

Building a WhatsApp Recipe Bot with Python, Flask, MongoDB and Twilio

Our world as it is today has experienced remarkable growth in various fields and aspects of life due to the consistent and creative distribution of information across various media.

In this article, we use the Twilio API to build an application that provides information on food and recipes to users over WhatsApp. This approach to accessing information will definitely feel more fun and natural to food lovers and chefs with WhatsApp installed on their phones.

User Journey

A user sends a message containing  the name of a particular recipe he/she is interested in learning about or preparing and receives a response with instructions to be followed to prepare the meal.

recipe bot demo

Tutorial Requirements

To follow this tutorial, you are expected to:

  • Have sufficient understanding of Python and Flask
  • Have Python 3 installed on your machine
  • Have MongoDB installed on your machine
  • Have Ngrok installed on your machine
  • Have a smartphone with an active phone number and WhatsApp installed.
  • Have a Twilio account. If you are new to Twilio create a free account now. If you use this link to sign up you will earn a $10 credit when you upgrade to a paid account.

Setting Up The Twilio WhatsApp Sandbox  

To get started, we need to create an account on Twilio and sign in. Since we would be working extensively with the Whatsapp API, you’d need to activate a Twilio sandbox for WhatsApp.

The Twilio Sandbox for WhatsApp allows you to immediately test with WhatsApp using a phone number without waiting for your Twilio number to be approved by WhatsApp. You can request production access for your Twilio phone number here.

To connect to the sandbox, log into your Twilio Console and select Programmable SMS on the side menu. After that, click on Whatsapp. This will open the WhatsApp sandbox page which contains your sandbox phone number and a join code.

twilio sandbox for whatsapp
 

To enable the Whatsapp sandbox for your phone, you need to send the join code starting with the word “join” to your sandbox phone number.

Afterwards, you’d receive a message confirming the activation of that phone number to use the sandbox. To add any other phone numbers, repeat the process above for each of them.

Now, let’s get to building the application.

Application Setup

As mentioned earlier, we are going to be using the Flask framework and MongoDB as our preferred database.

Creating the Application Directory and Virtual Environment

Make sure you have Python3 and MongoDB installed on your computer. Run the following commands in your terminal to  create the project folder and virtual environment for this project.

  • Create project directory named whatsapp_recipes
mkdir whatsapp_recipes 
  • Enter into the project directory
 cd whatsapp_recipes
  • Create a virtual environment for the project
python -m venv venv
  • Activate the virtual environment

For macOS and Linux users:

source venv/bin/activate

For windows users:

venv\Scripts\activate

The  virtual environment we have created helps create an isolated environment, separate from the global python environment to run our project.

Structuring the Project

Now that we have created the project, we need to set up its folder structure. In the application directory, run the command below to create the two directories we are going to need:

mkdir services utils

Next, create a file named app,py at the root of the project directory.

At this point, your folder structure should look like this:

project structure

Installing Project Dependencies

There’s one more step we need to take to successfully set up our project. Let’s install all the dependencies used in this project.

  • Flask - We will be using this to run our web server.
  • Pymongo - This library will be used to interface with the MongoDB database on your computer.
  • Twilio Python Helper library - The Twilio library will help us construct Twilio XML responses which we will be using to generate replies for received WhatsApp Messages. You can learn more about this in the Twilio docs.

Run the command below to install these dependencies:

pip install flask pymongo twilio

All done? Now let’s set up our database.

Database Setup

In this section, we are going to be inserting some dummy recipe data into our MongoDB database and create indexes on the collection so as to be able to perform full text search on the data.

You can download my sample recipes data here.

Run the commands below in your terminal to insert records into your database from this file. Note that data.json must be in the same directory as the current working directory on the terminal.

  • Open the python shell
python
  • Import the JSON package
import json
  • Import the MongoDB client
from pymongo import MongoClient
  • Configure a local database client
client = MongoClient('mongodb://localhost/')
  • Create new mongo instance and collection
recipes = client['twilio']['recipes']
  • Populate DB with data from text file
with open('data.json') as read_file:
    json_data = json.loads(read_file.read())
    for data in json_data:
        recipes.insert_one(data{'name': data['name'], 'steps': data['steps']})

The commands above will open the Python shell, loop over the data in the data.json file and insert the data into the recipes collection.

Next, we need to create an index for the collection. It is important to do this as it will speed up our search queries. That is, rather than search through the entire database, searches will be carried out only on indexed fields i.e the name field in this case.

Start the MongoDB CLI:

mongo

Then enter the following commands:

use twilio;
db.recipes.createIndex({name: 'text'});
quit();

The output to the above commands should look like the screenshots below:

mongo database output

Building the Application:

Let’s write the code that will handle all our database searches. We are going to be using the full-text search functionality of MongoDB to help match the records we have created, against the food names sent by the user.

Create a file called recipes.py in the services directory and paste the following inside:

from pymongo import MongoClient

client = MongoClient('mongodb://localhost/')
recipes = client['twilio']['recipes']


def search_recipe(search_word):
    cursor = recipes.find({'$text': {'$search': search_word}})
    result = []
    for data in cursor:
        result.append(data)
    return result

The search_recipe() function above receives the recipe name sent by the user, performs a search on the database and returns matching results.

Next, we are going to write a function to format the Mongo DB result into a readable format that can be sent as a message to the user. Create a file called message.py in the `utils directory and copy the following inside:

def convert_result_to_message(result):
    if len(result) == 0:
        return "Sorry, we currently don't have any recipe pertaining to your food."
    message = ""
    for data in result:
        message += f"Food: {data['name']}\n"
        message += "Steps\n"
        count = 1
        for step in data['steps']:
            message += f"{count}. {step}\n"
            count += 1
        message += '\n\n'
    return message

From the above code, when we can’t match the query against any record in our database, we return a default response. Otherwise, we return a response that includes all matching records with the following format:

Food: 
Some text here
Steps:
Some more text here

Finally, we are going to write the endpoint that will be called by Twilio when a user sends a WhatsApp message. Open your app.py  file and copy the following inside:

from flask import Flask, request
from twilio.twiml.messaging_response import MessagingResponse
from services.recipes import search_recipe
from utils.message import convert_result_to_message

app = Flask(__name__)


@app.route('/whatsapp', methods=['POST'])
def reply_with_recipe_info():
    food_name = request.values.get('Body')
    print('Message sent', food_name)
    recipes = search_recipe(food_name)
    message = convert_result_to_message(recipes)
    response = MessagingResponse()
    response.message(message)
    return str(response)


if __name__ == '__main__':
    app.run()

The /whatsapp route is where the fun happens. We use request.values.get(‘Body’) to get the message sent by the user. Afterwards, we pass the message to the search_recipe() function written earlier in our services/recipes.py file. The result is then passed to the convert_result_to_message() function which generates the user friendly message to be sent back as a response.

To return a response, the Twilio library is used to construct a TwiML payload as follows:

 

response = MessagingResponse()
response.message(message)

This response is returned as a string and is sent to the user over Whatsapp.

Voila! We are done. It’s testing time!

Testing the application

To run the application, execute the command below in your terminal:

python app.py

Next, you have to expose the port on which the application is running using ngrok so that your application is accessible over the Internet. In a new terminal session, execute the command below:

ngrok http 5000

This command tells ngrok to expose your application port over the internet. You should see an output like the one below which gives you a Forwarding URL through which your app can be accessed over the web. We will be making use of the secure URL, which starts with https://.

ngrok screenshot

Copy that URL, paste it into the “When a message comes in” space provided on your Twilio WhatsApp Sandbox Dashboard, and append the  /whatsapp  route to it. See image below.

whatsapp webhook configuration

You can now send a message to the phone number indicated on the Twilio WhatsApp sandbox and receive a response containing the steps for any of our sample recipes.

Demo

recipe bot screenshot

Conclusion

We have now come to the end of this tutorial. We successfully built an application that delivers food recipes over WhatsApp using Twilio, Python and Flask. Feel free to push the boundaries of this project and the Twilio API by improving the application implemented above and continue to work on other exciting projects like this one!

You will find the source code for this tutorial here on GitHub.

See you in the next one!✌🏿

 

Philip Obosi builds scalable web applications with JavaScript and Python. He is passionate about web performance, data visualization and the blockchain.