Dialogflowは無償で使える枠も大きく、ちょっとチャットボットを試してみようという場合に使いやすいツールです。
私が講師を務めている研修でも、よくDialogflowを取り上げたりしています。
もちろん、開発のお仕事でも使っているのですが、ちょっとハマったことがあったので、それについて書いておこうと思います。
まずはDialogflowをPython SDKで使う
ハマった話の前に、DialogflowのPython SDKの基本的な使い方から。Dialogflowのエージェント作成と、GCPでのサービスアカウントの作成、JSONキーの作成までは完了した後から書きます。
そこまでについては、こちらにまとめてあります。
Python SDKのインストール
pipを使ってふつうにインストールします。Python3.6以上が必要です。
pip install google-cloud-dialogflow
JSONキーを使用したDialogflowへの接続
Dialogflowへの接続はちょっと面倒です。locationはglobalを指定していますが、他のロケーションを使っている場合は、ここで変更できます。
session_idは、会話を維持するものなので最初に採番(例えばUUIDで)して、以後は同じ値を持ち回ると良いでしょう。
from google.oauth2 import service_account
from google.cloud import dialogflow_v2 as dialogflow
import uuid
dialogflow_credential_path = 'JSONキーのパス'
with open(dialogflow_credential_path, 'r') as f:
service_account_info = json.load(f)
location = 'global'
session_id = uuid.uuid4()
credential = service_account.Credentials.from_service_account_info(service_account_info)
session_client = dialogflow.SessionsClient(credentials=credential, client_options={'api_endpoint': '%s-dialogflow.googleapis.com:443' % (location,)})
project_id = '%s/locations/%s' % (service_account_info['project_id'], location,)
session_path = session_client.session_path(project_id, session_id)
Dialogflowと会話
detect_intent()を使ってDialogflowと会話します。引数として質問文の文字列を使う場合はTextInput、インテントのイベント名を指定する場合はEventInputなどで使い分けます。
question = 'こんにちは'
query_input = dialogflow.QueryInput(text=dialogflow.TextInput(text=question, language_code='ja'))
response = session_client.detect_intent(session=session_path, query_input=query_input)
query_result = response.query_result
QueryResultをどう扱うか
さて、ここからが本題です。response.query_resultにDialogflowからの回答が入っているのですが、これは単純なJSONとかじゃなくて、google.cloud.dialogflow_v2.types.session.QueryResultというクラスのオブジェクトです。
このQueryResultクラスは、proto.message.Messageを継承しています。
Dialogflowでは(というかGoogle Cloudの各種サービスでは?)、Googleが開発したProtobufというシリアライズフォーマットを使っていて、どうやらPython SDKにおいては、Proto Plus for Pythonというラッパーを使用しているようです。(いまひとつ、説明しきれない・・・)
例えば、こういう内容のQueryResultが返ってきます。(加工しています。)
query_text: ""
action: "ccc"
parameters {
}
all_required_params_present: true
fulfillment_messages {
text {
text: ""
}
}
output_contexts {
name: "projects/aaa/locations/global/agent/sessions/bbb/contexts/ddd"
lifespan_count: 4
parameters {
}
}
output_contexts {
name: "projects/aaa/locations/global/agent/sessions/bbb/contexts/ccc"
lifespan_count: 1
parameters {
}
}
intent {
name: "projects/aaa/locations/global/agent/intents/bbb"
display_name: "ccc"
}
intent_detection_confidence: 1.0
language_code: "ja"
例えば、output_contextsはDialogflowでのコンテキストの中身で、次のリクエストで渡す必要のある値だったりするのですが、この値は、proto.marshal.collections.repeated.RepeatedCompositeクラスのオブジェクトだったりします。
これがJSONとかなら話は単純なのに・・・。
QueryResultをJSON化したい
QueryResultを、どうやってとっても扱いやすいJSONにするか。
回答は、下記のとおり。
from google.cloud.dialogflow_v2.types.session import QueryResult
QueryResult.to_json(query_result)
分かってしまえば簡単なんですけどね。この回答にたどり着くのに2〜3時間も費やしてしまった・・・。
dict化したい
Pythonのdictにすることもできます。
プログラムでいろいろいじるなら、こちらの方が良いでしょう。
from google.cloud.dialogflow_v2.types.session import QueryResult
QueryResult.to_dict(query_result)
ということで、この情報をズバリと書いているところはまだ見つからなかったので。
ご参考にしていただければ幸いです。