Amazon Echo経由でLINE botにメッセージを投げてもらう(2)

Amazon Echo経由でLINE botにメッセージを投げてもらう - ごーちのにっき
の続きです。

主にAmazon Echo ~ Alexaの部分をまとめます。

f:id:kmgc:20171225231555j:plain 

Alexa Skills Kit(ASK)

ASKでAmazon Echo ~ Alexa ~ AWS Lambdaの流れを定義します。
https://developer.amazon.com/ja/

 

A. developer登録から設定はこのページ。
https://developer.amazon.com/ja/blogs/alexa/post/6e716e5c-55b0-445b-b936-9cfac4712e7b/training-1


B. Alexaの設定項目はこのページ。

https://developer.amazon.com/ja/blogs/alexa/post/07377568-2815-4028-8c21-409dd8e84fa2/alexa-training-jp-2nd

「アレクサ、フレックスで10:20」を受け取れるための設定をします。
「ユーザが発した音声データ」を「どういったルールで受け取るか」という設計をします。具体的な項目は次の通りとしました*1

  • 呼び出し名:フレックス
  • Slot名:time(10:20などが入る変数)
  • 想定する音声データ例:フレックスで9:50

[スキル情報]

スキルの種類:カスタム対話モデル
言語:Japanese
スキル名:MyFLex
呼び出し名:フレックス

[対話モデル]

インテントスキーマ

{
    "intents": [
        {"intent": "AMAZON.HelpIntent"},
        {
        "intent": "FlexIntent",
        "slots": [{
            "name": "time",
            "type": "AMAZON.TIME"
            }]
        }
    ]
}

インテントはユーザの要望を示す概念です。インテントに応じて異なる処理を定義するというモデルになっています。今回の例だと9:50で連絡して!という要望に答える形でFlexIntentという定義をしています。
Slot名はtimeと設計し、かつ時間として解釈させたいのでAMAZON.TIMEというあらかじめ用意されたスロット(ビルトインスロット*2 )を設定しました。
AMAZON.TIMEとして定義したことでAlexaからバックエンド(AWS Lambdaなど)へ渡す値が「HH:mm」という文字列になります。

なお、Intentに注目すると他にもAMAZON.HelpIntentがあります。これもあらかじめ用意されたインテント(ビルトインインテント*3です。理由なく、なんとなく使いました。

サンプル発話

FlexIntent {time}
FlexIntent {time} を 連絡して

設計で決めた音声データのルールを書きます。ユーザがインテントをこう話すだろうという文の構造をいくつか書きます。微妙なところは完璧ではないですが適当に補ってくれる印象です。(この設定だとフレックス「で」9:50 の 「で」の部分などです。)

 

とりあえずの設定はここまでです。残りは次へ次へでASKの設定を終えておきましょう。AWS Lambdaで処理ロジックを表現する場合は、作成したLambda Functionのarnを後で埋め込むだけで終わりです。

Lambda Function

ASKで定義した内容の中ではインテントスキーマがLambda Functionの作りに影響します。具体的には次の2個です。

  • intent
  • slots

Lambda Functionでは「このintentならこの処理」のように書きます。*4
Intentによってはslotsに音声入力値が入っています。今回であれば9:50などの時間を示した文字列です。それをslotsで定義したnameを指定して取得します。

作成したLambda Functionのhandlerは次です。*5

index.js

"use strict";
const Alexa = require('alexa-sdk');

// Lambda関数のメイン処理
exports.handler = function(event, context, callback) {
    var alexa = Alexa.handler(event, context); // Alexa SDKインスタンス生成
    alexa.registerHandlers(handlers); // ハンドラの登録
    alexa.execute(); // インスタンスの実行
};

var handlers = {
    // スキルの使い方を尋ねるインテント
    'AMAZON.HelpIntent': function () {
        this.emit(':tell', 'たとえば、フレックスで9:50と言ってください');
    },
    // 本題のインテント
    'FlexIntent': function () {
        var sign = this.event.request.intent.slots.time.value; // スロットtimeを参照
        var params = { Message: 'フレックス'+sign+'でお願いします。', Subject: 'hoge',
            TopicArn: 'arn:aws:sns:ap-northeast-1:XXXXXXXXXX:flex'
        };

        sendTxtMessage(params, myResult=>{
            this.emit(':tell','メッセージを受け付けました');
        }

    );
},
    'Unhandled': function () {
        this.emit(':ask', 'ask', 'ask more');
    },
};

function sendTxtMessage(params, callback) {
    var AWS = require('aws-sdk');
    AWS.config.update({region: 'ap-northeast-1'});
    var SNS = new AWS.SNS();
    SNS.publish(params, function(err, data){
        if (err) {// error handling
        }
        callback('ok');
    });
}

お決まりの部分(exports.handler=…)は無視して、次に注目します。
'FlexIntent': function () {
    var sign = this.event.request.intent.slots.time.value; // スロットtimeを参照

FlexIntent(=HH:mmで連絡して)に対応した処理で、slots.timeで時間を取得しています。この後は適当に加工するだけです。例えば次のような感じです。

var params = { Message: 'フレックス'+sign+'でお願いします。 //以下略

 

今回の設計ではこのLambda FunctionからAmazon SNSへpublishするため、それを実現しています。これについては次のエントリで。
(12/29 追記。まとめました。)

Amazon Echo経由でLINE botにメッセージを投げてもらう(3) - ごーちのにっき

 

*1:詳細はBのページ。ホント分かりやすい。。

*2:スロットタイプリファレンス | Custom Skills

*3:標準インテントを実装する | Custom Skills

*4:Javaですらまだ試してないので誤りであれば後で修正します

*5:Node.jsの書き方への突っ込みはぜひお願いします。。