こんにちは、AIチームの友松です。
この記事は以下の記事の続編となります。先にそちらをご覧いただいてから読むことをおすすめします。
今回は、DialogflowのEventという機能を紹介します。
これまでの記事ではContextとTraining Phraseによる対話の制御について説明してきました。
Dialogflowの動作としてはユーザの発話を受け取ってContextとTraining Phraseによって遷移先の決定を行い、ボットの発話を返却するというのが1回のリクエストの中で行われる内容です。
Eventを使うと、ユーザの発話を待たずしてeventを待ち受けているIntentへと遷移し、その遷移先のIntentの中身の発話を返すことができます。
つまり、1度のリクエストで2つのIntentを処理することができます。
Eventを発火するIntentではbotの発話を返さず、eventのみを返し、botの発話はeventによる遷移先のIntentで返すことになります。
まずは簡単なeventによる制御を作ってみます。
Fulfillmentにおいてeventを使うメリットは3点挙げられます。
まず1点目のポイントは、Output ContextとTraining Phraseによって複雑に遷移を制御していた部分が、eventによって簡潔に記述できるため、全体の設定や実装がシンプルになります。
2点目のポイントはコード側にbotのレスポンス文を記載する必要がないため、運用していく中で文言変更が必要になった際にコード側を変更することなくDialogflow側の変更のみで完結します。これはDialogflowの設計者とコードの実装者が異なる場合に非常に大きなメリットとなります。
3点目はend_conversationのフラグについてです。各IntentではSet this intent as end of conversation
という設定項目があります。これは対話の終端地点を示すフラグになっているのですが、Fulfillmentで遷移によってend of conversationをtrueにすべき場合とfalseにすべき場合が分岐する場合にContext+Training Phraseベースでやろうとした場合、各Intentで一つの値しかend of conversationの値を設定できないため、eventで遷移した先でそれぞれend of conversationを設定することでこちらを回避することができます。
前回の記事で紹介したWebhook Call+Contextによる営業時間の制御(図1)をEventに変えたパターン(図2)に変更したものを作成してみます。
ユーザーが発話した時間を捉えるエンティティとしてhourエンティティを正規表現のカスタムエンティティとして作成します。こちらは前記事と全く同じ設定となっています。
※今回は簡単化のために、0-23時以外の時間が発話されるケースは考慮しないものとします。
※また、システムエンティティで日時を扱えるものもありますがこちらも簡単化のために使用しません。
Welcome Intentは前回の記事と全く同じ設定です。
Request Reservation Hour Intentも前回の記事と全く同じ設定です。
このIntentに来るとWebhook宛にリクエストをし、コードによる制御を行います。コード部分は後ほど解説します。
こちらのIntentはeventを受け取って遷移するIntentです。そのため、Input ContextおよびTraining Phraseは無しになっています。Output Contextは後続の処理に応じて適切に付与してください。今回は簡単化のために無しとしています。
eventの設定には、eventという項目に文字列でキャッチするeventを指定するだけです。
eventにはparameterを含ませることができて、受け取ったparameterを$で指定することによってレスポンスに含めることができます。
こちらのIntentは一つ前のIntentのEventとResponseのみを変更したものになっています。
Webhookサーバーの実装も前回の記事をベースに変更を行っています。
import jsonimport redef 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 Exceptiondef 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)
変更点は21行目以降となり、コードはシンプルになっています。基本的な実装の解説は前記事に譲るとして変更点の差分のみ示します。
想定したとおりの分岐とレスポンスの挙動を確認することができました。
今回はDialogflow Essentialsにおけるコードを使ったeventの制御について解説しました。過去3回で紹介した内容によってDialogflow Essentialsの大枠の制御は可能になります。次回はclientからDialogflowを参照してチャットボットの実装を行う方法について解説します。
最後までご覧いただきありがとうございました。