LoginSignup
1
1

More than 5 years have passed since last update.

DialogflowのfulfillmentをAzureで実装する

Posted at

はじめに

AzureFunctionsって料金どれくらいかかるんでしょうか......(恐怖)
すごーく簡単にできるように頑張ります!

AzureFunction 側の設定・作成

Azure FunctionsでPython3とpipを使う - Qiita
が参考になりますので,こちらを見てPython3が使えるようにします.

AzureFunctions.py
import platform
print("Python '{0}'".format(platform.python_version())) 

[Info] Python '3.6.1'

と出れば準備は完了です.

上部の 関数のURLの取得 からURLをコピーしておきます.

Dialogflow の設定

Fulfillment

左側のタブ Fulfillment を選択,Webhookを有効にします.

URL に先ほどコピーしたAzureのURLをペーストし, DOMAINS

Enable webhook for all domains

に変更し,SAVEします.

intent

Azure側で処理したいintentの設定から, Enable webhook call for this intent をオン

これで準備は完了です.プログラムを書いていきます.

Dialogflow -> AzureFunctions

以下のjsonに色々入っているのでいじって情報を得ます.

Request.json
{
    "responseId": "ea3d77e8-ae27-41a4-9e1d-174bd461b68c",
    "session": "projects/your-agents-project-id/agent/sessions/88d13aa8-2999-4f71-b233-39cbf3a824a0",
    "queryResult": {
        "queryText": "user's original query to your agent",
        "parameters": {
            "param": "param value"
        },
        "allRequiredParamsPresent": true,
        "fulfillmentText": "Text defined in Dialogflow's console for the intent that was matched",
        "fulfillmentMessages": [
            {
                "text": {
                    "text": [
                        "Text defined in Dialogflow's console for the intent that was matched"
                    ]
                }
            }
        ],
        "outputContexts": [
            {
                "name": "projects/your-agents-project-id/agent/sessions/88d13aa8-2999-4f71-b233-39cbf3a824a0/contexts/generic",
                "lifespanCount": 5,
                "parameters": {
                    "param": "param value"
                }
            }
        ],
        "intent": {
            "name": "projects/your-agents-project-id/agent/intents/29bcd7f8-f717-4261-a8fd-2d3e451b8af8",
            "displayName": "Matched Intent Name"
        },
        "intentDetectionConfidence": 1,
        "diagnosticInfo": {},
        "languageCode": "en"
    },
    "originalDetectIntentRequest": {}
}

AzureFunctions -> Dialogflow

以下のようにレスポンスを作成し,Dialogflowに返却します.
最低限 fulfillmentText があればGoogle homeくんが喋ってくれます.

Response.json
{
    "fulfillmentText": "This is a text response",
    "fulfillmentMessages": [
        {
            "card": {
                "title": "card title",
                "subtitle": "card text",
                "imageUri": "https://assistant.google.com/static/images/molecule/Molecule-Formation-stop.png",
                "buttons": [
                    {
                        "text": "button text",
                        "postback": "https://assistant.google.com/"
                    }
                ]
            }
        }
    ],
    "source": "example.com",
    "payload": {
        "google": {
            "expectUserResponse": true,
            "richResponse": {
                "items": [
                    {
                        "simpleResponse": {
                            "textToSpeech": "this is a simple response"
                        }
                    }
                ]
            }
        },
        "facebook": {
            "text": "Hello, Facebook!"
        },
        "slack": {
            "text": "This is a text response for Slack."
        }
    },
    "outputContexts": [
        {
            "name": "projects/${PROJECT_ID}/agent/sessions/${SESSION_ID}/contexts/context name",
            "lifespanCount": 5,
            "parameters": {
                "param": "param value"
            }
        }
    ],
    "followupEventInput": {
        "name": "event name",
        "languageCode": "en-US",
        "parameters": {
            "param": "param value"
        }
    }
}

 intent別に処理を実装する.

Request -> queryResult.intent.displayName にDialogflowが判定したインテント名が格納されているので,これを見て処理を分けていきます.

intent_name = Result["queryResult"]["intent"]["displayName"]
if intent_name == "インテント名":
    処理
else:
    エラー処理など

サンプル

Recommend が来た時に現在放送中のラジオからランダムに返却して喋らせるやつ

Sample.py
# -*- coding: utf-8 -*-
import io
import os
import json
import random
import requests
import xml.etree.ElementTree as ET
from html.parser import HTMLParser

# 番組情報[info]がhtmlタグ付きなので削除に使用するクラス
class MyHtmlStripper(HTMLParser):
    def __init__(self, s):
        super().__init__()
        self.sio = io.StringIO()
        self.feed(s)

    def handle_starttag(self, tag, attrs):
        pass

    def handle_endtag(self, tag):
        pass

    def handle_data(self, data):
        self.sio.write(data)

    @property
    def value(self):
        return self.sio.getvalue() 

# インテントで処理を分ける
def intent_check(Result):
    intent_name = Result["intent"]["displayName"]
    if intent_name == "Recommend":
        return intent_Recommend(Result)
    else:
        return Build_Response('NO')

# intent[Recommend]の時
def intent_Recommend(Result):
    bangumi = Create_RadioData(None)
    output = 'ただいま,' + bangumi['station'] + 'で,' + bangumi['title'] + 'が放送中です.'
    return Build_Response(output)

# ETそのままのStationを受け取って,使いやすい辞書型に変換する
def Build_bangumiData(bangumi):
    station = bangumi.findtext('name')
    prog = bangumi[1][1]
    title = prog.findtext('title')
    info = MyHtmlStripper(prog.findtext('info')).value
    return dict(station=station, title=title, info=info)

# APIアクセスとStation選択をする    
def Create_RadioData(TEXT=None):
    url_radiko = "http://radiko.jp/v3/program/now/JP13.xml"
    res = requests.get(url_radiko)
    res.encoding = res.apparent_encoding
    root = ET.fromstring(res.text)
    stations = root[2]
    count = -1
    for child in stations:
        if not TEXT is None:
            if TEXT == child.get('id'):
                return Build_bangumiData(child)
        count += 1
    return Build_bangumiData(stations[random.randint(0, count)])

# レスポンス作成
def Build_Response(output):
    tmp = {
        'fulfillmentText': output
    }
    return tmp

# webhookの受信と送信.ここが一番長かった(マジ)
data = json.loads(open(os.environ['req'], encoding='utf-8').read())
returnData = intent_check(data["queryResult"])
response = codecs.open(os.environ['res'], 'w')
json.dump(returnData, response)
response.close()

おわり

Python3の日本語関連で詰まりすぎたので,次書く記事はそれにします......

参考文献

ありがとうございます.

Azure FunctionsでPython3とpipを使う - Qiita

python3でhtmlタグを除去 - Qiita

Dialogflow Fulfillment Webhook JSON Sample - Github

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1