Integrating Dialogflow v2 into Qiscus Multichannel

This article is an update to the previous one about Integrating Dialogflow into Qiscus SDK. Dialogflow v2 embraces the concept of service account and no longer uses client access token approach. Hence, there will be a gap in integrating Dialogflow bot into our services from the v1 point of view. We are going to use the Qiscus Multichannel Platform widget as user client instead of the Qiscus SDK widget in this article.

If you already have an existing agent in Dialogflow, it is recommended to create a back up file so that if something goes wrong, you can revert to v1 easily. You can do this by exporting the agent in the ‘Export and Import’ section in the settings panel and click ‘EXPORT AS ZIP’.

Setting up a Service Account

As mentioned above, in v2, Dialogflow is using the service account. Thus, in the first step, we are going to set up Dialogflow agent’s service account; more precisely, its key.

So let’s go to the settings page, and under the general tab, click on the service account name.

qiscus multichannel dialogflow

This will open up your Google Cloud Platform project’s service account page. In its table, you will see ‘Dialogflow integrations’ service account already created.

Click on the three vertical dots on the right and click the ‘Create Key’ option. Keep it as a JSON file type, and save it locally. We will use it later.

dialogflow

Prepare the Chatbot Webhook

As we already have the service account key, we will then set up our bot webhook to connect the Dialogflow agent with Qiscus Multichannel. In this article, we are going to use the codebase from the previous article located at https://bitbucket.org/qiscus/qiscus-dialogflow/. We will modify several parts of the codes.

Firstly, if you open up the codes, you will notice in the setup.py file that it is using the apiai python package. We are going to change this into the dialogflow package as the supported package for Dialogflow v2.

from setuptools import setup, find_packages

setup(
    name='qiscus_dialogflow',
    version='1.0',
    long_description=__doc__,
    packages=find_packages(),
    include_package_data=True,
    zip_safe=False,
    install_requires=[
        'flask',
        'dialogflow',
        'requests'
    ],
)

Next, as we only need to detect intent from text and get response from the agent, we are going to utilise the Dialogflow package. The example is illustrated here: https://github.com/googleapis/dialogflow-python-client-v2/blob/master/samples/detect_intent_texts.py. Let’s save the file as dialogflow_response.py in the main directory and modify the code a little to look like this:

def detect_intent_texts(project_id, session_id, texts, language_code="en_US"):
    """Returns the result of detect intent with texts as inputs.

    Using the same `session_id` between requests allows continuation
    of the conversation."""

    import dialogflow_v2 as dialogflow
    session_client = dialogflow.SessionsClient()

    session = session_client.session_path(project_id, session_id)
    print('Session path: {}\n'.format(session))

    text_input = dialogflow.types.TextInput(
        text=texts, language_code=language_code)

    query_input = dialogflow.types.QueryInput(text=text_input)

    response = session_client.detect_intent(
        session=session, query_input=query_input)

    return response.query_result.intent.display_name, \
           response.query_result.intent_detection_confidence, \
           response.query_result.fulfillment_text
# [END dialogflow_detect_intent_text]

Several modifications have been made here:

  • For language, we set en_US as the default language
  • Instead of using a list of statements, we will assume we only check one statement
  • Return intent, confidence value, and fulfilment text as bot’s response

We will have the directory structure appear as follows:

.
├── MANIFEST.in
├── Makefile
├── Procfile
├── README.md
├── app.json
├── qiscus_dialogflow
│   ├── __init__.py
│   ├── default_settings.py
│   ├── dialogflow_response.py
│   ├── static
│   │   └── styles.css
│   ├── templates
│   │   └── index.html
│   └── views.py
├── requirements.txt
├── run.py
├── settings.cfg
├── setup.py
├── tests
│   └── test_dialogflow.py

After that, let’s use it in view.py. Let’s modify the current view.py file into something like this below.

import os
import requests

from flask import render_template, request
from qiscus_dialogflow import app, dialogflow_response


DEBUG = os.environ.get("DEBUG")
APP_ID = os.environ.get("APP_ID")
SECRET_KEY = os.environ.get("SECRET_KEY")
BOT_EMAIL = os.environ.get("BOT_EMAIL")
BOT_NAME = os.environ.get("BOT_NAME")
QISMO_URL = "https://qismo.qiscus.com"
HEADERS = {"QISCUS_SDK_SECRET": SECRET_KEY}


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

        # get message from Qiscus Multichannel
        payload = request.get_json().get('payload')
        room_id = payload.get("room").get("id")
        message = payload.get("message").get("text")

        # get dialogflow response
        intent, confidence_level, fulfilment = dialogflow_response\
            .detect_intent_texts({{agent_name}}, "1", message)

        # post url
        url = "{}/{}/bot/api/v2/rest/post_comment".format(QISMO_URL, APP_ID)
        post_type = "text"
        data = {
            "sender_email": BOT_EMAIL,
            "room_id": room_id,
            "message": fulfilment,
            "type": post_type,
            "payload": {}
        }

        req = requests.post(url, headers=HEADERS, params=data)
        print(req.status_code)

        if req.status_code == 200:
            return "OK", 200
        else:
            return "Failed", req.status_code
    else:
        return "Qiscus Dialogflow webhook", 200


