【Alexa初心者向け】Alexa Skill Kitを噛み砕いて解説してみる

こんにちは、せーのです。今日はこのところ盛り上がりを見せるAmazonの音声認識プラットフォーム「Alexa」のスキルについて用語の説明から噛み砕いていきたいと思います。

Alexaについて

去年行われたre:Invent 2016にてAlexaが大プッシュされて専門のセッションが沢山行われたこと、またそのre:Inventにて紹介された新サービス「Amazon LEX」「Amazon Polly」がいずれもAlexaの機能がベースになっていること、先日行われたCESでもAlexaが搭載された製品が700以上紹介されたこと等を受けて今、全世界的にAlexaが注目されています。ちなみにAlexaそのものについては最近佐々木が集中的にブログを書いているのでそちらをご覧頂ければと思います。

ということでAlexaがどういうものなのか、おいしいのか、というお話はこのシリーズを読んでもらうとして、このエントリーでは実際にAlexaを使ってSkillを書いてみたいけど、何がどうなっているのかよくわからないという方を対象に、AlexaのCustom Skillの用語や構成、仕組みについて解説してみたいと思います。上のシリーズで佐々木が「今度はCustom Skillを作ってみたいと思います」と書いているのでそのうちCustom Skillの書き方についてエントリーが載ると思います(今日載ってたようです)。その時に「これは結局どういう仕組みになってるんだろう」と思った方がこちらのエントリーを思い出してくれれば、と思います。

Alexa Skillの構成

それではまずAlexaにおけるSkillとはどこに当たるのか。去年のre:Inventのスライドから見てみましょう。

alexaskillkit3

[Alexa]というのは音声認識サービス全体を指す総称です。Alexaには2つのフレームワークがあり、一つが音声認識や自然言語解釈等を行うAlexa Voice Service(AVS)、もう一つが様々な別の機能をSkillという形でパッケージングしてAlexa ServiceとつなげるAlexa Skill Kit(ASK)です。

alexaskillkit1

Alexa Skill Kitを細かく書くとこのような流れと機能を持ちます。どのような音声に反応するか、どのような単語をパラメータにしてどの機能を実行するのか、返ってきた答えをどのようにAlexaに戻すのか、これらを定義したパッケージ、API群をAlexa Skill Kitと呼び、そのうち実際に実行される機能の部分をSkillと言います。ASKを使ってSkillを作る、という理解がわかりやすいと思います。

ASKの種類

ASKには現在3つの種類があります。これをSkill Typeと言います。

  • Custom Skills
  • Smart Home Skills
  • Flash Briefing Skills

Custom Skills

その名の通り全て自由にイチから手作りで作っていくSkillのことです。自由なので書き方次第では何でもできます。Google Calendarと連携して「◯時にXXの会議室押さえといて」で予約を入れたり、「ペットの様子を映して」で家にある見守りカメラを起動させたり、、、要はAPIさえあればそれを声で操作する感覚でできるわけです(ちなみに私は自分の車のスターターを動かせるように仕組みを考え中です)。

ちなみにCustom SkillはAWSの審査を通った後は基本パブリックなAlexaサービス群に配置されます。他の人に見せたくない時はDevelopment[開発中]としてPublishするとプライベート空間にSkillを置くことができます。ですがあくまで「開発中」という定義のものなので自アカウントでしか見れません

Smart Home Skills

これはSkillの中でもスマートホーム機能に特化したSkillです。このSmart Home SkillsのAPIには予めスイッチのON/OFF、度合いを設定するパーセンテージ、温度調節等のインターフェースと各家電への認証を制御するAuthenticationの仕組みが組み込まれています。これらのAPIを使ってSkillを組み立てていく事でスマートホームシステムを組むことができます。

Flash Briefing Skills

これはFlash Briefing API、つまりニュースの配信サービス用のSkillになります。これはテキストや音声コンテンツを取得して配信する仕組みで、現在既に1000近くのニュースが配信されています。ニュースソースはHTTPSやRSSから、または直接JSONを指定したりも出来ます。

これらのうち今回は最も使うであろうCustom Skillを実装することを想定して中身を解説したいと思います。

解説

Echoに向けてこのような言葉を投げかけたとします。

