Today, we’re turning on BillPedutoBot, a Twitter bot that tweets the daily schedule of Pittsburgh’s mayor while having a bit of fun.

It’s a sister project of Where’s Bill?, a site we developed earlier this year to scrape, document and present Bill Peduto’s doings and whereabouts.

I’m working in my office until 1:00PM. (http://t.co/dw5GCsYGBH) — Robot Bill Peduto (@BillPedutoBot) March 26, 2014

Right now, BillPedutoBot is all business. But hopefully not for long! We’re opening him up to Pittsburgh’s developer community, looking for modifications to make him a bit more fun. (My next improvement? Attaching an animated GIF of Peduto chowing down on pierogies every time his schedule mentions food.) If you have an idea, jump in!

Who knows? Maybe we’ll find another use for this GIF.

In particular, we need help adding to the bot’s vocabulary, translating Official Mayoral Schedulese like “Coffee Meeting with Allegheny County Executive Rich Fitzgerald” into “I’m having coffee with Rich Fitzgerald this morning! What are you doing?” (Take a look at the Github repo to see how to modify the bot’s parser.)

Want to know how we built the bot? Read on.

I built this bot in Python using the Python-Twitter wrapper, which makes navigating Twitters API (and Oauth) really simple.

First task is to initialize a new Twitter object with my credentials from @BillPedutoBot.

api = twitter.Api(consumer_key=creds["consumer_key"], consumer_secret=creds["consumer_secret"], access_token_key=creds["access_token_key"], access_token_secret=creds["access_token_secret"])

Next, I queried Where’s Bill’s API, which (currently – will be expanded soon!) displays the earliest event coming up in the next hour.

event = urllib2.urlopen('http://newsinteractive.post-gazette.com/wheresbill/api').read()

That returns:

{ "title": "Meeting with Lenora Nemetz", "start": "13:00:00", "end": "13:30:00", "location": "Mayor's office, 414 Grant Street, Pittsburgh, PA 15219", "date": "2014-03-26", "published": "2014-03-26" }

All well and good, but “Meeting with Lenora Nemetz” isn’t as fun as “Hey! I’m meeting with Lenora Nemetz in five minutes!” So we have to parse the mayor’s schedule-speak into something a, uh, robot would actually say.

I did this by defining an expandable dictionary of regular expressions and accompanying output strings. For example, the parser looks for “Meeting” at the beginning of the string, and if it finds it, it outputs, “I’m meeting with <blank>.”

Here’s the full dictionary:

keywords = { "(?i)^(Coffee )?Meeting with ": "I'm meeting with %s", "(?i)^(Telephone )?Interview with ": "I have an interview with %s", "(?i)(conference call:|conference call) ": "I'll be on a conference call with %s", "(?i)standing meeting: ": "I have a regularly-scheduled meeting with %s", "(?i)^On air |Call-in |Call in ": "I'll be on air %s", "(?i)^Telephone call: ": "I'm on the phone with %s", "(?i) taping$": "I'm taping \"%s\"", "(?i)^Press conference: ": "I'm holding a press conference on %s", "(?i)^Press conference with ": "I'm holding a press conference with %s", "(?i)^Attending ": "I'm attending %s", "(?i)^(Speaking at |Speaking: )": "I'm speaking at %s", "(?i)^Visit from ": "I'm hosting a vist from %s", "(?i)^(Standing )?Weekly meeting ": "I have my weekly meeting %s", "(?i) meeting?": "I'm going to a %s meeting", "(?i) retreat?": "I'm holing up in a %s retreat", "(?i) reception?": "I'm receptioning at a %s reception", "(?i) luncheon?": "I'm eating at a %s luncheon", "(?i)^breakfast with ": "I'm having breakfast with %s", "(?i)^lunch with ": "I'm having lunch with %s", "(?i)^dinner with ": "I'm having dinner with %s", "(?i)^Return home ": "I'm going home to Pittsburgh%s! See see you soon.", "(?i)^(Travel|Drive|Driving) to ": "I'm leaving for %s", "(?i)^(Travel|Drive|Driving) from ": "I'm traveling from %s", "(?i)^Serve as": "I'm serving as %s", "(?i)^Working in office": "%sI'm working in my office until", }

Last bit adds a time element, generates a link to “Where’s Bill” and makes sure the tweet isn’t too long.

# If length is longer than 100 characters, truncate to fit in tweet message = message[:100] + "..." if (len(message) > 100) # Add time element start = datetime.strptime(event["start"], "%H:%M:%S").strftime("%I:%M%p").lstrip("0") end = datetime.strptime(event["end"], "%H:%M:%S").strftime("%I:%M%p").lstrip("0") # If formatted message has "until" in it, print the end time, not the beginning. if re.search("until$", message): message += " " + end + "." else: message += " at " + start + "." # Add link to Where's Bill message += " (http://newsinteractive.post-gazette.com/wheresbill/?date=" + event["date"] + "&time=" + event["start"].replace(":","") + ")"

Here’s a gist of the final code: