Google Home 連携でタスク登録 & 確認をしてみよう!

著者名:三宅 智子(サイボウズ)

目次

caution
警告

記事内で利用しているライブラリ「 request (External link) 」は、非推奨(deprecated)になりました。
HTTP リクエストができる他のライブラリ( axios (External link) など)や、 https.requst (External link) に書き換えることをおすすめします。

概要

皆さんこんにちは!
価格もお手軽なスマートスピーカーということで人気の Google Home (External link)
今回は kintone と連携してタスク登録と今日締め切りのタスク確認をします。
工夫するといろんなパターンの会話を作ることができますが、ここでは基本的な作り方を解説するためにシンプルな例で紹介したいと思います。
このサンプルコードは、Node.js でのコーディングを含みます。

シナリオ

大まかなシナリオは、以下の 2 つです。

  • タスク登録
  • 今日締切のタスク確認

Actions on googleとは

Google Assistant 用のアプリケーションを作成するためのプラットフォームです。
Google Assistant に独自のサービスを追加したり、Google Home と会話するためのアプリケーションを作成したりできます。
また、細かい会話ロジックの作成は、Dialogflow/Smart home/Actions SDK/Converse.AI のいずれかを選択して行います。
Converse AI は日本語での対話に対応していないので、ご注意ください。
詳細は公式サイト Google Assistant (External link) を確認してください。

Dialogflowとは

自然言語の対話プラットフォームです。
Google Assistant 上で、シンプルな会話ロジックを作成するためのアプリケーションです。
ちなみに Google Assistant 以外でのロジック作成にも使うことが可能です。
また、Webhook も利用できます。
詳細は Dialogflow ドキュメント (External link) を確認してください。

Firebaseとは

MBaas(モバイル Backend as a Service)と呼ばれるクラウドデータベースサービスです。
今回は Dialogflow 内でのスクリプト置き場 & 実行環境として利用しています。
まだβ版な点に注意して利用してください。

  • 公式サイト (External link)
  • 料金体系 (External link)
    今回は Firebase の Cloud Functions を利用します。
    Google 関連以外の API リクエストをする場合は、無料の Spark プランでは対応していないので、Flame や Blaze プランにアップグレードする必要があります。
    Flame や Blaze プランでも、無料で使える枠はあります。

完成イメージ

諸々の設定が完了して Google Home に話しかけてみると、以下のようなやりとりができます。
Actions on Google の Simulator で実行しています。(正式なアプリとしては公開していません)

会話の流れ

会話の詳細な流れは以下になります。
タスク追加や今日締切のタスク取得のところで、kintone へ HTTP Request をしています。

手順概要

Google Home 連携には各サービスでいくつか細かい設定が必要になります。
今回は以下の順番で設定します。

  1. kintone でのアプリ作成
  2. Google Home アプリのインストールと設定
  3. Actions on Google の設定
  4. Dialogflow の設定

下準備

  • kintone 環境
    kintone アカウントを持っていない方は、 1 年間無料の「 開発者ライセンス」を利用してください。
  • Google アカウント
  • Firebase Flame や Blaze プラン
caution
警告

Free プランだと kintone への HTTP Request ができません。
Firebase Flame や Blaze プランは、クレジットカードの登録が必要、かつ利用量によって料金が発生するので、ご利用の際はご注意ください。

kintoneのアプリ作成

タスクを登録 & 確認するための kintone アプリを作成します。

  1. kintone にログイン後、アプリストアから「To Do」アプリを追加します。
    アプリの追加方法はヘルプサイトの サンプルアプリを追加する (External link) を参照してください。

  2. 追加したアプリ内で以下のフィールド名とフィールドコードが存在することを確認してください。

    フィールドタイプ フィールド名 フィールドコード
    日付 締切日 Duedate
    文字列(1行) ToDo名 To_Do
  3. アプリ ID をメモしておいてください。
    のちほどコード内で指定します。
    例)https://{subdomain}.cybozu.com/k/xxx/ ←アプリIDはxxxの部分の数字です。

  4. API トークンを生成してください。
    アクセス権は、「レコード閲覧」と「レコード追加」にチェックを入れます。
    こちらものちほどコード内で指定するので、メモしておいてください。
    API トークンの生成方法は、 APIトークンを生成する (External link) を参照してください。

