[AWS re:Invent 2016 参加レポート]: 簡単なCustom Skillを作ってみてecho dotで試してみた #reinvent

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、せーのです。今ラスベガスです。今回はせっかくもらったecho dotを使って自分で作った簡単なSkillを動かしてみたいと思います。結構長いので気長に読み進めて見て下さい。

まずは簡単なものから作ってみよう

音声を使った入出力で色々なものが動かせるAmazon Alexaですが、実際に自分でSkillを作ってみようと思うと結構ハードルが高いです。

英語の壁

Alexaが理解できる言語は現在英語とドイツ語です。英語が得意ではない私にとってはAlexaと会話するだけでも翻訳サイトと首っ引きになったりします。

サンプルが結構難解

サンプルが用意されているのですが、実践的な内容が多く、ドキュメントも結構な量があります(それも英語)。読み解くのは結構時間がかかります。

公開に審査がある(7営業日くらい待たされる)

Skillを公開するのには審査があり、Best Practiceを読んで内容を修正してからでないと却下される可能性があります。

ということで普通に作ると結構色々手間がかかります。なので「言葉を投げたら言葉が返ってくる」という超絶簡単なSkillを作ってみたいと思います。上にあるように公開するのには手間がかかるのですが開発、ということであれば自分のアカウントのechoからは審査なしで呼び出せるっぽいので今回はそれを利用します。

やってみた

Alexa Skill kitを作る

ではやっていきましょう。まずはAlexaのDevelopersポータルに行きログインします。ログインはecho dotが登録されているAmazonアカウントで行います。ログインしたら[ALEXA]のメニューからAlexa Skill Kitを作成するボタンをクリックします。

alexa_custom_skill1

alexa_custom_skill2

[Add a New Skill]ボタンを押して作成を開始します。

alexa_custom_skill3

alexa_custom_skill5

まずはSkill情報を埋めます。Skill typeとはそのままSkillのタイプを示し、Custom Skillは「custom interaction model」です。ちなみに残りはそれぞれスマートホームでの操作(電気をつけたりエアコンを設定したり)、お知らせ情報の読み上げ(RSSとかを読み込んで話してくれる)のSkillを作る時に設定します。

alexa_custom_skill6

次にCustom Skill kitのキモ、連携モデルの作成に入ります。
連携モデルは主に「Intent Schema」と「Sample Utterances」の2つで構成されています。
Intent Schemaにはインプットされた入力に対するLambdaとの連携で使うIntent Name、Lambdaに渡す際のプロパティにあたるSlotを定義します。
Sample Utterancesは実際にechoに呼びかける時のサンプル文とどのIntent Nameを連携させるかを定義します。

上の例では「OguriCalling」というのがIntent Nameに当たり、「CallWord」というのがSlotに当たります。SlotのタイプはAmazonで既に規定されているタイプと自分で自由に作れる[Custom Slot]があります。今回は「CALL_WORD」というCustom Slotを作りたいと思います。このCALL_WORDというCustom Slotの定義を下で行います。[Add Slot Type]をクリックします。

alexa_custom_skill7

alexa_custom_skill8

出てきたエリアにCustom Slot名とその値をそれぞれ記述します。

alexa_custom_skill9

次にSample Utterancesを記述します。今回は[What do you gonna call(なんて呼ぶ?)]と聞かれたらOguriCallingのIntentと結びつけ、[Water][Morning]等CALL_WORDを呼ばれた場合はそれをそのまま引数としてOguriCallingと結ぶように設定します。

※非常に身内のネタなので意味は特に考える必要はありません。

alexa_custom_skill10

ここまでで一旦Custom Skill Kitの作成は置いておいて、Lambdaの作成に移ります。

Lambda Functionを作る

次に対応するLambda Functionの作成です。Alexa用のLambdaを作る時はバージニアリージョンにて行います。

alexa_custom_skill11

BluePrintから"Alexa"で検索したものから適当なサンプルを選択します。このサンプルを改変して作ったほうが速いです。

alexa_custom_skill12

TriggerがAlexaであることを確認します。

alexa_custom_skill13

とりあえず一旦何も考えずにFunctionをサンプルのまま作ってしまいましょう。IAM Roleはlambda_basic_executionで構いません。

alexa_custom_skill14

できました。

Lambdaのテスト

一旦lambdaが動くかどうかテストしてみましょう。[Congfigure test]を選択します。

alexa_custom_skill16

testのテンプレートから[Alexa start session]を選択します。

alexa_custom_skill15

saveしてtestします。

alexa_custom_skill17

