Alexa Skillをローカルで開発しよう
UI開発者 加藤2017年5月にAmazonは「Amazon Echo Show」というデバイスを発表しました。このデバイスは音声による操作が可能で、たとえば「Alexa, call Dad.」と頼めば父親にテレビ電話をかけることができ、「Alexa, what's the weather this week?」と尋ねれば今週の天気を表示してくれます。
このシステムは裏側で「Amazon Alexa」(以下、Alexa)という音声認識AIアシスタントが発話を分析し、その結果に対して「スキル」と呼ばれるアプリケーションを実行することで実現されています。2017年7月現在、15,000を超えるスキルが公開されています。どんなスキルがあるのかはAlexa Skillsのページに掲載されているので興味がある方はご覧ください。
今回はそのスキルをローカルで開発する方法についてご紹介いたします。まず前提知識として知っておきたいのが下記の3つです。
- インテント
- カスタムスロットタイプ
- サンプルの発話
スキルを実際に公開する際はこの3つの要素をアマゾンアプリ開発者ポータル上で定義する必要があります。それぞれの要素について簡単に説明していきます。
インテント
インテントはユーザーの発話に含まれるユーザーの要求を満たすアクションを表します。たとえば天気を取得するインテント「GetWeather」や、音楽を再生するインテント「PlayMusic」というように定義します。各インテントには「スロット」が含まれる場合があります。スロットとは発話の中で変化する可能性がある部分をさします。今日の新宿の天気を尋ねるときの一文を例として見てみましょう。
Alexa, ask Daily Weather for the weather of Shinjuku today.
「Daily Weather」はスキルの名前です。この例において「Shinjuku」や「today」はスロットとして定義するのが適しています。当然ユーザーは新宿区だけでなく品川区の天気を知りたい場合もありますし、今日ではなく明日の天気を知りたい場合もあるからです。インテントとスロットは下記のようにJSON形式で定義します。
{
"intents": [
{
"intent": "GetWeather",
"slots": [
{
"name": "Date",
"type": "AMAZON.DATE"
},
{
"name": "Location",
"type": "LIST_OF_WARD"
}
]
}
]
}
「GetWeather
」というインテントに対して先ほど説明した二つのスロットが定義されており、各スロットに対してはタイプが指定されています。Dateスロットに指定されている「AMAZON.DATE
」はAmazonがあらかじめ用意してくれているビルトインタイプです。Locationスロットに指定されている「LIST_OF_WARD
」はこの後説明するカスタムロットタイプにあたるもので開発者が新しく定義するタイプです。
カスタムスロットタイプ
ビルトインタイプでカバーされていないものについてはカスタムスロットタイプとして新しく定義する必要があります。先にあげた「LIST_OF_WARD
」の場合は東京23区の各名称を定義します。
※現状アメリカやヨーロッパの都市名はビルトインタイプとして存在しているのですが、アジアの都市はまだ用意されていないようでしたので、カスタムスロットタイプとして取り上げました。いずれはアジアの都市もビルトインタイプとして定義されると思います。
サンプルの発話
最後にサンプルの発話です。一つのサンプルは一つのインテントと紐付ける必要があります。
GetWeather how is the weather of {Sign}
GetWeather how will the weather of {Sign} be on {Date}
GetWeather get the weather
最初に対応するインテント名を明記し、スペースもしくはタブで区切った後に文章を明記していきます。このときスロットになる部分は波括弧{}
で囲います。天気を取得するだけでもたくさんのパターンが考えられますので、ユーザーが天気を知りたいときに使いそうなフレーズを洗い出します。このサンプルの数が多ければ多いほどAlexaの認識の精度が向上すると言ってよいでしょう。
スキルを開発する際はこの3つの要素がどれだけ正確に、そして豊富に定義されているかが重要になってきます。
ローカルで開発する方法
さて、基本となる要素が分かったところで、ローカルで開発する方法を説明していきます。まずはAlexaJSというコミュニティが公開しているリポジトリをダウンロードし展開します。
git clone https://github.com/matt-kruse/alexa-app-server.git
/examples/apps配下に実際のスキルのコードを配置していきます。今回はSpotifyのWeb APIを用いてプレイリストを再生するスキル「SpotifyPlayer」をつくってみました。ディレクトリ構造は下記のようになります。
/examples/apps/SpotifyPlayer/ ├ index.js //各インテントに対する処理を記述するファイル ├ SpotifyPlayer.js //Spotify APIと連携するモジュール ├ package.json
package.jsonには依存モジュールとして「alexa-app」をインストールしておきます。Spotify APIとの連携の方法はSpotify Web APIのページにリファレンスがありますので今回は省略させていただきます。
index.jsの中身は下記のようになっています。
'use strict';
module.change_code = 1;
var _ = require('lodash');
var Alexa = require('alexa-app');
var app = new Alexa.app('SpotifyPlayer');
var Player = require('./SpotifyPlayer');
var _player = new Player();
// スキルを立ち上げたときの処理
app.launch(function(req, res) {
var prompt = 'I\'m ready to control audio player on spotify.';
res.say(prompt);
});
// インテントの処理
app.intent('playPlaylist', {
'slots': {
'PLAYLISTNAME': 'AMAZON.MusicPlaylist'
},
'utterances': ['{|play|resume} {|playlist} {-|PLAYLISTNAME}']
}, function(req, res) {
var playlistName = req.slot('PLAYLISTNAME');
var response = res;
var reprompt = 'Tell me a playlist name to get play your playlist.';
// プレイリスト名が空の場合に実行される。
if (_.isEmpty(playlistName)) {
var prompt = 'I didn\'t hear a playlist name. Tell me an playlist name.';
response.say(prompt).reprompt(reprompt).shouldEndSession(false);
return true;
} else {
return _player.getPlaylist(playlistName).then(function(response) {
// プレイリストの再生が成功したときに実行される。
res.say('I\'ll play').send();
}).catch(function(err) {
// 指定のプレイリストが存在しない場合などに実行される
var prompt = 'I didn\'t have playlist data of ' + playlistName;
res.say(prompt).reprompt(reprompt).shouldEndSession(false).send();
});
}
}
);
module.exports = app;
examples配下にあるserver.jsをコマンドから実行し、ブラウザでlocalhostにアクセスすると下記のようにリクエストやスキーマが表示されます。(一部省略しています。)
まずRequestのType項目で「IntentRequest」を選択します。その下のIntent項目で実装したインテント「playPlaylist」を選択し、Send Requestをクリックすると、app.intent('playPlaylist')
の部分が実行され、その結果がResponseの項目に表示されます。
このコードではプレイリストが聞き取れなかった(ユーザーが何も発しなかった)場合、誤ったプレイリスト名を再生しようとした場合、再生に成功した場合の3パターンの処理を記述しています。res.say()
やreprompt()
は実際にAlexaが発話する部分です。
PLAYLISTNAME
スロットのタイプとして指定している「AMAZON.MusicPlaylist
」はビルトインタイプで、「work out」や「dance」といった一般的な音楽プレイリスト名が定義されています。その他のビルトインタイプについてはSlot Type Referenceのページに掲載されています。
また、app.intent
の引数に「utterances
」を指定しておくと、先ほど説明したサンプルの発話を自動で生成してくれます。この機能はAlexa Utterance Generatorの機能を使用したものでブラウザ上でも使用することが可能です。
以上でローカルでの開発は終了です。いきなりクラウドに展開して開発していくよりも、今回のようにまずはローカルで開発することで短時間でより多くのテストが可能になり、より品質の高いスキルを提供できると思います。またインテントやスロットタイプ、サンプルの発話も既に定義されているので、実際にクラウドに展開するのも容易でしょう。
Alexaはまだ英語とドイツ語にしか対応していませんが、ブラウザで試せるAlexa Skill Testing Toolというツールがありますので、興味があれば試してみてください。日本国内ではデバイスを購入することもできませんが、スキルの開発や公開はもちろん可能ですので日本のおもてなし文化をAlexaにのせて海外にお届けするのもよいかもしれませんね。