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


経緯と目的

仕事中調べ物をしていたら、明日のLambda枠が空いていたので勢いで登録してしまいました。
最近echo plus手に入れて、alexa 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にチェック付けていますが、多分必要ありません。

インテント

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


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

サンプル発話

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

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 関数を作成

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

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とかを読み込んでいたのですが今回は削除しました。

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);
    },
};
    '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タグについては、こちらを参考にさせて頂きました。

<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

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

まとめ

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

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