アルパカログ

カスタマーサポート (CS) とエンジニアリングを掛け算したい CRE (Customer Reliability Engineer) が気になる技術や思ったことなど。

Alexa スキルの作り方「Amazon Echo を喋らせる方法」解説

意外とハマり箇所が多かったので、Alexa スキルを作成して Amazon Echo を自由に喋らせる方法をまとめておく。

このエントリでは Node.js を使った例で説明しているが、もちろん他の対応言語でもできるはずだ。

Alexa スキルの仕組み

Alexa スキルを作り始める前に、Alexa スキルがどういう仕組みで動いているのかざっくり説明しておきたい。

f:id:otoyo0122:20180220134442p:plain

Echo に話しかけると発話情報は Alexa に送られ、Alexa からイベント情報が AWS Lambda に送られる。

Alexa スキルを開発するにあたって我々がやるべきことは大きく分けて2つだ。

  1. Alexa Developer Console で対話モデルを作成する
  2. Lambda 関数を作りスピーチテキストを返す

対話モデルの作成、Lambda 関数の作成の順で説明していく。

対話モデルの作成

対話モデルというと何かたいそうなものを作るように聞こえるが、Alexa Developer Console でフローを順にこなしていくだけなので心配しなくていい。

まずは Alexa Developer Console にログインしよう。

f:id:otoyo0122:20180220190830p:plain:w320

Alexa Skills Kit を選んで開始したら、スキルを新規作成しよう。

スキル情報

スキルの情報を下表の通り入力していこう。スキル名の理由は後でわかる。

f:id:otoyo0122:20180220191141p:plain:w480

項目
スキルの種類 カスタム対話モデル
言語 Japanese
スキル名 おじいさんのキャンディ
呼び出し名 おじいさんのキャンディー

入力したら保存して次に進もう。

対話モデル

対話モデルへ進むと Skill Builder が立ち上がるので、左カラム Intents 横の「ADD+」を選択する。

f:id:otoyo0122:20180220192540p:plain:w480

インテント名として「WerthersOriginalIntent」を入力して作成しよう。おっと、勘の良い人は気付いたかな?

次にインテントにサンプル発話を登録する。話しかけそうなテキストを適当に入力しておく。

f:id:otoyo0122:20180220192847p:plain:w480

ここでインテントについて簡単に説明しておこう。

インテントは私たちが対話モデルに解釈させたいユーザの意図で、ここで解釈された意図が後ほど Lambda に送られる。

インテントには Alexa Skills Kit のデフォルトで用意されているものもあり、例えば「会話を中断したい」や「使い方が知りたい」といったものがある。

サンプル発話を入力したら、上部ナビゲーションバーの「Configuration」から次に進もう (ちょっとわかりづらい)。

f:id:otoyo0122:20180220193436p:plain:w240

一度ここで置いて Lambda 側に取り掛かるのだが、その前にスキル ID を確認しておこう。

スキル ID の確認

スキルIDはスキル一覧から確認することができる。Labmda 側で必要になるのでメモしておこう。

amzn1.ask.skill.xxx がスキル ID だ。

f:id:otoyo0122:20180220194032p:plain:w320

Lambda 関数の作成

AWS マネジメントコンソール にログインし、Lambda 関数を新規作成する。

f:id:otoyo0122:20180220135744p:plain

「設計図」を選び、検索フィルターに "alexa" と入力すると「alexa-skill-kit-sdk-factskill」が出てくるので選択する。

f:id:otoyo0122:20180220135936p:plain

関数名は getWerthersOriginal とでもしておこう。ロールは適当に myAlexa としておく。

Alexa Skills Kit トリガーの追加

f:id:otoyo0122:20180220140230p:plain

「左側のリストからトリガーを追加します」を選ぶと左側にトリガーの一覧が出てくるので「Alexa Skills Kit」を選択する。

f:id:otoyo0122:20180220140404p:plain

そのまま画面を下にスクロールすると Alexa Skills Kit の設定項目があるので、スキル ID 欄に先ほど確認したスキルID を入力して追加しよう。

関数コードの設定

スクロールして上に戻り、今度は Lambda getWerthersOriginal を選択しよう。

すると Alexa Skills Kit の設定欄がコード編集画面に変わるので、下記のサンプルコードを入力しよう。

サンプルコード内の APP_ID の値は自分のスキル ID に変えておくように。

'use strict';

const Alexa = require('alexa-sdk');

const APP_ID = 'amzn1.ask.skill.xxx';  // TODO replace with your app ID (OPTIONAL).

const languageStrings = {
    'ja': {
        translation: {
            TALKSCRIPTS: [
                '私のおじいさんがくれた初めてのキャンディ。',
                'それはヴェルタースオリジナルで私は四歳でした。',
                'その味は甘くてクリーミィで、',
                'こんな素晴らしいキャンディをもらえる私は、',
                'きっと特別な存在なのだと感じました。',
                '今では私がおじいさん。',
                '孫にあげるのはもちろんヴェルタースオリジナル。',
                'なぜなら彼もまた、特別な存在だからです。',
            ],
            SKILL_NAME: 'おじいさんのキャンディ',
            HELP_MESSAGE: 'おじいさんのキャンディと言うと、おじいさんのセリフが聞けます。',
            HELP_REPROMPT: 'おじいさんのキャンディを聞きますか',
            STOP_MESSAGE: 'わかりました。',
        },
    },
};

const handlers = {
    'LaunchRequest': function () {
        this.emitWithState('WerthersOriginalIntent');
    },
    'IntentRequest': function () {
        if (this.event.request.intent.name === 'WerthersOriginalIntent') {
            this.emitWithState('WerthersOriginalIntent');
        }
    },
    'WerthersOriginalIntent': function () {
        const talkscripts = this.t('TALKSCRIPTS');

        // Create speech output
        const speechOutput = talkscripts.join('');
        this.emit(':tellWithCard', speechOutput, this.t('SKILL_NAME'), 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'));
    },
};

exports.handler = function (event, context) {
    const alexa = Alexa.handler(event, context);
    alexa.appId = APP_ID;
    // To enable string internationalization (i18n) features, set a resources object.
    alexa.resources = languageStrings;
    alexa.registerHandlers(handlers);
    alexa.execute();
};

Alexa はユーザの音声を受けると LaunchRequestIntentRequest のどちらかを Lambda に送る。

LaunchRequest は「アレクサ、<スキル名>を開いて」と呼び出したときに、IntentRequest は対話モデルで定義したインテントに対応する呼び出しを行ったときに対応している。

ちなみに上記コードでは大丈夫だが、Lambda の初期状態のコードでは下記のようなエラーとなる。

"errorMessage": "Invalid ApplicationId: amzn1.ask.skill.XXXXXXX"

これは alexa.APP_ID = APP_ID; の箇所が誤りで、 alexa.appId = APP_ID; にすると解決する。

保存と ARN のメモ

画面右上に表示されている ARN をメモしておき、保存する。

f:id:otoyo0122:20180220195332p:plain

これで Lambda 側の設定は完了だ。先ほど中断していた Alexa Developer Console に戻ろう。

設定と公開情報

サービスエンドポイントのタイプとして「AWS Lambda の ARN」を選択し、テキストフィールドに先ほどメモした ARN を入力しよう。

f:id:otoyo0122:20180220195632p:plain

テストはスキップし、公開情報は適当に埋めつつ進もう。途中スキルアイコンの設定がある。

スキルアイコンの設定

スキルアイコンの画像 (108*108px と 512*512px) を設定する必要がある。

f:id:otoyo0122:20180220195935p:plain:w320

開発バージョンなんだからそのまま使わせてくれよと思うが、あと少しなので頑張ろう。

Mac ユーザの場合、画像サイズの編集には sips コマンドが便利だ。

長方形の画像から 512px 四方の画像を作るには、短辺が 512px になるように拡大・縮小しクロップ (切り抜き) すれば良い。

例えば横長の画像では、短辺となる縦が 512px になるよう拡大・縮小する。

sips --resampleHeight 512 inputfile --out resampled_file

512px 四方でクロップする。

sips --cropToHeightWidth 512 512 resampled_file --out cropped_file

スキルのβテスト

いよいよ実機にスキルをインストールして動かしてみよう。

ここまでで全ての手順に ✅マークが付いているはずだ。

f:id:otoyo0122:20180220200012p:plain:w160

もしまだ ✅が付いていない手順があれば戻って確認しよう。「テスト管理」からβテストができる。

f:id:otoyo0122:20180220200107p:plain:w480

自分のメールアドレスを入力してβテストの招待メールを送ろう。

招待メール内にスキルをインストールするためのリンクがあるので、アレクサと連携した端末で開きスキルを有効化しよう。

f:id:otoyo0122:20180220200134p:plain:w240

スキルのインストールが完了した画面だ (iPhone)。

話しかけよう

「アレクサ、おじいさんのキャンディを開いて」と話しかけ、趣深いセリフが始まったら成功だ。

お詫びと訂正

  • IntentRequest による呼び出しコードを修正しました (2018/2/21)

参考リンク

こちらもあわせてどうぞ

alpacat.hatenablog.com