これにて kintone の設定は完了です。

Google Home アプリのインストールと設定

次は、Google Home を使うための初期設定です。

  1. 電源ケーブルを Google Home に差し込むます。
  2. 電源アダプターをコンセントに差し込みます。
  3. モバイルやタブレットで Google Home アプリをダウンロードして実行します。

Google 公式サイト (External link) やレビューサイトにも手順が載っているので、参考にしながら進めてください。
アプリで 言語設定を日本語へ変更 (External link) するのを忘れないようにしてください。

Actions on Googleの設定

続いて、Google Assistant 用のアプリケーションを作成します。
基本英語ドキュメントしかないのですが、日本語訳されている方がいるので、 Actions on Googleの開発者向けドキュメントの日本語訳リスト (External link) を私は活用させていただきました!

  1. Actions on Google の設定の前に、利用する Google アカウントで Google Home を利用するための設定を 1 つ行います。
    Googleアカウントのアクティビティ管理サイト (External link) にアクセスして、以下の項目を有効にしてください。

    • Web とアプリのアクティビティ(その下のチェックボックスにもチェックを入れる)
    • 音声アクティビティ
  2. Actions on Googleのサイト (External link) にアクセスします。

  3. Google アカウントにログインしていない場合は、Google Home と紐付けた Google アカウントでログインします。

  4. 「ACTIONS CONSOLE」ボタンをクリックします。

  5. 新規にプロジェクトを作成するので「Add/ import project」をクリックします。
    右上の赤枠のアイコンを見て、別の Google アカウントにログインされている場合は、アイコンをクリックしてアカウントを切り替えてください。

  6. 「Project name」と「Country/region」をそれぞれ以下に設定して、「CREATE PROJECT」ボタンをクリックします。

  7. Overview の画面に遷移するので、会話ロジック作成に利用する「Dialogflow」のボックス右下の「BUILD」をクリックします。

  8. 「CREATE ACTIONS ON DIALOGFLOW」ボタンをクリックして、Dialogflow の画面に移動します。

Dialogflowの設定

Actions on Google から Dialogflow アカウントが自動生成されて、以下の画面に移動するかと思います。
こちらで会話の詳細なロジックを組み立ていきます。

まず、Dialogflow を設定していく上でよく出てくる 2 つの言葉の意味を紹介します。

  • Intents:会話のブロックを作成する項目です。
  • Fulfillment:Webhook や Firebase の Inline Editor を使える項目です。
    ここで Node.js を記述して、kintone に HTTP Request をします。

