Tutorial for building CVilio

girl texting

Introduction

Twilio is a great tool for integrating SMS and phone call interfaces to your apps. Today, we're building a simple CV/Resume with an SMS interface.

We are building it with Python3, using Twilio's Python SDK and Flask web framework. You don't have to be an expert on Flask to follow along but I'm not going to go deep into how Flask works in this tutorial.

Whenever you see text like this: mkdir cvlio, you need to run it in your terminal window. Whenever you see code like this:

											from foo import bar
import json

sms_history = json.load(open('sms_history.json'))
									

you should write it into your editor inside a .py file.


Setup

With Python, it's a good practice to use virtualenv that allows us to contain the packages we use within the project.

pip install virtualenv
virtualenv -p python3 env
source env/bin/activate

Once we have our environment activated, we can install the packages we need. In this tutorial, we'll need to install Flask and Twilio Python SDK.

pip3 install Flask twilio

Lastly, we need to create a free Twilio account and buy a SMS-enabled phone number. You can do this by following Twilio's own guide.


Data

For this tutorial, we'll use a simple, read-only JSON file that stores our CV information. Since SMS limits us with both the length and presentation of our messages, it doesn't make too much sense to use more complex data structures.

I decided to structure the data in a form where the JSON has three main sections: introduction, experience and references. Those are the main content I feel is important but you can easily add your own by modifying the code later.

Introduction contains the text messages that will be sent when a new person texts your Twilio number. It's a good place to write down your "Hi, I'm Juhis" message as well as instructions for how to proceed with SMS commands.

References is simply a list of recommendations. I've found it really difficult to distill your recommendations into short, text message sized bits without distorting the message.

Experience contains an index key where you can define your sub-categories and one key for each of your experiences you want to share in your CV.

	
{
  "data": {
    "introduction": [
      "Hi! Welcome to Juhis' CV over SMS (with Twilio API). ",
      "For experience, reply with \"experience\". For references, reply with \"references\". ",
      "If you like what you saw and wanna learn more, reply with your email address and I'll get back to you ",
      "or check out my LinkedIn at https://www.linkedin.com/in/juhamattisantala/."
    ],
    "references": [
      "[retacted from public]",
      "[retacted from public]",
      "[retacted from public]",
    ],
    "experience": {
      "index": [
        "For my experience building dev communities, reply \"devcommunity\". ",
        "For my experience building tech startup communities, reply \"techstartup\". ",
        "For my experience teaching programming, reply \"teaching\". ",
        "For my experience hosting online communities, reply \"online\"."
      ],
      "devcommunity": [
        "Founder & Main Organizer, Developer Community ABC - 12/1988 -> :: ",
        "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus interdum purus quis congue cursus. Morbi dignissim ac lacus at dictum. Class aptent taciti sociosqu ad litora torquent per conubia nostra. ",
        "Vestibulum vestibulum risus mattis est rhoncus, ac tincidunt arcu molestie. Nulla ipsum dolor, vehicula in odio a, mollis bibendum mauris. ",
        "Vivamus et porttitor ex, ut lacinia leo. Nullam interdum risus nec dolor hendrerit finibus at eget lectus. Quisque condimentum diam eget nunc scelerisque."
      ],
      "techstartup": [
        "Community Manager, Tech Startup Community - 06/1989-02/1995 :: ",
        "Praesent consequat malesuada nisl, vitae cursus mauris elementum a. Proin porttitor mollis urna, vel feugiat nunc elementum sed. Sed semper, dui non efficitur lobortis. ",
        "Nullam eleifend nisi id dapibus tempus. Fusce et nibh mi. Vestibulum non commodo felis. Nullam scelerisque lacus efficitur, volutpat erat non, venenatis turpis. ",
        "Maecenas ornare libero risus, eu lobortis tortor egestas et. "
      ],
      "online": [
        "Online Community Host, Generic Slack Community - 08/1996-02/1999 ::",
	"Praesent consequat malesuada nisl, vitae cursus mauris elementum a. Proin porttitor mollis urna, vel feugiat nunc elementum sed. Sed semper, dui non efficitur lobortis. ",
        "Nullam eleifend nisi id dapibus tempus. Fusce et nibh mi. Vestibulum non commodo felis. Nullam scelerisque lacus efficitur, volutpat erat non, venenatis turpis. ",
        "Maecenas ornare libero risus, eu lobortis tortor egestas et. "
      ],
      "teaching": [
        "Programming Teacher, Education Facility - 01/2000-12/2018 :: ",
	"Praesent consequat malesuada nisl, vitae cursus mauris elementum a. Proin porttitor mollis urna, vel feugiat nunc elementum sed. Sed semper, dui non efficitur lobortis. ",
        "Nullam eleifend nisi id dapibus tempus. Fusce et nibh mi. Vestibulum non commodo felis. Nullam scelerisque lacus efficitur, volutpat erat non, venenatis turpis. ",
        "Maecenas ornare libero risus, eu lobortis tortor egestas et. "
      ]
    }
  }
}

Twilio Integration

Once we have our tools installed, data created and accounts registered, we get to the fun part: integrating with Twilio. Luckily, Twilio has made it really easy for us to get started so we can focus on building great products. There are multiple ways to interact with Twilio, we are gonna build a Flask app that provides an endpoint that Twilio will post whenever the phone number receives a text.

Once you have bought a Twilio phone number, go to https://www.twilio.com/console/phone-numbers/ and click on the number to enter its configuration page. Go to Messaging section and set it up as seen below:

While you are developing your app on local developer machine, Twilio recommends using ngrok which I've found really easy to setup and access. Once you have installed it, run ngrok http [port] and it will open a tunnel and give you a public URL that you can use as your webhook url.

It also has built-in dashboard for inspecting all HTTP requests made to its urls at http://127.0.0.1:4040/inspect/http (if you're not running ngrok, this URL will point nowhere).

We'll start by importing what we need and initializing Flask app.

											from flask import Flask, request, session
from twilio.twiml.messaging_response import MessagingResponse
import json

app = Flask(__name__)

Next, let's initialize our data. In addition to the cv.json file, I decided to use a simple JSON file to keep track of phone numbers that have already contacted us: we don't want to display the introduction message every time.

	cv_model = json.load(open('cv.json'))
sms_history = json.load(open('sms_history.json'))

Next, I've built a helper function that helps us retrieve the correct contents from our cv json.

def get_message(from_, message):
    msg = message.strip().lower()
    cv = cv_model.cv['data']

    if from_ not in sms_history:
        sms_history.append(from_)
        return cv['introduction']

    elif msg == 'experience':
        return cv['experience']['index']
    elif msg == 'references':
        return cv['references']

    elif msg in cv['experience']:
        return cv['experience'][msg]

    else:
        return ['Thanks for your message!']
			

Finally, we setup our Flask endpoint and run our app. Here we finally use Twilio's Python SDK and its MessagingResponse class that allows us to build an XML string that we return to the HTTP call from Twilio. After that, Twilio will send your message back to the number that originally sent the message and your CV is on-route.

									@app.route('/cvilio', methods=['POST'])
def sms_reply():
    from_ = request.values.get('From')
    message = request.values.get('Body')

    outbound_messages = get_message(from_, message)
    resp = MessagingResponse()
    resp.message('\n'.join(outbound_messages))

    outfile = open('sms_history.json', 'w')
    outfile.write(json.dumps(sms_history))

    return str(resp)

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

Now, if you save the file with name app.py and run this with python3 app.py and have your ngrok running (with ngrok http 5000), you can test it by sending an SMS to your Twilio number and expecting results.


Conclusions

Building an SMS integration to your app with Twilio couldn't be easier. In the code above, we basically have four lines of code related to Twilio integration and couple of configurations in the Twilio console in their website and boom, you're integrated.

There's plenty of other stuff Twilio empowers you to build and their guides and tutorials are really good, so check out https://www.twilio.com/docs/ and start building!