スロットを使って任意の入力を受け付けよう

2018年7月24日(火)
畠中 幸司(はたなか・こうじ)
連載2回目は「スロット」と呼ばれる機能を用いて、Alexaをより多くの入力に対応できるようにする。

Alexaとの複数回に渡るやりとり(ダイアログ)

ダイアログとは

Alexa Skills Kitにおけるダイアログとは、ユーザーによる一度の発話では収集しきれない情報を、何度かのやりとりを通じて得る方法です。このやりとりの間、収集途中の情報などを覚えておく、いわゆる状態管理を行う必要がありますが、これはスキル・インターフェース側でやってくれます。したがって、AWS Lambdaを使ったプログラム・コードでは、パラメーターとして渡されてくる情報に基づいて処理をすればよく、簡単に期待する動作結果を得られます。スキル・インターフェースとスキル・サービスの間の、ダイアログに関する動作の流れは次のようになっています。

スキル・インターフェースとスキル・サービスの間の情報のやりとり

スキル・インターフェースとスキル・サービスの間の情報のやりとり

一連の会話である「ダイアログ」が開始すると、「STARTED」というダイアログの状態コードがスキル・サービスに渡されます。このとき、スキル・サービスは、ダイアログの続きをスキル・インターフェースに委ねるために「Delegate」という返答をするとともに、スロットの既定の値をスキル・インターフェースに返すことができます。ダイアログの途中、まだ情報収集が完了していない間は「IN_PROGRESS」という状態コードが渡されます。このとき、スキル・サービスは単に「Delegate」と返答するだけで構いません。

ダイアログが完了すると「COMPLETED」という状態コードが渡されるため、スキル・サービスはスロットの値がそろっていることを期待して、処理を進めることができます。

ダイアログを追加する

開発者コンソールを開き、スキル編集画面の左メニューから「eventName」のスロット名をクリックすると、eventNameスロットの詳細を設定するページが開きます。イベント名を必須項目とするため、「このインテントを完了させるために、このスロットは必須ですか?」を選択します。

Alexaの音声プロンプト」の欄には以下の内容を入力して[Enter]を押します。

    どのイベントについて調べますか

イベント名を伝えずに来場者数を尋ねた場合に、Alexaはここに入力した言葉を使ってイベント名を聞き返します。

ユーザーの発話」欄には、以下のように入力して[Enter]を押します。

    {eventName}です
    {eventCity}で開催の{eventName}です

こちらは、上記の音声プロンプトに対するユーザーの返答例となります。設定が完了したら保存とビルドを忘れずに行いましょう。

スロット入力

スロット入力

スキル・サービスをダイアログに対応させる

さっそくコード例を示します。

リスト3:コード例2:code2-2/index.js

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

//=============================================================================
//TODO: The items below this comment need your attention.
//=============================================================================

//Replace with your app ID (OPTIONAL).  You can find this value at the top of
 your skill's page on http://developer.amazon.com.
//Make sure to enclose your value in quotes, like this: const APP_ID = 'amzn1
.ask.skill.bb4045e6-b3e8-4133-b650-72923c5980f1';
const APP_ID = 'amzn1.ask.skill.b6030ab0-d878-4bd3-bff0-790750d638d2';

const SKILL_NAME = '来場者カウント';
const HELP_MESSAGE = '来場者数を教えて、で今日の来場者数をお知らせします';
const HELP_REPROMPT = '何をお調べしますか';
const STOP_MESSAGE = '終了します';

const visitorCount = 156;


//=============================================================================
//Editing anything below this line might break your skill.
//=============================================================================

const handlers = {
    'LaunchRequest': function () {
        // このスキルを「開いて」とリクエストした場合に呼び出される
        // 今回は既定では何もしない

        this.emit(':responseReady');
    },
    'VisitorCountIntent': function () {
        // VisitorCountIntent に対応して呼び出される

        if (this.event.request.dialogState === 'STARTED') {
            // インテントObjectを取得する
            let updatedIntent = this.event.request.intent;

            // スロットの初期値をセットする
            updatedIntent.slots.eventDate.value = '2018-04-03';

            // スキル・インターフェースにダイアログの継続を依頼する
            this.emit(':delegate', updatedIntent); // 初期値あり
        } else if (this.event.request.dialogState !== 'COMPLETED') {
            // スキル・インターフェースにダイアログの継続を依頼する
            this.emit(':delegate');
        } else {
            // インテントObjectを取得する
            let intent = this.event.request.intent;

            // スロットの値を取得する
            var eventCity = intent.slots.eventCity.value;
            var eventName = intent.slots.eventName.value;
            var eventDate = intent.slots.eventDate.value;

            // 結果を生成する
            const speechOutput = eventCity + 'の' + eventName + 'の' + eventDate + 'の来場者数は' + visitorCount + '人です';
            // Alexa アプリで参照できる情報 (カード) を返す
            this.response.cardRenderer(SKILL_NAME, speechOutput);
            // 音声で返答する
            this.response.speak(speechOutput);

            this.emit(':responseReady');
        }
    },
    'AMAZON.HelpIntent': function () {
        const speechOutput = HELP_MESSAGE;
        const reprompt = HELP_REPROMPT;

        this.response.speak(speechOutput).listen(reprompt);
        this.emit(':responseReady');
    },
    'AMAZON.CancelIntent': function () {
        this.response.speak(STOP_MESSAGE);
        this.emit(':responseReady');
    },
    'AMAZON.StopIntent': function () {
        this.response.speak(STOP_MESSAGE);
        this.emit(':responseReady');
    },
    'SessionEndedRequest': function () {
        // Do nothing
    },
};

exports.handler = function (event, context, callback) {
    const alexa = Alexa.handler(event, context, callback);
    alexa.APP_ID = APP_ID;
    alexa.registerHandlers(handlers);
    alexa.execute();
};

VisitorCountIntent」を処理するハンドラーの中では、以下のようにダイアログの状態別に処理をしています。

リスト4:ダイアログの状態別の処理

if (this.event.request.dialogState === 'STARTED') {
    〜 STARTEDの場合の処理 〜
} else if (this.event.request.dialogState !== 'COMPLETED') {
    〜 途中(COMPLETED以外)の場合の処理 〜
} else {
    〜 COMPLETEDの場合の処理 〜
}

ダイアログの継続を指示するのは、下記に示した部分になります。

リスト5:ダイアログの継続指示

this.emit(':delegate', updatedIntent); //初期値あり

リスト6:別のダイアログの継続指示

this.emit(':delegate');

参考情報ですが、この連載ではスキル・サービスをAlexa Skills Kit SDK for Node.jsを使って実装しています。同SDKの詳しい説明は、GitHubのページで参照できます(英文)。

https://github.com/alexa/alexa-skills-kit-sdk-for-nodejs

テストしてみましょう。期待通りの結果になりましたか?

スキルのテスト結果

スキルのテスト結果

次回はいよいよ、Amazon Echo、Echo DotなどのAlexa対応デバイスを使ったテストに挑戦します。スキル・サービス側のプログラムも充実させていきますので、ご期待ください。

著者
畠中 幸司(はたなか・こうじ)

音楽と自然と猫を愛するソフトウェア&インフラエンジニア。日本ヒューレット・パッカード株式会社でクラウドネイティブなアプリケーションのためのインフラ提案、および構築業務に従事。2000年にウェブスタートアップでエンジニアとしてのキャリアをスタートして以来、メガソフト株式会社の3Dマイホームデザイナーシリーズの開発や、マイクロソフト日本法人にて Windows Phone、Microsoft Officeシリーズの開発など、数多くの国内およびグローバルな開発プロジェクトに携わる。建設業向けモバイルアプリSTUCCO(スタッコ)のスタートアップ起業経験、500 KOBE Pre-Acceleratorへの参加等を経て2017年より現職。

連載バックナンバー

開発ツール技術解説
第6回

Alexa:ステートフルなサービスと聞き取りやすい音声応答

2018/9/20
連載6回目は、ステートフルなサービスの構築と、Alexaの音声応答を聞き取りやすくする手法を紹介します。
開発ツール技術解説
第5回

Alexaのためのローカル開発環境を整備する

2018/9/4
連載5回目は、より高度なプログラム作成に先駆けて、Alexaのためのローカル開発環境を整備していきます
開発ツール技術解説
第4回

Alexa Skills Kit SDK for Node.jsについて知る

2018/8/21
連載4回目は、スキル・サービス側のコードに着目して、フレームワークの理解を深めていきます。

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています