Google Home連携でタスク登録 & 確認をしてみよう!
警告
記事内で利用しているライブラリ「
request
」は、非推奨(deprecated)になりました。
HTTPリクエストができる他のライブラリ(
axios
など)や、
https.requst
に書き換えることをおすすめします。
概要
皆さんこんにちは!
価格もお手軽なスマートスピーカーということで人気の
Google Home
。
今回はkintoneと連携してタスク登録と今日締め切りのタスク確認をします。
工夫するといろんなパターンの会話を作ることができますが、ここでは基本的な作り方を解説するためにシンプルな例で紹介したいと思います。
このサンプルコードは、Node.jsでのコーディングを含みます。
シナリオ
大まかなシナリオは、以下の2つです。
- タスク登録
- 今日締切のタスク確認
Actions on googleとは
Google Assistant用のアプリケーションを作成するためのプラットフォームです。
Google Assistantに独自のサービスを追加したり、Google Homeと会話するためのアプリケーションを作成したりできます。
また、細かい会話ロジックの作成は、Dialogflow/Smart home/Actions SDK/Converse.AIのいずれかを選択して行います。
Converse AIは日本語での対話に対応していないので、ご注意ください。
詳細は公式サイト
Google Assistant
を確認してください。
Dialogflowとは
自然言語の対話プラットフォームです。
Google Assistant上で、シンプルな会話ロジックを作成するためのアプリケーションです。
ちなみにGoogle Assistant以外でのロジック作成にも使うことが可能です。
また、Webhookも利用できます。
詳細は
Dialogflowドキュメント
を確認してください。
Firebaseとは
MBaas(モバイルBackend as a Service)と呼ばれるクラウドデータベースサービスです。
今回はDialogflow内でのスクリプト置き場 & 実行環境として利用しています。
まだβ版な点に注意して利用してください。
- 公式サイト
-
料金体系
今回はFirebaseのCloud Functionsを利用します。
Google関連以外のAPIリクエストをする場合は、無料のSparkプランでは対応していないので、FlameやBlazeプランにアップグレードする必要があります。
FlameやBlazeプランでも、無料で使える枠はあります。
完成イメージ
諸々の設定が完了してGoogle Homeに話しかけてみると、以下のようなやりとりができます。
Actions on GoogleのSimulatorで実行しています。(正式なアプリとしては公開していません)
会話の流れ
会話の詳細な流れは以下になります。
タスク追加や今日締切のタスク取得のところで、kintoneへHTTP Requestをしています。
手順概要
Google Home連携には各サービスでいくつか細かい設定が必要になります。
今回は以下の順番で設定します。
- kintoneでのアプリ作成
- Google Homeアプリのインストールと設定
- Actions on Googleの設定
- Dialogflowの設定
下準備
- kintone環境
kintoneアカウントを持っていない方は、1年間無料の「 開発者ライセンス 」を利用してください。 - Googleアカウント
- Firebase FlameやBlazeプラン
警告
FreeプランだとkintoneへのHTTP Requestができません。
Firebase FlameやBlazeプランは、クレジットカードの登録が必要、かつ利用量によって料金が発生するので、ご利用の際はご注意ください。
kintoneのアプリ作成
タスクを登録 & 確認するためのkintoneアプリを作成します。
-
kintoneにログイン後、アプリストアから「To Do」アプリを追加します。
アプリの追加方法はヘルプサイトの サンプルアプリを追加する を参照してください。 -
追加したアプリ内で以下のフィールド名とフィールドコードが存在することを確認してください。
フィールドタイプ フィールド名 フィールドコード 日付 締切日 Duedate 文字列(1行) ToDo名 To_Do -
アプリIDをメモしておいてください。
のちほどコード内で指定します。
例)https://{subdomain}.cybozu.com/k/xxx/ ←アプリIDはxxxの部分の数字です。 -
APIトークンを生成してください。
アクセス権は、「レコード閲覧」と「レコード追加」にチェックを入れます。
こちらものちほどコード内で指定するので、メモしておいてください。
APIトークンの生成方法は、 APIトークンを生成する を参照してください。
これにてkintoneの設定は完了です。
Google Homeアプリのインストールと設定
次は、Google Homeを使うための初期設定です。
- 電源ケーブルをGoogle Homeに差し込むます。
- 電源アダプターをコンセントに差し込みます。
- モバイルやタブレットでGoogle Homeアプリをダウンロードして実行します。
Google公式サイト
やレビューサイトにも手順が載っているので、参考にしながら進めてください。
アプリで
言語設定を日本語へ変更
するのを忘れないようにしてください。
Actions on Googleの設定
続いて、Google Assistant用のアプリケーションを作成します。
基本英語ドキュメントしかないのですが、日本語訳されている方がいるので、
Actions on Googleの開発者向けドキュメントの日本語訳リスト
を私は活用させていただきました!
-
Actions on Googleの設定の前に、利用するGoogleアカウントでGoogle Homeを利用するための設定を1つ行います。
Googleアカウントのアクティビティ管理サイト にアクセスして、以下の項目を有効にしてください。- Webとアプリのアクティビティ(その下のチェックボックスにもチェックを入れる)
- 音声アクティビティ
-
Actions on Googleのサイト にアクセスします。
-
Googleアカウントにログインしていない場合は、Google Homeと紐付けたGoogleアカウントでログインします。
-
「ACTIONS CONSOLE」ボタンをクリックします。
-
新規にプロジェクトを作成するので「Add/ import project」をクリックします。
右上の赤枠のアイコンを見て、別のGoogleアカウントにログインされている場合は、アイコンをクリックしてアカウントを切り替えてください。 -
「Project name」と「Country/region」をそれぞれ以下に設定して、「CREATE PROJECT」ボタンをクリックします。
-
Overviewの画面に遷移するので、会話ロジック作成に利用する「Dialogflow」のボックス右下の「BUILD」をクリックします。
-
「CREATE ACTIONS ON DIALOGFLOW」ボタンをクリックして、Dialogflowの画面に移動します。
Dialogflowの設定
Actions on GoogleからDialogflowアカウントが自動生成されて、以下の画面に移動するかと思います。
こちらで会話の詳細なロジックを組み立ていきます。
まず、Dialogflowを設定していく上でよく出てくる2つの言葉の意味を紹介します。
- Intents:会話のブロックを作成する項目です。
- Fulfillment:WebhookやFirebaseのInline Editorを使える項目です。
ここでNode.jsを記述して、kintoneにHTTP Requestをします。
これらを頭に置いた上で、設定していきましょう。
-
プロジェクトの初期設定をします。
「DEFAULT LANGUAGE」欄で、「Japanese - ja」を選択して、「CREATE」ボタンをクリックしてください。 -
Intentsの作成画面に移動します。
デフォルトで、「Default Fallback Intent」(エラーなどが起きた時の処理)と「Default Welcome Intent」(会話のきっかけ処理)が設置されているので、これはこのまま利用します。
この後はここに必要なIntentを増やしていく流れになります。 -
まずはGoogle Homeとの会話のきっかけとなる「Default Welcome Intent」を編集するので、クリックしてください。
以下の図に沿ってユーザーが何といったいった時に、どう答えるのかを指定します。
入力できたら上の「SAVE」ボタンをクリックして設定を保存してください。User says Text Response こんにちは こんにちは!kintoneに登録したいタスクを話しかけてください。
また「タスクを確認」と話しかけると、今日締切のタスクをお伝えします。 -
お気付きの方もいらっしゃると思いますが、Intentを設定している右側に「Test Console」があります。
いったん会話のきっかけがちゃんとできているかどうか確かめてみましょう!
ダイアログボックスに「こんにちは」と入力してみてください。
レスポンスに指定した値が入ってくれば成功です。
このまま続けて設定していきましょう。 -
次に、左メニューの「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に設定することで開発可能です。 -
左メニューより「Intents」に戻ります。
-
「CREATE INTENT」ボタンをクリックして、新規にタスク登録用のIntentを追加します。
-
下図に沿ってIntentの詳細設定をします。
設定できたら「SAVE」ボタンをクリックしてください。
「〇〇を追加」という合言葉で新規にkintoneにタスクを登録できます。
さらに質問に続けてタスクの締切日を答えると、それも併せてレコードに登録されます。Intent name User says Action Fulfillment AddTask タスクを追加
(タスクをクリックして、@sys.anyを選択)input.task
(パラメーターもtaskとdateを上図のとおり設定)Use webhookにチェック
(コード内で操作を制御するため) -
次に、今日締切のタスクを確認するためのIntentを作成します。
先ほどと同様に「CREATE INTENT」ボタンをクリックして、下図のとおり設定して、「SAVE」ボタンをクリックしてください。Intent name User says Action Fulfillment CheckTask - タスクを確認
- タスクの確認
- 今日のタスクは?
- 本日のタスク
- 今日締切のタスクは?
- 締切のタスクは?
check.task Use webhookにチェック
(コード内で操作を制御するため) -
あとは会話の終わりを定義してIntentの設定は完了です。
「CREATE INTENT」より以下のとおり設定して、「SAVE」ボタンをクリックします。Intent name User says Action Text response Google Assistant EndConversation - 終わり
- またね
- バイバイ
- ありがとう
end.conversation ありがとうございました!またね End conversationにチェック
(会話の最後のため) -
これで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リクエストを利用してください。'); } }); })();
-
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" } }
-
「DEPLOY」ボタンをクリックします。
下図のとおり、「View execution logs in the Firebase console」とログが出力されれば成功です。 -
実際にHTTP Requestが成功するか「Test Console」で会話をして試してみてください。
kintoneアプリ側にレコードが登録されたらOKです。 -
また「Inline Editor」下の「View execution logs in the Firebase console」のリンクをクリックしてください。
Firebaseの画面に遷移してログを見ることができるようになっているので、そちらも確認しておきましょう。
デバッグする時に活用できます。 -
ひとまずこれにて設定完了です。
動作確認
あとはActions on Googleの画面に戻って音声でのテストをしてみましょう!
実際にGoogle Homeを使ってもOKです。
-
作成したプロジェクトのOverview画面から「TEST DRAFT」をクリックして、Simulatorを立ち上げます。
-
Surfaceを「Speaker」に、Languageを「Japanese - ja」に設定して、左側の入力ダイアログにてテストを行います。
テスト用のSimulatorなので、会話のきっかけとして設定した「こんにちは」の代わりに、合言葉として必ず「テスト用アプリにつないで」という呼びかけが必要になります。
上記画像の「Overview > App Information > Edit > Detail > Sample invocations」箇所を設定することで「テスト用アプリにつないで」以外のきっかけで動作させることもできますが、ここでは割愛します。
Google Homeの実機でテストする場合は、「OK, googleテスト用アプリにつないで」と呼びかけてください。 -
会話をすると以下のようになります。
Google Homeでも試してみてください。 -
念のためkintoneにも無事レコードが登録されていることを確認します。
実際に運用するアプリケーションとして公開する場合は、Actions on Google画面(
本Tipsの動作確認 > 手順1の箇所
)で追加情報を記載して、審査を通す必要があります。
詳細については
Prepare to release your Action
を参照してください。
サンプルコードの解説
途中で出てきたNode.jsの実装ポイントを少し解説します。
今回はDialogflow V1 APIを利用しています。
大まかな流れだけ抜き出すと以下のようになります。
- ライブラリやモジュールのインストール
- addTask関数を定義して、その中でレスポンスの形式を定義 & kintoneへのHTTP Requestを送信
- 実行関数を定義
|
|
その他注意ポイントは以下です。
- 実行関数名は、必ず「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と会話をしてタスクの登録 & 確認ができましたでしょうか?
今回はシンプルな構成でしたが、工夫の幅は無限大です。
ぜひスマートスピーカーのメリットを活かした使い方を考えて、開発してみてください。
設定項目も多いので、最初は扱うのがたいへんですが、慣れれば楽しく連携できます!
このTipsは、2018年1月版kintoneで動作を確認しています。