AWS Lambdaを使ってAmazon Echoに機能追加してみた

Alexa Skills Kit
134件のシェア(ちょっぴり話題の記事)

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

はじめに

アメリカで発売が始まったAmazon Echoが届いたので、早速使ってみました。
Amazon Echoとは据え置き型のSiriのようなもので、音声を使って天気やニュースを聞いたり、単語の意味を調べたりできます。
IMG_2003

例えば、「Alexa, play music」と依頼すればAmazon Prime内の音楽から好みに合いそうな音楽を選んで流し、「Alexa, what time is it?」と聞けば現在時刻を教えてくれます。

Amazon Echoに話した内容はAWS上の音声サービスAlexaへと送られ、Alexaは離された内容に応じた処理を行い、結果をAmazon Echoに返します。
Amazon Echoの起動ワードが「Alexa」なので、僕はよく混同してしまうのですが、音声サービスの名前がAlexaで、デバイスの名前はAmazon Echoです。

Alexa Skills Kit

Alexaは最初から音楽再生やアラームなど幾つかの機能を備えていますが、Alexa Skills Kit(ASK)を利用するとAlexaに独自の機能(Alexa Skill)を追加することができます。

Amazon Echoへのリクエストは下図のようなフローでAlexa Skillに届き、処理されます。
askarchitecture
重要なのは、Alexaが音声データを解析し、テキストに変換を行ってくれるいう点です。
なので、Alexa Skillの方ではテキストでリクエストを受け取り、レスポンスもテキストで返すことができます。
詳しくはドキュメントを参照ください。

Alexa Skillの作成はAmazon Developer Console上で行います。
スクリーンショット 2015-08-04 21.32.01

Alexa Skillで設定する項目は下記です。

項目名 説明
Skill name スキル名です。
スキル一覧画面ではここで指定した名前が表示されます。
AlibabaSkill
Invocation Name スキル呼び出し時に使うキーワードです。 Alibaba
Endpoint 実際に処理を実施するアプリケーションのエンドポイントです。
ウェブサービスのURLまたはAWS LambdaのARNを指定します。
https://myskill.ishere.com/somepath
Intent Schema スキルが実行可能なアクションの一覧です。
JSONフォーマットで記述します。
{
  "intents": [
    {
      "intent": "OpenGateIntent",
      "slots": [
       {"name": "Keyword", "type": "LITERAL"}
      ]
    }
  ]
}
Sample Utterances Intentを発動させる時に発話されるフレーズの例です。 OpenGateIntent open {sesame|Keyword}
OpenGateIntent {sesame|Keyword} open
OpenGateIntent open {o simsim|Keyword}

上の例の場合、Amazon Echoに向かって次のように話しかけます。

Alexa, tell Alibaba that open sesame

最初にある「Alexa」はAmazon Echoの起動キーワード(wake word)です。Amazon Echoの設定画面でAlexaかAmazonのどちらかを選ぶことができます。
Alexaと呼びかけるとAmazon Echoの上部ランプが青く光り、リクエスト待ち状態になります。
そのあとに続く、「tell Alibaba that open sesame」がリクエストです。
「tell」はAlexaがサポートする会話開始用の単語で、直後にスキル発動キーワード(Invocation Name)とスキルに実施して欲しいアクションをつなげます。今回は「alibaba」と「open sesame」です。
Alexaはtell以外にaskやtalk、startなど普段の会話の中で使いそうな単語やフレーズをサポートしています。
これらは置き換え可能なので、

Alexa, talk to Alibaba and open sesame

でも全く同じリクエストとして扱われます。自然な文章になるフレーズを選んでください。サポートされているフレーズはこちらを参照ください。

ユーザからのリクエストを聞いたAlexaはAlibabaSkillを呼びだし、AlibabaSkillは指定されたエンドポイントにOpenGateIntentを実行するようにリクエストを送ります。
「open sesame」はSample Utterances設定により、「OpenGateIntent」にマッピングされています。
リクエストにはslotの内容("Keyword": "sesame")も含まれます。

Alexa Skillからのリクエストを処理するエンドポイントは別途用意する必要があります。
エンドポイントにはウェブサービスのURLかAWS LambdaのARNを指定できます。

AWS Lambdaを利用したAlexa Skillの作成

AWS Lambdaに用意されているサンプル「alexa-skills-kit-color-expert」をエンドポイントとするAlexa Skillを作成してみます。
全体的な処理の流れは次の図のようになります。 Alexa-skill

サンプルスキル概要

サンプルスキルで想定されているやりとりは次のように単純なものですが、Alexa Skillで出来ることが一通り分かるとても良いサンプルになっています。

  1. ユーザ:「Alexa, ask color expert.」
  2. Alexa:「Please tell me your favorite color?」
  3. ユーザ:「My favorite color is blue.」
  4. Alexa:「I now know your favorite color is blue. You can ask me your favorite color.」
  5. ユーザ:「What is my favorite color?」
  6. Alexa:「Your favorite color is blue.」

まず、AWS Lambdaでサンプル用スキルのエンドポイントを作成し、そのあと、Alexa Skills KitでAlexa Skillを作成します。

Lambdaファンクションの作成

AWSのマネジメントコンソールでヴァージニアリージョンのAWS Lambdaの管理画面を開いてください。
blueprint一覧から「alexa-skills-kit-color-expert」を選択し、ひたすらNextで進んでください。
スクリーンショット 2015-08-05 20.48.04
途中、IAM Roleを指定するところがあるので、「lambda_basic_execution」を指定してください。

確認画面は次のようになります。
「event source」はAlexaになっています。
スクリーンショット 2015-08-05 20.50.33

ファンクション作成後、サンプルスキルのエイドポイントとして指定するため、ARNを控えます。
スクリーンショット_2015-08-05_20_58_19

これでエンドポイントの準備は終了です。
次に、このエンドポイントを利用するAlexa Skillを作成します。

Alexa Skillの作成

Amazon Echoを登録しているAmazonアカウントと同じアカウントでAmazon Developer Consoleにログインします。
Alexa Skillsのマーケットはまだ準備中のため、現在は開発中のテストという形でAlexa Skillを利用することになります。
スクリーンショット 2015-08-05 21.17.54
ログイン後、「APPS&Services」の「Alexa」に移動し、
スクリーンショット 2015-08-05 21.18.37
「Alexa Skills Kit」を選択します。

Alexa Skillの設定を行います。
スクリーンショット_2015-08-05_21_32_39
今回は

  • Name: SampleSkill
  • Invocation Name: color expert
  • Endpoint: (先ほど作成したLambdaファンクションのARN)

としています。

次に、ユーザとAlexa Skillとのやりとり内容(Interaction Model)を定義します。
スクリーンショット 2015-08-06 10.09.39
Intent Schemaはスキルが実行可能なアクションの一覧なのでした。

{
  "intents": [
    {
      "intent": "MyColorIsIntent",
      "slots": [
        {
          "name": "Color",
          "type": "LITERAL"
        }
      ]
    },
    {
      "intent": "WhatsMyColorIntent",
      "slots": []
    },
    {
      "intent": "HelpIntent",
      "slots": []
    }
  ]
}

MyColorIsIntent、WhatsMyColorIntent、HelpIntentの3つのIntentを定義しています。
slotとはIntentの引数のようなものです。
MyColorIsIntentはユーザが自分の好みの色をAlexaに伝えるためのslot「Color」を持っています。
「Color」slotのタイプは「LITERAL」です。ユーザが話した内容がそのままテキスト変換されてAlexa Skillに送られます。
slotタイプは次の4種類があります。

  • LITERAL
  • NUMBER
  • DATE
  • TIME
  • DURATION

LITERAL以外はエンドポイントに渡される前にデータ変換がなされます。

例えば、

three

はLITERALの場合は、「"three"」という文字列でエンドポイントに渡されますが、NUMBERの場合は「3」という数字で渡されます。

today

はLITERALの場合は、「"today"」という発話通りの文字列でエンドポイントに渡されますが、DATEの場合は「"2015-08-06"」という日付を表す文字列で渡されます。

Sample UtterancesはIntentを発動させる時に発話されるフレーズの例なのでした。