これらを頭に置いた上で、設定していきましょう。

  1. プロジェクトの初期設定をします。
    「DEFAULT LANGUAGE」欄で、「Japanese - ja」を選択して、「CREATE」ボタンをクリックしてください。

  2. Intents の作成画面に移動します。
    デフォルトで、「Default Fallback Intent」(エラーなどが起きた時の処理)と「Default Welcome Intent」(会話のきっかけ処理)が設置されているので、これはこのまま利用します。
    この後はここに必要な Intent を増やしていく流れになります。

  3. まずは Google Home との会話のきっかけとなる「Default Welcome Intent」を編集するので、クリックしてください。

    以下の図に沿ってユーザーが何といったいった時に、どう答えるのかを指定します。
    入力できたら上の「SAVE」ボタンをクリックして設定を保存してください。

    User says Text Response
    こんにちは こんにちは!kintoneに登録したいタスクを話しかけてください。
    また「タスクを確認」と話しかけると、今日締切のタスクをお伝えします。
  4. お気付きの方もいらっしゃると思いますが、Intent を設定している右側に「Test Console」があります。
    いったん会話のきっかけがちゃんとできているかどうか確かめてみましょう!
    ダイアログボックスに「こんにちは」と入力してみてください。
    レスポンスに指定した値が入ってくれば成功です。
    このまま続けて設定していきましょう。

  5. 次に、左メニューの「Fulfillment」をクリックしてください。
    「Webhook」と「Inline Editor」の 2 つの選択肢が出てきますが、今回は Firebase にコードを置くので Inline Editor の方を「ENABLED」にします。
    Editor 下の「DEPLOY」ボタンを押して「View execution logs in the Firebase console」という文言が表示されるまで待ちます。(デプロイ自体に数分かかる場合があります)
    これで Intent をコード内で指定して操作できます。
    今はコードの編集は必要ありません。
    そのまま DEPLOY ボタンをクリックしてください。
    AWS の Lambda & API Gateway/Zapier/Microsoft Flow などで Webhook を生成した場合は、Webhook URL に設定することで開発可能です。

  6. 左メニューより「Intents」に戻ります。

  7. 「CREATE INTENT」ボタンをクリックして、新規にタスク登録用の Intent を追加します。

  8. 下図に沿って Intent の詳細設定をします。
    設定できたら「SAVE」ボタンをクリックしてください。
    「〇〇を追加」という合言葉で新規に kintone にタスクを登録できます。
    さらに質問に続けてタスクの締切日を答えると、それも併せてレコードに登録されます。

    Intent name User says Action Fulfillment
    AddTask タスクを追加
    (タスクをクリックして、@sys.anyを選択)
    input.task
    (パラメーターもtaskとdateを上図のとおり設定)
    Use webhookにチェック
    (コード内で操作を制御するため)
  9. 次に、今日締切のタスクを確認するための Intent を作成します。
    先ほどと同様に「CREATE INTENT」ボタンをクリックして、下図のとおり設定して、「SAVE」ボタンをクリックしてください。

    Intent name User says Action Fulfillment
    CheckTask
    • タスクを確認
    • タスクの確認
    • 今日のタスクは?
    • 本日のタスク
    • 今日締切のタスクは?
    • 締切のタスクは?
    check.task Use webhookにチェック
    (コード内で操作を制御するため)
  10. あとは会話の終わりを定義して Intent の設定は完了です。
    「CREATE INTENT」より以下のとおり設定して、「SAVE」ボタンをクリックします。

    Intent name User says Action Text response Google Assistant
    EndConversation
    • 終わり
    • またね
    • バイバイ
    • ありがとう
    end.conversation ありがとうございました!またね End conversationにチェック
    (会話の最後のため)
  11. これで Intent の設定がすべて完了したので、左メニューより Fulfillment にアクセスし、Inline Editor の「index.js」に kintone へ HTTP リクエストをするためのコードを記述します。
    コード部分は Dialogflow の Fulfillment にあらかじめ記載されているサンプルコードを一部そのまま利用しています。
    コード内の最初の方に kintone アプリの次の情報を記述している箇所があるので、それぞれの環境に合わせた内容に変更してください。

    • appId
    • token
    • domain

      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    
    /*
    * Google Home sample program
    * Copyright (c) 2018 Cybozu
    *
    * Licensed under the MIT License
    */
    
    (() => {
      'use strict';
    
      // Cloud Functions for Firebaseライブラリ
      const functions = require('firebase-functions');
    
      // Google Assistant helperライブラリ
      const DialogflowApp = require('actions-on-google').DialogflowApp;
      const googleAssistantRequest = 'google';
    
      // HTTP Request用モジュール
      const req = require('request');
    
      // kintoneアプリ情報(要編集)
      const subdomain = '<サブドメイン名(〇〇.cybozu.comの〇〇の部分)>';
      const appId = '<アプリID>';
      const token = '<APIトークン>';
    
      // kintoneへのタスク登録 & 確認関数
      const addTask = (request, response) => {
    
        let action = request.body.result.action;
        const parameters = request.body.result.parameters;
        const requestSource = (request.body.originalRequest) ? request.body.originalRequest.source : undefined;
        const app = new DialogflowApp({request: request, response: response});
    
        // Dialogflow送信用のGoogle Assistant Response作成関数
        const sendGoogleResponse = (responseToUser) => {
          if (typeof responseToUser === 'string') {
            app.ask(responseToUser);
          } else {
            let googleResponse = app.buildRichResponse().addSimpleResponse({
              speech: responseToUser.speech || responseToUser.displayText,
              displayText: responseToUser.displayText || responseToUser.speech
            });
    
            if (responseToUser.googleRichResponse) {
              googleResponse = responseToUser.googleRichResponse;
            }
    
            if (responseToUser.googleOutputContexts) {
              app.setContext(...responseToUser.googleOutputContexts);
            }
    
            // DialogflowとGoogle Assistantへのレスポンス送信
            app.ask(googleResponse);
          }
        };
    
        // Dialogflow送信用のResponse作成関数
        const sendResponse = (responseToUser) => {
          // もしレスポンスが文字列の場合、そのままユーザーへのレスポンスとして送信
          if (typeof responseToUser === 'string') {
            const responseJson = {};
            responseJson.speech = responseToUser;
            responseJson.displayText = responseToUser;
            // Dialogflowにレスポンス送信
            response.json(responseJson);
          } else {
            // もしレスポンスにリッチレスポンスや文章が含まれていた場合、それをDialogflowに送信
            const responseJson = {};
    
            responseJson.speech = responseToUser.speech || responseToUser.displayText;
            responseJson.displayText = responseToUser.displayText || responseToUser.speech;
            responseJson.data = responseToUser.richResponses;
            responseJson.contextOut = responseToUser.outputContexts;
    
            // Dialogflowへのレスポンス送信
            response.json(responseJson);
          }
        };
    
        // Intentごとの実行処理
        const actionHandlers = {
          // AddTask Intent発生時の処理
          'input.task': () => {
            // HTTPリクエストヘッダー
            const headers = {
              'Content-Type': 'application/json',
              'X-Cybozu-API-Token': token
            };
    
            // HTTPリクエストボディ
            const form = {
              app: appId,
              record: {
                To_Do: {
                  value: parameters.task
                },
                Duedate: {
                  value: parameters.date
                }
              }
            };
    
            const options = {
              url: 'https://' + subdomain + '.cybozu.com/k/v1/record.json',
              method: 'POST',
              headers: headers,
              json: form
            };
    
            // HTTPのPOSTリクエスト
            req(options, (error, resp, body) => {
              if (body) {
                const responseToUser = {
                  speech: '締切日' + parameters.date + 'でkintoneに' + parameters.task + 'を登録しました',
                  text: '締切日' + parameters.date + 'でkintoneに' + parameters.task + 'を登録しました'
                };
                sendResponse(responseToUser);
              } else if (error) {
                const responseToUser = {
                  speech: 'エラーが発生しました。コンソールをご確認ください',
                  text: 'エラーが発生しました。コンソールをご確認ください'
                };
                sendResponse(responseToUser);
              }
            });
          },
    
          // CheckTask Intent発生時の処理
          'check.task': () => {
            // HTTPリクエストヘッダー
            const headers = {
              'Content-Type': 'application/json',
              'X-Cybozu-API-Token': token
            };
    
            // HTTPリクエストボディ
            const form = {
              app: appId,
              query: 'Duedate = TODAY()',
              fields: ['To_Do']
            };
    
            const options = {
              url: 'https://' + subdomain + '.cybozu.com/k/v1/records.json',
              method: 'GET',
              headers: headers,
              json: form
            };
    
            // HTTPのGETリクエスト
            req(options, (error, resp, body) => {
              if (body) {
                const tasks = body.records.map((record) => {
                  return record.To_Do.value;
                });
                let responseToUser;
                if (tasks.length === 0) {
                  responseToUser = {
                    speech: '今日締切のタスクはありません',
                    text: '今日締切のタスクはありません'
                  };
                } else if (tasks.length > 0) {
                  responseToUser = {
                    speech: '今日締切のタスクは' + tasks + 'です',
                    text: '今日締切のタスクは' + tasks + 'です'
                  };
                }
                sendResponse(responseToUser);
              } else if (error) {
                const responseToUser = {
                  speech: 'エラーが発生しました。コンソールをご確認ください',
                  text: 'エラーが発生しました。コンソールをご確認ください'
                };
                sendResponse(responseToUser);
              }
            });
          },
    
          // 上記以外のIntent発生時の処理
          default: () => {
            // Googleリクエスト応答用にActions on Googleライブラリを利用
            if (requestSource === googleAssistantRequest) {
              const responseToUser = {
                speech: 'これはDialogflowからのメッセージです',
                text: 'これはDialogflowからのメッセージです'
              };
              sendGoogleResponse(responseToUser);
            } else {
              const responseToUser = {
                speech: 'これはDialogflowからのメッセージです',
                text: 'これはDialogflowからのメッセージです'
              };
              sendResponse(responseToUser);
            }
          }
        };
    
        if (!actionHandlers[action]) {
          action = 'default';
        }
        actionHandlers[action]();
      };
    
      // 実行関数
      exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
        // デバッグ用コード
        console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
        console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
    
        if (request.body.result) {
          addTask(request, response);
        } else {
          return response.status(400).end('不正なWebhookのリクエストです。v1かv2のWebhookリクエストを利用してください。');
        }
      });
    })();
  12. Inline Editor の「package.json」に以下を記述します。
    デフォルトの package.json に HTTP Request で利用する request モジュールを追記しています。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
    {
      "name": "dialogflowFirebaseFulfillment",
      "description": "This is the default fulfillment for a Dialogflow agents using Cloud Functions for Firebase",
      "version": "0.0.1",
      "private": true,
      "license": "Apache Version 2.0",
      "author": "Google Inc.",
      "engines": {
        "node": "~6.0"
      },
      "scripts": {
        "start": "firebase serve --only functions:dialogflowFirebaseFulfillment",
        "deploy": "firebase deploy --only functions:dialogflowFirebaseFulfillment"
      },
      "dependencies": {
        "actions-on-google": "^1.5.x",
        "firebase-admin": "^4.2.1",
        "firebase-functions": "^0.5.7",
        "apiai": "^4.0.3",
        "request": "2.83.0"
      }
    }
  13. 「DEPLOY」ボタンをクリックします。
    下図のとおり、「View execution logs in the Firebase console」とログが出力されれば成功です。

  14. 実際に HTTP Request が成功するか「Test Console」で会話をして試してみてください。
    kintone アプリ側にレコードが登録されたら OK です。

  15. また「Inline Editor」下の「View execution logs in the Firebase console」のリンクをクリックしてください。
    Firebase の画面に遷移してログを見ることができるようになっているので、そちらも確認しておきましょう。
    デバッグする時に活用できます。

  16. ひとまずこれにて設定完了です。

