Alexaにダイアログをデリゲートする
コードにスロット値を簡単に収集して確認できるようにするには、ダイアログモデルを作成して、ダイアログをAlexaにデリゲートします。ダイアログモデルは、プロンプト、およびスロット値とインテントを修正、検証、確認する発話を識別します。ダイアログをAlexaにデリゲートする場合、Alexaは、会話の次の手順を判断し、プロンプトを使用してユーザーに情報を求めます。
- Alexaにダイアログをデリゲートする方法
- 簡単なダイアログを自動的にAlexaにデリゲートする
- ランタイム時に会話を変更するために手動でデリゲートする
- スキルとインテントにデリゲートルールを設定する
- ダイアログモデル(対話モデルのスキーマ)に含まれるオートデリゲートのJSON
- 関連トピック
Alexaにダイアログをデリゲートする方法
Alexaにダイアログをデリゲートするには、2つの方法があります:
- スキル全体、または特定のインテントのいずれかで、オートデリゲートを有効にします。この場合、Alexaは、ダイアログモデルに従ってすべてのダイアログの手順を完了します。ダイアログが完成すると、Alexaは単一の
IntentRequest
を送信します。 Dialog.Delegate
ディレクティブで手動でデリゲートします。この場合、Alexaは会話ごとにスキルにIntentRequest
を送信します。- リクエストは、
dialogState
をSTARTED
、IN_PROGRESS
、またはCOMPLETED
に設定して、ダイアログの現在の状態を示します。 - 完了していないダイアログには、スキルは、
Dialog.Delegate
ディレクティブを返します。これにより、Alexaは次の手順のダイアログモデルを確認し、必要に応じて詳細な情報をユーザーにたずねるプロンプトを使用します。 - すべての手順が完了したら、スキルは
dialogState
がCOMPLETED
に設定された最後のIntentRequest
を受け取ります。
- リクエストは、
特定の対話に応じた正しいデリゲートルールは、ダイアログの複雑さによって異なります。コードでダイアログをまったく処理する必要がないため、オートデリゲートはもっと簡単です。Dialog.Delegate
で手動でデリゲートする方がより柔軟性があります。値をデフォルトにするなど、スキルがランタイム中に意思決定を行えるためです。Dialog
ディレクティブと組み合わせることで、必要に応じて、ダイアログを完全に制御するためにDialog.Delegate
を使用することもできます。
スキル全体に、包括的なデリゲートルールを設定することも、スキルの各インテントにデリゲートルールを設定することもできます。つまり、インテントの一部にオートデリゲートを使用して、それ以外には手動でデリゲート、またはデリゲートを行わないようにすることもできるということです。
簡単なダイアログを自動的にAlexaにデリゲートする
ダイアログの手順や入力するスロットが、ユーザーとのランタイム中の対話に応じて変化しない場合は、簡単なダイアログをデリゲートするよう、スキルを設定します。たとえば、惑星についての質問に答えるスキルについて考えてみましょう。スキルのインテントは、ユーザーがどの惑星についてたずねているか、名前を知る必要があります。この要件は、ダイアログ内での以前のやり取りに応じて変化するものではないため、これをAlexaにデリゲートします。
たとえば、この対話では、planet
スロットの値を収集するためのすべてのやり取りが完了したら、Alexaはスキルにインテントを1つだけ送信します。
ユーザー: 他の惑星の天気はどう?
Alexa: どの惑星について知りたいですか? (AlexaはGetPlanetWeather
インテントのplanet
スロットに定義されたプロンプトを使用して、ユーザーにプロンプトを出します。)
ユーザー: 太陽 (ユーザーがplanet
スロットの検証ルールに合わない値でプロンプトに応答します)
Alexa: 太陽に天気はありません。代わりに惑星の名前を言ってください。 (ユーザーの値は検証を通りませんでした。Alexaは、使用できる値をたずねるプロンプトで応答します。)
ユーザー: 火星。
ここで、planet
スロットには使用できる値が入力されたので、AlexaはスキルにIntentRequest
を送信します。インテントはGetPlanetWeather
です。これには「火星」という値を含む単一のスロットplanet
が含まれます。
このような対話を作成するには、次の手順を実行します。
GetPlanetWeather
インテントのplanet
スロットを必須スロットとして設定して、ユーザーに惑星をたずねるプロンプトを出します。planet
スロットのスロット検証ルールを有効にします。この場合、2つのルールがあります:- 値セットのみを拒否する:「太陽」などの特定の値を拒否して、もっとコンテキストに適したプロンプトを出します。このルールが最初に適用されます。
- スロットタイプの値と同義語のみを受け付ける:スロットのカスタムタイプに定義された値のみを受け付けます。ユーザーの値が最初のルールを通過した場合に、このルールが適用されます。
- ダイアログをAlexaに自動的にデリゲートするには、
GetPlanetWeather
を設定します。
この例では、このシナリオのGetPlanetWeather
のインテントハンドラーを示しています。ハンドラーはダイアログの状態を確認したり、planet
スロット値が有効な惑星を識別しているかどうかを検証する必要はありません。なぜなら、ダイアログモデルのスロット検証とオートデリゲートは、リクエストがスキルに送信される前にこれを処理するためです。
このサンプルコードはAlexa Skills Kit SDK for Node.js (v2)を使用しています。
この例では、惑星についての詳細は、PLANETS
マップに保存されています。これは、惑星についてのプロパティを、カスタムスロットタイプであるPlanetのスロット値に定義されたIDにマッピングします。
const GetPlanetWeatherHandler = {
canHandle(handlerInput){
const request = handlerInput.requestEnvelope.request;
return (request.type === 'IntentRequest'
&& request.intent.name === 'GetPlanetWeather');
},
handle(handlerInput){
const intent = handlerInput.requestEnvelope.request.intent;
let planetId = intent.slots.Planet.resolutions.resolutionsPerAuthority[0].values[0].value.id;
let planet = PLANETS[planetId];
let speechOutput = "" + planet.PrintName + "では" + planet.Weather"となるでしょう";
return handlerInput.responseBuilder
.speak(speechOutput)
.withShouldEndSession (true)
.getResponse();
}
};
このサンプルコードはAlexa Skills Kit SDK for Javaを使用しています。
この例では、惑星についての詳細は、Planet
列挙値に保存されています。この列挙値には、天気について説明した文字列などの情報のプロパティと、データを取得するためのgetterメソッドが含まれおり、カスタムスロットタイプであるPlanetのスロット値に定義されたIDと照合します。
package com.ask.factskill.handlers;
import com.amazon.ask.dispatcher.request.handler.HandlerInput;
import com.amazon.ask.dispatcher.request.handler.impl.IntentRequestHandler;
import com.amazon.ask.model.Intent;
import com.amazon.ask.model.IntentRequest;
import com.amazon.ask.model.Response;
import com.amazon.ask.model.Slot;
import com.ask.factskill.enums.Planet;
import java.util.Optional;
import static com.amazon.ask.request.Predicates.intentName;
import static com.amazon.ask.request.Predicates.requestType;
import static com.ask.factskill.util.Constants.*;
public class GetPlanetWeatherHandler implements IntentRequestHandler {
@Override
public boolean canHandle(HandlerInput handlerInput, IntentRequest intentRequest) {
return (handlerInput.matches(intentName("GetPlanetWeather")));
}
@Override
public Optional<Response> handle(HandlerInput handlerInput, IntentRequest intentRequest) {
Intent intent = intentRequest.getIntent();
Slot planetSlot = intent.getSlots().get(PLANET_SLOT);
String planetId = planetSlot
.getResolutions()
.getResolutionsPerAuthority().get(0).getValues()
.get(0).getValue().getId();
Planet planet = Planet.valueOf(planetId);
String speechText = "On " + planet.getPrintName() + ", you can expect " +
planet.getPlanetWeather();
return handlerInput.getResponseBuilder()
.withSpeech(speechText)
.build();
}
}
最初のダイアログの完了後に別のダイアログを開始する
オートデリゲートが有効な場合でもDialog.Delegate
を使うシナリオが1つあります。インテントハンドラーが完了したダイアログからDialog.Delegate
を返して、Alexaに別のインテントを呼び出して新しいダイアログを開始するよう指示します。
たとえば、BookFlight
インテントのダイアログを完了した後、AlexaにBookRentalCar
のダイアログを開始するよう指示する場合などです。BookRentalCar
のオートデリゲートが有効な場合、Alexaはダイアログのすべてのステップを処理してから、スキルにBookRentalCar
の完了したIntentRequest
を送信します。ダイアログが完了したら、スキルはIntentRequest
を1つ受け取ります。このとき、dialogState
はCOMPLETED
に設定されます。
2つ目のダイアログをトリガーするには、Dialog.Delegate
を返す際にupdatedIntent
を新しいインテントに設定します。新しいインテントでもオートデリゲートが有効な場合、Alexaはダイアログ全体を処理し、スキルは再びIntentRequest
を受け取ります。ダイアログが完了すると、dialogState
をCOMPLETED
に設定します。
ダイアログ中にインテントの変更やスロット値の更新を行うを参照してください。
ランタイム時に会話を変更するために手動でデリゲートする
ダイアログ中にもっと柔軟性が必要になった場合、Dialog.Delegate
ディレクティブを使用します。スキルは、対話のターンごとにIntentRequest
を受け取るので、コードはランタイム中の意思決定ができ、デリゲート前に他のアクションが実行できるようになります。複雑なダイアログの場合に、会話の流れをもっとスムーズにしたい場合に便利です。
手動デリゲートが適しているシナリオには、以下のようなものがあります:
- サービスで既に提供されている情報をユーザーがたずねないようにするために、必要なスロットの詳細を設定する必要がある場合。
- ユーザーの応答に応じて、さらに複雑なランタイム中の意思決定を行い、ダイアログでデリゲートと手動制御を組み合わせて使用する必要がある場合。
これらのシナリオの例については、次のシナリオを参照してください。
デフォルト値を設定するためにダイアログを手動でデリゲートする
PlanMyTripIntent
インテントには、ユーザーの出発地を収集するfromCity
スロットがあります。リクエストを完了するには、このスロットが必須ですが、通常、この値は変化しないため、スキルはユーザーの指定するデフォルトの出発地を保存します。ユーザーがこのデフォルトの出発地をシステムに保存した場合、オートデリゲートは毎回出発地をユーザーにたずねることになるので、ユーザーエクスペリエンス的にはよくありません。
代わりに、入力するインテントを更新して、fromCity
にデフォルト値を設定し、ダイアログをAlexaにデリゲートするようにできます。Alexaはスロット入力のプロンプトをスキップして、ダイアログの次の手順を実行します:
ユーザー: アレクサ、トリッププランを開いて、京都に行きたいと言って(AlexaはPlanMyTripIntent
インテントのtoCity
の値に「京都」が入力されているが、fromCity
には何も入力されていないIntentRequest
を送信します。)
スキルはユーザーを検出して、通常のデフォルトの都市が「神戸」であると判断します。従って、スキルは updatedIntent.slots.fromCity
が 神戸
に設定されたDialog.Delegate
ディレクティブを返します。
Alexa: 出発する日時はいつですか? (fromCity
を収集するために、Alexaはプロンプトをスキップします。これは既に入力されているためです。その後残りのスロットについての処理を続行します。)
対話が続きます。Alexaは、旅行の日付、旅行のモード、旅行についてのその他の情報を収集するために、引き続きプロンプトを使用します...
Alexa: わかりました。12月10日の神戸から京都への旅行を保存します。 (この対話中に、fromCity
がたずねられなかった場合でも、スキルにはこのスロット値を含める必要があることに注意してください。)
このダイアログは別のシナリオで動作します:
- ユーザーが、都市を指定して対話を開始した場合、
fromCity
にその値が入力され、デフォルト値は使用されません。 - ユーザーがデフォルトの都市を以前に設定しなかった場合は、
fromCity
は空のままになるため、Alexaはダイアログモデルに従って、ユーザーにプロンプトを出します。
このような対話を作成するには、次の手順を実行します。
- 必要なスロット(
toCity
,fromCity
、travelDate
)に応じて、PlanMyTripIntent
インテントの該当するスロットを設定し、プロンプトを出します。 PlanMyTripIntent
インテントのオートデリゲートを無効にします。- 出発地が提供されない場合は、
fromCity
スロットをデフォルト値として、Alexaとの残りのダイアログをデリゲートするようスキルにコードを追加します。
これを行うには、コードに別のハンドラーを使うこともできます。たとえば、次のようになります:
StartedPlanMyTripHandler
–dialogState
がSTARTED
の場合、PlanMyTripIntent
リクエストを処理します。fromCity
スロットの値を確認します。スロットが空の場合は、ユーザーがよく使うデフォルトの出発地を取得し、インテントのfromCity
スロット値を更新します。Dialog.Delegate
を返して、ディレクティブのupdatedIntent
プロパティに含まれるこの更新したインテントを渡します。Dialog.Delegate
を返す場合の、スロット値の変更についての詳細は、ダイアログ中にスロット値と確認ステータスを更新するを参照してください。
InProgressPlanMyTripHandler
–dialogState
がIN_PROGRESS
の場合、リクエストを処理します。すべてのリクエストにDialog.Delegate
を返すだけです。CompletedPlanMyTripHandler
–dialogState
がCOMPLETED
の場合、PlanMyTripIntent
リクエストを処理します。ダイアログが完了しているため、このハンドラーに送信されるインテントは、常に入力されたすべての必須スロットを含んでいます。ユーザーのリクエストを完了するには、スロット値を使用します。
このサンプルコードはAlexa Skills Kit SDK for Node.js (v2)を使用しています。
const StartedPlanMyTripHandler = {
canHandle(handlerInput){
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest' &&
request.intent.name === 'PlanMyTripIntent' &&
request.dialogState === 'STARTED';
},
handle(handlerInput){
const currentIntent = handlerInput.requestEnvelope.request.intent;
let fromCity = currentIntent.slots.fromCity;
// ユーザーがスロットを入力しなかった場合、fromCityの値は空です。この例では、
// getUserDefaultCity()は、永続ストレージから、ユーザーのデフォルトの都市を取得します。
if (!fromCity.value) {
currentIntent.slots.fromCity.value = getUserDefaultCity();
}
// the Dialog.Delegateディレクティブを返します
return handlerInput.responseBuilder
.addDelegateDirective(currentIntent)
.getResponse();
}
};
const InProgressPlanMyTripHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest' &&
request.intent.name === 'PlanMyTripIntent' &&
request.dialogState === 'IN_PROGRESS';
},
handle(handlerInput) {
const currentIntent = handlerInput.requestEnvelope.request.intent;
return handlerInput.responseBuilder
.addDelegateDirective(currentIntent)
.getResponse();
},
};
const CompletedPlanMyTripHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest' &&
request.intent.name === 'PlanMyTripIntent' &&
request.dialogState === 'COMPLETED';
},
handle(handlerInput) {
// このインテントがトリガーされた場合、すべての必須スロットが入力されます。
// このためデータを旅行についての応答にまとめます...
},
};
このサンプルコードはAlexa Skills Kit SDK for Javaを使用しています。
// これらのハンドラーのそれぞれは、Javaクラスです。簡単に説明すると、
// パッケージと各クラスのimport宣言は表示されません。
/**
* *****************************************
* StartedPlanMyTripHandler class
* *****************************************
*/
public class StartedPlanMyTripHandler implements IntentRequestHandler {
@Override
public boolean canHandle(HandlerInput handlerInput, IntentRequest intentRequest) {
return (handlerInput.matches(intentName("PlanMyTripIntent"))
&& intentRequest.getDialogState() == DialogState.STARTED);
}
@Override
public Optional<Response> handle(HandlerInput handlerInput, IntentRequest intentRequest) {
System.out.println("In StartedPlanMyTripHandler");
Intent intent = intentRequest.getIntent();
Slot fromCitySlot = intent.getSlots().get(FROM_CITY_SLOT_NAME);
if (fromCitySlot.getValue() == null){
// ユーザーがスロットを入力しなかった場合、getValueはnullを返します 。
//この例では、getUserDefaultCity()が永続ストレージから
// ユーザーのデフォルト値を取得します。
Slot updateSlot = Slot.builder()
.withName(FROM_CITY_SLOT_NAME)
.withValue(getUserDefaultCity())
.build();
// 更新したスロットをintentオブジェクトにプッシュします
intent.getSlots().put(FROM_CITY_SLOT_NAME, updateSlot);
}
// the Dialog.Delegateディレクティブを返します
return handlerInput.getResponseBuilder()
.addDelegateDirective(intent)
.build();
}
}
/**
* *****************************************
* InProgressPlanMyTripHandler class
* *****************************************
*/
public class InProgressPlanMyTripHandler implements IntentRequestHandler {
@Override
public boolean canHandle(HandlerInput handlerInput, IntentRequest intentRequest) {
return (handlerInput.matches(intentName("PlanMyTripIntent"))
&& intentRequest.getDialogState() == DialogState.IN_PROGRESS);
}
@Override
public Optional<Response> handle(HandlerInput handlerInput, IntentRequest intentRequest) {
System.out.println("In InProgressPlanMyTripHandler");
return handlerInput.getResponseBuilder()
.addDelegateDirective(intentRequest.getIntent())
.build();
}
}
/**
* *****************************************
* CompletedPlanMyTripHandler class
* *****************************************
*/
public class CompletedPlanMyTripHandler implements IntentRequestHandler {
@Override
public boolean canHandle(HandlerInput handlerInput, IntentRequest intentRequest) {
return (handlerInput.matches(intentName("PlanMyTripIntent"))
&& intentRequest.getDialogState() == DialogState.COMPLETED);
}
@Override
public Optional<Response> handle(HandlerInput handlerInput, IntentRequest intentRequest) {
System.out.println("In CompletedPlanMyTripHandler");
// このインテントがトリガーされた場合、すべての必須スロットが入力されます。
// このためデータを旅行についての応答にまとめます...
}
}
複雑なダイアログを処理するために、デリゲートを組み合わせて手動で制御する
コーヒーショップから飲み物を注文するスキルには、ユーザーが注文する飲み物の種類についての情報を収集する、いくつかのスロットを持つOrderIntent
があります。drink
スロットは、ユーザーが注文した飲み物がメニューにあるかどうかを確認するためのスロット検証を使用して設定します。インテントには、drink
の値に応じて入力する必要のある、追加スロットがあります:
drink
が「コーヒー」の場合は、coffeeRoast
drink
が「お茶」の場合は、teaType
この場合、スキルは対話中に何の値を引き出すかの意思決定を行う必要があります。これを管理するには、スキルはdrink
スロットを収集して検証するDialog.Delegate
を返して、次にcoffeRoast
とteaType
を入力するためにダイアログを手動で処理します。
ユーザー: アレクサ、コーヒーショップを開いて注文を始めて
Alexa: コーヒーとお茶のどちらにしますか?
ユーザー:靴( AlexaはスキルにOrderIntent
を持っているIntentRequest
を送信します。drink
スロットには、無効な値靴
が含まれます。)
ダイアログが完了していないので、スキルはDialog.Delegate
を返します。
Alexa: 靴はメニューにありません。コーヒーとお茶のどちらにしますか? (Alexaはdrink
スロットのスロット検証ルールで定義されたプロンプトで応答します。)
ユーザー: コーヒー (Alexa はスキルにdrink
をコーヒー
に設定したOrderIntent
を送信します。)
これで飲み物が決まり、スキルはダイアログを引き継いで、 coffeeRoast
値をたずねるためにDialog.ElicitSlot
を使用します。
Alexa: ローストはライト、ミディアム、ミディアムダーク、ダークのどれにしますか? (Dialog.ElicitSlot
ディレクティブの一部として提供されたプロンプトです。)
対話が続きます...
このような対話を作成するには、次の手順を実行します。
OrderIntent
インテントのdrink
スロットを必須スロットとして設定して、ユーザーにこの値をたずねるプロンプトを出します。飲み物固有のスロット(coffeeRoast
とteaType
)は必須ではありません。drink
スロットのスロット検証ルールを有効にします。これには、スロットのカスタムタイプには、メニューにあるすべての飲み物の値と同義語が含まれていると仮定して、スロットタイプの値を同義語のみを受け付ける ルールを使用できます。OrderIntent
のオートデリゲートを無効にします。drink
がまだ提供されていない場合、未完了のダイアログをデリゲートするコードを追加します。drink
の値に応じて、該当するスロットをたずねるコードを追加します。これには、Dialog.ElicitSlot
ディレクティブを使用します。drink
が「コーヒー」の場合、coffeeRoast
の値を引き出します。drink
が「お茶」の場合、teaType
の値を引き出します。
ダイアログの状態やdrink
スロットの値に応じて、インテントに応答する別のハンドラーを使用することができます:
CoffeeGivenOrderIntentHandler
–drink
が「コーヒー」だが、coffeeRoast
に値が入っていない場合に、OrderIntent
を処理します。コーヒーのローストの種類をたずねるために、Dialog.ElicitSlot
を返します。TeaGivenOrderIntentHandler
–drink
が「お茶」だが、teaType
に値が入っていない場合に、OrderIntent
を処理します。お茶の種類をたずねるために、Dialog.ElicitSlot
を返します。-
StartedInProgressOrderIntentHandler
–dialogState
が完了していない場合に、OrderIntent
リクエストを処理します。Dialog.Delegate
を返します。これで、drink
スロットに有効な値が入力されます。ASK v2 SDKで、コーヒーとお茶のハンドラーの後にこのハンドラーを登録して、該当するハンドラーがほかにない場合にのみ
StartedInProgressOrderIntentHandler
が使われるようにする必要があります。 CompletedOrderIntentHandler
–dialogState
がCOMPLETED
の場合に、OrderIntent
リクエストを処理します。ここで、インテントにはdrink
スロットの値と、coffeeRoast
またはteaType
のいずれかが含まれることになります。
このサンプルコードはAlexa Skills Kit SDK for Node.js (v2)を使用しています。
const StartedInProgressOrderIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === "IntentRequest"
&& handlerInput.requestEnvelope.request.intent.name === "OrderIntent"
&& handlerInput.requestEnvelope.request.dialogState !== 'COMPLETED';
},
handle(handlerInput) {
return handlerInput.responseBuilder
.addDelegateDirective()
.getResponse();
}
};
const CoffeeGivenOrderIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === "IntentRequest"
&& handlerInput.requestEnvelope.request.intent.name === "OrderIntent"
&& handlerInput.requestEnvelope.request.intent.slots.drink.value
&& handlerInput.requestEnvelope.request.intent.slots.drink.value === 'coffee'
&& !handlerInput.requestEnvelope.request.intent.slots.coffeeRoast.value
},
handle(handlerInput) {
return handlerInput.responseBuilder
.speak('ローストはライト、ミディアム、ミディアムダーク、ダークのどれにしますか?')
.reprompt('ローストはライト、ミディアム、ミディアムダーク、ダークのどれがいいですか?')
.addElicitSlotDirective('coffeeRoast')
.getResponse();
}
};
const TeaGivenOrderIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === "IntentRequest"
&& handlerInput.requestEnvelope.request.intent.name === "OrderIntent"
&& handlerInput.requestEnvelope.request.intent.slots.drink.value
&& handlerInput.requestEnvelope.request.intent.slots.drink.value === 'お茶'
&& !handlerInput.requestEnvelope.request.intent.slots.teaType.value
},
handle(handlerInput) {
return handlerInput.responseBuilder
.speak("紅茶、緑茶、ウーロン茶、白茶のどれにしますか?")
.reprompt("紅茶、緑茶、ウーロン茶、白茶のどれがいいですか?")
.addElicitSlotDirective('teaType')
.getResponse();
}
};
const CompletedOrderIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === "IntentRequest"
&& handlerInput.requestEnvelope.request.intent.name === "OrderIntent"
&& handlerInput.requestEnvelope.request.dialogState === "COMPLETED";
},
handle(handlerInput){
const drink = handlerInput.requestEnvelope.request.intent.slots.drink.value;
let type;
if (drink === 'コーヒー') {
type = handlerInput.requestEnvelope.request.intent.slots.coffeeRoast.value;
} else if (drink === 'お茶') {
type = handlerInput.requestEnvelope.request.intent.slots.teaType.value;
} else {
type = '水';
}
const speechText = `${type} ${drink}でよろしいですか?`;
return handlerInput.responseBuilder
.speak(speechText)
.getResponse();
}
};
このサンプルコードはAlexa Skills Kit SDK for Javaを使用しています。
// これらのハンドラーのそれぞれは、Javaクラスです。簡単に説明すると、
// パッケージと各クラスのimport宣言は表示されません。
/**
* *****************************************
* StartedInProgressOrderIntentHandler class
* *****************************************
*/
public class StartedInProgressOrderIntentHandler implements IntentRequestHandler {
@Override
public boolean canHandle(HandlerInput handlerInput, IntentRequest intentRequest) {
return handlerInput.matches(intentName("OrderIntent"))
&& intentRequest.getDialogState() != DialogState.COMPLETED;
}
@Override
public Optional<Response> handle(HandlerInput handlerInput, IntentRequest intentRequest) {
System.out.println("In StartedInProgressOrderIntentHandler");
return handlerInput.getResponseBuilder()
.addDelegateDirective(intentRequest.getIntent())
.build();
}
}
/**
* *****************************************
* CoffeeGivenOrderIntentHandler class
* *****************************************
*/
public class CoffeeGivenOrderIntentHandler implements IntentRequestHandler {
@Override
public boolean canHandle(HandlerInput handlerInput, IntentRequest intentRequest) {
Slot coffeeRoastSlot = intentRequest.getIntent().getSlots().get(COFFEE_ROAST_SLOT_NAME);
return handlerInput.matches(intentName("OrderIntent"))
&& handlerInput.matches(slotValue(DRINK_SLOT_NAME, "コーヒー"))
&& coffeeRoastSlot.getValue() == null;
}
@Override
public Optional<Response> handle(HandlerInput handlerInput, IntentRequest intentRequest) {
System.out.println("In CoffeeGivenOrderIntentHandler");
String speeechtext = "ローストはライト、ミディアム、ミディアムダーク、ダークのどれにしますか?";
String repromptText = "ローストはライト、ミディアム、ミディアムダーク、ダークのどれがいいですか?";
return handlerInput.getResponseBuilder()
.withSpeech(speeechtext)
.withReprompt(repromptText)
.addElicitSlotDirective(COFFEE_ROAST_SLOT_NAME, intentRequest.getIntent())
.build();
}
}
/**
* *****************************************
* TeaGivenOrderIntentHandler class
* *****************************************
*/
public class TeaGivenOrderIntentHandler implements IntentRequestHandler {
@Override
public boolean canHandle(HandlerInput handlerInput, IntentRequest intentRequest) {
Slot teaTypeSlot = intentRequest.getIntent().getSlots().get(TEA_TYPE_SLOT_NAME);
return handlerInput.matches(intentName("OrderIntent"))
&& handlerInput.matches(slotValue(DRINK_SLOT_NAME, "お茶"))
&& teaTypeSlot.getValue() == null;
}
@Override
public Optional<Response> handle(HandlerInput handlerInput, IntentRequest intentRequest) {
System.out.println("In TeaGivenOrderIntentHandler");
String speeechtext = "紅茶、緑茶、ウーロン茶、白茶のどれにしますか?";
String repromptText = "紅茶、緑茶、ウーロン茶、白茶のどれがいいですか?";
return handlerInput.getResponseBuilder()
.withSpeech(speeechtext)
.withReprompt(repromptText)
.addElicitSlotDirective(TEA_TYPE_SLOT_NAME, intentRequest.getIntent())
.build();
}
}
/**
* *****************************************
* CompletedOrderIntentHandler class
* *****************************************
*/
public class CompletedOrderIntentHandler implements IntentRequestHandler {
@Override
public boolean canHandle(HandlerInput handlerInput, IntentRequest intentRequest) {
return handlerInput.matches(intentName("OrderIntent"))
&& intentRequest.getDialogState() == DialogState.COMPLETED;
}
@Override
public Optional<Response> handle(HandlerInput handlerInput, IntentRequest intentRequest) {
System.out.println("In CompletedOrderIntentHandler");
Map<String, Slot> slots = intentRequest.getIntent().getSlots();
String drink = slots.get(DRINK_SLOT_NAME).getValue();
System.out.println("drinkスロットの値:" + drink);
String drinkType = "";
if (drink.equals("コーヒー")){
drinkType = slots.get(COFFEE_ROAST_SLOT_NAME).getValue();
} else if (drink.equals("お茶")){
drinkType = slots.get(TEA_TYPE_SLOT_NAME).getValue();
} else {
drinkType = "水";
}
String speechText = String.format(
"%1$s %2$sでよろしいですか?",
drinkType,drink);
return handlerInput.getResponseBuilder()
.withSpeech(speechText)
.withShouldEndSession(true)
.build();
}
}
スキルとインテントにデリゲートルールを設定する
すべてのスキルには、スキルレベルのオートデリゲート設定があります。このオプションは有効または無効にできます。オートデリゲートは、新しいスキルではデフォルトで有効になっています。
ダイアログモデルのある各インテントには、ダイアログデリゲートのルール設定があります。これは次の3つのオプションのうちいずれかに設定できます:
- オートデリゲートを有効化:スキル全体のデリゲートルールに関係なく、このインテントにオートデリゲートを使用します。
- オートデリゲートを無効化:全体のデリゲートルールに関係なく、このインテントにオートデリゲートを使用しません。
- スキル設定にフォールバック:スキル全体にオートデリゲートを使用します。最初にダイアログモデルをインテントに追加すると、これはそのインテントのデフォルトになります。
インテントのダイアログデリゲートのルール設定は、常にスキルレベルのオートデリゲート設定より優先されます。たとえば、オートデリゲートがスキルで有効になっているが、ダイアログデリゲートのルールが特定のインテントで無効になっている場合は、そのインテントではデリゲートは使用されません。
スキル全体のオートデリゲートオプションを設定する
スキルレベルのオートデリゲートオプションを、使用を予定しているほとんどのインテントに適用する場合は、必要に応じて、インテントレベルでオプションを上書きします。
- 開発者コンソールで、ビルド>カスタム>インターフェースに移動します。
- オートデリゲートオプションを有効または無効にし、インターフェースをクリックします。必ずモデルをビルドをクリックして対話モデルを再ビルドしてください。
ユーザーの対話モデルのJSONのオートデリゲートオプションを設定することもできます。
スキルレベルのオートデリゲート設定は、ダイアログモデルのないインテントでは無視されます。
インテントに使用するスキルのオートデリゲートルールを上書きする
ダイアログデリゲートのルールオプションは、ダイアログモデルのないインテントでは無効になります。
- 左側のナビゲーションでインテントをクリックして、インテントの詳細ページを開きます。
- ダイアログデリゲートのルールで、このインテントに使用するルールを選択します。
インテントのユーザーの対話モデルのJSONのオートデリゲートオプションを設定することもできます。
ダイアログモデル(対話モデルのスキーマ)に含まれるオートデリゲートのJSON
JSONエディターでダイアログモデル内のオートデリゲートオプションのJSON表現を確認し編集することができます。
スキル全体のオートデリゲートオプションは、interactionModel.dialog.delegationStrategy
で定義されます。
インテントのオートデリゲート設定は、interactionModel.dialog.intents[].delegationStrategy
で設定されます。インテントがスキル設定にフォールバックに設定されている場合は、このプロパティは存在しません。
次の例では、スキル全体のオートデリゲート設定は無効になっており、ダイアログモデルを持つ3つのインテントがあります。IntentWithAutoDelegation
インテントはスキルの設定を上書きします。IntentWithoutAutoDelegation
インテントはオートデリゲートを明示的に無効にします。これは、この場合のスキル全体の設定では冗長になります。IntentFallbackToSkillSetting
インテントは、スキル設定にフォールバックするため、delegationStrategy
は存在しません。
つまり、languageModel
とprompts
プロパティは表示されません。対話モデルJSONの詳細については、対話モデルのスキーマを参照してください。
{
"interactionModel": {
"dialog": {
"delegationStrategy": "SKILL_RESPONSE",
"intents": [
{
"name": "IntentWithAutoDelegation",
"delegationStrategy": "ALWAYS",
"confirmationRequired": false,
"prompts": {},
"slots": [
{
"name": "planet",
"type": "Planet",
"confirmationRequired": false,
"elicitationRequired": true,
"prompts": {
"elicitation": "Elicit.Slot.227876833021.1360336347514"
},
"validations": [
{
"type": "isNotInSet",
"prompt": "Slot.Validation.227876833021.1360336347514.650882724620",
"values": [
"おひさま",
"太陽",
"私たちの太陽"
]
},
{
"type": "hasEntityResolutionMatch",
"prompt": "Slot.Validation.227876833021.1360336347514.445874299877"
}
]
}
]
},
{
"name": "IntentWithoutAutoDelegation",
"delegationStrategy": "SKILL_RESPONSE",
"confirmationRequired": false,
"prompts": {},
"slots": [
{
"name": "color",
"type": "AMAZON.Color",
"confirmationRequired": false,
"elicitationRequired": true,
"prompts": {
"elicitation": "Elicit.Slot.199336742512.1106707015044"
}
}
]
},
{
"name": "IntentFallbackToSkillSetting",
"confirmationRequired": false,
"prompts": {},
"slots": [
{
"name": "name",
"type": "AMAZON.US_FIRST_NAME",
"confirmationRequired": false,
"elicitationRequired": true,
"prompts": {
"elicitation": "Elicit.Slot.789417862303.645497121610"
}
}
]
}
]
}
}
}
関連トピック
最終更新日: 2022 年 01 月 31 日