とりあえず Alexa スキル動かすだけ

いつもナビタイムの「次のバス」スキルにお世話になっていました。

これは「最寄りのバス停を登録しておくと "次のバスのスキルを開いて" というだけで次のバスが何分後に来るか、さらにその次のバスは何時何分か」を教えてくれる便利なスキルです。

ところが、このスキルが今月末にサービス終了するようです。

これは非常に困るので自分で Alexa スキルを作ります。

Alexa スキルは作ったことがなく、「Lambda とか DynamoDB くらいは使うんだろうなー」くらいに考えていましたがどうやらスキルを作るのに AWS は不要らしいです。

もちろん凝ったものを作ろうと思えば別でしょうが、今回は時刻表引いて返すだけのドシンプルなものです。

できれば簡単に作りたいですね。

さっそく作るぜ!

Alexa Developer Console とゆーのに EC サイト(NOT AWS)の Amazon アカウントでログインします。

スキルの作成 をクリック。

適当にスキルの名前を付けます。「次のバス」って名前を付けちゃうと既存ナビタイムアプリとウェイクワードが衝突します。

まあいいでしょう。どのみち後で変えることになります。

エクスペリエンスのタイプを「その他」に設定。

この項目自体にあまり意味はなくて、次の「モデルを選択する」で選べる選択肢のフィルタリングに使われてるっぽいです。

モデルは「カスタム」に設定。

カスタムにしとけば後で融通利くかなという感じ。変にプレビルド設定されてもよくわからんし。

「ヘルプドキュメント」のリンクが貼られてるが読みませ~ん。家電使うときに困ってから説明書読むタイプです。

ホスティングサービスは「Alexa-hosted(Python)」にしました。

下画像の内容を見る限りだと Alexa-hosted が Alexa 側で Lambda と DynamoDB の無料枠を使わせてくれるみたい。

Alexa-hosted でも無料枠を超えたら AWS アカウントに紐づける必要があるようです。

なぜ Node.js でなく Python なのか。わざわざ Python の選択肢あるのにサーバ側 JavaScript で書くの辛くない?ってだけです。

ホストリージョンは「オレゴンに」設定。そもそも東京リージョンという選択肢はない(独自のプロビジョニング を選択してたら使えるのかな?)。

うーん、バス時刻聞くだけなのに海越えていくなんてロマン溢れる~☆彡

ちな、バージニア北部よりオレゴンの方がちょっと速いみたいです。まあ普通に海底ケーブル太平洋通ってるから西海岸の方が速い。

各AWSリージョンとのネットワーク遅延を計測したい | DevelopersIO

テンプレートは「スクラッチで作成」を選択。これは悩んだが、まぁググればそれっぽいコードがゴロゴロ落ちてるだろという期待。

最終的な設定はこちら。

とりま動かすぜ!

さっそく意味わからんポータルが出てきた!右側の「スキルのビルド」の部分はビルド設定っぽいが全部チェックマークついてるので無視。

上タブで「テスト」に移動し、非公開 -> 開発中 に変更。

マイクアイコンを長押ししながら発話すると返答が返ってきます。すごい!

上タブで「公開」に移動し、適当に入力。

そうか、オレゴンリージョンにデプロイするからソフトウェア輸出規制に引っかかる恐れがあるのか。個人情報も企業機密や軍事機密もないのでOKでしょう。

ベータテストができないとのことで困る。が、とりあえず進めるところまで進んでみる。

エラーが出てきた!やったー!!これさえ解消すればベータテストできるはず。

サンプルフレーズを入力。これに伴い、スキル名を 次のバス から バスの時間 に変更。

スキルアイコンを適当に作る。アイコンビルダーないかなーと思ったらやはりあった。神。

dev.classmethod.jp

適当にバスのアイコンを作って設定。

さっきのベータテストの設定が記入できるようになったので適当に記載し有効化。

※メアド晒したくないので画像上はブランクです。

ベータテストは有効期限付きかー。まあそりゃそうか。

永続的にデプロイしたいがそのためにはやはり「Alexa for Business」が必要なんだろうか。

再度検証するとエラーは全て解消してました。

招待メールが届いているのでリンクをクリックし、スキルをデバイス側に登録する。

さっそく実行!※注意:再生するとあなたの家の Alexa が反応します

www.youtube.com