動作確認

あとは Actions on Google の画面に戻って音声でのテストをしてみましょう!
実際に Google Home を使っても OK です。

  1. 作成したプロジェクトの Overview 画面から「TEST DRAFT」をクリックして、Simulator を立ち上げます。

  2. Surface を「Speaker」に、Language を「Japanese - ja」に設定して、左側の入力ダイアログにてテストを行います。
    テスト用の Simulator なので、会話のきっかけとして設定した「こんにちは」の代わりに、合言葉として必ず「テスト用アプリにつないで」という呼びかけが必要になります。
    上記画像の「Overview > App Information > Edit > Detail > Sample invocations」箇所を設定することで「テスト用アプリにつないで」以外のきっかけで動作させることもできますが、ここでは割愛します。
    Google Home の実機でテストする場合は、「OK, google テスト用アプリにつないで」と呼びかけてください。

  3. 会話をすると以下のようになります。
    Google Home でも試してみてください。

  4. 念のため kintone にも無事レコードが登録されていることを確認します。

実際に運用するアプリケーションとして公開する場合は、Actions on Google 画面( 本Tipsの動作確認 > 手順1の箇所)で追加情報を記載して、審査を通す必要があります。
詳細については Prepare to release your Action (External link) を参照してください。

サンプルコードの解説

