Sketching a Slack Slash Parliamentary Auto-Responder Using AWS Lambda Functions

Across a couple of recent posts, I’ve explored how to use a webhook manager to implement the a simple Slack bot that handles queries from Slack and return information from the UK Parliament data API (Searching the UK Parliament API from Slack Slash Commands Using a Python Microservice via Webhooks) and how to use AWS Lambda functions to construct a simple Slack slash command responder (Implementing Slack Slash Commands Using Amazon Lambda Functions – Getting Started).

So this morning, I thought I’d have a go at getting a Slack slash command responder using AWS Lambda functions to handle a couple more queries. Here’s where I got to…

First up, asking for committees that a member of parliament sits on:


Secondly, a query on who the current members of a particular committee are:


One rationale for supporting this sort of query is to provide fingertips information access to a researcher through a unified conversational interface.

To trigger the responses, I’ve used a regular expression that tries to capture several different question types:

x='committees that Andrew Turner is on"
regexp=re.compile(r'.*(?:committees[ (?:that|does|is)]*) (.*?)(( (:?is )?(on|sits on|sit on|a member of))|$)')

Obviously, this is not very advanced in terms of natural language processing, but the domain is a simple one and the number of forms that a query requesting this sort of information might take will probably be quite simplistic – and predictable!

Having extracted the member’s name (for a lookup of the committees a member is on) or the committee name when trying to look up the members of a particular committee), a URL is generated that can request the data from the Parliament members API. For example:

def committee_URL(c):
    return comm_url.format(urlencode(urlargs))

We can this use this URL to get some JSON data back:

def getJSON(url):
    q = Request(url)
    q.add_header('accept', 'application/json')
    r= urlopen(q)
    return json.loads(a.decode('utf-8-sig'))

The next step is to parse the JSON response to pull out the information we want, and convert it to a simple text string:

def committeeMembers(members,c):
    if members['Members'] is None: return None
    for m in members['Members']['Member']:
        tl.append('{} ({})'.format(m['FullTitle'],m['Party']['#text']))
    return 'Members of the {}: {}'.format(c,', '.join(tl))

This text string can then be returned to Slack as the slash command response.

[UPDATE…] Here’s another example… The members’ API can look up MP by location, constituency or postcode; so if we try them in turn, we can take in a wide variety of location styles; and it only takes a really simple regular expression to prime the pattern match for what I guess is a wide range of possible conversational gambits for requesting this information:


As with the members API, the Parliament data API will also return JSON responses to valid queries (I used the Parliament data API in the original demo). There’s quite a few APIs to play with – datasets so as and when I get a moment, I may try to code some more of them up as conversational responders:-)

One comment

  1. Cédric Lombion

    This is really cool and should be the future of Open Data interfaces. People shouldn’t have to download a dataset to get key insights from it, and they shouldn’t have to decypher labels to create a custom visualisations, which is the state of the art of “accessible” open data portals today.

    Would it be easy to query a google spreadsheet using this method? That sounds like a great way for a team member to query internal data that s/he might not be acquainted with.

    Thanks for sharing!