@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'POST':
        return "POST method is not supported here", 404
    else:
        return render_template('index.html', app_id=APP_ID)

If you notice in the code above, we are no longer using the apiai package, and we also removed the init_user() function. Instead, we are using:

# get dialogflow response
intent, confidence_level, fulfilment = dialogflow_response.detect_intent_texts({{agent_name}}, "1", message)

with the specific agent_name to get Dialogflow agent’s response.

Before we run the codes, let’s add a service account key as the environment variable for GOOGLE_APPLICATION_CREDENTIALS to service account key JSON. To do so, you could do it like in the terminal:

$ export GOOGLE_APPLICATION_CREDENTIALS="path/to/your/service_account_key.json"

Then run the codes:

$ make run

FLASK_APP=qiscus_dialogflow DIALOGFLOW_SETTINGS=../settings.cfg venv/bin/flask run
 * Serving Flask app "qiscus_dialogflow"
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

And to make it globally accessable, we are going to utilise ngrok:

$ ngrok http 5000
ngrok by @inconshreveable                                                                                                                                                                                              (Ctrl+C to quit)
                                                                                                                                                                                                                                       
Session Status                online                                                                                                                                                                                                   
Session Expires               7 hours, 59 minutes                                                                                                                                                                                      
Version                       2.3.29                                                                                                                                                                                                   
Region                        United States (us)                                                                                                                                                                                       
Web Interface                 http://127.0.0.1:4040                                                                                                                                                                                    
Forwarding                    http://a1fde2ba.ngrok.io -> http://localhost:5000                                                                                                                                                        
Forwarding                    https://a1fde2ba.ngrok.io -> http://localhost:5000                                                                                                                                                       
                                                                                                                                                                                                                                       
Connections                   ttl     opn     rt1     rt5     p50     p90                                                                                                                                                              
                              2       0       0.02    0.01    0.05    0.10

Please note, this method will only work in a local environment. To set it up when you deploy it in your server, such as Heroku or others, please refer to the articles below:

Setting up Qiscus Multichannel

Qiscus Multichannel is an additional product from Qiscus SDK. it is running on top of Qiscus SDK itself. It provides several channels as means to obtain conversations from users and respond to them from one dashboard. One of the channels that we can use is the Qiscus Widget. If you have seen this widget in the previous article before, we are going to use it again here.

In this section, we are going to setup Qiscus Multichannel to connect to the Dialogflow agent. We are going to also use the widget to interact with our agent. If you haven’t had any Qiscus Multichannel account yet, please go to https://multichannel.qiscus.com and register to get one. We give every user a two-week free trial to get familiar with our product.

Now let’s go to the Integration page and select the Bot Integration tab:

dialogflow

In the page above, we have Agent ID, App ID, Qiscus Secret Key, and Qiscus Webhook Bot URL. We save them in the env variables as we are going to use these credentials to post to Qiscus Multichannel as Bot’s responses as written in the view.py file above.

Next, let’s grab the generated URL from ngrok and put it on the Bot Webhook URL. In our case, the URL is https://a1fde2ba.ngrok.io/. Since we use /webhook as our webhook endpoint, the bot webhook URL is https://a1fde2ba.ngrok.io/webhook/. Click “Connect” to connect it.

Qiscus Widget

We have set up our bot webhook for Dialogflow agent and we have also connected it to Qiscus Multichannel. The last thing to do is to use Qiscus Widget to get messages from users. Still in the Integration page, click Qiscus Widget tab and click the <> button to get a snippet code of the widget to be used in the client side. Copy it:

Now, let’s go back to the codes, and open up index.html in the templates directory and paste the code there:

<html>
  <head>
    <title>Qiscus Multichannel Widget</title>
  </head>
  <body>
    <script>
        document.addEventListener('DOMContentLoaded', function() {
            var s,t; s = document.createElement('script'); s.type = 'text/javascript';
            s.src = 'https://s3-ap-southeast-1.amazonaws.com/qiscus-sdk/public/qismo/qismo-v2.js'; s.async = true;
            s.onload = s.onreadystatechange = function() { new Qismo({{ app_id | tojson | safe }}); }
            t = document.getElementsByTagName('script')[0]; t.parentNode.insertBefore(s, t);
        });
    </script>
  </body>
</html>

As soon as you have finished it, open up the ngrok generated URL in the browser, such as in the image below, and start a chat:

In summary, to be able to use Dialogflow in one of Qiscus’ products, we need to have an intermediate webhook service to connect both services together. This intermediate service will act as a webhook which connects messages from Qiscus and pass it to the Dialogflow agent and obtain the response back to pass it back to Qiscus. In our example, we used Python to build this webhook service, but it’s not limited to this. As Dialogflow is using a service account for authentication, we can utilise any libraries that will handle it. You can read more here.

This code repository is located here.

Comments

Leave a Comment

Show Buttons
Hide Buttons