Amazon Echoがついに日本でリリースされ、日本語版のAlexa開発環境も公開されましたね。
僕のもとにはまだAmazon Echoの購入招待メールが届かず寂しい思いをしておりますが、開発について語れることはいくつかありそうなので、今回はAlexa Skillのエラーハンドリングについて語りたいと思います。
お品書き
- ユーザーが予期せぬ言葉を発してきた
- 予期せぬ発話に対応したはずなのにまたエラー
- ユーザーが黙ってしまった
- アカウントはリンクされてますか?
以上の4点について対処方法を紹介したいと思います。
ユーザーが予期せぬ言葉を発してきた
例えば外食検索サービスを作っていたと仮定して、以下の例を考えましょう。
例)
Skill 「和食、中華、イタリアンなど、どんな種類の料理を食べたいですか?」
User 「具志堅用高」
みたいにユーザーがやばいやつだった場合にはきちんと「何言ってんだお前。こっちはどんな種類の料理を食べたいか聞いてるんだ」と返してやる必要があります。
Google HomeのAction開発によく使用されるDialogflowであればfallback intentが用意されていますが、Alexaの場合その役割を担うintentがデフォルトで用意されていません。
自分で用意してあげましょう。
対処方法
intentSchemaのintents配列のトップに以下のようにfallback intentを追加する。
{
"intents": [
{
"intent": "FallbackIntent"
},
{
"intent": "AMAZON.YesIntent"
},
{
"intent": "AMAZON.NoIntent"
},
]
}
更にSampleUtterancesでFallbackに落としたい文言を書く。
とりあえず「あ」とかだけでもFallbackに落ちてくれますが、絶対にFallbackに落としたい文言も書いておくと良いでしょう。
FallbackIntent あ
FallbackIntent 具志堅用高
予期せぬ発話に対応したはずなのにまたエラー
上記の対応をした上でもまだ予期せぬ発話へのエラーハンドリングとしては足りていません。
こんな例で考えてみましょう。
例)
Skill 「和食、中華、イタリアンなど、どんな種類の料理を食べたいですか?」
User 「3000円」
Skill 「スキルからの応答に問題があります」(Skill終了)
なんとFallbackを設定したにも関わらずそちらには落ちず、Skillは不吉なメッセージを残して勝手に終了してしましました。
なんてこったい!
実はこの外食検索サービスは以下のような手順でお店を探すサービスだったとします。
- 駅名・地名を聞く
- 料理の種類を聞く
- 価格帯を聞く
- 3つの条件からお店を検索する
3番に価格帯を聞く
という項目があります。
怪しいですね。
そうです、今回ユーザーは料理の種類を聞かれているにも関わらず早まって価格帯を言ってしまったのです。
今いるStateで呼び出せるintentではないけれどもintentSchemaに登録されているintentの場合は中途半端に反応してしまうようです。
Skillの質問をちゃんと聞けよと思いますが、何度もSkillを使ってなれてくると質問を聞かずにしゃべってくることも無きにしもあらず。
対処方法
ask
を使用するstateの中では必ずUnhandled
を設定してやりましょう。
var cuisineTypeHandlers = Alexa.CreateStateHandler(states.CUISINE_TYPE_MODE, {
cuisineType: function() {
var message = '和食、中華、イタリアンなど、どんな種類の料理を食べたいですか?'
this.emit(':ask', message, message);
},
/* 省略 */
Unhandled: function() {
var message = '和食、中華、イタリアンなど、どんな種類の料理を食べたいですか?';
this.emit(':ask', message, message);
}
});
ユーザーが黙ってしまった
Skill起動中にユーザーが黙ってしまうこともあるでしょう。
もしくは宅配便が来て放置されるとか。
Alexaは8秒以上放置されるとaskのreprompt設定されたメッセージを喋り(多分設定したほうが良い)、更に8秒以上放置されるとセッションを終了します。
この時何も対処していないと「スキルからの応答に問題があります」と言われてしまいます。
対処方法
ask
を使用するstateの中では必ずSessionEndedRequest
を設定してやりましょう。
SessionEndedRequest
でemit
することはできないので関数の中身は空で大丈夫です。
var cuisineTypeHandlers = Alexa.CreateStateHandler(states.CUISINE_TYPE_MODE, {
cuisineType: function() {
var message = '和食、中華、イタリアンなど、どんな種類の料理を食べたいですか?'
this.emit(':ask', message, message);
},
/* 省略 */
SessionEndedRequest: function() {}
});
アカウントはリンクされてますか?
actions on googleとDialogflowを使っている場合はチェックボックスによる設定だけで、アカウントがリンクされていない旨を示すメッセージを読み上げや、Google Homeアプリへのアカウントリンクカードを送信をしてくれるので楽ちんです。
一方、Alexaではアカウントリンクがされているかを確認し、Alexaアプリにカードを出力するようコーディングしてやる必要があります。
対処方法
最初に呼び出されるintentに以下のようなコードを書いておけば良いでしょう。
if (!alexa.event.session.user.accessToken) {
var message = 'アカウントリンクされてないのでアプリからリンクよろしくです。'
this.emit(':tellWithLinkAccountCard', message);
}
alexa
はalexaのhandlerです。
まとめ
音声UIはユーザー入力の自由度が高いのでとにかくエラーハンドリングが大事です。