Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9445

初心者が Googleアシスタント と Vue.js を使ってスマートディスプレイアプリを作ってみた

$
0
0

はじめに

いちあき(@ichiaki_kazu)と言います。初めてのQiita記事です。

僕はこれまでアセンブラやHTMLくらいしか触ってこなかった(ほぼ)ノンプロフリーランスです。
それをフリーランスというのか置いといて…

11月に行った「Google Nest Hub対応スマートディスプレイスキルを作ろう!【Vue.js】」というハンズオンが楽しかったので、勉強も兼ねてハンズオン内容を参考にしつつ自分で作ってみました。

この記事の目的

  • 自身のやったことを整理して定着させる
  • 共に音声アプリの概要を掴んでもらえたらな

もしかしたらこの通りやっても動かないかもしれないので鵜呑みにしないでください。
※知識不足により誤っている部分がある可能性があります。その時は優しく指摘してください…

参考資料

・「Google Nest Hub対応スマートディスプレイスキルを作ろう!【Vue.js】」(2020/1に大阪でも開催)
・Qiita「滑舌チェックスキルをGoogle Nest Hubで実装してみた」

完成物

音声でアプリを呼び出して、出てきたくだものの画像を見て名前を当てるゲームです。
幼児になら使ってもらえるかなって…

今回使ったもの

  • Google Nest Hub:実機動作確認のため
  • Dialogflow:自然言語処理
  • Vue.js(VueCLI):アプリの画面生成
  • Azure Functions(CLI):内部の処理(クイズ部分とか入出力とか)
  • Vuetify:Vueで使えるフレームワーク
  • IntaractiveCanvas:(重要)Googleアシスタントアプリで画面描写に必要なライブラリ

実際に作ってみる

作るに当たってポイント部分だけを解説していきます。
実際に作ってみたい人は「滑舌チェックスキルをGoogle Nest Hubで実装してみた」をまず確認すると良いと思います。

1.Dialogflow(言語処理をする)

Googleアシスタントによって入力された音声の処理を行います。
Intent(インテント)を作成することで、言葉に反応して何かを返します。

1-1.インテント作成

20191213_056_dialogflow.cloud.google.com.png
作成するIntentは4つ

Intent名内容 
Default Welcome Intentアプリ起動の言葉
EndIntentアプリ終了の言葉
MainIntentアプリ起動中の言葉
StartIntentアプリ起動後に開始する言葉

1-2.実際にインテントを作る(例:StartIntent)

アプリ起動後にゲームを開始するための言葉を登録します。
20191213_061_dialogflow.cloud.google.com.png

  • Training phrases:反応する言葉を登録
  • Fulfillment:webhookでやりとりするためチェックを入れる

その他のインテントも同じように作ります。
ちなみに「Response」には反応時返すメッセージを登録できます。
詳しくは参考記事をご覧ください。

2.Vue.js(アプリ画面を作る)

アプリの画面描写部分を作っていきます。
ざっくりとやることは以下の通り

  • プロジェクト作成(vuetifyも入れる・今回はrouterも)
  • index.htmlにIntaractivCanvasのAPI追加
  • App.vueの修正
  • Home.vueの修正
  • HelloWorld.vueの修正

2-1.プロジェクト作成

プロジェクトを作ってvuetifyを入れます。

vue create kudamonoquiz-app
vue add vuetify

今回はプロジェクト作成時にrouterも入れておきました。

2-2.index.htmlにIntaractiveCanvasのAPI追加

画面描写のキモである「InteractiveCanvas」のAPIを引っ張ってきます。

public/index.html(12行目あたり)
<scripttype="text/javascript"src="https://www.gstatic.com/assistant/interactivecanvas/api/interactive_canvas.min.js"></script>

2-3.App.vueの修正

ここではヘッダー部分とrouterへの連携をしています。
routerは初期状態でHome.vueに流れます。

src/App.vue
<template><v-app><v-app-barapp><v-toolbar-titleclass="headline text-uppercase"><span>くだものくいず</span></v-toolbar-title></v-app-bar><v-content><router-view/></v-content></v-app></template>

2-4.Home.vueの修正

コンポーネント「HelloWorld.Vue」を表示するようにします。

src/Home.vue
<template><HelloWorld/></template><script>importHelloWorldfrom'../components/HelloWorld.vue'exportdefault{name:'home',components:{HelloWorld}}</script>

2-5.HelloWorld.vueを修正(ポイント)

app側のメインコンテンツです。

