← all posts

Raspberry Pi - Python - Talking Twitter Client

Anyway, I was reading an article on the raspberry pi wiki about methods of implementing text to speech and that got me thinking about potential solutions which could make use of it. I had this idea about a talking twitter client, a program which would automatically read tweets out as and when they arrived, so one evening while the wife was watching Holby City, this is what I created.

It uses oauth to authenticate with twitter before opening a twitter user stream, the program then waits for data to appear, when it does, it uses google translate to create an mp3 file which is then stream by mplayer and hey presto, the Pi talks the tweet!

Its not really a finished program, more, a proof of concept, but I thought it might be useful for other people who want to use twitter in their projects and need a starting point. There is also a great tutorial about consuming twitter streams using python, where I got some of the code for this program

There are a few pre-requisites to getting this to work.

Create a twitter app You need to create a twitter app using your twitter id, you can do this by visiting dev.twitter.com, signing on, and clicking create app; if you are having problems see a previous blog post of mine, automatically posting updates to twitter, which has some in-depth instructions.

Install python-oauth I used leah’s python oauth module to authenticate with twitter.

Install distribute If you have never installed python modules before you are going to need to install the python setup tools, module, distribute, see blog post, python - installing modules, for info on how to do this.

Install git-core In order to get the code from github you need to install git-core tools.

sudo apt-get install git-core

Get the code from git

git clone https://github.com/leah/python-oauth.git

Install the module

cd python-oauth
sudo python setup.py install

Install pycurl pycurl is used to connect to the twitter streams.

sudo apt-get install python-pycurl

Install mplayer mplayer is used to output the audio stream.

sudo apt-get install mplayer

Create talking twitter client program

nano ttc.py

Cut and paste the program into it and save.

#!/usr/bin/env python
# An experimental talking twitter client for the Raspberry Pi
# written in Python, by Martin O'Hanlon
# www.stuffaboutcode.com

from oauth.oauth import OAuthRequest, OAuthSignatureMethod_HMAC_SHA1
from hashlib import md5
import json, time, random, math, urllib, urllib2, pycurl, subprocess, sys

# twitter oauth keys, get your from dev.twitter.com
CONSUMER_KEY = 'consumer key'
CONSUMER_SECRET = 'consumer secret'
ACCESS_TOKEN = 'access token'
ACCESS_TOKEN_SECRET = 'access token secret'

# function to download a file from a url, used for testing
def downloadFile(url, fileName):
    fp = open(fileName, "wb")
    curl = pycurl.Curl()
    curl.setopt(pycurl.URL, url)
    curl.setopt(pycurl.WRITEDATA, fp)
    curl.perform()
    curl.close()
    fp.close()

# returns the appropriate google speech url for a particular phrase
def getGoogleSpeechURL(phrase):
    googleTranslateURL = "http://translate.google.com/translate_tts?tl=en&"
    parameters = {'q': phrase}
    data = urllib.urlencode(parameters)
    googleTranslateURL = "%s%s" % (googleTranslateURL,data)
    return googleTranslateURL

# function to download an mp3 file for a particular phrase, used for testing
def downloadSpeechFromText(phrase, fileName):
    googleSpeechURL = getGoogleSpeechURL(phrase)
    print googleSpeechURL
    downloadFile(googleSpeechURL, fileName)

# output phrase to audio using mplayer
def speakSpeechFromText(phrase):
    googleSpeechURL = getGoogleSpeechURL(phrase)
    subprocess.call(["mplayer",googleSpeechURL], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

# class for managing tokens
class Token(object):
    def __init__(self,key,secret):
        self.key = key
        self.secret = secret

    def _generate_nonce(self):
        random_number = ''.join(str(random.randint(0, 9)) for i in range(40))
        m = md5(str(time.time()) + str(random_number))
        return m.hexdigest()

# talking twitter client
class TalkingTwitterStreamClient:
    def __init__(self, streamURL):
        self.streamURL = streamURL
        self.buffer = ""
        self.conn = pycurl.Curl()
        self.conn.setopt(pycurl.URL, self.streamURL)
        self.conn.setopt(pycurl.WRITEFUNCTION, self.on_receive)
        self.conn.perform()

    def on_receive(self, data):
        sys.stdout.write(".")
        self.buffer += data
        if data.endswith("\n") and self.buffer.strip():
            content = json.loads(self.buffer)
            self.buffer = ""
            #debug - output json from buffer
            #print content

            if "friends" in content:
                self.friends = content["friends"]

            if "text" in content:
                print u"{0[user][name]}: {0[text]}".format(content).encode('utf-8')
                speakSpeechFromText(u"A tweet from {0[user][name]}".format(content))
                #downloadSpeechFromText(u"A tweet from {0[user][name]}".format(content), "./tweet.mp3")
                speakSpeechFromText(u"{0[text]}".format(content))
#downloadSpeechFromText(u"{0[text]}".format(content), "./tweet.mp3")

# get the url needed to open the twitter user stream, including signature after authentication
def getTwitterUserStreamURL():
    STREAM_URL = "https://userstream.twitter.com/2/user.json"

    access_token = Token(ACCESS_TOKEN,ACCESS_TOKEN_SECRET)
    consumer = Token(CONSUMER_KEY,CONSUMER_SECRET)

    parameters = {
        'oauth_consumer_key': CONSUMER_KEY,
        'oauth_token': access_token.key,
        'oauth_signature_method': 'HMAC-SHA1',
        'oauth_timestamp': str(int(time.time())),
        'oauth_nonce': access_token._generate_nonce(),
        'oauth_version': '1.0',
    }

    oauth_request = OAuthRequest.from_token_and_callback(access_token,
                    http_url=STREAM_URL,
                    parameters=parameters)
    signature_method = OAuthSignatureMethod_HMAC_SHA1()
    signature = signature_method.build_signature(oauth_request, consumer, access_token)

    parameters['oauth_signature'] = signature
    data = urllib.urlencode(parameters)
    return "%s?%s" % (STREAM_URL,data)

# Run Talking Twitter Client
client = TalkingTwitterStreamClient(getTwitterUserStreamURL())

#some useful debug commands, comment out running the client and uncomment the command
#get twitter stream url, including oauth signature
#print getTwitterUserStreamURL()
#download a speech file from google
#downloadSpeechFromText("hello, how are you today", "./downloadedFile.mp3")
#output phrase to audio
#speakSpeechFromText("hello, how are you today")
#start talking twitter client

Run the program

python ttc.py

Press CTRL C to exit and wait a few moments, this is for pycurl to give up the connection.

Limitations (found so far!)

Google translate seems to have a maximum length of string it will create an mp3 for, I found in testing that some tweets weren’t output and it was because google didn’t return an mp3 because it was too long.

There is no mechanism for recovering from errors, such as a the stream going down, it just falls over!