Actions on Googleは、スマートスピーカー、携帯電話、車、テレビ、ヘッドフォンなど、5億以上のデバイスにわたって、Googleの仮想パーソナルアシスタントであるGoogleアシスタントの機能を拡張するためのソフトウェアを作成できる、開発者向けプラットフォームです。
ユーザーは、食料品の購入や乗車予約など、何かを達成するためにGoogleアシスタントを会話に加えることができます(現在の機能の完全なリストについては、アクションディレクトリをご覧ください)。開発者は、Actions on Googleを使用して、ユーザーとサードパーティのフルフィルメントサービスとの間の楽しく効果的な会話体験を簡単に作成し活用することができます。
このコードラボでは、Actions on Googleを使った基本的なアクションを開発します。そして、そのアクションに対して、Daily UpdatesやPush Notificationsを使った、よりリッチな体験を追加します。
このコードラボは、Actions on GoogleおよびDialogflowを使用した基本的なアクションの開発方法についての詳細な説明は行いません。一般的なアクションの開発方法については、Build Actions for the Google Assistant (Level 1) や Build Actions for the Google Assistant (Level 2) を参照ください。
このコードラボでは、次の機能を備えた対話アクションを作成します。
以下のツールがあなたの環境に必要となります。
Daily UpdatesやPush Notificationsといった機能を解説する前に、まずは土台となるアクションを準備しましょう。このコードラボでは、「デイリーニュース」アクションを作ります。「デイリーニュース」アクションが提供する機能は、以下とします。
具体的には、以下のような会話を想定します。このままでは十分なニュースサービスとは言えませんが、コードラボのサンプルアクションとしては十分です。
この会話は、ユーザからアクションに対して問いかけを続けていくことで対話が進みます。このコードラボでは、後ほど以下の問いかけについて、通知をサポートします。
アクションを作成するには、Actions Projectを作成し、アクションごとに2つの内容(インテントとフルフィルメント)を定義します。
コードラボのこのセクションでは、Actions ConsoleでActions projectを設定する方法について説明します。
このコードラボで作成するアクションをテストするには、必要な権限を有効にする必要があります。
Actions projectは、Actions directory のリストに掲載されるメタデータ(名前、説明、カテゴリ)を持つあなたのアクションのコンテナです。
アクションの構築を開始するには、まず以下のようにActions projectを作成します。
Actions projectを作成したら、Dialogflowエージェントを作成して、あなたのプロジェクトに関連付けを行います:
エージェントの作成が成功した場合は、Intents ページに移動します。あなたは、Dialogflowエージェントがユーザーの要求にどのように応答するかをカスタマイズできるようになりました。
では、先ほど作成したDialogflowエージェントを使って、会話を定義していきましょう。このコードラボでは、以下のインテントを定義することで、デイリーニュースアクションの会話を組み立てます。
すべてのActions projectには、ユーザが会話を開始するためのエントリポイントとして機能するウェルカムインテントが必要です。ウェルカムインテントは、ユーザがアクション名を発声して明示的にアクションを呼び出すときにトリガーされます。
デフォルトでは、Dialogflowは私たちのためにウェルカムインテントを作成しています。このコードラボでは、ユーザーが "テスト用アプリにつないで" と発言したときにトリガーされるウェルカムインテントを変更します。
以下の手順に従って、ウェルカムインテントを修正します。
ユーザが会話を終えたい際の Quit インテントを作成します。Dialogflowに対して以下の操作を行ってください。
ここから、ユーザが希望するニュースの条件を指定するためのインテントを作成しましょう。まず、24時間以内に起きた最近のニュースを希望する Recent News インテントを作成します。Dialogflowにて以下の操作を行ってください。
次に、ユーザが指定した日付のニュースを希望する Past News インテントを作成します。Dialogflowにて以下の操作を行ってください。
これにより、Dialogflowは "今日の" の部分が日付だと自動的に認識します。そして、日付を示す @sys.date というシステムエンティティの date
パラメータが割り当てられます。
最後に、最新のニュースを希望する Latest News インテントを作成します。Dialogflowにて以下の操作を行ってください。
以上でデイリーニュースアクションの基本的なインテントの作成は完了です。しかし、まだデイリーニュースアクションとの会話を行うことはできません。
先ほど、いくつかのインテントを作成しましたが、そのほとんどはフルフィルメントの呼び出しを ON に設定しました。ここでは、フルフィルメントのコードを作成します。
フルフィルメントは、Webhookで呼び出されるプログラムコードです。このコードラボでは、Webhookを構築してデプロイするために、Dialogflow Console のインラインエディタを使います。あなたのアクションにwebhookを構築するために、以下を行います:
"use strict";
const functions = require("firebase-functions");
const {
dialogflow,
Suggestions,
RegisterUpdate,
UpdatePermission
} = require("actions-on-google");
// SDKの利用準備
const app = dialogflow({
debug: true
});
// "Default Welcome Intent"を処理するハンドラ関数の登録
// 指定範囲のニュース一覧取得関数
// 返事をする関数
// "Recent News"を処理するハンドラ関数の登録
// "Past News"を処理するハンドラ関数の登録
// "Latest News"を処理するハンドラ関数の登録
// "Setup Daily Updates"を処理するハンドラ関数の登録
// "Finish Daily Updates Setup"を処理するハンドラ関数の登録
// "Setup Push Notifications"を処理するハンドラ関数の登録
// "Finish Push Notifications Setup"を処理するハンドラ関数の登録
// SDKをFirebase Functionsとして登録
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);
Webhookのためのこのコードは、JavaScriptで実装されています。Dialogflowのインラインエディタを使うと、あなたのWebhookコードはCloud Functions for Firebaseを使ってクラウド内のマネージド環境にデプロイされます。
このWebhookコードは、Actions on Google Node.js クライアントライブラリを使って、アシスタントがWebhookに送信するHTTPリクエストに応答しています。そのライブラリを使うことで、あなたは Dialogflow API のラッパーとして振る舞う DialogflowApp
オブジェクトを作成することができます。
このコードラボでは、DialogflowApp
オブジェクト型の app
変数を作成しています。
index.js 内に、以下のコードを追加してください。追加場所は、コメント行が書かれている場所です。
// "Default Welcome Intent"を処理するハンドラ関数の登録
app.intent("Default Welcome Intent", conv => {
conv.ask("デイリーニュースをお伝えいたします。いつのニュースを聞きたいですか?");
conv.ask(new Suggestions(["最新のニュース", "最近のニュース", "昨日のニュース"]));
});
app.intent()
関数は、インテントを処理するコールバックを宣言するために使用されます。この app.intent()
関数は、2つの重要な引数を受け取ります。
コールバック関数の第1引数には、以下の値が渡されます。
Dialogflow Conversation
オブジェクト(変数名: conv
)。これは、ダイアログの状態をクライアントライブラリで抽象化したものであり、現在アクティブなDialogflowコンテキスト、ユーザのデバイスのサーフェスで利用可能な機能など、Webhookへの着信要求の値を表すプロパティを含みます。Default Welcome Intentハンドラ関数では、以下の処理を行っています。
conv.ask()
関数に文字列を渡すことで、ユーザへの返事をGoogleアシスタントに渡しています。conv.ask()
関数に Suggestions
オブジェクトを渡すことで、ユーザへの返事と共に、Suggestion Chip をGoogleアシスタントに渡しています。Suggestion Chip を使うことで、もしユーザが画面付きデバイスを利用している場合には、文字入力や発話をすることなく、タップするだけでGoogleアシスタントに問いかけができるようになります。具体的には、以下のように返事の吹き出しの下に、Suggestion Chipが表示されます。
index.js 内に、以下のコードを追加してください。追加場所は、コメント行が書かれている場所です。
// 指定範囲のニュース一覧取得関数
const getNews = (start, end) => {
return [
{
created: new Date("2018-09-24T09:00:00+0900"),
contents: "夕方からゲリラ豪雨になる予報です。"
},
{
created: new Date("2018-09-24T22:30:00+0900"),
contents: "明日19日の午前10時からJavaScript勉強会が社内で行われます。ぜひご参加ください。"
},
{
created: new Date("2018-09-25T10:00:00+0900"),
contents: "ついに利用ユーザ数がのべ1億人を突破しました!"
}
].filter(x => {
// 指定された範囲に限定する
return (start <= x.created.getTime()) && (x.created.getTime() <= end);
}).sort((a, b) => {
// ニュースの古い順に並び替える
return a.created.getTime() - b.created.getTime();
}).map(x => {
// コンテンツだけ返す
return x.contents;
});
};
本来であれば、ニュースはデータベースなどから動的に取得するべきですが、このコードラボでは固定的にニュース一覧を得るための getNews()
関数を作ることにします。上記のコードでは、3つのニュースを定義しています。ニュースの内容は自由で良いですが、 created
で指定される日時は、以下を含めてください。それは、動作確認時に役に立ちます。
ここで、もう一つ便利な関数を追加します。いくつかのインテントを処理するコールバック関数からユーザに返事を送る際に、Suggestion Chipを含めます。何度もSuggestion Chipを指定するコードを書くのは良くないので、返事を送信するための reply()
関数を作りましょう。index.js 内に、以下のコードを追加してください。追加場所は、コメント行が書かれている場所です。
// 返事をする関数
const reply = (conv, message) => {
conv.ask(message);
conv.ask(new Suggestions([
"毎日受け取る", "リアルタイムに受け取る",
"最新のニュース", "最近のニュース", "昨日のニュース"
]));
};
では、ニュースを提供する関数を使って、各種インテントの処理を作成していきます。まずは、24時間以内のニュース一覧を伝えるための Recent News インテントハンドラ関数です。 index.js 内に、以下のコードを追加してください。追加場所は、コメント行が書かれている場所です。
// "Recent News"を処理するハンドラ関数の登録
app.intent("Recent News", conv => {
// 24時間以内のニュースを得る
const news = getNews(Date.now() - 24 * 60 * 60 * 1000, Date.now());
// 返事をする
if (news.length === 0) {
reply(conv, "最近のニュースは特にありません。いつのニュースを知りたいですか?");
} else {
reply(conv, `最近のニュースです。${news.join("")}以上です。いつのニュースを知りたいですか?`);
}
});
24時間以内にニュースがあるかどうかで、返事の内容を変化させています。
次に、最新のニュース1件を伝えるための Latest News インテントハンドラ関数です。 index.js 内に、以下のコードを追加してください。追加場所は、コメント行が書かれている場所です。
// "Latest News"を処理するハンドラ関数の登録
app.intent("Latest News", conv => {
// 24時間以内のニュースを得る
const news = getNews(Date.now() - 24 * 60 * 60 * 1000, Date.now());
if (news.length === 0) {
reply(conv, "最新のニュースは特にありません。いつのニュースを知りたいですか?");
} else {
reply(conv, `最新のニュースです。${news[news.length - 1]}いつのニュースを知りたいですか?`);
}
});
ここでは、24時間以内のニュースを最新のニュースの対象としています。
最後に、ユーザが指定した日付のニュースを伝えるための Past News インテントハンドラ関数です。 index.js 内に、以下のコードを追加してください。追加場所は、コメント行が書かれている場所です。
// "Past News"を処理するハンドラ関数の登録
app.intent("Past News", (conv, {date}) => {
// 指定日付のニュースを得る
const start = new Date(date).setHours(0, 0, 0, 0);
const news = getNews(start, start + 24 * 60 * 60 * 1000 - 1);
// 返事をする
if (news.length === 0) {
reply(conv, "その日のニュースは特にありません。いつのニュースを知りたいですか?");
} else {
reply(conv, `その日のニュースです。${news.join("")}以上です。いつのニュースを知りたいですか?`);
}
});
Recent News インテントハンドラ関数や Latest News インテントハンドラ関数と違って、Past News インテントハンドラ関数では、Dialogflowの解析結果を一つ受け取っています。先ほどは conv
引数一つのみでしたが、ここでは {date}
という第2引数を指定しています。Past News インテントをDialogflow Consoleで登録した際に、 @sys.date
エンティティの date
パラメータが自動的に認識されたのを覚えていますか?ここでは、その認識された値を受け取り、ニュースの検索条件として利用しています。
Past News インテントハンドラ関数の記述が終わったら、 DEPLOY ボタンを押してコードをFirebaseにデプロイしてください。
ここまでの作業によって、デイリーニュースアクションは基本的な機能を提供することができるようになりました。ここで、Actions Console シミュレータを使って、実際に動作確認を行ってみましょう。
Actions Console シミュレータであなたのアクションをテストするには、以下を行います:
ここまでで、デイリーニュースアクションの基本的な機能の実装が終わりました。
このセクションでは、デイリーニュースアクションに対して、Daily Updatesを追加します。ユーザが毎日指定の時間に最近のニュースに関する通知をDaily Updatesを使って受け取ることができるように機能追加を行います。
アクションがDaily Updatesを利用することで、ユーザは毎日指定された時刻に通知を受け取ることができます。ユーザがその通知をタップすると、Googleアシスタントによってそのアクションが呼び出され、さらにアクションに含まれる特定のインテントがトリガーされます。
Daily Updatesによってユーザにアクションから通知が行われる流れは、以下となります。
RegisterUpdate
クラスを使って、Daily Updatesの登録をActions on Googleに依頼します。このコードラボでは、最近のニュースを伝える Recent News インテントをDaily Updatesとして登録できるようにします。
最初に、ユーザが最近のニュースを毎日受け取りたいことを伝えるためのインテントをDialogflowに追加します。Dialogflow Consoleにて以下の操作を行ってください。
次に、Daily Updatesを登録する処理を行う Setup Daily Updates インテントハンドラ関数を追加します。 index.js 内に、以下のコードを追加してください。追加場所は、コメント行が書かれている場所です。
// "Setup Daily Updates"を処理するハンドラ関数の登録
app.intent("Setup Daily Updates", conv => {
// Daily Updatesの登録を要求する
conv.ask(new RegisterUpdate({
intent: "Recent News",
frequency: "DAILY"
}));
});
Daily Updatesを登録するために、SDK が提供する RegisterUpdate
クラスを使います。その際に、以下の情報を与えます。
intent
- ユーザが通知をタップした際にトリガーされるインテントの名前を指定します。frequency
- Daily Updatesを示す "DAILY" 文字列を指定します。これにより、Googleアシスタントがアクションの代わりにユーザに指定時刻を問い合わせします。
ユーザがGoogleアシスタントに時刻を指定した後に、Actions on Googleはアクションに actions_intent_REGISTER_UPDATE
イベントを送信します。このイベントを受け取るためのインテントをDialogflowに追加します。Dialogflow Consoleにて以下の操作を行ってください。
フルフィルメントにて actions_intent_REGISTER_UPDATE
イベントを処理する関数を追加します。 index.js 内に、以下のコードを追加してください。追加場所は、コメント行が書かれている場所です。
// "Finish Daily Updates Setup"を処理するハンドラ関数の登録
app.intent("Finish Daily Updates Setup", (conv, params, registered) => {
if (registered && registered.status === "OK") {
conv.close("毎日ご指定の時間にニュースをお届けいたします。また会いましょう。");
} else {
reply(conv, "気が向いたら登録してください。いつのニュースを知りたいですか?");
}
});
Daily Updates が正しく登録されたかどうかは、 app.intent()
関数の第2引数で渡しているコールバック関数の第3引数として渡される値を見ることで判断することができます。上記のコードでは、 registered
という引数です。この値が undefined ではなく、 status 値として "OK" がセットされていれば、Daily Updates が登録されたことになります。
もしDaily Updatesが登録されていれば、 conv.close()
関数を使って、返事をすると同時に会話を終了します。
Daily Updates機能を使ってユーザに通知を送信するためには、Actions on Google Consoleにて、インテントをDaily Updateの対象として登録することが必要です。登録を行うために、以下の操作を行います。
では、Daily Updatesの動作確認を行いましょう。Actions on GoogleのActions シミュレータではなく、スマートフォンにて動作確認を行ってください。動作確認の手順は、以下となります。
通知を解除する場合は、受け取った通知にある「停止」をタップします。これにより、Googleアシスタントは通知を止めて良いかどうか聞いてきますので、"はい" と答えてください。
ここからは、デイリーニュースアクションに対して、Push Notificationsを追加します。ユーザに最新のニュースをリアルタイムで通知する機能をPush Notificationsを使って実現します。
Push Notifications機能を利用することで、通知をユーザにいつでも送信することができます。ただし、通知の送信は、ユーザから許諾を得た後に可能となります。ユーザが受け取った通知をタップすると、Googleアシスタントによってそのアクションが呼び出され、さらにアクションに含まれる特定のインテントがトリガーされます。
Push Notificationsによってユーザにアクションから通知が行われる流れは、以下となります。
UpdatePermission
クラスを使って、Push Notificationsによる通知の許可をActions on Googleに依頼します。このコードラボでは、最新のニュースを伝える Latest News インテントをPush Notificationsにより通知できるようにします。このセクションでは、最初にユーザに通知を送信することを許諾してもらうために必要な機能を追加します。
最初に、ユーザが最新のニュースをリアルタイムで受け取りたいことを伝えるためのインテントをDialogflowに追加します。Dialogflow Consoleにて以下の操作を行ってください。
次に、Push Notificationsを希望する処理を行う Setup Push Notifications インテントハンドラ関数を追加します。 index.js 内に、以下のコードを追加してください。追加場所は、コメント行が書かれている場所です。
// "Setup Push Notifications"を処理するハンドラ関数の登録
app.intent("Setup Push Notifications", conv => {
conv.ask(new UpdatePermission({
intent: "Latest News"
}));
});
Push Notificationsによる通知の送信についてユーザから許諾を得るために、SDK が提供する UpdatePermission
クラスを使います。その際に、以下の情報を与えます。
intent
- ユーザが通知をタップした際にトリガーされるインテントの名前を指定します。これにより、Googleアシスタントがアクションの代わりにユーザに通知を送信して良いかどうかの問い合わせを行います。
ユーザがGoogleアシスタントに許諾するかどうかを返答した後に、Actions on Googleはアクションに actions_intent_PERMISSION
イベントを送信します。このイベントを受け取るためのインテントをDialogflowに追加します。Dialogflow Consoleにて以下の操作を行ってください。
フルフィルメントにて actions_intent_PERMISSION
イベントを処理する関数を追加します。 index.js 内に、以下のコードを追加してください。追加場所は、コメント行が書かれている場所です。
// "Finish Push Notifications Setup"を処理するハンドラ関数の登録
app.intent("Finish Push Notifications Setup", (conv, params, granted) => {
if (granted) {
const userId = conv.arguments.get("UPDATES_USER_ID");
console.log("userId", userId);
conv.close("ニュースをすぐにお届けいたします。また会いましょう。");
} else {
reply(conv, "気が向いたら登録してください。いつのニュースを知りたいですか?");
}
});
Push Notifications による通知の送信をユーザが許可したかどうかは、 app.intent()
関数の第2引数で渡しているコールバック関数の第3引数として渡される値を見ることで判断することができます。上記のコードでは、 granted
という引数です。この値が undefined ではなければ、ユーザが通知の送信を許可したことになります。
ここで、 conv.arguments.get("UPDATES_USER_ID")
という処理を行うことで、通知の送信を許可したユーザのID文字列を取得しています。本来であれば、この値をデータベースに格納するなどが必要ですが、このコードラボではログに出力しています。この値は、後ほどActions APIを使って通知を送信する際に必要となります。
もし通知の送信が許可されていれば、 conv.close()
関数を使って、返事をすると同時に会話を終了します。
Push Notifications機能を使ってユーザに通知を送信するためには、Actions on Google Consoleにて、インテントをPush Notificationsの対象として登録することが必要です。登録を行うために、以下の操作を行います。
では、Push Notificationsを使って通知を行うために必要となるユーザ許諾について、動作確認を行いましょう。このコードラボでは、Daily Updatesの時と同じように、スマートフォンにて動作確認を行いましょう(実際にはActions シミュレータでも大丈夫です)。動作確認の手順は、以下となります。
ここで、通知の送信を許諾したユーザのID文字列をログから見つけます。以下の操作を行ってください。
userId: ...
という行を探します。そこに書かれている文字列が対象ユーザのID文字列です。これをメモしておきます。Push Notificationsによる通知の送信を許諾したユーザのID文字列を得ることができれば、実際に通知を送信することが可能です。
このセクションでは、先ほど通知の送信を許可したユーザ向けに、実際に通知を送信するための機能を作成します。このコードラボでは、通知の送信処理について、フルフィルメントとしてではなく、単独のJavaScriptファイルとして作成します。
Push Notificationsを使って通知を送信する際には、Actions APIを利用します。Actions on GoogleやDialogflowにプロジェクトを作っただけでは、Actions APIを使うことはできません。Google Cloud Platformにて、Actions APIを利用可能に設定する必要があります。
以下の操作を行って、Actions APIを有効にしてください。
Actions APIが有効になった後に、Actions APIのダッシュボード画面が表示されます。
通知を送信するためのActions APIを利用するために、Google Cloud Platformにてサービスアカウントキーを発行します。発行されたサービスアカウントキーにより、Actions APIを利用するためのクライアント認証が行われます。
以下の操作を行って、サービスアカウントキーを発行してください。
ここからは、通知を送信するためのJavaScriptファイルの作成に取りかかります。まずは、以下の手順を行って、ディレクトリを作成して、Node.jsプロジェクトを開始します。
daily-news-codelab
ディレクトリを作成して、その中に移動します。mkdir daily-news-codelab
cd daily-news-codelab
npm
コマンドを使って、Node.jsプロジェクトを作成します。いくつか質問されますが、全て Enter キーを押して回答します。npm init
npm install googleapis --save
npm install request --save
Node.jsプロジェクトの準備が整いました。手元に以下があることを確認してください。
先ほど作成した daily-news-codelab
ディレクトリ内に、以下の内容で send-notification.js
という名前でファイルを作成してください。
"use strict";
const {google} = require("googleapis");
const key = require("<SERVICE_ACCOUNT_KEY_JSON_FILE_PATH>");
const request = require("request");
const jwtClient = new google.auth.JWT(
key.client_email,
null,
key.private_key,
[
"https://www.googleapis.com/auth/actions.fulfillment.conversation"
],
null
);
jwtClient.authorize((err, tokens) => {
const options = {
userNotification: {
title: process.argv[2]
},
target: {
userId: "<TARGET_USER_ID>",
intent: "Latest News",
locale: "ja-JP"
}
};
request.post("https://actions.googleapis.com/v2/conversations:send", {
auth: {
"bearer": tokens.access_token
},
json: true,
body: {
customPushMessage: options
}
}, (err, response, body) => {
console.log(response.statusCode + ":" + response.statusMessage);
});
});
send-notification.js
ファイルの中に、修正すべき箇所が2つあります。以下の内容で修正を行ってください。
<SERVICE_ACCOUNT_KEY_JSON_FILE_PATH>
- サービスアカウントキーのJSONファイル<TARGET_USER_ID>
- 通知を送信するユーザのID文字列コードの前半部分は、サービスアカウントキーのJSONファイルの内容を読み込み、アクセストークンを得るための処理となります。その後、 request()
関数を使って、Actions API のエンドポイントに対して、通知を送信するために必要となる情報を渡しています。具体的には、以下の内容を指定します。
通知のタイトル文字列は、 process.argv[2]
として、 send-notification.js
ファイルを実行する際のコマンドライン引数として渡すことができるようにしています。
ターミナル内で以下のコマンドを実行してください。
node send-notification.js "ユーザ数1億人突破!"
以下のように表示されれば、通知の送信依頼が正常に受け付けられたことになります。
200:OK
スマートフォンに通知が来ていることを確認してください。そして、通知をタップしてください。
通知を解除する場合は、受け取った通知にある「停止」をタップします。これにより、Googleアシスタントは通知を止めて良いかどうか聞いてきますので、"はい" と答えてください。
おめでとうございます!
あなたは今、Actions on Googleを使った会話型のユーザインタフェースを構築して、ユーザに積極的に通知を送信してUser Engagementを高める機能を追加する方法を知ることができました。
Daily UpdatesおよびPush Notificationsの使い方を学ぶために、Googleはよりリッチなコードサンプルを提供しています。
Actions on Googleについて学ぶために、以下のリソースについても参考にすることができます:
Twitter @ActionsOnGoogle をフォローしてください。また、あなたが開発したものを #AoGDevs にてシェアしてください。
次に行く前に、このフォームを使って私たちにフィードバックを送ってください!