src/Home.vue
<template><v-container><!-- スタートページ --><v-layouttext-centerwrapv-show="target === 'top'"><v-flexxs12md-10><h3class="display-3 font-weight-bold mb-10"></h3></v-flex><v-flexxs12><h1class="display-2 font-weight-bold mb-10">くだものえいご
        </h1></v-flex><v-flexxs12mb-4><v-btncolor="success"@click="start">スタート</v-btn></v-flex></v-layout><!-- 問題表示ページ --><v-layouttext-centerwrapv-show="target === 'kudamono'"><v-flexxs12md-10><h3class="display-3 font-weight-bold mb-10"></h3></v-flex><v-flexxs12mb-4><h1class="display-1 font-weight-bold mb-3">【くだものえいご】
          </h1></v-flex><v-flexxs12mb-4><imgclass="img":src="imgurl"alt="くだもの画像"></v-flex><v-flexxs12mb-4><h5class="display-1 font-weight-bold mb-3">このくだものはなーんだ?
          </h5></v-flex></v-layout><!-- 正解後の表示ページ --><v-layouttext-centercolumnalign-centerv-show="target === 'congratulation'"><v-flexxs12mb-10><h3class="display-3 font-weight-bold"></h3></v-flex><v-flexxs12mb-4><imgclass="img"alt="congratulation"src="../assets/congratulation.png"></v-flex><v-flexxs12mb-4><imgclass="img":src="imgurl"alt="くだもの画像"></v-flex><v-flexxs12mb-4><h2>だいせいかい!<br>これは{{kotae}}{{tango}})だよ!</h2></v-flex><v-flexxs12mb-10><v-btnlargecolor="success"@click="start">スタート</v-btn></v-flex></v-layout></v-container></template><stylescoped>.img{width:300px;}.endimg{width:200px;}</style><script>exportdefault{data(){return{target:'top'}},created(){varme=thisconstcallbacks={onUpdate(data){if('kudamono'indata){me.kotae=data.kudamono.kotae,me.tango=data.kudamono.tango,me.imgurl=data.kudamono.imgurl,me.target=data.kudamono.target}},}interactiveCanvas.ready(callbacks)},methods:{start(){interactiveCanvas.sendTextQuery('スタート');}}};</script>

ざっくり解説するとこのファイルでは3つがポイントだと思います。

  • targetの状態で表示するコンテンツ(開始時・ゲーム時・正解時)を分ける
  • functionから送られてくるdata(画像URLや問題)をセットし、使用する
  • 最初にスタートボタンを押した時 interactiveCanvas.sendTextQuery('スタート');でDialogflowに「スタート」という文字列を送る

特に文字列を送る昨日はinteractiveCanvasならではなので、ポイントかと思います。

2-6.package.json確認

後々動かす際にnpmインストールするのでpackage.jsonの確認をします。

{
  "name": "kudamonoquiz-app",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build"
  },
  "dependencies": {
    "core-js": "^3.4.3",
    "vue": "^2.6.10",
    "vue-router": "^3.1.3",
    "vuetify": "^2.1.0",
    "vuex": "^3.1.2"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "^4.1.0",
    "@vue/cli-plugin-router": "^4.1.0",
    "@vue/cli-plugin-vuex": "^4.1.0",
    "@vue/cli-service": "^4.1.0",
    "sass": "^1.19.0",
    "sass-loader": "^8.0.0",
    "vue-cli-plugin-vuetify": "^2.0.2",
    "vue-template-compiler": "^2.6.10",
    "vuetify-loader": "^1.3.0"
  }
}

おそらくこの状態だと思いますが、念のための確認です。

3.Azure Functions(内部のプログラムを作る)

3-1.CLIツールをインストールする

とりあえずCLIツールをインストールします

npm install -g azure-functions-core-tools 

3-2.プロジェクトを作成する

このあたりは完全にこの記事と同じです。

$ mkdir kudamonoquiz-app-functions
$ cd kudamonoquiz-app-functions
$ func init                             # 選択肢が出てくるのでnodeとjavascriptを選ぶ
$ func new                              # Http triggerを選択し、kudamonoquiz-appという名前で作成する
$ npm init -y
$ npm i -s actions-on-google@2.10.0     # 2.10.0を入れる
$ npm i -s azure-function-express       # azure-function-expressを入れる
$ npm i -s express
$ npm i -s firebase-admin

3-3.functions.jsonを編集