こんな感じでレスポンスのログが出たら成功です。

つなげる

では先程のAlexa Skill KitとLambda Functionをつなげてみましょう。先程置いておいたAlexa Skill KitのページからNextボタンを押すとConfigurationのページに移ります。

alexa_custom_skill18

EndpointにLambda ARNを選択しリージョンを[North America]にチェックを入れたら表示されるボックスに作成したLambda FunctionのARNをコピーします。

Nextボタンを押したらSkill Kitの完成です。

alexa_custom_skill19

Lambda Functionの改変

ではLambda Functionに戻ってcodeを改変してみましょう。Alexaに対応するLambdaの場合、通常のexports.handlerメソッド内でeventTypeを拾い、そこからTypeによって色々な関数に飛ばしている、という書き方をしています。実際のデータが来るのは[IntentRequest]というeventTypeなので、そこに定義されているonIntentという関数内を書き換えればOKです。

function onIntent(intentRequest, session, callback) {
    console.log(`onIntent requestId=${intentRequest.requestId}, sessionId=${session.sessionId}`);

    const intent = intentRequest.intent;
    const intentName = intentRequest.intent.name;

    console.log("intentName: " + intentName);
    // Dispatch to your skill's intent handlers
    
    const sessionAttributes = {};
    const cardTitle = 'Oguri Said';
    var speechOutput = '';
    // If the user either does not reply to the welcome message or says something that is not
    // understood, they will be prompted again with this text.
    var repromptText = 'Call again';
    var shouldEndSession = false;

    if (intentName === 'OguriCalling') {
        if (!intentRequest.intent.slots.CallWord.value){
            speechOutput = "I am General of Water. Call me WATER."
        } else {
            console.log("CallWord: " + intentRequest.intent.slots.CallWord.value);
            var val = intentRequest.intent.slots.CallWord.value;
            if (val == "water"){
                speechOutput="morning!";
            }else if(val == "morning"){
                speechOutput="Oh, I fell asleep.";
            }else if (val == "haisho"){
                speechOutput="Don't say haisho.";
            }
        }
        callback(sessionAttributes,
            buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
    
    } else {
        throw new Error('Invalid intent');
    }
    
}

speechOutputに返事を、repromptTextにAlexaが聞き取れなかった際の固定返答を書いておきます。
残りのサンプルの要らない関数は削除しておくとスッキリしていいですね。

textテスト

ではまずはtextでテストしてみましょう。Skill Kitのページに戻ると下の方にシュミレーションのコンテンツがあります。

alexa_custom_skill20

この[Enter Utterance]という所にechoに呼びかける内容を書いてAskボタンを押すと左側にLambdaに飛ぶRequest内容が、右側にLambdaから返ってくるResponse内容が表示されます。この場合は「Hello oguri」というワードは特に設定していないのでResponseのoutputSpeechは空になっています。このResponseの所にInvalid XXXXXXというようなメッセージが見える時はLambdaの中でエラーが起きている確率が高いので、Requestの部分をそのままコピーしてLambdaのTestに貼り付けてエラーログを確認するといいでしょう。

仕上げ

さて、今回は公開するわけではないのであまり関係ないのですが一応Skill Kitの仕上げをしておきます。先程のTest画面からNextボタンを押すと公開時のDescription等の設定、コンプライアンスのチェック設定の画面をご紹介しておきます。

alexa_custom_skill21

alexa_custom_skill22

alexa_custom_skill23

これでOKです。最後の画面で「Submit for Certification」を押すと公開設定としてロックされ、審査が開始します。間違ってこのボタンを押してしまった時はWithdrawボタンを押して申請を解除しておきましょう。

alexa_custom_skill24

実機でテスト

では最後に実機でテストしてみましょう。http://alexa.amazon.com/からSkill - my Skillと辿っていくと先程作ったSkillが見えるかと思います。

alexa_custom_skill26

echoに対してこのSkillがセットされているのを確認しましたので実際にecho dotを使ってSkillを動かしてみます。

Alexa Sample from Tsuyoshi Seino on Vimeo.

成功です。

まとめ

いかがでしたでしょうか。簡単なSkillであればコツはあれど意外とサクサク作れることがおわかりかと思います。まずは自分で簡単なSkillを作ってみて、段々複雑なものにステップアップしていくのが良いかと思います。

Amazon echo dotは日本技適未通過の製品ですので日本在住者が日本国内で使用すると電波法違反となります。日本でAmazon Alexaを試す際はエミュレーションサイト(https://echosim.io/welcome?next=%2F)をお使い下さい。