WhatsMyColorIntent what's my favorite color
WhatsMyColorIntent what is my favorite color
WhatsMyColorIntent what's my color
WhatsMyColorIntent what is my color
WhatsMyColorIntent my color
WhatsMyColorIntent my favorite color
WhatsMyColorIntent get my color
WhatsMyColorIntent get my favorite color
WhatsMyColorIntent give me my favorite color
WhatsMyColorIntent give me my color
WhatsMyColorIntent what my color is
WhatsMyColorIntent what my favorite color is
WhatsMyColorIntent yes
WhatsMyColorIntent yup
WhatsMyColorIntent sure
WhatsMyColorIntent yes please
MyColorIsIntent my favorite color is {green|Color}
MyColorIsIntent my favorite color is {red|Color}
MyColorIsIntent my favorite color is {blue|Color}
MyColorIsIntent my favorite color is {orange|Color}
MyColorIsIntent my favorite color is {gold|Color}
MyColorIsIntent my favorite color is {silver|Color}
MyColorIsIntent my favorite color is {yellow|Color}
MyColorIsIntent my favorite color is {black|Color}
MyColorIsIntent my favorite color is {white|Color}
HelpIntent help
HelpIntent help me
HelpIntent what can I ask you
HelpIntent get help
HelpIntent what commands can I ask
HelpIntent what commands can I say
HelpIntent what can I do
HelpIntent what can I use this for
HelpIntent what questions can I ask
HelpIntent what can you do
HelpIntent what do you do
HelpIntent how do I use you
HelpIntent how can I use you
HelpIntent what can you tell me

精度を上げるためユーザが話しそうなことを出来るだけたくさん並べています。

最後に、テストを有効にして、自分のAmazon Echoでこのスキルが利用できるようにします。
スクリーンショット 2015-08-06 10.10.39

これで新しいAlexa Skillが完成しました。

Amazon Echoの管理画面で確認するとスキルが追加されていることが確認できます。
スクリーンショット 2015-08-05 18.23.51
スクリーンショット 2015-08-05 18.24.01

動作確認してみます。

動作確認

Lambdaファンクションのスクリプトを修正し、Alexaとのやりとりをログに出力するようにしました。
想定問答通りにAmazon Echoに話しかけてみます。

サンプルスキル発動

僕:

Alexa, ask color expert.

下記リクエストがAlexaからエンドポイントのLambdaファンクションに送られます。

{
    "version": "1.0",
    "session": {
        "new": true,
        "sessionId": "amzn1.echo-api.session.775c547f-f710-42ea-9881-a22206dc7942",
        "application": {
            "applicationId": "amzn1.echo-sdk-ams.app.[unique-value]"
        },
        "user": {
            "userId": "amzn1.account.[unique-value]"
        }
    },
    "request": {
        "type": "LaunchRequest",
        "requestId": "amzn1.echo-api.request.95736e09-b4b0-4035-ada7-9c7da4de84b9",
        "timestamp": "2015-08-06T20:20:02Z"
    }
}

新しいセッションが開始されています。
セッションが続く間は同じsessionIdがAlexaから渡されます。

「applicationId」はAlexa Skill毎にユニークなIDです。
Lambdaファンクション作成時に、イベントソースとしてAlexa Skills Kitを指定しました。
スクリーンショット 2015-08-05 20.48.58
特定のAlexa SkillではなくAlexa Skills Kit全体がイベントソースとなる点に注意ください。
つまり、誰が作ったAlexa Skillでも、このLambdaファンクションのARNをエンドポイントとして指定すれば、自由にLambdaファンクションを利用できてしまいます。
なので、Lambdaファンクションの利用を制限するためには、スクリプト内でapplicationIdをチェックする必要があります。

if (event.session.application.applicationId !== "amzn1.echo-sdk-ams.app.[unique-value-here]") {
  context.fail("Invalid Application ID");
}

リクエストタイプは「LaunchRequest」となっています。
「ask (Invocation Name)」という呼び出しでIntentが指定されていないので、スキルの発動のみを要求しています。

これに対する、Lambdaファンクションからのレスポンスは下記です。

