Alexa Skill開発のハマりどころメモ

先日から招待制・申し込み受付中ステータスなAmazon Echo。ここで動くAlexa Skillを開発しようと思っている人も多いかと思います。私見では一番のハマりどころはEchoをどうやって手に入れるか、二番目は夜、家人が寝静まった中、どうやって開発するのか(シミュレーター上で文字入力するのか、ヘッドホン差したEchoにブツブツ小声で囁きかけるのか)ではないかと思いますが、それ以外のハマりどころを徒然なるままにメモとして残しておきます(自分がオカしなこと言ってたら直すようにします)。

***
2017/12/08 その１に関しては対処方法を追加しました。
2017/11/27 その５に関しては(やはり)私の問題だったということで記述を追加しました。
***


# ハマりどころ
## その１ Amazonアカウント
実は私もよく消化しきれていないので、間違っていそうな気はするのですが、かつて日本にKindleがなかった時代に米国Amazon.comのアカウントで買いためたKindle書籍を、日本でKindleがサービスインしたときに移行だの何だの苦労した記憶がおぼろげにあるのですが、Alexa Skillを開発する上で、必要なアカウントが(重複含め)４つあると考えています。

1. Amazon.co.jpアカウント - 日本で日本語のスキルを日本在住の人に使ってもらうというのであれば、Amazon.co.jpからEcho買って、Amazon.co.jpのアカウントとEchoを(スマホ上のAlexaアプリで)紐づけるのが一般的
2. Alexa開発者ポータル(https://developer.amazon.com/ja/alexa )のアカウント - スキル開発(対話モデルや各種定義・設定)
3. AWS(https://aws.amazon.com/jp/) - サービスエンドポイント(音声認識結果をもとに何らかの処理をして返答となる発話を作成)はLambdaの関数として実装するのが一般的
4. 開発者フォーラム(https://forums.developer.amazon.com/spaces/293/index.html )やナレッジベース(https://forums.developer.amazon.com/spaces/301/alexa-skills-kit-knowledge-base-jp.html ) - 目を通しておきたい情報あり

別にアカウントなど使い分けせずとも、Amazon.co.jpのアカウント１つを使いまわせばいいのですが、これまでのAWSとのお付き合いの行きがかり上、AWSの方はAmazon.comのアカウントを使っているといった事情があると、途端に上述の４サイト間を行き来していると自分が何のアカウントでどこにログインしているのか途端にわからなくなってしまい、スキルやLambda関数なりあると思っていたものがなかったりです。

私自身がAmazon.com, Amazon.co.jp, Amazon.cnに個別のアカウントがあって(それぞれPrime会員登録しているから)という事情はあるのですが。

こちらのハマりの対処法に関しては、クラスメソッドのせーのさんが書かれたブログエントリが参考になります。「Amazon.comアカウントが優先してAlexaアプリに入れない問題の解決法(https://dev.classmethod.jp/voice-assistant/solution-of-a-problem-amazon-com-account-conflict/ )」

## その２ Lambda関数内でのアプリケーションIDの指定
スキルを作成するとスキルIDならぬアプリケーションIDが割り当てられ、一方、そのスキルから呼び出されるLambda関数の側でも当該アプリケーションIDを指定する必要があります(...と書いたものの、実際にはOptional)。Lambda関数の作成では、設計図をテンプレートととして丸写しして、必要なところを書き換えればよいので、ゼロからnode.jsなり何なりのコードを書くより、はるかに楽。とはいうものの、たとえば、alexa-skill-kit-sdk-factskillなんてのを指定して出てきたソースコードには、

```js
const APP_ID = undefined;  // TODO replace with your app ID (OPTIONAL).
(中略)
exports.handler = function (event, context) {
    const alexa = Alexa.handler(event, context);
    alexa.APP_ID = APP_ID;
    // To enable string internationalization (i18n) features, set a resources object.
    alexa.resources = languageStrings;
    alexa.registerHandlers(handlers);
    alexa.execute();
};
```

と書かれているものの、alaxa.APP_IDではなく、alexa.appIdなんじゃないかと思います。

## その３ Skill Builder上で日本語入力したときの挙動が変
これは環境に依存しているのかも知れない(おかしいのは私の環境だけかも知れない)ですが、日本語を変換しながら入力して確定するタイミングで、「にほんご」→「日本語日本語」みたいに重複出力されたりイラっとくることが多いです(ちなみに私の環境はWindows 10上のChrome  62.0.3202.94(64bit)でかな漢字変換はMicrosoft IME)。

## その４ 必須スロットの入力を求める対話機能が(非実機環境で)テストできない
私のこだわりでもあるのですが、必須スロットの内容を以下に対話的に聞き出すか(「レストラン」→「どちらの場所ですか」)と、推定できるならわざわざ聞かない(「レストラン」→「どちらの場所ですか」→「新橋」→「これこれこんなレストランがあります」→「今晩の天気は？」→(文脈から場所を引き継いで解釈してほしい))でほしいのですが、Skill Builder上でもスロットに対してREQ(必須)指定し、問い返し用の発話を定義しておくことで、Lambda関数側で対話コントロールのためのコードを最小限にする(会話を委任する)ことができます(バンザーイ！)。

が、開発者コンソールのサービスシミュレーターではこの必須スロットの問い返し対話がサポートされておらず、悩んでいた後に、Dialogディレクティブのリファレンス(https://developer.amazon.com/ja/docs/custom-skills/dialog-interface-reference.html )の中ほどに、「注: サービスシミュレーターは、Dialogディレクティブのテストをサポートしていません。」の文章を見たときは頭の中、真っ白になりました。

## その５ 標準インテントとオーバーラップするスキルは作れない？(きっとそんな訳はない)
こちらは全く自分でも自信がなく、単に自分の作り方が悪いだけで、Alexaには非がない ~~ような気もするのですが、システムが標準で提供するようなインテントと重なる、例えば、ホームデバイスの電源をオン・オフするであるとか、場所を指定してレストランを検索するであるとかといったスキルがサービスシミュレーター上で文字入力で試している限りはうまく動作しているようなのですが(そもそも自作スキル単体のテストだからというのもあるのだろう)、Echosim.io(https://echosim.io )なりEcho実機で動作確認するとうまく動かない。Echosimの方では、「Alexa、(スキル名)を開いて」の後の発話であっても、システム標準の機能がアクティブになってしまうし、実機だと何かよくわからないけど動きませんみたいな返答が帰ってきてしまう。自分の作りが悪いのだろう(システムが定義するインテントのハンドラでちゃんとやるべきことをやっていない、といったところか)とは思う。~~

こちらは識者から教示をいただきました。Lambda関数中の各インテントハンドラの末尾で this.emit()で処理終了するのですが、引数の指定に誤りがあって対話が終了している、ようです。自分でも対話(Dialog)制御はちゃんと理解したうえでまとめたいと思っています(上述のその４とも関連します)。


## その６ 音声認識結果がどういったかな漢字交じり表記で通知されるのか分からない
おそらくは対話モデルの各Intent内に与えられたSample Utterance(発話例)をベースに(賢いやり方で)統計グラマでも作っているのかな(つまり、通知の際にかな漢字交じり表記がどうなるのかは、Sample Utteranceの発話に依存する)のかな？と勝手に想定しているのだが、たとえば、SlotのoptionとしてAmazonが提供するSlot Type(例えば、AMAZON.NUMBER)だと日本語環境でどんな表記で通知されるのかがわからない(半角数値なのか漢数字なのか、位取りのカンマが入るかどうかなど)。

## その７ Slot Typeを自分で定義したときのIDと同義語の扱いが今イチよく分かっていない
これは完全に自分の調査不足を棚に上げた言い方なのだけれども、こんなSlot Typeを定義したときに、

|VALUE|ID(OPTIONAL)|SYNONYMS|
|:---:|:----------:|:------:|
|天気|CAT_WEATHER|空模様,雲行き|
|レストラン|CAT_RESTAURANT|食事|

ユーザの発話に含まれる語がVALUEそのものであろうと、SYNONYMSの中のいずれかであろうと、Lambda中の処理はIDで振り分けつつ、ユーザに対する返答には言われた語で返す(「東京の天気は？」と聞かれたら「今日の東京の天気は～」で返し、「東京の空模様は？」と聞かれたら「今日の東京の空模様は～」で返す)方法が追い切れてない(トホホ)。

***

さてさて思いつきで勝手なことをあれこれ書いてきましたが、Amazon EchoなりAlexaを貶めようという気持ちは1gもなくて、むしろ、iPhoneが出始めた頃と同じような感動を感じています。つまり、個々のスペックで〇×表をまとめれば、iPhoneは当時のガラケーと比較して〇が少なく×が多い結果になったでしょうが、今、生き残っているのは〇が多かったガラケーではない。つまり、気に留めるべき点は〇がどれだけ多いかではなく、たった１つであってもどこに〇があるかであり、それがAWSが誇る(さらに言えばこれからも続々と拡充されていく)クラウドサイドの機能群ということになるのだと私は考えています。