kun432's blog

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

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

Voiceflow TIPS #3 変数と永続セッションとFlow Block

ちょっと間が空いてしまいましたが、VoiceflowのTIPSの第3回です。

前回、Voiceflowの変数はすべて永続的だということを書きました。

で、この前提で複雑なスキルを作ると大体こういうことになります。

f:id:kun432:20190803173511p:plain

もう地獄ですね・・・これを避けるために今回はローカル変数を作るためのブロック、Flow Blockをご紹介します。

ということで調べていたら、実は上記の記事に誤りがあることがわかりました・・・そのあたりの訂正も含めて、ご紹介します。


Flow Blockとは?

Flow Blockってなんぞや?使ったことない、と思う方もいらっしゃるかと思いますが、そんな方でも実は普通に使っています。Help や Stopのアレです。

f:id:kun432:20190803211129p:plain

f:id:kun432:20190803213638p:plain

f:id:kun432:20190803211118p:plain

で、これを自分で作れるのがFlow Blockです。大規模なスキルになってくると、全体像が非常に大きくなり、逆に細かいところがわかりにくくなりますが、これを小分けにすることでその部分だけの処理に集中しやすいということですね。

ただそれだけだとあまりメリット感がないと思うかもしれません。実はもう一つ大事なことがあります。

Flow Blockの中では、ローカル変数が使えて、変数のスコープはFlow Block内になります!

これはとても重要ですね。ちなみにVoiceflowの中で上記の変数のことを『フロー変数』というみたいです。ではサンプルのスキルを作りながら説明していきます。

サンプルスキルの全体像

まず最初に全体全体としてはこんな感じです。一本道のスキルの途中で、Flow Blockを入れてます。

f:id:kun432:20190803213856p:plain

Flow Blockの中身はこんな感じです。こちらも一本道で、そんな凝ったことはしてません。

f:id:kun432:20190803213910p:plain

両方とも、途中のSet Blockで変数をいじって、変数のスコープがどうなるかを見てみるのが目的です。では順次やっていきましょう。

1. 変数の作成

まず最初にグローバル変数を作りましょう。ちなみにVoiceflowでは「プロジェクト変数」と言います。"projectVar"という名前にしてます。

f:id:kun432:20190803221500p:plain

2. Speak Block追加

Speakブロックを追加して、projectVarの中身を確認します。音楽つけてるのはわかりやすくするためですね。

f:id:kun432:20190803232018p:plain

3. Flow Block追加

ではFlow Blockを使っていきましょう。Flow Blockを配置して、Speak Blockからつなげます。Flow Blockのメニューから”Create New Flow”をクリックします。

f:id:kun432:20190803223300p:plain

Flow Blockの名前をつけます。ここでは「テストフロー」にします。

f:id:kun432:20190803223559p:plain

こうなります。

f:id:kun432:20190803224525p:plain

Canvasが一新されましたね。スキル新規作成直後に表示されているメインのフローから、Flow Blockを経由して、こちらのフローにジャンプしてくるようなイメージで考えるとわかりやすいです。ちなみに、スキル新規作成直後に表示されているメインのフローを「ROOTフロー」といいます。では、「テストフロー」の中を作っていきます。

4. Flow内の変数の作成

テストフローにいる状態で、変数のメニューを表示させます。

f:id:kun432:20190803230034p:plain

で、ここでいつもどおり変数を作る前に、"Create Variable (Project)"をクリックします。

f:id:kun432:20190803230544p:plain

すると・・・

f:id:kun432:20190803230609p:plain

表示が”Project”から"Flow"に変わったのがわかるでしょうか? このようにFlow Blockの中でしか使えない「フロー変数」を作成する場合は、変数の種類を切り替える必要があります。

では、「フロー変数」を作成してみます。

f:id:kun432:20190803231544p:plain

いつもの変数と違う場所に表示されていますねー。はい、これでOKです。

では続けて、テストフロー内のブロックを作成していきます。

4. Flow内のブロックの作成

ここは以下のような感じでサラッと作成していきます。

  • Speakブロックを作って、プロジェクト変数 "projectVar" と フロー変数 "testflowVar"の中身を確認
  • Setブロックでそれぞれインクリメント(+1)する
  • 再度、Speakブロックを作って、インクリメント後のプロジェクト変数 "projectVar" と フロー変数 "testflowVar"の中身を確認

f:id:kun432:20190803234505p:plain

f:id:kun432:20190803234519p:plain

f:id:kun432:20190803234533p:plain

ちなみに、Flow Blockで作成したフローからROOTフローに戻る場合には何もしなくて良いです。上記のフローだと最後のSpeak Blockの先がないので、自動的にROOTフローに戻ります。逆に明示的にフローの中で終了させる場合にはExitブロックを最後においてフローを繋げる必要があります。Stop Flowが参考になるかと思いますのでそちらを確認してみてください。

ではメインのROOTフローに戻って続きを作っていきます。

5. ROOTフローの続き

一旦ROOTフローに戻ったということを話すだけのブロックを追加します。

f:id:kun432:20190803235422p:plain

さらに変数をインクリメントするためにSet Blockを追加します。ここでテストフローと同じように"projectVar"と"testflowVar"をインクリメントしようとすると・・・

f:id:kun432:20190803235843p:plain

プロジェクト変数"projectVar"は見えますが、テストフロー内で作成したフロー変数"testflowVar"は見えません。変数の画面でもフロー変数は見えませんね。

f:id:kun432:20190804000849p:plain

このようにFlow Blockで作成したフローの中で作成したフロー変数はフローの外からは呼び出すことができなくなっており、きちんとフロー変数にはスコープがあることがわかります。逆にいうとプロジェクト変数はフローの中からも見えますので、グローバルになっているということですね。

最後にプロジェクト変数がどうなっているかを確認するために、Speakブロックを作成します。

f:id:kun432:20190804000432p:plain

はい、これで終了です。アップロードしてテストしてみましょう。

テスト

ではテストして変数の値がどのように変化するのかを見ていきましょう。

f:id:kun432:20190804001356p:plain

フロー内でグローバル変数がインクリメントされているのがわかりますね。面白いのはここからです。もう一度実行してみます。

f:id:kun432:20190804001516p:plain

わかりますか?

プロジェクト変数は、前回のTIPSでお伝えしたとおり、「永続扱い」になりますので、2回目の最初で1回目の最後の値から継続されています。逆に、フロー変数は、前回の最後の値を記憶していません。すなわち「永続ではない」ということですね。これは非常に重要です。

で、実は、このフロー変数、メインのROOTフローでも作れます!どういうことかを見ていきましょう。

ROOTフローでのフロー変数

ROOTフローでフロー変数を作成します。変数を切り替えるのを忘れないでください。今回は"rootflowVar"という名前で作ります。

f:id:kun432:20190804002812p:plain

最初と最後のSpeak Blockで"rootflowVar"の中身を確認するように修正します。

f:id:kun432:20190804003147p:plain

f:id:kun432:20190804003205p:plain

Set Blockで同じようにインクリメントします。まずはROOTフローのSet Block。

f:id:kun432:20190804003352p:plain

次に、テストフロー内のSet Blockですが、、、、

f:id:kun432:20190804003602p:plain

はい、選択できません、つまりROOTフローで作成した変数であってもフロー変数として作成すると、他のフローからは見れないということですね。このようにフロー変数については非常にスコープが厳格になっています。

ではテストしてみます。2回続けてテストした結果を並べます。

f:id:kun432:20190804010523p:plain

ROOTフローで定義したフロー変数、1回目でインクリメントしてますが、2回目の最初に0になっているのがわかりますね?このように、ROOTフローであっても、フロー変数として定義したものは、永続扱いになりません。つまり、Flowブロックを使わなくても、Voiceflowでは、永続ではない変数もちゃんと作れるということです!

以前の記事で、全ての変数が永続扱いになると書いてましたが、すいません、私の確認漏れでした。記事の内容を訂正するとともに、参考にされた方には謹んでお詫び申し上げます・・・・

ROOTフローと他のフロートのフロー変数の受け渡し

フロー変数については、ここまでで書いたとおり、変数のスコープがそのフロー変数を作ったフローの中に限定されていて、たとえROOTフローであっても見れない、逆も然り、ということでした。じゃあ子フロー(便宜的にROOTフローではない他のフローの変数をこういう言い方にしときます)の中からROOTフローの変数を見たい場合にはすべてプロジェクト変数、つまり永続変数にしないといけないのか?というとそういうわけではありません。

Flow Blockでは、変数の受け渡しができるようになっています。これを使って、ROOTフローのフロー変数を小フローでフロー変数として受け取り、またそれをもとに戻せばよいです。ちょっと見にくいかもしれませんが、こんな感じです。

f:id:kun432:20190804013834p:plain

ほんと、関数の引数と戻り値みたいな感じになりますねー。

まとめ

ということで、繰り返しになりますが、以前の記事で、全ての変数が永続扱いになると書いてたのは、私の確認漏れと決めつけから来ている誤りでした。この記事を持って訂正させていただき、参考にされた方には謹んでお詫び申し上げます、申し訳ありませんでした・・・・

が、ちょびっとだけ言い訳すると・・・

あれは気づけない!

です・・・。

以前はこんな感じでもう少し明示的にグローバルとローカルの区別ができるようになっていたんですね。

f:id:kun432:20190804011322p:plain

それがこれですよ?単なる文字列にしか見えませんよ、これ・・・

f:id:kun432:20190804011314p:plain

デザインが変わってからそのメニューがなくなって選べるようなところが見当たらなくなったので、Flow Blockの中はローカルになるように割り切ったのかなぁ?とか勝手に思ってて、またFlow Blockが必要となるような規模の大きなスキル作ることもないので、全く気づいてませんでした。ドキュメントにも一応記載あるんですけど、ドキュメントが変化に追いついてなかったりというのも結構あるので、スルーしていた次第・・・・

最近大きめのスキルを作るようになってこれやっぱり辛いなーと思ってFlow Blockいじっててやっと気づきました。重ね重ね、前回の記事をご覧いただいた方には申し訳ありません・・・不便だなと思ったところは、勝手に自己解決せずに積極的に改善要求あげていかないといけないし(そしたら気づいてたはず)、もっと深堀りしていかないととダメだなーというのを、お恥ずかしながら改めて痛感しました、ハイ・・・


ということで、まとめです。今回は多分間違ってないです😅😅😅

  • Flow Blockの中でしか使えないフロー変数を定義できる。他のFlow Block(ROOTフローも含めて)からも見えない。
  • フロー変数は永続化されない。つまり次回以降のセッションでは初期化される。
  • ROOTフローで作成したプロジェクト変数は、グローバル変数となり、どこからでも読み書きできる。
  • ROOTフローで作成したプロジェクト変数は、永続扱いとなり、セッションを跨いでも維持される。
  • ROOTフローでもフロー変数を作ることができる、すなわち、そのセッション内でしか有効でない変数と、セッションを跨いで有効な永続変数を、使い分けることができる。
  • ROOTフローとFlow Blockでフロー変数の受け渡しができる

こうやってまとめると、改めてほんとよく考えてあるなーと思います。Flow Blockを使えば変数のスコープも定義できるし、それに限らず、永続・非永続もきちんと使い分けれる、これなら大きめのスキルでもかなり作りやすくなるんじゃないかなーと思います。なかなか使うことの少ないBlockだと思いますが、ぜひご活用いただければと思います!