{
    "version": "1.0",
    "sessionAttributes": {},
    "response": {
        "outputSpeech": {
            "type": "PlainText",
            "text": "Welcome to the Alexa Skills Kit sample, Please tell me your favorite color by saying, my favorite color is red"
        },
        "card": {
            "type": "Simple",
            "title": "SessionSpeechlet - Welcome",
            "content": "SessionSpeechlet - Welcome to the Alexa Skills Kit sample, Please tell me your favorite color by saying, my favorite color is red"
        },
        "reprompt": {
            "outputSpeech": {
                "type": "PlainText",
                "text": "Please tell me your favorite color by saying, my favorite color is red"
            }
        },
        "shouldEndSession": false
    }
}

「outputSpeech」がAmazon Echoから流れるスピーチの内容、
「reprompt」はユーザがIntent Schemaで定義したIntentを返さない場合に流されるスピーチの内容、
「card」はAmazon EchoアプリやAmazon Echoの管理画面で表示される内容です。
レスポンス後もセッションは続くので「shouldEndSession」はfalseです。

下記のスピーチがAmazon Echoから流れ

Alexa:

Welcome to the Alexa Skills Kit sample, Please tell me your favorite color by saying, my favorite color is red

Amazon Echoの管理画面には以下のカードが表示されます。
スクリーンショット 2015-08-06 16.06.09

セッションは続いているので、Amazon Echoの青いランプは付いたままです。

好みの色回答

僕:

My favorite color is brown

Amazon Echoの青いランプがついたままなので、起動ワード「Alexa」は不要です。

{
    "version": "1.0",
    "session": {
        "new": false,
        "sessionId": "amzn1.echo-api.session.775c547f-f710-42ea-9881-a22206dc7942",
        "application": {
            "applicationId": "amzn1.echo-sdk-ams.app.[unique-value]"
        },
        "user": {
            "userId": "amzn1.account.[unique-value]"
        }
    },
    "request": {
        "type": "IntentRequest",
        "requestId": "amzn1.echo-api.request.26f51dd8-fab8-40fa-ba11-9a69f46c9868",
        "timestamp": "2015-08-06T20:20:40Z",
        "intent": {
            "name": "MyColorIsIntent",
            "slots": {
                "Color": {
                    "name": "Color",
                    "value": "brown"
                }
            }
        }
    }
}

セッションが続いています。
「My favorite color is {xxx|Color}」はSample Utterancesで「MyColorIsIntent」にマッピングされているので、リクエストタイプは「IntentRequest」になり、Intent名「MyColorIsIntent」と「Color」スロットの値が渡されています。

これに対するLambdaファンクションからのレスポンスです。

{
    "version": "1.0",
    "sessionAttributes": {
        "favoriteColor": "brown"
    },
    "response": {
        "outputSpeech": {
            "type": "PlainText",
            "text": "I now know your favorite color is brown. You can ask me your favorite color by saying, what's my favorite color?"
        },
        "card": {
            "type": "Simple",
            "title": "SessionSpeechlet - MyColorIsIntent",
            "content": "SessionSpeechlet - I now know your favorite color is brown. You can ask me your favorite color by saying, what's my favorite color?"
        },
        "reprompt": {
            "outputSpeech": {
                "type": "PlainText",
                "text": "You can ask me your favorite color by saying, what's my favorite color?"
            }
        },
        "shouldEndSession": false
    }
}

先ほどは空だった「sessionAttributes」がセットされています。
sessionAttributesを使うことで、セッションの間、Alexaに値を保存させることができます。

下記のスピーチがAmazon Echoから流れ

Alexa:

I now know your favorite color is brown. You can ask me your favorite color by saying, what's my favorite color?

セッションは続きます。

好みの色確認

僕:

What is my favorite color?

