話題の記事

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

2015.08.07

この記事は公開されてから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はスキルが実行可能なアクションの一覧なのでした。

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を発動させる時に発話されるフレーズの例なのでした。

Sample Utterances

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ファンクションに送られます。

リクエスト(Alexa ->

{
    "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ファンクションからのレスポンスは下記です。

レスポンス(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」は不要です。

リクエスト(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ファンクションからのレスポンスです。

レスポンス(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?

リクエスト(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]"
        },
        "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ファンクションからのレスポンスです。

レスポンス(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リソースを制御することもできます。 他にもたくさんのサンプルが公開されているので、試してみたいと思います。