完成したAlexa
こんな感じで会話をしながら、最終的にslackに投稿してくれるAlexa Skillを実装しました。
Alexaからslackに投稿できるスキル作ったhttps://t.co/uvWrFhfqLl
— Takayoshi Makabe (@Takayoshi_ma) March 5, 2021
リモートワークの悩み
きっとQiitaを見てる大半の人はエンジニア、そうでなくとも何かしらIT関係のお仕事をしている方が多数かと思います。コロナの影響で一気にリモート化が進んだIT業界、自らも気づけばフルリモート生活が長らく続いています。
『出勤する時間が無くなった』、『無駄な会議が無くなって業務時間の短縮に繋がった』など、個人的にリモートワークに対してはポジティブな印象を抱いているのですが、中には「家事と仕事が同時に襲ってくる」、「子供の世話で手が離せなくてストレスを感じてしまう」など、必ずしも良いことばかりでは無いという方も多いように見受けられます。そんな中、「家事とかしながらslackに簡単なメッセージ投稿できたら楽じゃね?」と思い、今回Alexaからslackに投稿できるスキルを実装しました。決して「これでベッドにいながら話しかけるだけで出勤!!」とかのために実装したのでは無いので悪しからず!
仕様
下記のシーケンス図は正常系の処理になります。
(補足)
- Skillの呼び出し名は「スラック」とする。「Alexa、スラック」や「Alexa、スラック起動して」などどと話しかければ、スキルが起動する。
- 起動後に「Slackを起動しました。どの様に投稿しますか?」と聞き返す。ユーザーが投稿内容をつぶやいた後、「Slackに◯◯」と投稿してもよろしいですか?」と聞き返す。
- 2の後、「はい、イエス、オッケー」などをユーザーが発話するとslackへの投稿を行う。
- 2の後、「だめ、いや、ノー」などをユーザーが発話するともう一度「どの様に投稿しますか?」と聞く。
- 2の後、「はい」や「いいえ」に関連するワード以外(例:キツネ)を発話すると「キツネと投稿しますよろしいですか?」と聞く。
- 無事、Slackへの投稿が終了した場合、「Slackに◯◯と投稿しました。」と発話する。
- 投稿するワークスペースは1つだけ。またchannnelも1つだけとする。
- 何らかの原因で投稿が完了しなかった場合、その旨をユーザーに伝える。
Slack API
SlackAPIを使い、投稿をポストできるように準備します。この方の記事の通り進めていけば問題なくできました。このアプリをslackのチャンネルに追加することで、投稿することが確認できました。
curl -X POST 'https://slack.com/api/chat.postMessage' \
-d 'token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
-d 'channel=#general' \
-d 'text=Alexa Talk Appです。投稿してみたよ。'
curl -X POST 'https://slack.com/api/chat.postMessage' \
-d 'token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
-d 'channel=#general' \
-d 'text=これはさっきと違ってslackAPIを利用することで僕の代わりにアプリが僕のアカウントで話してる'
上記のシェルスクリプトを実行して以下のように投稿できれば成功です。
slackに投稿する方法をググった際、これより先にwebhookを使う方法が出てきました。そちらの方法だと追加したアプリ自身が投稿することは簡単に出来たのですが、私自身のアカウントを使用して投稿したい場合、この方が簡単そうなので、今回はこちらの方法で実装していくことにしました。
Alexa Skill
Alexa SkillからLambdaにきちんと投稿内容を飛ばせるようにするために簡単な設定を行います。Alexaにはインテントやシノニム、スロットを使って、幾つもの会話パターンを事前登録する機能があります。例えば以下のようにスロットを設定するとAlexaは{}部分に入るワードをリクエストjsonの中に組み込んで出力します。
{post}って投稿して
{post}ってお願い
{post}でよろしく
ただ毎回、毎回「って投稿して」って言うのも煩わしいので、今回は下記の通り3つのインテントスロットとスロットタイプを設定しました。
これで、この中のどれかの発言をした場合、Alexa側で指定されたスロットとしてlambdaにリクエストを飛ばしてくれます。ただ実際問題、どのスロットに該当しないワードを発話したい場合の方が殆どだと思います。 ((例)今日は休みます。)
その場合、Alexa側で自動的にどれかのスロットに分類してリクエストを飛ばしてくるのですが、labda側で強制的にpost_slot
に値をswapすることで、より自然なコミュニケーションになる様に工夫しています。
Lambda
まず関数を適切なロールをアタッチして上で作成します。次にLambda側のトリガーに先ほど作成したAlexaSkill側のSkillIDを登録し、次にAlexa側にエンドポイントとしてLambdaのARN
を登録します。設定が終わりましたら、以下のレポジトリ [GitHub] をローカルにクローンして、必要なモジュールをインストールしzipで圧縮後、先ほど作成したlambdaにソースコードをアップロードします。
# クローンしたディレクトリに移動後、初期化&必要なモジュールをインストール
$ npm install
$ npm install --save ask-sdk-core
$ npm install --save ask-sdk-model
$ npm install --save request
# 圧縮後lambdaにアップロード
$ zip -r {ファイル名} index.js node_modules
尚、コード内にトークンを直書きするのも色々危ないので、lambda側でSLACK_ENDPOINT
、TOKEN
、CHANNEL
の三つを環境変数として予め登録しています。また、AlexaSkillの方もインテントやエンドポイントの設定が終わった後にきちんとデプロイしないと、正しく動作しません。
あとがき
「こんなの作ってもどうせ使わない」とか思う人も多いと思います。実際僕もそうでした(笑)ただ意外に使い出してみると結構手放せなくなるのがスマートスピーカーの良いところ。これは使ってみないと分かりません。ぜひ皆さんもAlexaいじってみてください(スマホからもアプリとしてインストールできます。)