kun432's blog

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

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

Voiceflow TIPS #15 Integration Block でカスタムAPI連携

1日遅れてしまいましたが、Voiceflow夏休みAdvent Calendarの15日目です。

Googleスプレッドシート連携は一休みして、今日はIntegration Blockを使って、他の外部のAPIとの連携をやってみたいと思います。

VoiceflowのIntegration Blockでできるのは以下の3種類です。

  1. Googleスプレッドシート連携
  2. Zapier連携
  3. カスタムAPI連携

中身的にはすべて、外部のAPIとの連携なのですが、1と2は一般的な使い方に絞って、VoiceflowのGUIの中で設定を可能にしたものとなってます。なので、Googleスプレッドシート・Zapier以外の、他のAPIと連携したい場合は「カスタムAPI」を使う必要があります。カスタムAPI連携を使うには、APIに関する基本的な知識や、接続したいAPIサービスごとの仕様などを確認したりする必要がありますが、使いこなせると非常に多くのサービスと連携ができるようになるので、ぜひ使ってみてください。

ではまずスキルの実行イメージから。


アレクサ、「郵便番号検索」をひらいて

郵便番号検索スキルです。7桁の郵便番号を言ってください。

6500042

郵便番号「6500042」ですね。お調べいたしますのでお待ち下さい。

(♪音楽)

郵便番号「6500042」は「兵庫県神戸市中央区波止場」です。

ご利用ありがとうございました。(♪音楽)


郵便番号をいうと住所を教えてくれるという非常にシンプルなものですね。こういうAPIはたくさんありますが、今回は事前登録等なしで使える、以下のAPIを使ってみようと思います。

なお、APIの利用については、API提供元の利用規約を必ず確認、同意の上、利用するようにしてください。

スキルの全体図

f:id:kun432:20190816011555p:plain

とてもシンプルですね。大まかな流れとしては、

  1. 郵便番号をユーザの発話から取得する
  2. 取得した郵便番号を元に、APIにリクエストする
  3. APIの実行結果が返ってくるので、それを整形して発話する。

という感じなので、ブロックの役割としてはこうなります。

f:id:kun432:20190816012114p:plain

それぞれ見ていきましょう。

ユーザの発話から郵便番号を取得する。

ここはそんなに難しくないですね。Capture Blockを使って、ユーザから郵便番号を取得し、変数に入れます。

f:id:kun432:20190816020821p:plain

f:id:kun432:20190816020702p:plain

f:id:kun432:20190816020713p:plain

f:id:kun432:20190817000851p:plain

ちょっとクセがあるのは、郵便番号のような数字だけど数字じゃない数値の扱いです。例えば、北海道札幌市北区の郵便番号は「0010000」なんですが(0で始まる郵便番号があることを初めて知りました・・・)、これをアレクサにそのまま読ませるとこうなります。

いちまん

何も指定しないと、純粋な数値として判断するので、最初のゼロがカットされちゃうのですね。こういう場合は、SSMLで読み方を指定してあげます。

<say-as interpret-as="digits">0010000</say-as>

読み上げはこうなります。

れい れい いち れい れい れい れい

「桁(digits)」と解釈して読む、ということですね。最初のより悪くはないですけど、実際に喋らせてみると、数字と数字の間は短いし、できれば「れい」じゃなくて「ぜろ」って読み上げてほしいですよね。

なので、ちょっと本来の使い方ではないのですが、こういうのもあります。

<say-as interpret-as="telephone">0010000</say-as>

書いてあるとおり、「電話番号」ですね。7桁と10桁のみなのですが、うまく読み上げてくれます。

ぜろ、ぜろ、いち、ぜろ、ぜろ、ぜろ、ぜろ

ちなみに、4桁とかでもちゃんと「ぜろ」と読んでくれますけど、数字と数字の間は短めです。

今のは発話する場合なんですが、受け取る場合も考慮が必要です。数字を受け取るスロットタイプには、AMAZON.Number、か、AMAZON.FourDigitNumberを使うのが良さそうですが、以下のクラメソさんのサイト見ると、AMAZON.FourDigitNumberを使うのが良さそうですね。FourDigitといいつつ、4桁以外も取れるようですし。

APIの実行

では今日の本題ですね。受け取った郵便番号をAPIに投げます。Integration Blockを使うのですが、まず最初にAPIの説明を見てみましょう。

郵便番号検索API - zipcloudを見るとこう書いてあります。

f:id:kun432:20190816214226p:plain

リクエストURL

ベースとなるURLは以下になります。

http://zipcloud.ibsnet.co.jp/api/search

これがAPI送信先になります。ただし、「何」について問い合わせるかはどこにも書いてませんね。そこで、

このURLにリクエストパラメータを加え、リクエストを行います。

リクエストパラメータと呼ばれる可変な値を付与します。今回の例だと「郵便番号」がこれにあたります。ではこのパラメータにはどんなものがあるのか?どういうふうに指定するか?というところが以下となっています。

パラメータ名 項目名 必須 備考
zipcode 郵便番号 7桁の数字。ハイフン付きでも可。完全一致検索。

3つほどのパラメータがありますが、必須なのは”zipcode”だけですね。これだけをパラメータ指定すればよいわけです。で実際に送る場合の例です。

(例)郵便番号「7830060」で検索する場合 http://zipcloud.ibsnet.co.jp/api/search?zipcode=7830060

リクエストURLに”?”をくっつけて、”パラメータ名=パラメータの値”という風にリクエストパラメータを指定して送ればよいわけですね。で、こういうふうにURLにパラメータを指定して送るやり方を「GET」といいます。もう一つ、主要な贈り方としては「POST」というのもあります。「GET」か「POST」かは、APIの利用時には必要な情報で、これによってパラメータの指定の仕方が変わってきたりします。

APIを利用する場合は、こういったAPI側の仕様を事前に確認して、それに従ってリクエストをしないと結果が得られない、ということを覚えておいていただければよいかと思います。

では、必要な情報は揃いましたので、実際に設定していきましょう。

Integration Blockを置いて、右のメニューから「Custom API」をクリックします。

f:id:kun432:20190816220958p:plain

Custom APIのメニューが表示されますので、順次設定します。まず、最初にAPIへのリクエスト方法を選択します。今回は「GET」でしたよね?ということで、"Make a GET Request"をクリックします。

f:id:kun432:20190816221239p:plain

次にGETリクエストの設定をしていきます。URLのところが「リクエストURL」の入力になりますので、先程のURL「http://zipcloud.ibsnet.co.jp/api/search」を入力します。そして、「リクエストパラメータ」の設定を行いますので、”Param”をクリックします。

f:id:kun432:20190816221516p:plain

思い出してほしいのですが、パラメータは”パラメータ名=パラメータの値”でしたよね?このように、パラメータは名前と値の「ペア」になりますので、このペアを追加するわけですね。ということで、"+Add pair"をクリックします。

f:id:kun432:20190816222009p:plain

するとkeyとvalueという入力項目が出てくると思います。パラメータ名とパラメータ値のペアは、"key & value"とも言われます。したがって、ここにそれぞれを入力すればよいわけですね。keyにパラメータ名"zipcode"、valueに変数"{zipcode}"を指定します。変数指定の場合は最初に"{"を入力して、リストに表示されたものを選択することに注意してください。設定したら”Next”をクリックします。

f:id:kun432:20190816223129p:plain

次に、レスポンスと変数の紐付けです。TIPS #12 の Googleスプレッドシート連携の「検索」の時にも説明しましたが、リクエストの「結果」として受け取ったデータ(レスポンス)を変数に入れることで、以降の処理でそれを使えるようになりますので、ここで紐付けの設定が必要です。とりあえず、"Add Output Mapping"をクリックしてみましょう。

f:id:kun432:20190816224007p:plain

先ほどと同じように、入力する箇所が2つあります。右はVariableと書いてあり、レスポンスを保存しておくための変数をリストから選択して、ということはなんとなくわかっていただけると思います。左のObject Pathとはなんでしょうか?

これを理解するためには、実際にどういうレスポンスが返ってくるかを見てもらったほうが早いと思います。

まず、とりあえずレスポンスを受け取るための変数を作りましょう。変数のメニューから、今回は"res"というフロー変数を作成しました。

f:id:kun432:20190816230012p:plain

変数を作成したら、Integration Blockをクリックして、Mapping Outputをクリック、先程の設定画面を表示し、以下のように、Object Pathに"response"を入力、Variableは"{res}"を選択して、Nextをクリックしてください。

f:id:kun432:20190816230659p:plain

では、"Testing Integration" をクリックしてみてください。

f:id:kun432:20190816230900p:plain

画面中央にテスト実行を行うためのメニューが表示されます。zipcodeに適当な郵便番号を入力して、"RUN"をクリックしてみてください。

f:id:kun432:20190816231228p:plain

すると右下に結果が表示されます。

f:id:kun432:20190816231426p:plain

この中で結果として使いたいのは、真ん中にある"address"の1~3あたりですよね?これを取るにはどうすればよいか?試しにaddress1にカーソルを合わせてみてください。青いクリップボードのアイコン(小さいですけど)が表示されるのがわかりますか?これが表示されたらクリックしてみてください。

f:id:kun432:20190816232543p:plain

そして、再度、Mapping Outputのところをクリックして、"Add Output Mapping"をクリック、Object Pathのところでペーストしてみてください。すると、値が入るのがわかりますでしょうか?

f:id:kun432:20190816233245p:plain

ちょっと見えにくいので、以下に貼っときます。

response.results.0.address1

これ、よく見てみると、さっきのデータの先頭部分がだいたい順番に並んでる感じなのがわかるでしょうか?

f:id:kun432:20190816233515p:plain

一般的なAPIのレスポンスは、”JSON"というフォーマットで返ってくることが多いのですが、JSONというのは、データを「構造化」したものになっています。上記のデータでいうと、「responseという箱の中にresultsという箱があって、resultsは複数の箱に分かれていて、その中の0番目の箱にはさらにaddressという箱があり、中に"兵庫県"という値が入っている」という感じですね。したがって、特定の値を取り出す場合には、上記のような箱の名前を順番に"."(ドット)でつなぎ合わせることで、必要な値の「住所」というか「場所」を指定してあげるという形になります。

JSONについては、たくさん説明しているサイトが有るのですが、以下のサイトあたりがわかりやすいのではないかなと思います。

reffect.co.jp

これで、特定の値の取り出し方がわかったと思うので、address1〜3についても同じように設定してください。そして、それぞれを入れておくための変数も作る必要がありますね。

f:id:kun432:20190816234940p:plain

最終的にはこんな感じになります。

f:id:kun432:20190816235003p:plain

見にくいですね、、、こういう場合には、Integration Blockの右上にある、歯車アイコンをクリックして、Expandをクリックしてみてください。

f:id:kun432:20190816235653p:plain

画面中央にIntegration Blockと同じメニューが表示されるので、Mapping Outputをクリックしてみてください。

f:id:kun432:20190816235818p:plain

おお!見やすいですね!このように右のメニューで見にくい場合は、Expandを使うことで広く見れます。Expandメニューは他のブロックでも使えますので活用してください。

f:id:kun432:20190816235933p:plain

ただし、残念ながら、このExpandメニューは現在バグが有り、"+ Add Pair" とか "+ Add Output"などのボタンが効かない状態になってます・・・そのうち治ると思いますが、現時点では参照するだけにしか使えませんのでご注意下さい。

あと、最初に作った"response"と"res" のペアはもう不要なので削除しておいて下さい。

これでカスタムAPIの設定は終了です。

APIの結果データを使った発話とエラー時の発話

郵便番号をAPIにリクエストして、レスポンスとして住所を取得しましたので、あとは発話させるだけです。

f:id:kun432:20190817000641p:plain

あと、忘れてはいけないのは、API実行は失敗する場合もあるということです。その場合も踏まえて、エラーメッセージを発話するブロックを追加しておくのも大事ですね。

f:id:kun432:20190817000400p:plain

テスト

ではテストです。

f:id:kun432:20190817003852p:plain

うまく行ってますね。もう一つ。

f:id:kun432:20190817003912p:plain

あれ、だめですねぇ、、、確認してみたんですが、Alexa からはきちんと "0010000" で渡っているので、Voiceflow側で数値に変換しちゃってるみたいですね・・・ということで、少し修正。Code Blockで少しいじります。

f:id:kun432:20190817004746p:plain

こういうコードを差し込んであります。

zipcode = '0'.repeat(7 - (zipcode + '').length) + zipcode + '';

zipcodeが数値で渡されてくるので、文字列化して桁数をチェック。郵便番号は7桁なので足りない分だけ頭に"0"を文字列としてくっつけるという感じですね。さぁどうでしょうか?

f:id:kun432:20190817005025p:plain

一応ちゃんと渡ってますね。・・・が、最後がおかしいな・・・・Integration Blockでテストしてみます。

f:id:kun432:20190817005146p:plain

あー、なるほど、この郵便番号に紐付いた住所にはaddress3がないのですね・・・さらに修正。やっつけ感満載ですねw

f:id:kun432:20190817010401p:plain

f:id:kun432:20190817010427p:plain

f:id:kun432:20190817010412p:plain

addr_allという新しい変数を用意して、addr1〜3についてそれぞれなにか値が入っていればそこにどんどん連結していく、つまり、上のaddr3のように何も入ってない場合はスルーするって感じですね。最後に話すところも先程まではaddr1〜3を直接話させていましたが、連結させたaddr_allを話すようにしました。さぁ、これでどうだ?

f:id:kun432:20190817010617p:plain

はい、うまくいきましたねー、汗

今回の結論としては、数値のチェックやテストはしっかりやりましょう、ということで(違


いかがだったでしょうか?最後バタバタしちゃいましたが、APIとは関係ないところなので、そこは置いといて・・・

APIの設定は、連携したいAPI

  • リクエストの送り方
  • レスポンスの受け取り方

を、APIのドキュメントなどで確認した上で、指定されたとおりに(Voiceflow上で)設定するということが必要になります。最初のうちは難しいかもしれませんが、簡単そうなものから始めて、徐々に複雑なものに挑戦する、という形でいろいろやっていただければ、設定の勘所みたいなものがわかるようになると思いますので、トライアンドエラーで頑張ってみてください!

あと、最後に注意です。

  • APIの利用は、API提供元の利用規約を必ず確認、同意の上、利用するようにしてください。
  • API実行に失敗する場合もあります。きちんとエラー時の処理を忘れないようにご注意ください。
  • 場合によっては、スキル利用者にもAPI利用規約に同意して頂く必要があります。その場合には、スキル申請時に、利用規約やプライバシーポリシー等の準備も必要になる場合がありますのでご注意ください。

APIをうまく活用して、スキル開発の幅を広げていただければ幸いです。