[日本語Alexa] AMAZON.Numberで作成した必須スロットで適当な数(たくさん!とか、いっぱい!)を受け付ける〜より自然に会話できるスキル作成のために〜
1 はじめに
前回、「〜より自然に会話できるスキル作成のために〜」とい題して、自然な発話でインテントに導入する方法を検討してみました。
今回は、数の表現を、自然な会話で受け取る方法を考えてみました。
2 バラの注文
サンプルは、バラの注文を行うスキルです。注文には、「本数」の指定が必要です。
U:アレクサ、お花屋さんでバラを下さい A:何本になさいますか? U:5本、下さい A:ありがとうございます。バラを5本、お届けします。
OrderIntentには、本数を表現するnumberというスロットがあり、これが必須となっています。
numberのタイプは、AMAZON.Numberとなっており、数値を受け取れるようになっています。
ダイアログモデルのコードは、非常にシンプルです。
const handlers = { 'LaunchRequest': function () { this.emit(':ask','お花屋さんスキルでは、バラの注文ができます。バラを5本下さい。と言ってみて下さい。'); }, 'OrderIntent': function () { if (this.event.request.dialogState !== 'COMPLETED'){ this.emit(':delegate'); } else { let intent = this.event.request.intent; let number = intent.slots.number.value; this.emit(':tell', 'ありがとうございます。バラを' + number + '本、お届けします。'); } }, // ・・・省略・・・ };
しかし、ユーザーは、正確に本数を言わない場合があります。 「たくさん下さい!」とか、「いっぱい下さい!」みたいな・・・・
numberスロットのタイプは、AMAZON.Numberなので、当然これを受け取ることができず、スキルは、次のようにポンコツな答えを返してしまう事になります。
U:アレクサ、お花屋さんでバラを下さい A:何本になさいますか? U:沢山下さい A:ありがとうございます。バラを 本、お届けします。
3 スロット値のバリデート
elicitSlotを使用すると、スロット値のバリデートが可能です。require指定で入ってきたnumberスロットが想定外の値の場合、これを聞き直すようにコーディングすると、以下のようになります。
let intent = this.event.request.intent; let number = intent.slots.number.value; let num = Number(number); if(1 <= num && num <= 100) { this.emit(':tell', 'ありがとうございます。バラを' + number + '本、お届けします。'); } else { let slotToElicit = 'number'; let speechOutput = 'すいません、ちょっと聞き取れませんでした。もう一度、本数を教えてください'; this.emit(':elicitSlot', slotToElicit, speechOutput, speechOutput); }
これにより、お花屋さんスキルは、適当な数値(ここでは、1本以上100本以下としました)を聞き取れなかった場合、「すいません、ちょっと聞き取れませんでした・・・」のように、もう一度、本数を言ってもらうようになります。
U:アレクサ、お花屋さんでバラを下さい A:何本になさいますか? U:沢山下さい A:すいません、ちょっと聞き取れませんでした。もう一度、本数を教えてください U:100本下さい A:ありがとうございます。バラを100本、お届けします。
しかし、やっぱり本数を答える必要があります。「たくさん」とか「いっぱい」のようなユーザーの自然な対話には対応出来ていません。
4 自然な表現をカスタムスロットで受け取る
まずは、「たくさん」とか「いっぱい」を表現する言葉を列挙し、カスタムスロットを作成します。
次に、このカスタムスロットをタイプとしたスロット「ここではmany」をnumberのUtterancesにひっそり入れておきます。
こうすることで、本数を問い合わせた際に、多くの数を表現する言葉が含まれていると、manyに値が入ることになります。
numberに値が入っているがその内容が無効で、かつ、manyに値が入っていれば、ユーザーが数字ではなく「たくさん」を表現した言葉を発話したことになります。
そこで、この条件をトリガーに、this.emit(':delegate') で、numberスロットを100に書き換えることにしました。
ただし、this.emit(':delegate') は、dialogState が COMPLETEDになってからは使用できませんので、コードは、説明上、ちょっと雑ですが以下のようになります。
'OrderIntent': function () { let intent = this.event.request.intent; if (intent.slots.number.value) { // 値が入っている場合 let number = intent.slots.number.value; let num = Number(number); if(!(1 <= num && num <= 100)) { if (intent.slots.many != undefined && intent.slots.many.value != undefined) { // 「たくさん」を表現するカスタムスロットにに値が入っている場合 let updatedIntent = this.event.request.intent; updatedIntent.slots.number.value = '100'; this.emit(':delegate', updatedIntent); return; } } } if (this.event.request.dialogState !== 'COMPLETED'){ this.emit(':delegate'); } else { let intent = this.event.request.intent; let number = intent.slots.number.value; let num = Number(number); if(1 <= num && num <= 100) { this.emit(':tell', 'ありがとうございます。バラを' + number + '本、お届けします。'); } else { let slotToElicit = 'number'; let speechOutput = 'すいません、ちょっと聞き取れませんでした。もう一度、本数を教えてください'; this.emit(':elicitSlot', slotToElicit, speechOutput, speechOutput); } } },
動作しているようすです。「たくさん」みたいな表現も本数指定も受け付けることが出来ました。
5 最後に
今回は、数値指定を自然に入力できる方法について検討してみました。ドキュメントに明確な記述があるわけでは無いので、あくまで、やって見た上での結果でしかありません。 でも、自然な発話に対応できるインテントを定義する方法としては、一考の余地はあるのでは?と考えています。