あれ。。。全然反応しない。。。

コンソールを見返す。ウェイクワードっぽい設定箇所は以下。

  • ビルド > 呼び出し > スキルの呼び出し名
  • 公開 > 公開名
  • 公開 > サンプルフレーズ

で、さっき 次のバス から バスの時間 に設定しなおしたのは「公開設定」のみ。

公開設定は文字通り「公開するための設定」であって、Alexa スキルの設定ではないですね。ただのスキルの説明文です。

なので、「スキルの呼び出し名」を変更する必要がありました。

再度スキルをビルドし、テスト。ちゃんと答え返ってきてるっぽい!

ちょっとだけコード書くぞ!

コード書くといっても返答を日本語にするだけです。

上タブから「コードエディタ」へ移動。すでにサンプルコードが書かれてる。

以下の GitHub サンプルと同じコードだと思われ。

github.com

さっきのテストコードでの返答が "Welcome, you can say Hello or Help. Which would you like to try?" だったので、LaunchRequestHandler の中身の文字列だけ書き換えればよさそう。

書き換え前

書き換え後

ワードで分岐するような性質のスキルを作るわけじゃないので、handler_input は触らなくていいですね。

「保存」「デプロイ」し、テストタブに移動してテストする。

ちゃんと動いた!

既に Lambda へ反映されてるのでデバイス側のスキルは更新しなくてもいいかな?

とりま Alexa にしゃべりかける。

www.youtube.com

動いてはいるが、返答を2回繰り返したり、なんか英語話し出したりしている。

たぶん FallbackIntentHandler に反応してる。

ちょっとコードの意味を調べる。

developer.amazon.com

an_handle:can_handleメソッドは、SDKによって呼び出され、指定されたハンドラーが受け取ったリクエストを処理できるかどうかを判断します。この関数はハンドラー入力オブジェクトを受け付け、ブール型を返すように想定されています。メソッドがTrueを返せば、ハンドラーによってリクエストが正常に処理されたと考えられます。Falseを返す場合、ハンドラーが入力リクエストを処理できず、したがって実行されず完了もしなかったと考えられます。HandlerInputオブジェクトにはさまざまなアトリビュートがあるため、リクエストを正常に処理できるかどうかをSDKが判別するための任意の条件を作成できます。 handle:handleメソッドは、リクエストハンドラーを呼び出すときにSDKによって呼び出されます。この関数には、ハンドラーのリクエスト処理ロジックが含まれており、ハンドラー入力を受け取り、応答オブジェクトを返します。

blog.serverworks.co.jp

Alexaでの意味はユーザーの意図や目的を実現するためのアクション、といったところでしょうか。ユーザーが豆知識を教えてほしいという目的のときは「豆知識」というと「GetNewFactIntent」が実行され、ユーザーがヘルプを聞きたいときは「ヘルプ」と言うと「HelpIntent」が実行されるという感じですね。ユーザーの目的ごとにインテントが必要になる、というイメージです。  今回追加する「FallbackIntent」はユーザーが意図や目的をもってAlexaに話しかけても、Alexa側にそれに対応するためのインテントがない場合に実行されるインテントです。ちょっと特別なインテントですね。 とゆーことで、LaunchRequestHandler 以外のハンドラーを使わないようにする。

ふむふむ... そーゆーことか!わかったぞぉ!

今回作るスキルはインテントとか全く関係ないのでインテントハンドラーは必要ない。

SkillBuilder.add_request_handler をコメントアウトすれば無効化できる気がする。

ただし、最後のガードとしてまるっと例外キャッチする sb.add_exception_handler(CatchAllExceptionHandler()) は残しておく。

保存・デプロイして手元の Alexa で試した結果。

2回発話してしまうこと以外は想定通り(ちゃんと最後に例外キャッチした結果が返ってくる)。

www.youtube.com

今日は夜遅いのでここまで!

次はバス時刻表をしゃべらせるようにコーディングしていきます。

残課題

  • 1回しゃべったら自動的にスキルを終了する
  • 現在時刻から後ろで一番近いバス時刻と2番目に近いバス時刻をしゃべらせる ※最終便の場合、もうそれ以降バスがない場合の処理を忘れずに
  • ベータテストじゃなくちゃんとプライベートでホストする方法を探す(Skill for Business しかないのか。。。???)