Website chatbot using Dialogflow CX custom integration

In this article I will explain how you can create a custom integration with Dialogflow CX for your website bot. You will need someone on your team with some reasonable amount of Python programming experience to be able to follow along and implement this.

I am using Zoho SalesIQ as the UI layer (from the 4 layers of a Dialogflow bot), but you can also use these same basic principles to create an integration with whichever channel you are interested in.

I recommend using PythonAnywhere, but you can use other hosts if you can follow the steps outlined here. But Heroku does not have a free plan anymore, and other hosts like Render usually impose limits on number of hours of use per month. Note that PythonAnywhere allows you to run this code for free basically forever.

Here are the steps:

Download the service account JSON file for your bot with the role “Service Account”.

Create a Flask app on PythonAnywhere as described here. You will be using the second option – manual configuration.

Follow this StackOverflow answer to a) minify your JSON (remove all whitespace) and b) add the whole minified JSON as GOOGLE_APPLICATION_CREDENTIALS into your .env file

As the comment indicates, you just copy/paste the whole JSON into the configuration variable and make sure you don’t have any new lines. You can use an online tool to remove whitespace from JSON.

This is the Python script you will use for the integration

import json
import logging
import os

import flask
import requests
from dotenv import load_dotenv
from flask import request
from google.auth.transport import requests as google_requests
from google.oauth2 import service_account

load_dotenv()

app = flask.Flask(__name__)


@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'POST':

        req = request.get_json(silent=True, force=True)
        try:
            if 'message' in req and 'text' in req.get('message'):
                response_json = {
                    "action": "reply",
                    "replies": [
                        "Sorry, there was some problem. Please try again later"
                    ]
                }
                json_str = os.getenv('GOOGLE_APPLICATION_CREDENTIALS')
                json_data = json.loads(json_str)
                json_data['private_key'] = json_data['private_key'].replace('\\n', '\n')
                CREDENTIAL_SCOPES = ["https://www.googleapis.com/auth/cloud-platform"]
                credentials = service_account.Credentials.from_service_account_info(
                    json_data, scopes=CREDENTIAL_SCOPES)
                credentials.refresh(google_requests.Request())
                bearer_token = credentials.token

                usermsg = req.get('message').get('text')
                session_id = req.get('visitor').get('active_conversation_id')
                project_id = os.getenv('PROJECT_ID')
                location_id = os.getenv('LOCATION_ID')
                agent_id = os.getenv('AGENT_ID')
                url = f'https://dialogflow.googleapis.com/v3/projects/{project_id}/locations/' \
                      f'{location_id}/agents/{agent_id}/environments/-/sessions/{session_id}:detectIntent'
                headers = {
                    'Content-Type': 'application/json; charset=utf-8',
                    'Authorization': 'Bearer ' + bearer_token
                }
                payloadjson = {
                    "queryInput": {
                        "languageCode": "en",
                        "text": {
                            "text": usermsg,
                        }
                    },
                    "queryParams": {
                        "timeZone": "Asia/Calcutta"
                    }
                }
                payload = json.dumps(payloadjson)
                response = requests.request("POST", url, headers=headers, data=payload)
                result = json.loads(response.text)
                response_msgs = result['queryResult']['responseMessages']

                for response_msg in response_msgs:
                    if 'payload' in response_msg and 'platform' in response_msg.get('payload'):
                        if response_msg.get('payload').get('platform') == 'ZOHOSALESIQ':
                            response_json = response_msg.get('payload')
                    if 'text' in response_msg:
                        response_json['replies'] = response_msg['text']['text']
                return response_json

        except Exception as e:
            logging.exception("Response Error")

        return 'Post request'
    else:
        return 'Get request'


if __name__ == '__main__':
    app.run()

This is the requirements.txt file. Install these requirements using pip install -r command.

flask
google-api-python-client
python-dotenv

This is what my .env file looks like. Yours should have the same keys but use the appropriate values based on your bot settings.

Now follow these steps to build the webhook integration in your Zobot.

This is what the integration looks like: