AWS経由でPepperの聞き取りをAlexaに任せてみた

#はじめに
この記事は2019/11/19のIoTLTで発表した内容をもとに
AWS経由でPepperとAlexaを連携させた会話システムを作った際の

* Alexaスキルを作る過程で参考にした記事
* Alexaと他のアプリを連携させる際にハマったポイント

についてまとめたものになります。

メインはAlexaスキルにおけるDynamoDBを使った他のアプリとの連携についての説明なので、Alexaに興味がある方のお役に立てれば幸いです。
LTの時のスライドは[こちら](https://www.slideshare.net/ssuser831037/alexapeppertalk)

#Pepperは聞き取りができない
Pepperはマイクの性能がイマイチで*<b>聞き取りができません。</b>
つまり、Pepperはコミュニケーションロボットであるにも関わらず<b>人と会話ができません。</b>
これは致命的、、、

ということで今回はPepperの聞き取り機能を実用的なレベルに引き上げる方法として
<b>AlexaにPepperの聞き取りを任せる</b>システムを作りました。

これにより欠点だった聞き取り能力をAlexaに補ってもらい、
持ち前の親しみやすさを存分に発揮できる最強のPepperが出来上がるはずです。
多分。


以下AlexaとAndroidアプリであるPepperのシステムとの連携をする上で
参考にした記事やハマったところをまとめていきます。


_*雑音がない環境で真正面から話しかければ聞き取れます。_
_しかし複数人が話しかけてきたり雑音がある環境では実用的出ないのが実情です。。_

#Alexaスキル作成時のハマりどころ

Alexaスキルの開発にはAmazonの提供するAlexa Skill Kitと*AWS Lambdaを使います。
なおLambdaではNode.jsを使いました。

僕はAlexaスキルの開発は未経験だったのですが、以下の一連の記事がとても参考になりました。
[Alexa SDK for Node.js Ver2入門（その１）はじめの一歩](https://dev.classmethod.jp/cloud/alexa-sdk-v2-first/)

Alexaスキルの開発を始めた時に盛大にハマったのが<b>AlexaスキルSDKのバージョン</b>についてです。

現在のNode.jsのSDKのバージョンはVer2ですが、初心者向けの記事はVer1のものが多く
Ver1でのスキルの作成の基本を学んだ後Ver2の記事をみて混乱、、ということが多々ありました。

上の記事はVer2に対応した初心者向けの記事なので、混乱することなくスキル開発の基本が習得できるためおすすめです。
初めてのスキル作成から会話の作り方、Alexaスキルから*AWS DynamoDBへのデータの格納までスキル開発で必要な知識が一通り網羅されているので、これをベースに様々なスキルへ応用ができると思います。

_*Lambdaに触ったことがない方でも上の記事に概要があります。_
_*DynamoDBについてはあまり説明がないので、触ったことのなかった僕は適宜調べながら進めました。_

#DynamoDBでのデータ共有
今回はDynamoDBへデータを格納できるというところに目をつけ、
DynamoDBを通してPepperのAndroidアプリとの連携に応用してみました。
システムの全体像は以下のようになります。
<img width="638" alt="スクリーンショット 2019-11-27 20.33.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505521/9a3f1833-edf4-47e8-70f4-de2bed24ca1b.png">

AlexaスキルのLambdaからDynamoDBに格納したデータに
PepperのAndroidアプリからAPI Gateway経由でアクセスします。

AndroidアプリからDynamoDBのデータを一定時間ごとにGETし、
それを元にAlexaが聞き取った音声のデータや会話の状態を取得します。
Androidアプリの方で受け取ったデータを元に返すメッセージを決定し
その内容をPepperに発話させるという流れです。

まず上で紹介した記事を参考にDynamoDBにアクセスするためのAdapterを用意します。

```
const config = {tableName: 'xxx', // <= DynamoDBのテーブル名
				createTable: true}; // <= テーブルを自動生成する場合true
const DynamoDBAdapter = new Adapter.DynamoDbPersistenceAdapter(config);

```
exports.handlerの設定に 'withPersistenceAdapter(DynamoDBAdapter)' を追加します。


```
let skill;
exports.handler = async function (event, context) {
    if (!skill) {
      skill = Alexa.SkillBuilders.custom()
        .addRequestHandlers(
			LaunchRequestHandler,
            xxx, // スキルで使うHandlerを設定
			xxx)
		.withPersistenceAdapter(DynamoDBAdapter)
		.addErrorHandlers(ErrorHandler)
        .create();
    }
    return skill.invoke(event);
}
```

SDKではデフォルトでid、attributeという要素が設定されます。
idはプライマリキーで"amzn1.ask.account.xxxx"というようにAlexaスキルのスキルIDになっています。
attributeはMap型でこの中に複数の要素を設定することができます。
なので例えばString型のhoge, Number型のhugaというデータを格納したい時はattributeの要素として設定してやることになります。
<img width="1403" alt="スクリーンショット 2019-11-27 21.24.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505521/7cee7fea-03e3-91d0-4c73-35b22e52c729.png">
データへのアクセスについては、任意のインテントのHandlerで行います。
最初のアクセスの際にattributeに要素が追加されます。
以下は呼び出された時に「わー」と発話しつつ、このattributeのhogeの中身を"ほげほげ"に設定するインテントのサンプルです。

```
const xxxxxxxHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'IntentRequest' &&
             handlerInput.requestEnvelope.request.intent.name === 'xxxxxxxIntent';
    },
    handle(handlerInput) {
		return new Promise((resolve, reject) => {
			handlerInput.attributesManager.getPersistentAttributes()
			.then((attributes) => {
				attributes.hoge = "ほげほげ";
    		  handlerInput.attributesManager.setPersistentAttributes(attributes);
    		  return handlerInput.attributesManager.savePersistentAttributes();
    		})
    		.then(() => {
    		  resolve(handlerInput.responseBuilder
    		    .speak("わー")
    		    .getResponse());
    		})
    		.catch((error) => {
    		  reject(error);
    		});
		});
    }
};
```

上で紹介した記事のコードを参考にしてやってみたところLambdaでエラーが出てしまったため、同期処理にPromiseを使っています。
もし紹介した記事のコードでうまくいかない場合は参考にしてみてください。

#Pepper側の処理
ここまででAlexaスキルからDynamoDBへデータをアップするところまでができました。
あとはPepperのAndroidアプリからこのデータへアクセスできるようにしてやります。

まず以下のようにAPI Gatewayを使いLambda経由で以下のようにDynamoDBにアクセスできるようにしてやります。
この設定については[この記事](https://qiita.com/miutex/items/d80c9ff0290966eb0cf8)を参考にしました。
<img width="962" alt="スクリーンショット 2019-11-28 0.44.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505521/3086ef66-2dd3-13cd-0eb9-4d9d7b94cd30.png">
そして設定したURLにAndroidアプリから一定周期でアクセスしてやることでAlexaとAndroidアプリ間でデータを共有することができ、連携を取ることができるようになります！

Android側の処理は今回のメインでないので省略いたします。
#終わりに
実際にデモを作ってみたところ問題なく連携が取れるようになりました。
Alexaを補聴器がわりに従えたPepperがこれから躍進することに期待しましょう。

今回はAlexaとPepperとの連携でしたが、API GatewayでURLにアクセスできればどんなアプリケーションでもAlexaと連携が取れるので応用の幅は広そうですね。

Pepperが最近Androidアプリとして開発できるようになりました。
Androidアプリを開発したことがある方は簡単に作ることができると思います。
Pepper開発については[アトリエ秋葉原](http://pepper-atelier-akihabara.jp/)というところが無料でワークショップをやっているのでおすすめです。
Pepperの開発も新鮮で楽しいのでぜひ一度やってみてください！