2019年6月12日に日本でもGoogle Nest Hubが発売されました。日本初のGoogleアシスタント画面付きスマートスピーカーです。
やはり手に入れたからには、スマートスピーカーのアクション(スキル)を作りたいですよね!
開封の儀の記事はこちらを見てください。
https://note.mu/gaomar/n/n855952289aeb
画面付き対応はAlexaならAlexa Presentation Language(APL)を使ってリッチなコンテンツを作成することができます。Google Nest Hubも同様にSDKが公開されています。
Google Nest HubではInteractive Canvas
という機能を使って実装していきます。
https://developers.google.com/actions/interactivecanvas/
■2019年7月22日
仕様が変わったので修正しました。
https://www.eisbahn.jp/yoichiro/2019/07/interactive_canvas_changes.html
完成動画
実際に組み込んだ動画です。BMI測定ボタンの画面はVue.jsで作成しています。身長と体重はDialogflowで処理を任せています。
結果画面で再度Vue.jsの画面に戻ってDialogflowから結果の値を取得して画面に反映させるという流れ。
Google Nest HubでBMI測定してみた。Interactive Canvas使えばリッチな表現が出来ますね!表示しているのでVue.jsで作っています#nesthub pic.twitter.com/Bu6dnFYPLQ
— がおまる@スマートスピーカーアプリ開発入門発売中! (@gaomar) June 19, 2019
1. Dialogflowの設定
1-1. Intentの設定
アクションを起動したら必ず最初に呼ばれるIntentを作成します。
Intent名はwelcome
としました。Webhookを行うので、②のように有効化します。