alexaskillkit4

最初の「Alexa」はWake Wordと呼ばれ、Echoのマイクがこの言葉を拾うとクラウドにあるAlexaと通信を開始し、以降の言葉がストリーミングとしてクラウドに送られます。ちなみにEchoのマイクはスタンバイ時は無指向性で「Alexa」と呼ぶと、呼びかけた方角が水色に、それ以外の方向は紺色に光ります。以降は水色の方角の集音が高くなり、より音声コマンドを拾いやすくなる、という仕組みです。

次の「ask」はLaunchフレーズ(起動フレーズ)と言い、この次にくる単語がSkill名であることをAlexaに伝えます。Launchフレーズはask以外にも「tell」や「launch」「load」「begin」「open」「start」等があり、これらの言葉をSkill名に使うことは出来ません。この他に接続詞を用いてSkill名を示す方法もあります。例えば上で言えば「Alexa, can you give me a fact from Anime Facts」と呼びかけた場合も「from」をAlexaが聞き取って、その後ろにある「Anime Facts」がSkill名だな、と判断します。

最後の「for a fact」はUtteranceと言われます。Utteranceは「発話」「発言」と訳されます。Alexa Skill Kitでは「Sample Utterances」という項目があり、そこにUtterancesと実際に実行されるSkillが結びつく形で設定されます。つまりここで「for a fact」と言うことによって、「for a fact」というUtteranceがどのIntent(後述)と結びつくのかをSample UtteranceからAlexaが判断することになります。ここの文章解釈にもDeep Learningの機能が使われており、多少の言葉のブレがあってもAlexaが聞き取ってくれます。上で言うと「ask Anime Facts for a fact」、つまりアニメの豆知識的なものを教えてほしい、という意味なので「fact」が「trivia」とかでも恐らくAlexaは同じ意味だと解釈して「for a fact」というUtteranceが設定されているところと同じIntentが起動するでしょう。

Custom Skillの設定

それでは次にCustom Skillを設定する際に必要となる用語について解説します。用語はそれぞれ

  • Utterance
  • Intent
  • Intent Schema
  • Slot

となり、関係性はこんな感じです。

alexaskillkit7

ではこちらの設定を例に解説していきます。

alexaskillkit5

Utterance

Utteranceは実際に話された言葉がどのIntentと結びつくかを表したものです。またこの中に中カッコでSlot名を指定することにより変数的な設定もできます。

Slot

SlotはIntent Schemaにて指定された型に基づいて変数的に処理される部分です。例えば上の例であればSlot「Answer」は「AMAZON.NUMBER」という型が指定されています。ここに「One」や「Two」等の数字を表す言葉が入ってくると、Alexaはその部分を自動的に数字の「1」「2」に変換しLambdaに引き渡します。

Slot type(型)にはAmazonが予め用意したものと、カスタムに自分で作れるもの(Custom Slot)があります。Custom Slotは例えば「Flower」というSlot名で「Rose」「Lily」などの単語を設定しておくことでAlexaに投げかけられた言葉から花の名前を変数としてLambdaに引き渡す事ができます。

Intent

IntentはAlexaに発せられた言葉と実際のSkill内の機能をつなぎ合わせる変数のような役割を指します。上の例でいくと「the answer is ◯◯」や「my answer is ◯◯」とAlexaに話しかけるとAnswerIntentというIntentが反応して、Lambdaがキックされる時に"Intent.name"として渡されます。受け取ったLambdaはそのIntent.nameを元に処理を分岐していくように実装します。

Intent Schema

Intent SchemaはSlotとその型、Intentの関係をまとめたJSON形式の設定項目です。Utteranceの情報とこのIntent Schemaを元にLambdaに送るRequestが作成されます。

Lambda側

それでは次にLambda側を見ていきましょう。まずはLambdaに送られるRequestについてです。

Request

上のUtterancesとIntent Schemaを設定し「the answer is one」と話しかけた場合、AlexaからLambdaへはこのようなRequestが送られます。

