kun432's blog

Alexaなどスマートスピーカーの話題中心に、Voiceflowの日本語情報を発信してます。たまにAWSやkubernetesなど。

〜スマートスピーカーやVoiceflowの記事は右メニューのカテゴリからどうぞ。〜

Voiceflow TIPS #12 Googleスプレッドシート連携で作るゼロカロリースキルもどき 〜スプレッドシートの検索〜

Voiceflow夏休みAdvent Calendarの12日目です。

7日目でやったGoogleスプレッドシート連携、第1回ということで、スプレッドシートに登録された豆知識をランダムに呼び出すスキルを作りました。今回から複数回にわけて一つのスキルを作るハンズオン形式でGoogleスプレッドシート連携の使い方をご紹介していきたいと思います。

サンプルとなるスキルは、某所でバズっていた「ゼロカロリースキル」へのリスペクトを込めて、「ゼロカロリースキルもどき」を作ってみたいと思います。ただし、あっちは技術のオンパレードで、こっちは技術をほとんど使わない、かなり低グレードなものになる見込みなので、多大な期待はご遠慮頂ますようお願い致します・・・。

今回はまず「検索」からやってみたいと思います。

スキルはのイメージはこんな感じです。


アレクサ、「ゼロカロリースキル」をひらいて

ゼロカロリースキルです。カロリーを知りたい食べ物の名前を言ってください。

ドーナツ

ドーナツですね。ドーナツは、形がゼロを表しているから、ゼロカロリーです。他にも聞きますか?


登録は後から追加することとして最初はいくつかのサンプルを入れてやってみたいと思います。

Googleスプレッドシートの準備

こんな感じのスプレッドシートを用意してください。

  • スプレッドシート名は「ゼロカロリースキル」とします。
  • 1行目はヘッダです。"recipeName"が「食べ物の名前」、"reason"が「理由」になります。
  • 2行目以降に食べ物の名前を理由を入力していきます。
  • シート名は"recipes"にします。ここは日本語だとうまく行かないのでご注意ください。

f:id:kun432:20190812180359p:plain

しかし見れば見るほどすごい理論だな、これw

Voiceflowのフロー

全体像はこんな感じです。今回最低限のエラー処理しかしてないのでご注意ください。

f:id:kun432:20190812192902p:plain

順に見ていきましょう。

変数の作成

ユーザからのスロット兼スプレッドシートからの結果を受ける変数を用意します。"varRecipe"が「食べ物名」で、"varReason"が「理由」です。ホントはもっと分けたほうがいいんでしょうが、そこまで複雑でもないのでこれでいいでしょう。

f:id:kun432:20190812202604p:plain

① スキル開始

開始のメッセージを発話させます。

f:id:kun432:20190812202711p:plain

② Interaction Blockで検索を受けるインテントの設定

食べ物名を受け付けるインテントを作ります。まず、スロットは"slot_recipe"という名称で、AMAZON.Foodを使います。

f:id:kun432:20190812203105p:plain

インテントで、サンプル発話を入力していきます。「○○○のレシピ」「○○○のレシピを教えて」「○○○」って感じで、○○○で食べ物名を取るsearch_intentを作ります。

f:id:kun432:20190812203114p:plain

最後にインテントの分岐です。先程作ったsearch_intentのフローを作ります。ちょっと見えにくいですが、ここで受け取ったスロット"slot_recipe"を変数"varRecipe"に入れます。

f:id:kun432:20190812203123p:plain

③④ Integration BlockでGoogleスプレッドシートの検索

いよいよ、検索です。Integration Blockを使って、Googleスプレッドシートから食べ物名を検索、その理由を取得します。Integration Blockの設定を見ていきます。

まず、データの検索というか取得になりますので"Retrive Data"を選択、Googleアカウントの連携がまだであれば、ここで"Add User"して、Googleログインしてしてください。

f:id:kun432:20190812203846p:plain

次に、スプレッドシートの設定です。スプレッドシートは「ゼロカロリースキル」、シートは「recipes」を選びます。

f:id:kun432:20190812204233p:plain

次に、検索条件です。ランダムに抽出する場合は特に意識しませんでしたが、キーを元に検索する場合は個々で設定が必要です。スプレッドシートの"recipeName"カラムから"varRecipe"の値が該当するもの、という形になります。

ちなみに、Googleスプレッドシートの場合、この条件は一つ、かつ、合致するものしか設定できません。すなわち、複数の条件だったり、比較(>、<、>=、<=)みたいな、複雑な条件は設定できないということです。なので、本当のデータベースのような柔軟な使い方は難しいですね。(そのような用途に適した別のサービスとして、airtable というものがありますが、それはまた別の機会で)

f:id:kun432:20190812204358p:plain

返ってきた結果を取得します。"recipeName"カラムと"varRecipe"が合致した行から、"reason"カラムの値を取って、"varRecipe"に入れます。ここに「理由」が入っているので次のブロック以降で発話させればよいわけです。

f:id:kun432:20190812205244p:plain

あと、Googleスプレッドシートへのアクセスが何らかの理由でできなかった場合は、Failから④に流れるようにして、エラーを伝えるようにしておけばよいでしょう。

f:id:kun432:20190812205114p:plain

⑤⑥⑦ If Blockで検索結果の判定

Integration Blockでユーザが発話した「食べ物名」に基づいた「理由」が取得できている想定ですが、ユーザの発話した食べ物名がスプレッドシート上になかった場合、recipeNameはundefined(定義されていない)を返します。ここは少しプログラミング的になってしまうのですが、undefinedは空でもゼロでもない特殊な値で、If Blockの標準的な比較ではチェックができません。そこでIf BlockのAdvanced Expressionという機能を使って、かんたんなプログラムを入力してチェックします。

最初のIf Blockの状態はこんな感じです。

f:id:kun432:20190812211012p:plain

普段だと、ここで変数名を設定して、値を入力することになりますが、Advanced Expressionの場合はこれをすべて入力で行います。まず、=の行にカーソルを合わせるとゴミ箱アイコンが表示されるのでこれをクリックします。

f:id:kun432:20190812210701j:plain

入力欄が消えて1行だけになりました。次に右端の「」のアイコンをクリックします。

f:id:kun432:20190812210803j:plain

するとメニューが表示されるので、一番下のExpressionを選択します。

f:id:kun432:20190812210817j:plain

表示が変わったのがわかりますか?先程までは"Variable Name"となっていたところが"Enter Your Expression Here"となっていますね。これでAdvanced Expressionモードに切り替わったということです。

f:id:kun432:20190812210829j:plain

で、最後に、プログラムを入力します。

f:id:kun432:20190812210842j:plain

コードもこちらに貼っときます。変数のところはそのままでは使えませんので、必ず"{"を入力して表示される変数名を選択するようにして下さい。

equal({varReason},undefined)

要は"varReason"がundefined、すなわち、結果が返ってこなければ、その食べ物名が登録されていない、ということになるので、再度食べ物名を発話させるためにInteraction Blockに戻ります。

f:id:kun432:20190812212025p:plain

逆にvarReasonがundefinedでない、すなわち、結果が返ってきたということであれば、その食べ物名ならびに理由が登録されている、ということで、それらを発話する流れになります。

f:id:kun432:20190812212144p:plain

これでGoogleスプレッドシートを使った検索の大枠の流れはほぼ完了です。

あと、少し補足しておくと、If BlockのAdvanced Expression、なんとなく、JavaScriptっぽい感じはするけどけど、うまく動かないし、何だろうなーと思っていましたが、どうやら以下らしいです。

ドキュメントの下の方にチョロっと書いてありました・・・

ということで、undefinedかどうかのチェックはこんな感じになるみたいです。

equal({varReason},undefined)

普通の数値とか文字列の比較だと特に問題ないんですが、少し複雑な書き方とはになるとうまく動かなかった理由がやっとわかりました。今後はIf BlockのAdvanced Expressionを安心して使えそうです。

⑧⑨⑩ 繰り返しの確認

最後の部分はこれまでにも何度か説明してますが、「はい」「いいえ」を確認して、「はい」なら繰り返しなのでInteraction blockに戻って食べ物名を取得、「いいえ」なら終了させるというやつですね。詳細は割愛しますので、画面キャプチャを見ていただければと思います。

f:id:kun432:20190812202232p:plain

f:id:kun432:20190812202244p:plain

f:id:kun432:20190812202254p:plain

テスト

ではテストしてみましょう。

f:id:kun432:20190812212635p:plain

食べ物名が登録されているものは理由が説明され、登録されていないものは再度食べ物名を確認していますね。

まとめ

ということで、「Googleスプレッドシート連携で作るゼロカロリースキルもどき」の第1回は「検索」について説明しました。Googleスプレッドシート連携では複数条件の指定した検索などができないため、データベースのような凝ったことはできませんが、非常にお手軽に使えるという雰囲気が伝われば幸いです。

間に別のテーマを挟むかもしれませんが、次回は「スプレッドシートへの登録」をご紹介します。

しかし、ほんとあの「ゼロカロリースキル」はすごいなー。@gaomarさん、半端ない!