How to manage context from your Python webhook in Dialogflow ES

This tutorial used to refer to inline webhooks before. But I have updated it to use a simple Python based webhook for two reasons: I don’t recommend using the fulfillment library and Python is better suited than NodeJS for Dialogflow bots.

The problem

A little while back I wrote a post about getting the user’s complete birthdate in DialogFlow. Turns out, the issue is somewhat non-trivial. Since DialogFlow will accept a date with only a month and a day (e.g. March 15th) as a valid input for the @sys.date entity, the user may not enter a year. The real issue, of course, is that DialogFlow will automatically append the current year as the year in the entered date. This is not just missing information, but it is actually wrong information.

The date.partial field

One way to handle this is to get the user’s input as a @sys.date, and make the parameter value you extract to be $date.partial. Check out the link above to see a little animated gif which shows you how to do that. For now, I will proceed on the assumption that you have already done that.

Validation on the webhook

At this point, we will be validating the input to check if the $date.partial captured the full date or only a partial date. If it captures a partial date, then DialogFlow will send a message to the user asking for the date. On the other hand, if it captured the complete birthday, DialogFlow will simply send a message prompting for the next response.

The flowchart

As I mentioned in previous posts, I suggest creating flowcharts for your chatbots using Mindomo.

So here is the Mindomo flowchart which describes this flow. You can take a look at this video course to understand the conventions I use in the flowchart.

Notice that the next input we wish to get is the user’s last name. Usually the way we build such a conversation in DialogFlow is by setting a context with an appropriate name.

Defining the intents

Let us define our intents one by one.

First we create an intent called book.appointment

Next we create the provides.birthdate intent

Next we define the provides.birthyear intent

Finally we define the provides.lastname intent

On the webhook, we check if the birthdate value starts with ‘UUUU’. If it does, we change the output context to get_birth_year (note: you can cancel the get_last_name context by setting the lifespan to zero)

def check_birth_year(req):
    try:
        query_result = req.get('queryResult')
        birthdate = query_result.get('parameters').get('birthdate')
        context_prefix = get_context_prefix(query_result)
        result = {
            'fulfillmentText': 'What is your last name?'
        }
        if str(birthdate).startswith('UUUU-'):
            result = {
                'fulfillmentText': 'What is your birth year?',
                "outputContexts": [
                    {
                        "name": f'{context_prefix}/await_birth_year',
                        "lifespanCount": 1
                    },
                    {
                        "name": f'{context_prefix}/await_last_name',
                        "lifespanCount": 0
                    }
                ]
            }
        with open('result.json', 'w', encoding='utf-8') as f:
            json.dump(result, f, ensure_ascii=False, indent=4)
        return result
    except Exception as e:
        error_str = str(e)
        result = {
            'fulfillmentText': generic_error_message
        }
        return result

Demo

Let us check to see if the bot works as expected

The raw interaction log confirms that all the user input has been collected properly