AWS Lambdaを使ってAmazon Echoに機能追加してみた
はじめに
アメリカで発売が始まったAmazon Echoが届いたので、早速使ってみました。 Amazon Echoとは据え置き型のSiriのようなもので、音声を使って天気やニュースを聞いたり、単語の意味を調べたりできます。
例えば、「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に届き、処理されます。 重要なのは、Alexaが音声データを解析し、テキストに変換を行ってくれるいう点です。 なので、Alexa Skillの方ではテキストでリクエストを受け取り、レスポンスもテキストで返すことができます。 詳しくはドキュメントを参照ください。
Alexa Skillの作成はAmazon Developer Console上で行います。
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, ask color expert.」
- Alexa:「Please tell me your favorite color?」
- ユーザ:「My favorite color is blue.」
- Alexa:「I now know your favorite color is blue. You can ask me your favorite color.」
- ユーザ:「What is my favorite color?」
- Alexa:「Your favorite color is blue.」
まず、AWS Lambdaでサンプル用スキルのエンドポイントを作成し、そのあと、Alexa Skills KitでAlexa Skillを作成します。
Lambdaファンクションの作成
AWSのマネジメントコンソールでヴァージニアリージョンのAWS Lambdaの管理画面を開いてください。 blueprint一覧から「alexa-skills-kit-color-expert」を選択し、ひたすらNextで進んでください。 途中、IAM Roleを指定するところがあるので、「lambda_basic_execution」を指定してください。
確認画面は次のようになります。 「event source」はAlexaになっています。
ファンクション作成後、サンプルスキルのエイドポイントとして指定するため、ARNを控えます。
これでエンドポイントの準備は終了です。 次に、このエンドポイントを利用するAlexa Skillを作成します。
Alexa Skillの作成
Amazon Echoを登録しているAmazonアカウントと同じアカウントでAmazon Developer Consoleにログインします。 Alexa Skillsのマーケットはまだ準備中のため、現在は開発中のテストという形でAlexa Skillを利用することになります。 ログイン後、「APPS&Services」の「Alexa」に移動し、 「Alexa Skills Kit」を選択します。
- Name: SampleSkill
- Invocation Name: color expert
- Endpoint: (先ほど作成したLambdaファンクションのARN)
としています。
次に、ユーザとAlexa Skillとのやりとり内容(Interaction Model)を定義します。 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でこのスキルが利用できるようにします。
これで新しいAlexa Skillが完成しました。
Amazon Echoの管理画面で確認するとスキルが追加されていることが確認できます。
動作確認してみます。
動作確認
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を指定しました。 特定の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の管理画面には以下のカードが表示されます。
セッションは続いているので、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リソースを制御することもできます。 他にもたくさんのサンプルが公開されているので、試してみたいと思います。