こんにちは、AIチームの友松です。
この記事は以下の記事の続編となります。先にそちらをご覧いただいてから読むことをおすすめします。
- 【AI Shift Advent Calendar 2021】Dialogflow Essentialsの基本動作の解説
- Dialogflow Essentials コードを使った複雑なレスポンスの作成方法
- Dialogflow Essentials コードを使ったeventの制御
これまではDialogflowでの対話設計の方法について執筆しましたが、今回は作成したDialogflow Agentにリクエストをして、簡易なチャットボットを作成します。
1. 権限設定
Dialogflowを外部から呼び出すことができるようにするために権限設定を行います。
- Dialogflowの設定ページのProject IDの記載部分をクリックしGCPのプロジェクトページに移動

2. IAMと管理ページに移動

3. サービスアカウント作成ページよりサービスアカウントの作成を行う。

4. 作成したサービスアカウントの鍵を作成します。鍵を管理 -> 鍵を追加 -> 新しい鍵を追加 -> キーのタイプをJSONを選択 -> 作成 の手順で作成ができます。作成したjsonファイルを任意の場所に格納してください。

5. サービスアカウントへの権限設定
IAMのページに移動し、追加を選択します。

先程作成したサービスアカウントを入力し ロールとして Dialogflow APIクライアント
のロールを付与します。
2. Dialogflowの設定
前回の記事の対話をベースに拡張を行います。前回はユーザが予約希望として伝えた時間を営業時間判定をするところまで説明しましたが、一連の対話として対話が完結するまで対話シナリオを膨らませて、対話終了のIntentにend_conversationを設定し、対話の終了を区別できるように変更します。

2.1 Entityの設定
yes Entity

「はい」を拾うためのEntityを設定します。はいの言い換えとして考慮しうるものをsynonymに追加すると色々なパターンで拾うことができます。
no Entity

「いいえ」を拾うためのEntityを設定します。いいえの言い換えとして考慮しうるものをsynonymに追加すると色々なパターンで拾うことができます。
hour Entity

「時間」を拾うためのEntityを設定します。Regexp entityを選択肢、正規表現でパターンを記述します。
2.2 Intentの設定
Welcome Intent

- Input Context: 無し
- Output Context: Confirmation(lifespan=1)
- Training Phrase: こんちには
- Event: welcome
- Response:
- end_conversation:
- fulfillment:
Welcome Intentは前回までのものとほぼ同じ設定なのですが、追加事項としてEventでwelcomeを設定しています。これによって、テキストで「こんにちは」を拾う以外にもeventでこちらのIntentに遷移することができます。
チャットボット作成時、最初のフックとしてイベントを使うことでBotの発話を引っ張ることができます。
Request Reservation Hour Intent

- Input Context: Confirmation
- Output Context: 無し
- Training Phrase: <@hour> Entity
- Event: 無し
- Response: エラーが起きました
- end_conversation: off
- fulfillment: on
Webhook Callを呼び出すIntentになります。設定は前記事を全く同じになっています。
After Business Hour Intent

- Input Context: 無し
- Output Context: 無し
- Training Phrase: 無し
- Event: after_business_hours
- Response: $hour_int時ですね。こちらは営業時間外なので受付できません。ご利用ありがとうございました。
- end_conversation: on
- fulfillment: off
こちらのIntentは前回の差分としてResponse文言を若干変更、そして新たにend_conversationの設定をオンにしています。end_conversationをonにすると、そのIntentにたどり着いたときに会話の終了地点かどうかを受け取ることができます。
During Business Hour Intent

- Input Context: 無し
- Output Context: reservation(lifespan=1)
- Training Phrase: 無し
- Event: during_business_hours
- Response: $hour_int時ですね。こちらは営業時間内です。$hour_int時に予約をお取りしてもよろしいでしょうか?
- end_conversation: off
- fulfillment: off
こちらのIntentは前回の差分としてResponse文言を若干変更しています。こちらのIntentは後ろに対話が続くのでOutputContextを設定し、end_conversationはoffにします。
reservation_yes Entity

- Input Context: reservation
- Output Context: 無し
- Training Phrase: <@yes> Entity
- Response: 予約を受け付けました。ご利用ありがとうございました。
- end_conversation: on
- fulfillment: off
こちらのインテントは予約の実行有無を肯定した際に遷移するIntentです。end_conversationをonにします。
reservation_no Intent

- Input Context: reservation
- Output Context: 無し
- Training Phrase: <@no> Entity
- Response: 予約は行いませんでした。ご利用ありがとうございました。
- end_conversation: on
- fulfillment: off
こちらのインテントは予約の実行有無を否定した際に遷移するIntentです。end_conversationをonにします。
3 Webhookサーバーの実装(Cloud Function)
Webhookサーバーの実装も前回と全く同じです。詳しい説明はそちらに譲ります。
import json
import re
def main(request) -> str:
body = request.get_json() # Request Body
intent_name = body["queryResult"]["intent"]["displayName"]
if intent_name == "Request Reservation Hour Intent": # Enable webhook call for this intent.を指定したintent名
return fulfillment_request_reservation_hour(body)
else:
raise Exception
def fulfillment_request_reservation_hour(body):
session = body["session"] # sessionId
hour = body["queryResult"]["parameters"]["hour"] # ユーザー発話から抽出したhourパラメータ
hour_int = int(re.search(r'\d+', hour).group()) # ◯時の表現から数字部分を抜き出す
if hour_int >= 24:
raise Exception
elif 10 <= hour_int <= 19:
event_name = "during_business_hours"
else:
event_name = "after_business_hours"
res = {
"followupEventInput": {
"name": event_name
"parameters": {
"hour_int": hour_int
}
}
}
return json.dumps(res)
4. Pythonクライアントの作成
準備
$ pip install google-cloud-dialogflow
必要なライブラリのインストールを行います。
コードの実装
from google.cloud import dialogflow_v2 as dialogflow
import uuid
import os
# 1. 初期化処理ブロック
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "{YOUR CREDENTIAL FILE PATH}"
project = "{YOUR DIALOGFLOW PROJECT ID}"
session = str(uuid.uuid4())
session_client = dialogflow.SessionsClient()
session_path = session_client.session_path(project=project, session=session)
# Welcome発話処理ブロック
print("----チャット開始----")
# 最初のbot発話はEventInputを発火することで取得。
event = "welcome"
event_input = dialogflow.types.EventInput(
name=event,
language_code="ja-JP"
)
query_input = dialogflow.types.QueryInput(event=event_input)
response = session_client.detect_intent(
dialogflow.types.DetectIntentRequest(
query_input=query_input,
session=session_path
)
)
# 対話ブロック
# 会話終了フラグ(end_conversation)を検知するまでループする。
while True:
response_text = response.query_result\
.fulfillment_messages[0]\
.text.text[0]
print(f"Bot: \n{response_text}\n")
# 会話終了判定
end_conversation_flg = (
response.query_result.diagnostic_info is not None
and "end_conversation" in response.query_result.diagnostic_info
and response.query_result.diagnostic_info["end_conversation"]
)
if end_conversation_flg:
print("----チャット終了----")
break
print("User:")
user_text = input()
print("\n")
# 2回目以降のbot発話はuserからのTextInputをもとに取得。
text_input = dialogflow.types.TextInput(
text=user_text,
language_code="ja-JP"
)
query_input = dialogflow.types.QueryInput(text=text_input)
response = session_client.detect_intent(
dialogflow.types.DetectIntentRequest(
query_input=query_input,
session=session_path
)
)
実際にBotを作成します。
初期化ブロック
初期化ブロックでは、Dialogflowクライアントの初期化を行います。また第1章で作成したサービスアカウントのJSONのパスをGOOGLE_APPLICATION_CREDENTIALSの環境変数に設定します。
Welcome発話処理ブロック
Welcome発話処理ブロックでは、welcome Eventを発火することでWelcome IntentのResponseを引っ張ってきて会話を開始します。イベントの発火にはsession_client.detect_intentにEventInputを渡すことで実現できます。
対話ブロック
対話ブロックではend_conversationが発火するまで対話を継続するようなループを行います。ユーザの入力を標準入力から受け取り、session_client.detect_intentにTextInputを渡すことで実現できます。
5. 動作確認
実際にチャットボットが動作する様子を動画で示します。
営業時間 -> 予約実行 -> 対話終了
営業時間 -> 予約未実行 -> 対話終了
営業時間外 -> 対話終了
まとめ
今回は作成したDialogflow Agentにリクエストをして、簡易なチャットボットを作成する方法について執筆しました。今回は非常にシンプルな実装で行いましたが、こちらを拡張することでDialogflowを組み込んだ様々なチャットボットを作ることができます。簡単にできるのでぜひお試しください。