问题
I am writing an Alexa dialog with intent confirmation. When confirmation is denied I want to restart the same dialog again by delegating to this very dialog. I am proceeding like described in this stack overflow question. As described in the solution to this question I do the delegation when the dialogState
is still IN_PROGRESS
. In my case Alexa always responds with the not very meaningful message There was a problem with the requested skill's response. No error message in the application log.
My skill model and the lambda code are as follows:
{
"interactionModel": {
"languageModel": {
"invocationName": "hello",
"intents": [
{
"name": "UserIntent",
"slots": [
{
"name": "UserName",
"type": "AMAZON.FirstName",
"samples": [
"My name is {UserName}",
"I am {UserName}",
"{UserName}"
]
}
],
"samples": [
"My name is {UserName}",
"I am {UserName}"
]
}
],
"types": []
},
"dialog": {
"delegationStrategy": "SKILL_RESPONSE",
"intents": [
{
"name": "UserIntent",
"confirmationRequired": true,
"prompts": {
"confirmation": "Confirm.Intent.UserName"
},
"slots": [
{
"name": "UserName",
"type": "AMAZON.FirstName",
"confirmationRequired": false,
"elicitationRequired": true,
"prompts": {
"elicitation": "Elicit.Slot.UserName"
}
}
]
}
]
},
"prompts": [
{
"id": "Elicit.Slot.UserName",
"variations": [
{
"type": "PlainText",
"value": "What is your name?"
}
]
},
{
"id": "Confirm.Intent.UserName",
"variations": [
{
"type": "PlainText",
"value": "You are {UserName}. Is this right?"
}
]
}
]
}
}
const DeniedUserIntentHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest' &&
request.intent.name === 'UserIntent' &&
request.dialogState === 'IN_PROGRESS' &&
request.intent.confirmationStatus === 'DENIED';
},
async handle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
const currentIntent = request.intent;
const userName = Alexa.getSlotValue(handlerInput.requestEnvelope, 'UserName');
console.log(`DeniedUserIntentHandler:
request.dialogState=${request.dialogState}, request.intent.confirmationStatus=${request.intent.confirmationStatus}, userName=${userName}`);
return handlerInput.responseBuilder
.speak('Username was not confirmed. Please try again.')
.addDelegateDirective({
name: 'UserIntent',
confirmationStatus: 'NONE',
slots: {}
})
.getResponse();
}
};
What I am missing?
回答1:
You did not specified whether you DeniedUserIntentHandler
get triggered or not. if the error is generated inside DeniedUserIntentHandler
then it is due to the wrong format of Delegate Directive
.
your return response should be like :
return handlerInput.responseBuilder
.speak('Username was not confirmed. Please try again.')
.addDelegateDirective({
"type": "Dialog.Delegate",
"updatedIntent": {
name:"UserIntent",
confirmationStatus:"NONE",
slots: {
UserName: {
name:"UserName",
confirmationStatus:"NONE",
source:"USER"
}
}
}
})
.getResponse();
The reason you are deleting the intent's previous state because you want your intent action to start from beginning.
You can also use your code like this: reference https://forums.developer.amazon.com/questions/92334/answering-no-to-intent-confirmation.html?childToView=206243#comment-206243
currentIntent.confirmationStatus = "NONE";
Object.keys(currentIntent.slots).forEach(
(slotName) => {
var slot = intent.slots[slotName];
delete slot.value;
slot.confirmationStatus = "NONE";
}
);
var delegatedirective = {"type": "Dialog.Delegate",
"updatedIntent": currentIntent};
回答2:
The problem you are facing now is real one. This issue is also mentioned in amazon forum.
However you can achieve similar behavior with slight modification. Activate slot value confirmation for UserName
and remove confirmation for UserIntent
.
Your interaction model would be similar like below:
{
"interactionModel": {
"languageModel": {
"invocationName": "demo app",
"intents": [
{
"name": "UserIntent",
"slots": [
{
"name": "UserName",
"type": "AMAZON.FirstName",
"samples": [
"My name is {UserName}",
"I am {UserName}",
"{UserName}"
]
}
],
"samples": [
"My name is {UserName}",
"I am {UserName}"
]
},
{
"name": "AMAZON.NavigateHomeIntent",
"samples": []
}
],
"types": []
},
"dialog": {
"intents": [
{
"name": "UserIntent",
"delegationStrategy": "SKILL_RESPONSE",
"confirmationRequired": false,
"prompts": {},
"slots": [
{
"name": "UserName",
"type": "AMAZON.FirstName",
"confirmationRequired": true,
"elicitationRequired": true,
"prompts": {
"confirmation": "Confirm.Slot.247378890994.1277345498514",
"elicitation": "Elicit.Slot.UserName"
}
}
]
}
],
"delegationStrategy": "ALWAYS"
},
"prompts": [
{
"id": "Elicit.Slot.UserName",
"variations": [
{
"type": "PlainText",
"value": "What is your name?"
}
]
},
{
"id": "Confirm.Slot.247378890994.1277345498514",
"variations": [
{
"type": "PlainText",
"value": "your name is {UserName} , right ?"
}
]
}
]
}
}
you can add this single code handler:
const UserIntenStartedHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest' &&
request.intent.name === 'UserIntent';
},
async handle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
const currentIntent = Alexa.getIntentName(handlerInput.requestEnvelope);
const slot = Alexa.getSlot(handlerInput.requestEnvelope, 'UserName');
if (slot.confirmationStatus !== 'CONFIRMED') {
return handlerInput.responseBuilder
.addDelegateDirective(request.intent)
.getResponse();
} else {
return handlerInput.responseBuilder
.speak('your Final name is ' + slot.value + '. cheers')
.withShouldEndSession(true)
.getResponse();
}
}
};
回答3:
Thanks to the reply of @tahiat I was able to figure out my original problem. In the updated intent the slots object must contain the intent's slots (without a value). But his first code snippet contains an error. Ether use
.addDirective({
"type": "Dialog.Delegate",
"updatedIntent": {
name:"UserIntent",
...
}
})
or use
.addDelegateDirective({
name:"UserIntent",
...
})
since addDelegateDirective
expects an intent as a parameter.
But now I am facing another problem. I use confirmation in my dialog. When I go back to the initial state of UserIntent
after confirmation was denied I never get prompted with the confirmation message. This is because request.intent.confirmationStatus
keeps its value, which is 'DENIED'
, although I have reset it in updateIntent
to 'NONE'
.
来源:https://stackoverflow.com/questions/62855239/alexa-recursive-intent-delegation-when-using-confirmations