途中で出てきた Node.js の実装ポイントを少し解説します。
今回は Dialogflow V1 API を利用しています。

大まかな流れだけ抜き出すと以下のようになります。

  1. ライブラリやモジュールのインストール
  2. addTask 関数を定義して、その中でレスポンスの形式を定義 & kintone への HTTP Request を送信
  3. 実行関数を定義
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
(() => {
  'use strict';

  // ライブラリやモジュールのインストール
  const functions = require('firebase-functions');
  const DialogflowApp = require('actions-on-google').DialogflowApp;
  const googleAssistantRequest = 'google';
  const req = require('request');

  // /// 中略 /////

  // kintoneへのタスク登録 & 確認関数
  const addTask = (request, response) => {

    let action = request.body.result.action;
    const parameters = request.body.result.parameters;
    const requestSource = (request.body.originalRequest) ? request.body.originalRequest.source : undefined;
    const app = new DialogflowApp({request: request, response: response});

    // Dialogflow送信用のGoogle Assistant Response作成関数
    const sendGoogleResponse = (responseToUser) => {
      // /// 中略 /////
    };

    // Dialogflow送信用のResponse作成関数
    const sendResponse = (responseToUser) => {
      // /// 中略 /////
    };

    // Intentごとの実行処理
    const actionHandlers = {
      // AddTask Intent発生時の処理
      'input.task': () => {
        // /// 中略 /////

        // HTTPのPOSTリクエスト
        req(options, (error, resp, body) => {
          if (body) {
            const responseToUser = {
              speech: '締切日' + parameters.date + 'でkintoneに' + parameters.task + 'を登録しました',
              text: '締切日' + parameters.date + 'でkintoneに' + parameters.task + 'を登録しました'
            };
            sendResponse(responseToUser);
          } else if (error) {
            const responseToUser = {
              speech: 'エラーが発生しました。コンソールをご確認ください',
              text: 'エラーが発生しました。コンソールをご確認ください'
            };
            sendResponse(responseToUser);
          }
        });
      },

      // CheckTask Intent発生時の処理
      'check.task': () => {
        // /// 中略 /////

        // HTTPのGETリクエスト
        req(options, (error, resp, body) => {
          if (body) {
            const tasks = body.records.map((record) => {
              return record.To_Do.value;
            });
            let responseToUser;
            if (tasks.length === 0) {
              responseToUser = {
                speech: '今日締切のタスクはありません',
                text: '今日締切のタスクはありません'
              };
            } else if (tasks.length > 0) {
              responseToUser = {
                speech: '今日締切のタスクは' + tasks + 'です',
                text: '今日締切のタスクは' + tasks + 'です'
              };
            }
            sendResponse(responseToUser);
          } else if (error) {
            const responseToUser = {
              speech: 'エラーが発生しました。コンソールをご確認ください',
              text: 'エラーが発生しました。コンソールをご確認ください'
            };
            sendResponse(responseToUser);
          }
        });
      },

      // 上記以外のIntent発生時の処理
      default: () => {
        // /// 中略 /////
      }
    };

    if (!actionHandlers[action]) {
      action = 'default';
    }
    actionHandlers[action]();
  };

  // 実行関数
  exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
    // /// 中略 /////
    if (request.body.result) {
      addTask(request, response);
    } else {
      return response.status(400).end('不正なWebhookのリクエストです。v1かv2のWebhookリクエストを利用してください。');
    }
  });
})();

