[日本語Alexa] ダイアログモードの途中で別のインテントに遷移、そして再び戻って来る

最近、ダイアログモデルで必須スロットへの誘導を行っている最中に、別のインテントに遷移できるようになったそうです。 って事で、やってみました。
2018.03.30

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

1 はじめに

本日公開されたAlexaブログで、下記のような記述がありました。

Previously, the dialog model required the user to complete the dialog in order to switch context to a different intent, but recent updates to dialog management now make it possible to switch context between intents.

最近、ダイアログモデルで必須スロットへの誘導を行っている最中に、別のインテントに遷移できるようになったそうです。

って事で、やってみました。

2 コーヒーショップ

例として作成したのは、コーヒーを注文するスキルです。

(1) CoffeeOrderIntent

最初に作成したのは、CoffeeOrderIntentです。 「コーヒーを一つ下さい」、「コーヒーを下さい」、「ショートを一つ下さい」のような発話でこのインテントに入ります。

スロットには、サイズ{size}と数量{number} があり、どちらも必須スロットになっているため、以前の動作では、全てのスロットに値が入るまで、このインテントを抜けることが出来ませんでした。

(2) ListOfSizeIntent

次に作成したのは、ListOfSizeIntentです。サイズの種類がよく分からないユーザーの質問に答えるインテントです。

3 実装

(1) スロットを復元しない場合

これを実装するコードは、以下のようになります。

'ListOfSizeIntent' : function() {
    this.emit(':ask', 'サイズは、ショート、トール、グランデ、ベンティの4種類です');
},
'CoffeeOrderIntent': function () { 
    let intent = this.event.request.intent;
    if (this.event.request.dialogState !== 'COMPLETED'){
        this.emit(':delegate');
    } else {
        const size = intent.slots.size.value;
        const number = intent.slots.number.value;
        const output = size + 'を' + number + 'つ、ご用意します。';
        this.emit(':tell', output);
    } 
}

一応これでも、動作します。

しかし、せっかくダイアログモードで取得したスロットが、再び、戻って来た時に忘れさられていて、注文の続きが出来ているとは言えません。

(2) スロットを復元する

そこで、スロットの値をセッションアトリビュートに保存して、再び返ってきた時に復元するようにしたものが下記です。

'ListOfSizeIntent' : function() {
    this.emit(':ask', 'サイズは、ショート、トール、グランデ、ベンティの4種類です');
},
'CoffeeOrderIntent': function () { 
    let intent = this.event.request.intent;

    const intentName = 'CoffeeOrderIntent';
    if (this.event.request.dialogState !== "COMPLETED") {
        // アトリビュートにデータが入っている場合
        if (this.attributes[intentName]) {
            // スロット値を復元する
            let slots = this.attributes[intentName].slots;
            Object.keys(slots).forEach(slot => {
                if (slots[slot].value) {
                    intent.slots[slot] = slots[slot];
                }
            }, this);
        } else {
            // アトリビュートにデータが入っていない場合は、現在のスロットを保存する
            this.attributes[intentName] = this.event.request.intent;
        }
    } else {
        // ダイアログモード終了時にアトリビュートのデータは消しておく
        delete this.attributes[intentName];
    }

    if (this.event.request.dialogState !== 'COMPLETED'){
        this.emit(':delegate', intent);
    } else {
        const size = intent.slots.size.value;
        const number = intent.slots.number.value;
        const output = size + 'を' + number + 'つ、ご用意します。';
        this.emit(':tell', output);
    } 
}

今度は、最初に取得したスロット{number}が、復元されているのが分かります。これだと、ユーザーは、一連の流れで注文出来ているように感じるでしょう。

4 最後に

今回は、ダイアログモードがCOMPLETEDになる前に、別のインテントに遷移する動作を確かめてみました。今まで、ダイアログモードに入った後は、その中でしか動けないと考えていましたので、色々と設計が変わってきそうです。

再びダイアログモードのインテントに入って来るためのサンプル発話や、不用意に別のインテントに遷移してしまわないような配慮などが必要になってくるかも知れません。

あまりインテントの種類の多いスキルは、今後、難しいような予感もします。

5 参考リンク


How to Enable Alexa to Switch Context Mid-Conversation with Dialog Management