続いてBMI測定を行いたいので、BMIのIntentを作成します。
Intent名はbmi
としました。Training phrasesはbmi
という言葉に反応させます。
パラメータは下記の通り
PARAMETER NAME | ENTITY | VALUE | PROMPTS |
---|---|---|---|
height | @sys.number | $height | 身長をお答えください |
weight | @sys.number | $weight | 体重をお答えください |
1-2. Fulfillmentの設定
Inline Editorを有効にしてプログラムを記述します。HtmlResponse
にスマートディスプレイ用の設定を記述します。
キー名 | 説明 |
---|---|
url | 画面に表示させたいホームページのURLを指定します |
suppress | trueにするとマイクの応答が無くなります。falseにすると引き続きマイクの入力が有効になります |
data | ここに渡したい値を設定します |
'use strict';
const functions = require('firebase-functions');
const {dialogflow, HtmlResponse} = require('actions-on-google');
const app = dialogflow({debug: true});
// 起動時Intent
app.intent('welcome', (conv) => {
conv.ask('あなたのBMIを測定します。測定開始ボタンを押してください。');
conv.ask(new HtmlResponse({
url: `https://{表示させたいホームページのURL}`, /* 動作確認したい場合はこちらのURLを指定してください 「https://gaomar-nesthub-demo.netlify.com/」 */
suppress: true
}));
});
// BMI測定処理
app.intent('bmi', (conv, {height, weight}) => {
const bmiVal = (parseFloat(weight) / (parseFloat(height)/100 * parseFloat(height)/100)).toFixed(1);
var speechText = `あなたのBMIは${bmiVal}です。`;
conv.ask(speechText);
conv.ask(new HtmlResponse({
url: `https://{結果画面のURL}`, /* 動作確認したい場合はこちらのURLを指定してください 「https://gaomar-nesthub-demo.netlify.com/result」 */
suppress: true,
data: {
bmi: speechText,
},
}));
});
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);
1-3. package.jsonを編集
package.jsonは下記の設定をします。2019年6月現在、actions-on-googleはpreview
版でしか動作しない模様です。
その他のバージョンやライブラリは下記を指定します。
※2019年8月1日に2.10.0が正式リリースされました。
"dependencies": {
"actions-on-google": "2.10.0",
"firebase-admin": "~7.0.0",
"firebase-functions": "^2.2.0"
}
{
"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": "8"
},
"scripts": {
"start": "firebase serve --only functions:dialogflowFirebaseFulfillment",
"deploy": "firebase deploy --only functions:dialogflowFirebaseFulfillment"
},
"dependencies": {
"actions-on-google": "2.10.0",
"firebase-admin": "~7.0.0",
"firebase-functions": "^2.2.0"
}
}
2. Actions on Googleの設定
Actions on Googleの設定でInteractive Canvasを有効にしないと実際に使えません。
2-1. Interactive Canvasを有効化にする
左側メニューにあるDirectory information
をクリックします。Additional Information部分にある、カテゴリーを必ずGames & fun
にします。
このカテゴリーにすると、Interactive Canvasのチェックが出てくるのでこれを有効にします。
3. 表示する画面の設定
Vue.jsで実装しています。デプロイ先はどこでも構いませんが、Netlifyが素晴らしいのでそちらにデプロイしています。
3-1. Vue.jsの設定
画面に表示する部分はVue.jsで実装しました。ドキュメントはこちらに詳しく掲載されています。
https://developers.google.com/actions/interactivecanvas/build/web-app
Interactive CanvasのAPIをindex.htmlに適用します。
12〜13行目でAPIを呼び出しています。UIライブラリーにVuetifyを設定しているので、余計なものもありますが、環境に応じて設定してください。
<script src="https://www.gstatic.com/assistant/immersivecanvas/js/immersive_canvas_api.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>nesthub-demo</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons">
<!-- Load Assistant JavaScript -->
<script src="https://www.gstatic.com/assistant/immersivecanvas/js/immersive_canvas_api.js"></script>
</head>
<body>
<noscript>
<strong>We're sorry but nesthub-demo doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
3-2. タイトルページ
アクション起動時に表示されているタイトルページの設定例です。単純にボタンを置いてるだけでのシンプルなページです。
キーポイントはボタンを押した時に実行されるinteractiveCanvas.sendTextQuery
です。
これは、Google Assistant側にbmi
という文字列を送っています。これは1-1で設定したbmiという言葉に反応して、BMI測定が開始してほしいためです。
<template>
<v-container>
<v-layout
text-xs-center
wrap
>
<v-flex mb-4>
<h1 class="display-2 font-weight-bold mb-3">
こんにちはNest Hub!
</h1>
<v-btn large color="success" @click="bmiStart">BMI測定開始</v-btn>
</v-flex>
</v-layout>
</v-container>
</template>
<script>
export default {
methods: {
bmiStart () {
// Google Assistantに 「bmi」 という文字列を送る
interactiveCanvas.sendTextQuery('bmi');
}
}
}
</script>
3-3. 結果画面
測定結果を表示させる画面です。キーポイントはinteractiveCanvas.ready(callbacks)
です。
この画面が呼ばれたらcreated()部分が呼ばれます。これで、毎フレームonUpdate()が実行されます。
1-2で設定したFulfillmentのindex.jsでdataの値を投げている部分があったと思います。
そのdataで指定したbmiという値をここで受け取っています。
<template>
<v-container>
<v-layout
text-xs-center
wrap
>
<v-flex mb-4>
<h1 class="display-3 font-weight-bold mb-3">
【BMI測定結果】
</h1>
</v-flex>
<v-flex
xs12
mb-5
>
<h3 class="display-2 font-weight-bold mb-3">
// 結果を表示する
{{result}}
</h3>
</v-flex>
<v-flex
xs12
mb-5
>
<v-btn large color="success" @click="bmiStart">もう一度やる</v-btn>
</v-flex>
</v-layout>
</v-container>
</template>
<style>
</style>
<script>
export default {
data () {
return {
result: ''
}
},
created () {
var me = this
const callbacks = {
onUpdate(data) {
// bmiの値が飛んできたら取得する
if ('bmi' in data) {
me.result = data.bmi
}
},
}
interactiveCanvas.ready(callbacks)
},
methods: {
bmiStart () {
interactiveCanvas.sendTextQuery('bmi');
}
}
}
</script>
まとめ
シンプルな構成ですが、これでDialogflow ⇔ Actions on Google ⇔ Vue.jsの連携をすることができました。
カテゴリがゲームカテゴリーでないとInteractive Canvasが使えないのが辛いですが、ゲームの演出には使えるかと思いました。
ドキュメントにも記載されていますが、あくまで画面は補助的な役割をするので、メインはVUIということを忘れないようにしましょう!
AlexaのAPLよりやれることが増えているので、個人的にはInteractive Canvasの方が使いやすいと感じました。
今回使用したファイルはGitHubにあがっています。
https://github.com/gaomar/nesthub-demo
システム化のご検討やご相談は弊社までお問い合わせください。
https://i-enter.co.jp/contact/