PR

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

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のWebサイトにログインすることでさまざまな限定特典を入手できるようになります。

Think IT会員サービスの概要とメリットをチェック

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