-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'tropo-colors/master'
- Loading branch information
Showing
8 changed files
with
247 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
*.py[c|o] | ||
*~ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
web: python heroku/simple_colors.py |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
Tropo Colors | ||
============ | ||
|
||
This is a simple application built with Redis and Tropo to change the color of | ||
the background of a web page on voice command. It is meant to be as simple as | ||
possible, so that it can be used as an example to teach programming. | ||
|
||
Explanation | ||
----------- | ||
|
||
There are three parts to this application: | ||
|
||
* A Tropo script (``tropo/colors.py``) that asks the user for a color, | ||
* A server-side Itty app (``heroku/simple_colors.py``) that handles the | ||
storage and retrieval of the current color from a Redis data store, and | ||
* A client-side script that checks on updates to the stored color. | ||
|
||
The Tropo script is made to be uploaded to a Tropo account. The Itty app can | ||
be uploaded to Heroku (or anywhere else that can run and serve Python apps). | ||
|
||
The Tropo app that you create to run the script should be assigned a phone | ||
number. When you call that number, Tropo will run the script, asking for a | ||
color. If it recognizes the color, it will send out a signal (``request``) to | ||
the Itty app to save the color. The Itty app will receive the ``request`` and | ||
store the color in a Redis datastore (``bucket``). | ||
|
||
In the mean time, the client side script will be watching the value of the | ||
color stored in the ``bucket`` and, when it changes, updating the web page. | ||
|
||
Why Itty? | ||
--------- | ||
|
||
I normally create my apps in Django. I could have created a Django project for | ||
this, and used an SQLite database or something, but I wanted something that I | ||
could do in about one module, and that I didn't have to do too much additional | ||
explanation to get through. | ||
|
||
So, I started to try Flask (zachwill has a great flask-heroku starter project | ||
on github), but I found that even this seemed to obfuscate what I was trying | ||
to get across. In addition to my framework being light-weight, I wanted my | ||
code to be as light-weight as possible as well, since this is a pedagogical | ||
tool. I don't mind Flask myself, but I felt that things like:: | ||
|
||
@request('/colors', methods=['POST']) | ||
... | ||
|
||
were too much. Itty is the lightest, lowest-configuration framework for Python | ||
I've seen, and gets the point across nicely. For example, the above route in | ||
Itty is:: | ||
|
||
@post('/colors') | ||
... | ||
|
||
A minor difference to be sure, but one big enough to sway me. | ||
|
||
Why the Tropo hosted script instead of HTTP API? | ||
------------------------------------------------ | ||
|
||
There are two ways to use Tropo, and I picked one. At first, I used the Tropo web | ||
API, but decided to simplify things by using a Tropo script instead for two | ||
reasons: | ||
|
||
* I was afraid that the overhead of explaining the HTTP back-and-forth that | ||
is done between Tropo and the server app would get in the way of the | ||
programming concepts. | ||
* Using the script, I get to use more of simpler concepts like iteration and | ||
conditionals, reinforcing these concepts and keeping the async HTTP requests | ||
to a minimum. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<html> | ||
<head> | ||
<title>Tropo Colors</title> | ||
|
||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script> | ||
<script> | ||
$(document).ready(listenForColorChanges); | ||
|
||
function listenForColorChanges() { | ||
var url = '/color'; | ||
|
||
$.get(url, function(data, status, $xhr) { | ||
$('body').css('background-color', data); | ||
$('body h1').html('The color is ' + data); | ||
|
||
setTimeout(listenForColorChanges, 1000); | ||
}); | ||
} | ||
</script> | ||
</head> | ||
|
||
<body> | ||
<h1>The color is ...</h1> | ||
|
||
<p>Call (415)889-8683 to change the color.</p> | ||
<p><a href="https://github.com/mjumbewu/tropo_colors">(see the code...)</a></p> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import os | ||
import urlparse | ||
|
||
ROOT = os.path.dirname(__file__) | ||
|
||
## | ||
# Redis -- a data store | ||
# | ||
# Redis is the data storage system that we use for this project. It allows you | ||
# to store data in really simple ways. Heroku gives us easy access to a redis | ||
# data store using a service called Redis To Go. We have to parse out the | ||
# pieces to use it. | ||
|
||
redis_info = urlparse.urlparse(os.environ.get('REDISTOGO_URL', 'redis://user:pass@host:9999/')) | ||
|
||
REDIS = { | ||
'host': redis_info.hostname, | ||
'password': redis_info.password, | ||
'port': redis_info.port, | ||
'db': 0, | ||
} | ||
|
||
## | ||
# itty -- a web framework | ||
# | ||
# There are several web frameworks for Python, and each give you different | ||
# built-in capabilities. For this application, we want to use as simple a | ||
# framework as possible, and itty is about as simple as it gets. Here we set | ||
# up the "host" and "port" (two things that are fundamental to being able to | ||
# locate things on the web) that Heroku expects to use. | ||
|
||
ITTY = { | ||
'host': '0.0.0.0', | ||
'port': int(os.environ.get('PORT', 8080)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
from itty import * | ||
import redis | ||
import settings | ||
|
||
|
||
## | ||
# Path : / | ||
# Method : GET | ||
# | ||
# This is the main path for the application. It just gives you the html page | ||
# that you use to view the app. For example, in your browser, go to the url: | ||
# | ||
# http://tropo-colors.herokuapp.com/ | ||
# | ||
# (The last '/' on that url because of the definiton below) | ||
# | ||
@get('/') | ||
def _(request): | ||
return serve_static_file(request, 'colors.html', settings.ROOT) | ||
|
||
|
||
## | ||
# Path : /color | ||
# Method : GET | ||
# | ||
# This is the path that will allow you to get the current color from the | ||
# database. For example, in your browser, go to: | ||
# | ||
# http://tropo-colors.herokuapp.com/color | ||
# | ||
# We use this to tell the web page what color it should be. | ||
# | ||
@get('/color') | ||
def _(request): | ||
bucket = get_a_bucket() | ||
|
||
color = bucket.get('color') or 'white' | ||
return color | ||
|
||
|
||
## | ||
# Path : /color | ||
# Method : POST | ||
# | ||
# This path can also be used to set the current color for the web page. Notice | ||
# that this definition starts with @post instead of @get like the others. By | ||
# convention, on the web, GET usually means "retrieve something", and POST means | ||
# "store something". So, in this case, we're storing the color. | ||
# | ||
@post('/color') | ||
def _(request): | ||
bucket = get_a_bucket() | ||
|
||
color = request.body | ||
bucket.set('color', color) | ||
return color | ||
|
||
|
||
## | ||
# This function will return a bucket (a Redis data storage structure) that we | ||
# can use to store or retrieve colors. | ||
def get_a_bucket(): | ||
bucket = redis.Redis(**settings.REDIS) | ||
return bucket | ||
|
||
|
||
run_itty(**settings.ITTY) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
itty | ||
redis | ||
tropo-webapi-python |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
from httplib import HTTPConnection | ||
# This script also uses two function from the Tropo module: 'ask', and 'say'. | ||
# Normally this would look like: | ||
# | ||
# from tropo import ask, say | ||
# | ||
# However, in this case, these functions are imported automatically from the | ||
# 'tropo' module on Tropo's server. | ||
|
||
|
||
color_names = ( | ||
'White, Black, Gray, Red, Maroon, Orange, Brown, Yellow, Olive, ' | ||
'Lime, Green, Cyan, Teal, Blue, DarkBlue, Fuchsia, Violet, Purple') | ||
|
||
|
||
def run(): | ||
|
||
say("Tell me a color and I'll show it to you.") | ||
|
||
while True: | ||
|
||
answer = ask("What color do you want?", | ||
{'choices': color_names + ', Stop'}) | ||
|
||
if answer.value == 'NO_MATCH': | ||
say("I'm sorry, I didn't understand. Please try again.") | ||
|
||
elif answer.value == 'Stop': | ||
say("Ok, I'll stop. Goodbye.") | ||
break | ||
|
||
else: | ||
color = answer.value | ||
save(color) | ||
say("Ok, I'll change the color to " + color) | ||
|
||
|
||
def save(color): | ||
conn = HTTPConnection('tropo-colors.herokuapp.com') | ||
conn.request('POST', '/color', body=color) | ||
|
||
|
||
run() |