その他注意ポイントは以下です。

  • 実行関数名は、必ず「dialogflowFirebaseFulfillment」にする。
  • Google Assistant からのレスポンスにはさまざまな形式があるので、それをうまく変換する関数を用意する。
  • actionHandlers 内で、作成した Intent ごとの処理を記載する。
  • 指定した Intent 以外が発生した場合は、default Intent に誘導する。

注意事項

  • Dialogflow V2 API も利用可能ですが、本 Tips では V1 API を利用しているので、API VERSION を変更すると動作しない場合があります。
  • Firebase はβ版なので、ご利用の際にはご注意ください。
  • 今回の Google Home 連携は Dialogflow の「Test console」と Actions on Google の「Simulator」でのみ利用できます。
    アプリを公開する際は、別途手続きが必要ですので、ドキュメントを確認してください。
  • 英語のみの対応でよい場合は、Dialogflow ではなく、Converse AI を選択すると、GUI のみで簡単に設定できます。
    HTTP Request 部分もほとんどコードを書かずに済みます
  • kintone の Basic 認証も設定している場合は、認証情報を追記してください。

おわりに

無事 Google Home と会話をしてタスクの登録 & 確認ができましたでしょうか?
今回はシンプルな構成でしたが、工夫の幅は無限大です。
ぜひスマートスピーカーのメリットを活かした使い方を考えて、開発してみてください。
設定項目も多いので、最初は扱うのがたいへんですが、慣れれば楽しく連携できます!

information

この Tips は、2018 年 1 月版 kintone で動作を確認しています。