Choose Your Own Adventure Presentations with Reveal.js, Python and WebSockets
Time to read: 15 minutes
You’re preparing a technical talk on your new favorite open source project to present to your local software meetup group.
—————
How do you proceed? If you choose to create another passe linear slide deck, load up Microsoft PowerPoint. If you decide to build a childhood nostalgia-packed Choose Your Own Adventure presentation, continue reading this blog post.
—————
Good choice! To create our Choose Your Own Adventure presentation we’ll use Reveal.js, Flask, WebSockets and Twilio SMS. Our final product will have decision screens like the following screenshot where SMS votes from the audience are counted and displayed in real-time to determine the next step in the presentation story. Once the votes are tallied the presenter can click the left choice or the right choice to go to the appropriate next slide in the presentation.
Take a look at the DjangoCon US 2014 ”Choose Your Own Django Deployment Adventure” video if you want to see an example of a Choose Your Own Adventure presentation in action.
What we’ll need
- Reveal.js for browser-based presentations
- Python with application dependencies:
- Flask
- Flask-SocketIO for handling websockets with Flask
- Flask-Script for utility commands such as running our Flask server
- Gunicorn to run our server
- redis-py for interacting with Redis
- Redis for calculating results and short-term vote storage
- A Twilio account with an SMS number so audiences can vote which path the presentation should follow
- Ngrok for a secure tunnel to our local server running the presentation
Do you want to skip typing out the code yourself? Check out this open source repository on GitHub. The Git repository contains the final code as well as intermediate tags named tutorial-step-1, tutorial-step-2 and tutorial-step-3 for each section below.
Building the Presentation
Let’s first create the directory structure necessary for our project. The nested subdirectories will look like the following screenshot. Our base directory name and Flask app directory name will be “cyoa”, an acronym for “Choose Your Own Adventure.”
At the base cyoa/ directory create a file named requirements.txt with the following content in it. These are the dependencies for our project that we’ll install in a moment.
This application uses Flask to serve up the presentation. The Flask-Script extension will assist us in creating a manage.py file with helper commands to run the web application. The Flask-SocketIO extension handles the server-side websockets communication.
First create a new virtualenv outside the base project directory to separate your Python dependencies from other apps you’re working on.
Activate the virtualenv before we install the dependencies.
To install these dependencies run the following pip command on the command line.
Create a file named cyoa/manage.py with the following contents.
The above manage.py file will help us run our Flask application with the python manage.py runserver command once we’ve put more of the pieces in places.
Next create a file cyoa/cyoa/config.py (the cyoa/cyoa subdirectory is where most of our Python code will live other than manage.py) and add the below code to create the configuration variables we’ll need for our Flask application.
Here’s a run down of what each of these environment variables specified in config.py is for:
- DEBUG – True or False for whether Flask should display error messages if something goes wrong
- SECRET_KEY – a long key that should be kept secret
- REDIS_SERVER – in this case likely to be localhost or wherever Redis is running
- REDIS_PORT – generally set to 6379 for the default Redis port
- REDIS_DB – set to 0
- TWILIO_ACCOUNT_SID – found on your Twilio account dashboard
- TWILIO_AUTH_TOKEN – also found on your Twilio account dashboard
- TWILIO_NUMBER – a number you’ve purchased on Twilio
Set the DEBUG and SECRET_KEY environment variables now. The Redis and Twilio environment variables will be set in the next section.
Setting up environment variables depends on your operating system. There are guides for every major operating system, whether that is Ubuntu Linux, Mac OS X and Windows.
The next file we need to create is cyoa/cyoa/__init__.py, which will set up the core pieces for our the Flask app.
Next create a file named cyoa/cyoa/views.py and put the following code inside.
For now the above file contains a single view named landing. This view landing obtains a presentation name from the URL and checks the cyoa/cyoa/templates/ directory for an HTML template file matching that name. If a matching file is found, landing renders the HTML template. If no file name matches the presentation name in the URL, landing returns a 404 HTTP response.
We’re awfully close to getting to fire up this presentation to take a look at it. An HTML template file along with some static files are necessary for displaying the presentation. Create a Reveal.js presentation in templates directory named cyoa/cyoa/templates/cyoa.html. Add the following HTML inside this file.
As you can see in the HTML there are three locally hosted static CSS files and a JavaScript file you’ll need for your project. Download these files from GitHub or download and extract this cyoa.tar.gz archive into the cyoa/cyoa/static directory. The CSS and JavaScript files we need are the following:
- js/reveal.js – code for creating the beautiful Reveal.js presentation
- css/default.css – default style for Reveal.js decks
- css/reveal.css – required for running Reveal.js presentations properly
- css/zenburn.css – necessary for syntax highlighting within a presentation
With these files in place we can try out the presentation to make sure everything so far is in working order. Fire up Flask with the following command.
Now we can view the initial version of the presentation by going to http://localhost:5001/cyoa/ in the browser. Flask will find the cyoa.html file in the templates directly and serve that up so you can view it.
However, the presentation will only come up on your own computer. To access the presentation from other computers you’ll need to deploy to a hosting server or create a localhost tunnel using a tool such as Ngrok. Sign up for Ngrok and download the Ngrok tunnel application.
Fire up ngrok on port 5001 where our Flask application is running. See this configuring Ngrok post if you’re running Windows. On Linux and Mac OS X Ngrok can be run with the following command when you’re in the directory that ngrok is located in.
You’ll see a screen like the following. Take note of the unique https:// forwarding URL as we’ll need that again in a minute for the Twilio webhook.
You can now pull the presentation both from the localhost URL as well as the forwarding URL set up by ngrok.
Accepting SMS votes
So far we’ve written the Python code to serve a Reveal.js presentation and exposed it via a localhost tunnel. Now we need a way for the audience to vote on which path they want the presentation to go. To do that we’ll show a Twilio phone number on the screen and use Twilio SMS to let the audience vote. If you’ve already got an account grab a new or existing phone number, otherwise sign up and upgrade a Twilio account.
We’ll need to set up the message webhook so that each vote SMS to the Twilio number is sent to our Flask app. The Twilio number screen should look like the following.
Paste in your Ngrok forwarding URL, which will look like “https://[unique Ngrok code].ngrok.com”, along with “/cyoa/twilio/webhook/” to the Messaging Request URL text box then hit save. For example, if your Ngrok tunnel is “1d4e144c” your URL to paste into the webhook text box should look like the following URL.
https://1d4e144c.ngrok.com/cyoa/twilio/webhook/
Now Twilio will send a POST HTTP request to the ngrok port forwarding URL which will be sent down to your localhost server.
Make sure to update the phone number in your cyoa/cyoa/templates/cyoa.html presentation file. Look for the line like the following and replace it with your Twilio number.
However, we’re not yet ready to accept those incoming SMS votes. First we need to ensure Redis is running and write Python code to persist votes to it.
Ensure that Redis server is installed on your system since that will be our temporary vote storage system. There’s a quickstart installation guide available for your operating system of choice if you’re unfamiliar with Redis. In that quickstart you just need to go from the beginning through the “Starting Redis” section and you’ll be set for finishing this project.
Let’s add code in our cyoa/cyoa/views.py file for the Twilio webhook HTTP POST that occurs on an inbound SMS. We’ll increment a counter for each keyword texted in by people in the audience.
It’d be useful to have a way to clear out votes from Redis in between rehearsals for our presentation. Update cyoa/manage.py with a new function to clear votes from Redis.
If Flask and ngrok are still running we can test this out now, otherwise fire them up and let’s text either “left” or “right” to your Twilio number.
When you test out SMS inbound text messages you should receive the “Thanks for your vote!” response like in the screenshot below.
At this point those inbound text message votes are also being stored in Redis. We’re so close to wrapping up this code at this point let’s write a bit more Python to test that the messages are indeed in Redis and propagate the results to the presentation via websockets.
Adding WebSockets for Real-time Updates
We need one more new Python file to handle the server-side websockets communication. Websockets allow streams of communication between the client and server. In our presentation that allows the vote counts to be updated on the presentation slide as soon as the server emits a new message. Add a file named cyoa/cyoa/websockets.py with the following code to set up the server-side websockets implementation.
The above code in the update_count function allows the websocket clients, in this case the browser that loads the presentation, to connect to the websockets stream and receive future messages.
Add one line to the bottom of cyoa/cyoa/__init__.py to import the websockets.py file we just wrote.
Update cyoa/cyoa/views.py with the following highlighted lines. We’re adding the socketio.emit call so votes are passed via websockets to the presentation.
Add the highlighted code below to the cyoa/cyoa/templates/cyoa.html HTML presentation file. This code relies on the websockets JavaScript library and JQuery that was included with the file when we originally created it.
Fire up Flask with Ngrok again. Check out http://localhost:5001/cyoa/ on your browser and you’ll see the same presentation as before. However, text your vote of ‘left’ or ‘right’ to your number and the votes will appear like in the screenshot below without any page refresh.
Wrapping it up
You now have a Flask app that can serve up Reveal.js presentations where the audience can interact with the slide on screen by texting in their votes.
Now it’s up to you to create the Choose Your Own Adventure content!
Let me know what new Choose Your Own Adventure presentation stories you come up with or open a pull request to improve the code base. Contact me via:
- Email: makai@twilio.com
- GitHub: Follow makaimc for repository updates
- Twitter: @mattmakai
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.