Рекурсивное делегирование намерений Alexa при использовании подтверждений - PullRequest
2 голосов
/ 12 июля 2020

Я пишу диалог Alexa с подтверждением намерений. Когда в подтверждении отказано, я хочу снова перезапустить тот же диалог, делегировав его именно этому диалогу. Я действую так, как описано в этот вопрос о переполнении стека. Как описано в решении этого вопроса, я делаю делегирование, когда dialogState по-прежнему IN_PROGRESS. В моем случае Alexa всегда отвечает не очень значимым сообщением Возникла проблема с ответом запрошенного навыка . В журнале приложения нет сообщения об ошибке.

Моя модель навыков и лямбда-код следующие:

{
  "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();
  }
};

Что мне не хватает?

Ответы [ 3 ]

1 голос
/ 15 июля 2020

Проблема, с которой вы сейчас столкнулись, реальна. Эта проблема также упоминается в amazon forum . Однако вы можете добиться аналогичного поведения с небольшими изменениями. Активировать подтверждение значения слота для UserName и удалить подтверждение для UserIntent. Ваша модель взаимодействия будет похожа на следующую:

{
"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 ?"
                }
            ]
        }
    ]
  }
}

вы можете добавить этот единственный обработчик кода:

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();
    }
  }  
};
1 голос
/ 14 июля 2020

Вы не указали, сработает ваш DeniedUserIntentHandler или нет. если ошибка генерируется внутри DeniedUserIntentHandler, то это связано с неправильным форматом Delegate Directive.

ваш ответ должен быть таким:

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();

Причина, по которой вы удаляете предыдущее состояние намерения, потому что вы хотите, чтобы действие вашего намерения начиналось с самого начала.

Вы также можете использовать свой код следующим образом: ссылка 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};
0 голосов
/ 15 июля 2020

Благодаря ответу @tahiat я смог решить свою первоначальную проблему. В обновленном намерении объект slots должен содержать слоты намерения (без значения). Но его первый фрагмент кода содержит ошибку. Эфир использует

.addDirective({
  "type": "Dialog.Delegate", 
  "updatedIntent": { 
     name:"UserIntent", 
     ...
  }
})

или

.addDelegateDirective({
  name:"UserIntent", 
  ...
})

, поскольку addDelegateDirective ожидает намерение в качестве параметра.

Но теперь я столкнулся с другой проблемой. Я использую подтверждение в своем диалоге. Когда я go возвращаюсь в исходное состояние UserIntent после отказа в подтверждении, я никогда не получаю сообщение с запросом подтверждения. Это потому, что request.intent.confirmationStatus сохраняет свое значение, которое составляет 'DENIED', хотя я сбросил его в updateIntent на 'NONE'.

...