はじめに
ブログ初投稿、開発部の辻です。
技術的なことをちょいちょい書いていければなぁと思っています。
最近Alexaスキルの開発を担当していますが
開発中はAmazon Echoと会話をすることが多く
テスト中には、隣の人から「またAlexaに怒ってる」という感想をいただきました。
目次
概要
スキルの中でユーザから情報を聞き出したいときはスロットを使用することになります。
正直、スロット値を集める処理は面倒大変です。
そこでDialogモデルを使用することで、スロット値が入力されるまでの処理をAlexaにおまかせすることができます。
従来の書き方
まず、Dialogモデルを使わないスキルを作成します。
今回は、サバ料理を注文するスキルを作っていきたいと思います。
「アレクサ、サバショップで味噌味のサバ料理を3つ」のように話しかける感じです。
スロットタイプの設定
サバ料理の味(Taste)をスロット値に入力します。
今回は
- 味噌
- 醤油
- 塩
数量を扱うためAMAZON.NUMBER
もスロットタイプに追加しておきます
インテントの設定
サバ料理を注文するインテントを作成します。
名前はBuyMackerelFoodIntent
にしました。
Lambdaのコード
const Alexa = require('ask-sdk-core'); const LaunchRequestHandler = { canHandle(handlerInput) { return handlerInput.requestEnvelope.request.type === 'LaunchRequest'; }, handle(handlerInput) { const speechOutput = 'いらっしゃいませ。何を注文しますか?'; const reprompt = '味噌味、醤油味、塩味などがあります。何を注文しますか?'; return handlerInput.responseBuilder .speak(speechOutput) .reprompt(reprompt) .getResponse(); } }; const BuyMackerelFoodIntentHandler = { canHandle(handlerInput) { return handlerInput.requestEnvelope.request.type === 'IntentRequest' &amp;&amp; handlerInput.requestEnvelope.request.intent.name === 'BuyMackerelFoodIntent'; }, handle(handlerInput) { let taste = handlerInput.requestEnvelope.request.intent.slots.taste.value; let amount = handlerInput.requestEnvelope.request.intent.slots.amount.value; let session = handlerInput.attributesManager.getSessionAttributes(); /* 味を決める */ if (taste === undefined &amp;&amp; session.taste === undefined){ return handlerInput.responseBuilder .speak('何味にしますか?') .reprompt('味噌、醤油、塩から選べます。何味にしますか?') .getResponse(); } else { if (taste) { session.taste = taste; handlerInput.attributesManager.setSessionAttributes(session); } else { taste = session.taste; } } /* 個数を決める */ if (amount === undefined &amp;&amp; session.amount === undefined){ return handlerInput.responseBuilder .speak('いくつにしますか?') .reprompt('何個必要ですか?') .getResponse(); } else { if (amount) { session.amount = amount; handlerInput.attributesManager.setSessionAttributes(session); } else { amount = session.amount; } } const speechOutput = <code>${taste}味のサバ料理を${amount}つ承りました。</code>; return handlerInput.responseBuilder .speak(speechOutput) .getResponse(); } }; const ErrorHandler = { canHandle () { return true; }, handle (handlerInput, error) { const message = "すみません、うまく聞き取れませんでした。もう一度言ってください。"; return handlerInput.responseBuilder .speak(message) .reprompt(message) .getResponse() } }; const skillBuilder = Alexa.SkillBuilders.custom(); exports.handler = skillBuilder .addRequestHandlers( LaunchRequestHandler, BuyMackerelFoodIntentHandler ) .addErrorHandlers(ErrorHandler) .lambda();
スロット値が入力されているかを確認する処理なんかは、おなじような処理が並んでますね。
テスト
無事注文できましたね
しかし、このコードだとスロット値が増えるとその分if-elseが増え見づらいコードとなってしまいます。
次にDialogモデルを使用した場合です。
Dialogモデルを使用する
Dialogモデルを使用するには一部設定を有効にする必要がありますので、やっていきたいと思います。
インテントスロット
スロット入力から「このインテントを完了させるために、このスロットは必須ですか?」を有効にし
Alexaがどのように尋ねるかと、ユーザがどのように返事をするかを定義します。
今までプログラムに書いていたことを、Alexa側に書く感じですね。
Lambdaのコード
const Alexa = require('ask-sdk-core'); const LaunchRequestHandler = { canHandle(handlerInput) { return handlerInput.requestEnvelope.request.type === 'LaunchRequest'; }, handle(handlerInput) { const speechOutput = 'いらっしゃいませ。どの味を注文しますか?'; const reprompt = '味噌味、醤油味、塩味などがあります。何を注文しますか?'; return handlerInput.responseBuilder .speak(speechOutput) .reprompt(reprompt) .getResponse(); } }; const BuyMackerelFoodIntentHandler = { canHandle(handlerInput) { return handlerInput.requestEnvelope.request.type === 'IntentRequest' &amp;&amp; handlerInput.requestEnvelope.request.intent.name === 'BuyMackerelFoodIntent'; }, handle(handlerInput) { let taste = handlerInput.requestEnvelope.request.intent.slots.taste.value; let amount = handlerInput.requestEnvelope.request.intent.slots.amount.value; let {dialogState} = handlerInput.requestEnvelope.request; if (dialogState !== 'COMPLETED') { return handlerInput.responseBuilder .addDelegateDirective() .getResponse(); } else { const speechOutput = <code>${taste}味のサバ料理を${amount}つ承りました。</code>; return handlerInput.responseBuilder .speak(speechOutput) .getResponse(); } } }; const ErrorHandler = { canHandle () { return true; }, handle (handlerInput, error) { const message = "すみません、うまく聞き取れませんでした。もう一度言ってください。"; return handlerInput.responseBuilder .speak(message) .reprompt(message) .getResponse() } }; const skillBuilder = Alexa.SkillBuilders.custom(); exports.handler = skillBuilder .addRequestHandlers( LaunchRequestHandler, BuyMackerelFoodIntentHandler ) .addErrorHandlers(ErrorHandler) .lambda();
テスト
変更前と同じことができました!
結論
Dialogモデルを使用すると、AlexaはdialogState
をリクエストに追加します。
この値がCOMPLETED
になるまでAlexaにお任せができる感じです。
スロットが入力されたかどうかの処理はAlexa側でやってくれるため、プログラムで処理する必要がありません。
今まで自分で判定していた処理を減らすことができ、不具合の原因を減らすことができます。
スロットの数が2つ程度なら従来の方法でも対処できそうですが、4つとかになるとDialogモデルが効果的になると思いますよ!
投稿者プロフィール
最新の投稿
- AWS2021年12月2日AWS Graviton3 プロセッサを搭載した EC2 C7g インスタンスが発表されました。
- セキュリティ2021年7月14日ゼロデイ攻撃とは
- セキュリティ2021年7月14日マルウェアとは
- WAF2021年7月13日クロスサイトスクリプティングとは?