Alexa Recursive Intent Delegation when using Confirmations

大兔子大兔子 提交于 2020-08-08 05:36:45

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!