Dialogflowによる会議室検索チャットボットの簡単開発

フューチャー Advent Calendar 2019（2）の23日目です。

# はじめに

2019年4月に新卒入社しました。
約8ヶ月過ごして会議室の場所を調べるのに手間がかかるなと感じていました。
手間がかかる理由は以下です。

* 地図がない
* 会議室に部屋番号がついておらず固有名詞で呼ばれている
* イントラに会議室の場所が記載されているがモバイル端末からアクセスするにはユーザビリティの低い専用アプリが必要
* そもそもイントラに場所が記載されていない会議室もある

そこで会議室名を入力すると場所を教えてくれるチャットボットを開発しようと思いました。
弊社はG-Suiteを契約しているため[Hangouts Chat](https://gsuite.google.co.jp/intl/ja/products/chat/)をチャットアプリとして使用しています。Hangouts Chatでチャットボットを作成する方法はいくつかありますが今回は[Dialogflow](https://dialogflow.com/)というサービスを使用しました。
後ほど詳しく説明しますが以下のようなチャットボットが簡単に作成できます。

![Screenshot at Dec 22 17-21-21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519681/3e636d41-f18f-b532-aabf-b89033c9bb0a.png)

※ニュートン、オイラー、マクスウェルは架空の会議室名です

# Dialoflowとは？

ユーザ・サービス間の対話インターフェースを開発できるサービスです。
チャットボットや音声アシスタントがユーザの問いかけに対してどのように応答するのかをGUIベースで簡単に設定することができます。

# なぜDialogflow？

DialogflowはGoogleのマシンラーニングによる自然言語処理技術を活用しておりその利便性を体感してみたいなと思ったためです。他の方法と比較してDialogflowを選んだわけではありません。今回の機能であればGASでも実現できると思います。実際に使用してみてGASと比較したメリットは以下の2点と感じました。

* コーディング量が少ない
 * 自然言語処理に関する部分はGUIから設定できます
 * GUIの設定で実現できない箇所のみコードを書きました
* 様々なサービスと連携できるためDialogflowでBotを作成すれば再利用が可能
  * Google アシスタントといったGoogleのサービスはもちろんのこと以下のように多くのサービスとの連携機能を提供しています

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519681/d27b3a9e-388f-eb05-b530-d10675bc24f1.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519681/218ed7c0-c6de-ffd3-a95e-381c2791b138.png)

# 構成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519681/39036e0d-e95a-6e05-2322-f4217070acac.png)

Cloud Functions for Firebaseを利用する理由は、Dialogflowでは質問に含まれる会議室名に応じて会議室の場所を返すことができないためです。詳細は後述します。

# ボットの作成手順

DialogflowではAgentやEntity、Intentといったものを作成する必要があります。各概念の説明は[公式ドキュメント](https://cloud.google.com/dialogflow/docs/concepts)とQiita記事:[Dialogflow入門](https://qiita.com/kenz_firespeed/items/0979ceb05e4e3299f313)が参考になりました。
各概念の説明は少なめに手順を詳細に説明します。

## 前提

以下のような会議室が存在すると仮定します。(会議室の場所はより詳細に書いても良いと思います)

||会議室名|会議室の場所|
|:---:|:---:|:---:|
|1|ニュートン|3階の北側|
|2|オイラー|3階の東側|
|3|マクスウェル|3階の南側|

## Dialogflowのコンソールにアクセス

Dialogflowの設定はコンソールから行います。

* (i) [Dialogflow](https://dialogflow.com/)にアクセスします
* (ii) **Go to console**をクリックします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519681/255a71ee-6405-15ab-c221-707781c9cd94.png)

## Agentの作成

Agentはユーザの発言に応じて必要な処理を行い返答します。Agent単位でどんなサービスを提供するのか定義します。今回の場合でいえば、「ニュートンはどこ？」というユーザの発言から**ニュートン**という会議室の名前を特定し、ニュートンの場所を調べ、ニュートンの場所をユーザに返答します。

* (i) サイドメニューの**Create new agents**をクリックします
* (ii) **Agent name**の入力欄に`WhereIsRoom`と入力し**Default language**をJapaneseにします
* (iii) **Create**ボタンをクリックします

## Entityの作成

Entityはユーザの発言から何をパラメータとして取り出すのか定義します。今回の場合でいえば会議室の名前をパラメータとして取り出します。

* (i) サイドメニューの**Entites**をクリックします
* (ii) **Create Entity**ボタンをクリックします
* (iii) **Entity name**入力欄に`Room`と入力します
* (iv) **Click here to edit entry**をクリックし**Reference value**と**Synonym**を以下の表に従って入力します
  * Synonymにカタカナを入力したらひらがなや英語にも対応できるか試してみましたが駄目だったため、ひらがなと英語も入力しています

||Reference value|Synonym|
|---:|:---:|:---:|
|1|ニュートン|ニュートン、にゅーとん、newton|
|2|オイラー|オイラー、おいらー、euler|
|3|マクスウェル|マクスウェル、まくすうぇる、maxwell|


* (v) **Fuzzy mathcing**のチェックボックスをチェックします
  * ユーザがtypoした場合にも会議室名を正しく認識させることができます
      * 例えば、ニュートリ、newtomなどとtypoしてもニュートンという会議室名をユーザが意図して発言したと認識させることができます

* (vi) **Save**ボタンをクリックします

* Entityの設定画面は以下のとおりです

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519681/ce4b9f46-3f61-960b-2bb5-197643da3f15.png)

## Intentの作成

Intentでユーザの問いかけに対してどのような処理をするのか設定します。

* (i) サイドメニューの**Intents**をクリックします
* (ii) **Create intent**をクリックします
* (iii) **Intent name**入力欄に`Tell Room Location`と入力します
* (iv) 以下のように**Training phrases**を入力します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519681/242ef4c8-b2e9-f14a-c763-8162ab41f673.png)

* (v) **Fulfillment**セクションで**Enable webhook call for this intent**のトグルボタンをOnにします
  * Intentのレスポンス機能では1つの質問の意図(ここでは会議室の場所を知りたい)に対して複数のランダムなレスポンスしか設定できず、質問に含まれる会議室名に応じて場所を返すことができないためFulfillmentを利用します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519681/41de4f23-283f-bd55-f995-73544aaa9731.png)

## Fulfillmentの作成

Fulfillmentは外部のサービス(DBやAPI)を利用してユーザにレスポンスを返せるようにする機能です。
DialogflowではCloud Functions for Firebaseを利用して、外部サービスを提供するサーバを立てずともNode.js環境で処理を記述することができます。今回はこれを利用して会議室名に応じて場所を返却する処理を作成します。

* (i) サイドメニューの**Fulfillment**をクリックします
* (ii) **Inline Editor (Powered by Cloud Functions for Firebase)**のトグルボタンをOnにします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519681/d9d57c8f-774d-f562-aa52-7b8e9b1d9967.png)

* (iii) **index.js**に以下のコードを記述します
  * 会議室は何年かに一度増えるだけであるため会議室名と場所をコードに直接書いています

```js:index.js
// See https://github.com/dialogflow/dialogflow-fulfillment-nodejs
// for Dialogflow fulfillment library docs, samples, and to report issues
'use strict';
 
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card, Suggestion} = require('dialogflow-fulfillment');
const roomLocation = {
    "ニュートン": "3階の北側",
    "オイラー": "3階の南側",
    "マクスウェル": "3階の西側"
  };
 
process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements
 
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
  const agent = new WebhookClient({ request, response });
  console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
  console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
  
  function tellRoomLocation(agent) {
    agent.add(agent.parameters.Room + 'の場所は' + roomLocation[agent.parameters.Room] + 'です');
  }

  // Run the proper function handler based on the matched Dialogflow intent name
  let intentMap = new Map();
  intentMap.set('Tell Room Location', tellRoomLocation);
  agent.handleRequest(intentMap);
});
```

* (iv) **Deploy**ボタンをクリックします

## Hangouts Chatと統合

[公式ドキュメントの手順](https://cloud.google.com/dialogflow/docs/integrations/hangouts?hl=ja)を参考にしました。

* (i) サイドメニューの**Integration**をクリックします
* (ii) **Hangouts Chat**をクリックします
* (iii) 誰がボットをインストールできるようにするか選択し**Start**をクリックします

# ボットを使ってみる

## ボットの追加

* (i) [Hangouts Chat](https://chat.google.com/)にアクセスします
* (ii) ボットの検索欄に`WhereIsRoom`と入力しボットを追加します

## 会議室の場所を聞く

![Screenshot at Dec 22 17-21-21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519681/c381c626-588b-0a37-b89b-60f1974e1529.png)

typoにも対応できます。

![Screenshot at Dec 22 17-26-44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519681/a1253519-39c1-4c8a-624e-60a3c79d9ffc.png)

チャットルームにボットを追加すれば会議開催時にメンションしてメンバーに場所を知らせることができます。

![Screenshot at Dec 22 17-30-58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519681/8193a9f2-db5c-b817-37d8-e0e6f1bf6ba7.png)