{
  "session": {
    "sessionId": "SessionId.310369d9-2797-4d66-9a5c-f2265745a7e9",
    "application": {
      "applicationId": "amzn1.ask.skill.08b1377c-0526-4c9b-a980-7641a34200d4"
    },
    "attributes": {},
    "user": {
      "userId": "amzn1.ask.account.AFBJW3743QO7DMGFRRVNCKUXZJNQHSQPQ5Q6NNV3Z3LPJ724A367DOIQRVYAK7Z3L6YTDLGEVCWAA3LRLTPMP4TX5VVB3N3V7WHRU2IJJKK2MQPXIYUMW4FOL53RZPLLHQMMT2S3OKPIUZVS3IM7ZDS7RUDIYGMVYZ5I75YXSG5XOKKFKCHK3IGRMNZ2DBG4GCJTUBE3CFYQ5SA"
    },
    "new": true
  },
  "request": {
    "type": "IntentRequest",
    "requestId": "EdwRequestId.3c8939e1-ed42-4d56-b438-87dc568b8a7e",
    "locale": "en-US",
    "timestamp": "2017-02-01T01:43:53Z",
    "intent": {
      "name": "AnswerIntent",
      "slots": {
        "Answer": {
          "name": "Answer",
          "value": "1"
        }
      }
    }
  },
  "version": "1.0"
}

それでは主な項目を順に見ていきましょう

SessionId / Session.new

Alexaと会話を続ける上で重要になる項目です。同じSkill内で会話を続けたい場合、Lambdaは前回までの会話にて得られた情報をSessionの中のAttributesに書き込みながら同じSessionIdにてLambdaに情報を渡していきます。初めてLambdaが起動した時はSession.newがtrueとなります。

request.type

request.typeには

  • LaunchRequest(スキルを呼び出したものの特定のUtteranceに入らなかった時)
  • IntentRequest(スキルを呼び出して特定のUtteranceに当てはまった時)
  • SessionEndedRequest(エラーが起きた、一定時間喋らなかった等でセッションを切る通知を送る時)

の3種類があります。それぞれのtypeによって処理内容を変えるように実装します。

intent.name

Intent.nameは先に説明したように会話の内容によって振り分けられたIntent名が入ります。それぞれのIntent名に合った処理を実装します。

intent.slots.<Slot名>.name / intent.slots.<Slot名>.value

Slot名とSlotの値は変数的に使います。例えばAMAZON.DATE型で「today」という内容のSlotが入ってきた場合、intent.slots.<Slot名>.valueは「2017/02/01」というDATE型に変換されてLambdaに渡されますので、Lambda内で日付チェック等に使えますね。

Response

次にLambdaで処理をした後に返ってくるResponseを見てみましょう。

{
  "version": "1.0",
  "response": {
    "outputSpeech": {
      "type": "PlainText",
      "text": "You are collect!!"
    },
    "card": {
      "content": "SessionSpeechlet - You are collect!!",
      "title": "SessionSpeechlet - Answer",
      "type": "Simple"
    },
    "reprompt": {
      "outputSpeech": {
        "type": "PlainText",
        "text": "Answer your next question."
      }
    },
    "shouldEndSession": false
  },
  "sessionAttributes": {}
}

また主な項目を見ていきましょう。

response.outputSpeech.text

Lambdaで処理した返答がここに入ります。ここのtextがAlexaによって音声に変換されてEchoに届きます。

card

ここにはEcho等の音声認識デバイスではなくAlexaアプリ(日本リージョンではローンチされていません)を使用した場合に画面に返ってくる「Card」の内容が入ります。

reprompt.outputSpeech.text

response.outputSpeechを出力した後、一定時間何も話さなかった場合にこのreprompt.outputSpeech.textが音声変換されてEchoに届きます。

shouldEndSession

セッションが終了する必要がある場合にはここがtrueになります。

sessionAttributes

今までのやり取りで蓄積されてきた情報がkey-value形式で入ります。

このようにしてやり取りを重ねて処理が完了するような実装を書いていきます。

まとめ

いかがでしたでしょうか。ASKを実際に組んでみよう、という時につまづきそうな用語や構成を中心に解説しました。Custom Skillを作成する際にわからなくなったらこちらのエントリーを見返してみて下さい。
ここ数日でAmazon Echoが年内に日本発売か、という記事が世間を騒がせております。日本で発売になった時に既にSkillが作れるように準備しておきましょう!

参考リンク