完全にこの記事と同(ry
GETのみに変更して、どこからでもアクセスできるようanonymousにします。

kudamonoquiz-app/functions.json
{"bindings":[{"authLevel":"anonymous",//anonymousにしておく"type":"httpTrigger","direction":"in","name":"req","methods":["post"//getは使わないので消しておく]},{"type":"http","direction":"out","name":"res"}]}

3-4. index.jsを編集

ワードが入力された際にインテントに応じて処理を変えます。

kudamonoquiz-app/index.js
constcreateHandler=require("azure-function-express").createHandler;constexpress=require("express");const{dialogflow,HtmlResponse}=require('actions-on-google');constapp=dialogflow({debug:false});//スタート処理app.intent('StartIntent',async(conv)=>{//問題の生成constkudamonoquiz=[{"imgurl":"/img/banana.jpg","kotae":"バナナ","tango":"banana"},{"imgurl":"/img/cherry.jpg","kotae":"チェリー","tango":"cherry"},{"imgurl":"/img/grape.jpg","kotae":"グレープ","tango":"grape"},{"imgurl":"/img/melon.jpg","kotae":"メロン","tango":"melon"},{"imgurl":"/img/orange.jpg","kotae":"オレンジ","tango":"orange"},{"imgurl":"/img/peach.jpg","kotae":"ピーチ","tango":"peach"},{"imgurl":"/img/remon.jpg","kotae":"レモン","tango":"remon"},{"imgurl":"/img/strawberry.jpg","kotae":"ストロベリー","tango":"strawberry"}];constwordIndex=Math.floor(Math.random()*kudamonoquiz.length);constselKudamono=kudamonoquiz[wordIndex];conv.contexts.set('game',5,selKudamono);conv.ask('このくだものを英語で言ってみてね');selKudamono["target"]="kudamono";conv.ask(newHtmlResponse({data:{kudamono:selKudamono}}));});//ゲーム処理app.intent('MainIntent',async(conv,{any})=>{constcontext=conv.contexts.get('game');if(context.parameters.kotae===any){conv.contexts.delete('game');conv.ask(`大正解。答えは ${context.parameters.kotae}でした! もう一度クイズをするなら「する」終了するなら「終了」と言ってください。`);context.parameters["target"]="congratulation"}else{conv.ask('よくわかりませんでした。もういちど言ってみてね。');}conv.ask(newHtmlResponse({data:{kudamono:context.parameters}}));});//起動時app.intent('Default Welcome Intent',(conv)=>{conv.ask('果物英語をはじめるには、スタートボタンを押してください。');conv.ask(newHtmlResponse({url:'https://{表示させたいホームページのURL}',supperss:true}));});//functionの名前を一致させておくconstexpressApp=express();expressApp.post('/api/kudamonoquiz-app',app);module.exports=createHandler(expressApp);

実際に動かしてみる

プログラムを動かしていきます。

Vue.jsの起動

npmインストール

kudamonoquiz-appでnpmインストールします。

cd ./kudamonoquiz-app
npm install

プログラム実行

npm run serve

これでhttp://localhost:8080にアクセスできます。
トップ画面が表示されます。
僕はこのあとngrokを使いましたがとりあえずこれでも動くと思います。

Azurefunctionsの起動

npmインストール

kudamonoquiz-functionでnpmインストールします。

cd ./kudamonoquiz-function
npm install

index.js内にアプリのURLを記述する

kudamonoquiz-function/kudamonoquiz-app/index.js(抜粋)
//起動時app.intent('Default Welcome Intent',(conv)=>{conv.ask('果物英語をはじめるには、スタートボタンを押してください。');conv.ask(newHtmlResponse({url:'http://localhost:8080',supperss:true}));});

ローカルサーバを起動する

func host start

http://localhost:8080/でアプリが起動します。

Dialogfrowの設定

FulfillmentのwebhookURLを指定する

20191214_062_dialogflow_cloud_google_com.png

テストする

IntegrationからGoogle Assistantを選択
Dialogflow.png

出てきたポップアップで「Auto-preview changes」にチェック入れて「TEST」
Dialogflow2.png

Developから名前(アプリ呼び出しの呼び名)
Develop.png

Deployで「category」を「Games&fun」にする。※InteractiveCanvasに必須
Deploy2.png

InteractiveCanvasをYesにする。
Deploy3.png

Testから実際に動作を確認する。
Androidスマホがある方はそちらからでも確認できます。
Test.png

今回はテストまでなのでデブロイはなしで、ここまでとなります。
ここまで実施すれば実機でテストバージョンとして動作確認もできます。

以上です。
もしかしたら手順漏れなどあるかもしれませんが大体こんな流れです。
興味ある方は是非是非試してください〜

僕も答えられるかわかりませんが、不明点がありましたらお願いします!

宣伝みたいな

【大阪】Google_Nest_Hub対応スマートディスプレイスキルを作ろう!【Vue_js】_-_connpass.png
https://atlabo.connpass.com/event/157824/
2020年の1/23(木)に僕がスマートディスプレイにハマったきっかけのハンズオンが大阪でも開催されます。
興味ある方はおすすめですのでぜひ!※僕もスタッフとして行きます


Viewing all articles
Browse latest Browse all 9445

Trending Articles