{
    "version": "1.0",
    "session": {
        "new": false,
        "sessionId": "amzn1.echo-api.session.775c547f-f710-42ea-9881-a22206dc7942",
        "application": {
            "applicationId": "amzn1.echo-sdk-ams.app.[unique-value]"
        },
        "attributes": {
            "favoriteColor": "brown"
        },
        "user": {
            "userId": "amzn1.account.[unique-value]"
        }
    },
    "request": {
        "type": "IntentRequest",
        "requestId": "amzn1.echo-api.request.c8ebb9d3-1984-46d5-b5bd-a9fa71de3140",
        "timestamp": "2015-08-06T20:20:50Z",
        "intent": {
            "name": "WhatsMyColorIntent"
        }
    }

先ほどセットした「sessionAttributes」がリクエストに含まれています。
「What is my favorite color?」は「WhatsMyColorIntent」にマッピングされているので、そのIntent名が渡されています。

これに対するLambdaファンクションからのレスポンスです。

{
    "version": "1.0",
    "sessionAttributes": {},
    "response": {
        "outputSpeech": {
            "type": "PlainText",
            "text": "Your favorite color is brown, goodbye"
        },
        "card": {
            "type": "Simple",
            "title": "SessionSpeechlet - WhatsMyColorIntent",
            "content": "SessionSpeechlet - Your favorite color is brown, goodbye"
        },
        "reprompt": {
            "outputSpeech": {
                "type": "PlainText",
                "text": null
            }
        },
        "shouldEndSession": true
    }
}

これでやりとりは終了なので「shouldEndSession」がtrueとなっています。

下記のスピーチがAmazon Echoから流れ

Alexa:

Your favorite color is brown, goodbye

セッションが終了し、Amazon Echoの青ランプが消えます。

さいごに

今回のサンプルはかなり単純なスキルでしたが、動いた時は興奮しました。
エンドポイントにLambdaが使えるので、言葉でAWSリソースを制御することもできます。
他にもたくさんのサンプルが公開されているので、試してみたいと思います。

  • https://blog.tinms.biz Tomoharu Ito

    Alexa Skills kit の図なのですが、Alexa のとこはAVS(Alexa Voice Service)のほうが正確かなと思います。(Alexa は、AVSとASKあわせてAlexaなので、少し誤った理解にならないかなと思い、失礼ながら投稿させていただきました。)
    図がわかりやすいのでFBでシェアさせていただきました。m(_ _)m
    横槍すみません。

    • Yokota Shinsuke

      ご指摘くださりありがとうございます!
      執筆当時はAlexaの全体が見えていなかった(とくにAlexa Voice Serviceは全く理解できていなかった)ため不正確な図になっています。
      また、Alexaと言いつつAlexa Skills Kitのアイコンになってますね。

      現在の理解では、AVS、ASK、Alexaの3つをまとめてAlexaサービスと考えた方が良い気がしています。
      AVSですがドキュメントには
      “AVS is comprised of interfaces that correspond to client-functionality, like speech recognition, audio playback, and volume control.”
      とあるので、音声入出力デバイスに対するAlexa側のインターフェースという理解です。
      また、ASKは
      “The Alexa Skills Kit lets you teach Alexa new skills.”
      とあるので、Alexaがカスタムスキルを発動できるようにするための定義という理解です。

      なので、AVS経由でエンドユーザの音声データを受け取り、ASKの定義内容に沿ってスキルを発動させるAlexaという部品を仮定した方が理解しやすい気がしています。

      図にすると下記のような理解です。
      確信はないので漏れや誤りがあればご指摘いただけると幸いです。
      https://uploads.disquscdn.com/images/2b9c7802fd219da92703e0830d77508cee2f298113e11aa50416c312c306c2df.png

      • https://blog.tinms.biz Tomoharu Ito

        わざわざ図まで。。。なんかすみません。。

        こちら見ていただくと、同じような感じですね。
        こちらは”supported by two powerful frameworks”とあり、AVSとASKはalexaを使うためのフレームワークととらえると、しっくりきますねw
        https://www.slideshare.net/AmazonWebServices/please-meet-amazon-alexa-and-the-alexa-skills-kit/6

        • Yokota Shinsuke

          提示いただいた図、わかりやすいですね。
          ありがとうございます!

          問題の図をAVS、ASKを含めたより詳しいものに書き換えてみたところ、Skillの説明図としてはやや煩雑なものになってしまいました。
          なので本投稿では正確さは犠牲にして、アイコンをASKのものからAlexaのものに変更して対応しました。

          AVSやASKを含めたAlexa全体の説明は別の投稿で行おうと思います。

          また、お気付きの点がございましたらご指摘いただけると嬉しいです。