Alexaをダイヤルアップ接続させるジョークアプリ作ってみた

# 経緯と目的


仕事中調べ物をしていたら、明日のLambda枠が空いていたので勢いで登録してしまいました。
最近echo plus手に入れて、[alexa skillトレーニング](https://developer.amazon.com/ja/alexa-skills-kit/training/building-a-skill)を勉強したので、復讐がてら簡単に作って投稿してみます。

とりあえず目的は以下

1. alexa skill kitを使って何か作る
2. 今日中（残り4時間）で作って記事を書く
3. とりあえず動かすのを目的に
4. 色々書いてみる
5. 楽しむ

まだ勉強し始めたばかりなので、色々間違っていたり、ダサいコーディングもありますが寛大な目で見てください

## 時間記録

20:00 帰宅、PC起動、qiita執筆開始
20:10 食事　200円引きの寿司
20:30 食事終了、skill作成、lambda作成、S3作成
21:10 youtubeで息抜き
22:00 テストしながらコーディング
23:00 動画撮影、qiita編集
23:30 投稿

## 何を作るか

alexa skillには色々な人がskillを作成して公開しています。
私も部屋のライトをphillipsのhueに変えたり、amazon music unlimitedに入って
気分によって音楽を変えたりニュース聞いたりレシピ聞いたり毎日が楽しくてしょうがありません。

今回は流石に技術も時間も無いので、どうせならハイテクなalexaにローテクっぽい事をさせてみようと思います。

というわけで、alexa をダイヤルアップ接続させるジョークアプリを作ってみます！
あくまでジョークアプリなので、一切接続しませんし出来ません。
slとかfortuneコマンドとか好きなんです。

### スキル開発

スキル概要を入力
今回は対話モデルですが、そこまで対話させません。
ステートも使わない予定です。
ここで入力した、alexa 【呼び出し名】 を開いて
と言うと、alexaが開きます。
Audio Playerにチェック付けていますが、多分必要ありません。

![84741863a47a1fc44e15efd5bdca47ab.png](https://qiita-image-store.s3.amazonaws.com/0/183246/965b7bcf-536f-6a7f-eb0b-3aaf6dff9544.png)

### インテント

インテントはとりあえずこれのみ
シンプル！
インテントとは、イベント名みたいなものです。
ここで設定したインテント毎にlambda上で細かい処理を書けます。

```json

{
  "intents": [
    {
      "intent": "StartDialUp" //回線が繋げる時のインテント
    },
    {
      "intent": "AMAZON.HelpIntent" //ヘルプインテント
    }
  ]
}
```

### サンプル発話

サンプル発話には以下を設定
ここに入力した【インテント名　発話】を話しかけてLambdaで処理を行います

```text
StartDialUp 接続 を 開始して
StartDialUp ダイヤルアップ回線 に 繋いで
StartDialUp 回線 を 繋いで
StartDialUp はい
StartDialUp 繋げて
```

### S3にファイルアップロード

1. クリエイティブ・コモンズライセンスのダイヤルアップ接続音を探してDL
2. ビットレートを48kbpsにしなくてはならないため ffmpeg をインストールして変換
3. ffmpeg -i foo.mp3 -ac 2 -codec:a libmp3lame -b:a 48k -ar 16000 bar.mp3
4. S3にバケットを作成し、ダイヤルアップ接続の音をアップロード
5. 公開に設定するのを忘れない

### Lambda 

1. AWSにログインしてLambdaを作成
2. 設計図からalexa-skill-kit-sdk-factskillを選択
3. connectToDialup 関数を作成

![6fa6d6faf5830d99a57ba625d72da51e.png](https://qiita-image-store.s3.amazonaws.com/0/183246/035a8111-b9a1-914b-28be-0cd42a391e1a.png)

4.左から Alexa Skills Kitを選択し保存

![ff68fe06325a1346a46636251e19e1b8.png](https://qiita-image-store.s3.amazonaws.com/0/183246/981ebab5-bb89-dc5a-cb1e-557ecde22c4f.png)

5.connectToDialupを選択し、ソースコードにデフォルトでalexa-sdkが読み込まれたindex.jsがあるのでそれを編集

先週弄ったときとデフォルトが変わっているので困惑…
多言語用の変数があるようなので、よく分からないけど試しに追加。
結局殆ど使っていませんが、多言語対応するさいはこちらで各言語入れればいいので楽ですね。

```index.js
    'ja': {
        translation: {
            FACTS: [
                'ダイヤルアップ回線に接続したいですか？',
            ],
            SKILL_NAME: 'ダイヤルアップ回線',
            GET_FACT_MESSAGE: 'ダイヤルアップ回線に接続しますか？',
            HELP_MESSAGE: 'ダイヤルアップ回線を開いてと言ってください',
            HELP_REPROMPT: 'ダイヤルアップ回線を開いてと言ってください',
            STOP_MESSAGE: 'もっと早い回線が見つかりましたのでそちらに切り替えます',
        },
    },
```

6.コードを変更

今回はそこまで変えていません。
AMAZON.HelpIntent　の中で、先程の各言語毎のFACTSとかを読み込んでいたのですが今回は削除しました。

```js:index.js
const handlers = {
    'LaunchRequest': function () {
        this.emit('GetFact');
    },
    'GetNewFactIntent': function () {
        this.emit('GetFact');
    },
    'GetFact': function () {
        // Get a random space fact from the space facts list
        // Use this.t() to get corresponding language data

        const speechOutput = this.t('GET_FACT_MESSAGE');
        this.emit(':ask', speechOutput);
    },
    'AMAZON.HelpIntent': function () {
        const speechOutput = this.t('HELP_MESSAGE');
        const reprompt = this.t('HELP_MESSAGE');
        this.emit(':ask', speechOutput, reprompt);
    },
    'AMAZON.CancelIntent': function () {
        this.emit(':tell', this.t('STOP_MESSAGE'));
    },
    'AMAZON.StopIntent': function () {
        this.emit(':tell', this.t('STOP_MESSAGE'));
    },
    'StartDialUp': function () {
        let speechOut = '回線につなげます';
        speechOut += "<break time ='1s' />";
        speechOut += "<audio src='https://s3-ap-northeast-1.amazonaws.com/hoge/hogehoge.mp3' />";
        speechOut += "<break time ='1s' />";
        
        // 遅延しているような声
        let complete = "ダ,イ,ヤ,ル,アッ,プ,回,線,に,つ,な,が,り,ま,し,た";
        let completes = complete.split(',');
                completes.forEach(function(val, key){
            if (Math.floor( Math.random() * 6 ) % 3 === 0) {
                speechOut += "<break time ='1s' />";
            }
            speechOut += val;
            if (Math.floor( Math.random() * 6 ) % 3 === 0) {
                speechOut += "ーー";
            }
        });
        
        this.emit(':tell', speechOut);
    },
};
```

```js
    'StartDialUp': function () {
        let speechOut = '回線につなげます';
        speechOut += "<break time ='1s' />";
        speechOut += "<audio src='https://s3-ap-northeast-1.amazonaws.com/hoge/hogehoge.mp3' />";
        speechOut += "<break time ='1s' />";
        
        // 遅延しているような声
        let complete = "ダ,イ,ヤ,ル,アッ,プ,回,線,に,つ,な,が,り,ま,し,た";
        let completes = complete.split(',');
                completes.forEach(function(val, key){
            if (Math.floor( Math.random() * 6 ) % 3 === 0) {
                speechOut += "<break time ='1s' />";
            }
            speechOut += val;
            if (Math.floor( Math.random() * 6 ) % 3 === 0) {
                speechOut += "ーー";
            }
        });
```
音声を流すのはここの処理になります。
SSMLタグについては、[こちら](https://kotodama.today/?p=251)を参考にさせて頂きました。

```html
<audio src='https://s3-ap-northeast-1.amazonaws.com/hoge/hogehoge.mp3' />
```
このように記述することで、音声ファイルを流せますが、以下ご注意ください。

>使用するMP3にはいくつかの条件があります。
　・ インターネット上でホスティングされた HTTPSエンドポイントで提供されていること。
　・ SSL証明書がオレオレ証明書ではなくAmazonの基準を満たす証明書であること。（公式サイトではAWS S3の使用を提案しています）
　・ カスタマーの個人情報やその他デリケートな情報を含んでいないこと
　・ 有効なMP3ファイルであること（MPEG version 2）
　・ 90秒以内であること
　・ ビットレートが48KB/sであること
　・ サンプルレートが16,000Hzであること

あと無駄に遅延しているような声を追加しています。
とりあえず動かしてみます。

[![IMAGE ALT TEXT HERE](http://img.youtube.com/vi/0jVKGmW66IM/0.jpg)](http://www.youtube.com/watch?v=0jVKGmW66IM)

動いた！
最後の遅延してるっぽい声微妙でしたね
他にいいやり方あれば色々試してみたいです

### まとめ

短時間でも簡単にスキルを作れるalexa skill kitとlambdaは素晴らしい！
こういうジョーク系のアプリって審査通るのかな？

何か面白そうなアイディアがあればまた作ってみます！