Alexa input validation for type AMAZON.NUMBER using dialog model

安稳与你 提交于 2019-12-06 04:11:25

Always validate slots in your backend, and whenever your number-slot is not returning a numeric value, do not delegate, instead use Dialog.ElicitSlot directive to make Alexa ask for that particular slot.

Ex:

// if number-slot validation fails

return handlerInput.responseBuilder
   .addElicitSlotDirective(slotToElicit)
   .speak("Please provide a number")
   .reprompt("Please provide a number")
   .getResponse();

With Dialog.Delegate directive you cannot send outputSpeech or reprompt from your code. Instead those defined in interaction model will be used. However, at any point, you can take over the dialog rather than continuing to delegate to Alexa.

More on Dialog directives here

I believe I've found a solution -- I'm not sure it's the best solution, but it appears to work.

In the CompletedPlanMyTripHandler, I added the following check to the handle method:

handle(handlerInput) {
    const currentIntent = handlerInput.requestEnvelope.request.intent;

    let slots = currentIntent.slots;
    let badInputSlot;
    for (let x in slots) {
        if (slots.hasOwnProperty(x) && slots[x].hasOwnProperty('value')) {
            if (isNaN(slots[x].value)) {
                badInputSlot = x;
                break;
            }
        }
    }
    if (badInputSlot) {
        return handlerInput.responseBuilder.speak('I do not understand. Please respond with a number.').reprompt('Please respond with a number').addElicitSlotDirective(badInputSlot, currentIntent).getResponse();
    } else {
        return handlerInput.responseBuilder
            .addDelegateDirective(currentIntent)
            .getResponse();
    }
},

What it's doing is in the for loop its checking the the slots on the intent, seeing if each one has a value property (which is only added once a response has been supplied), and then does an isNaN check on it to see if the value is in fact valid. If it is not, we need to ask the user again for that value, so we store the slot's name in badInputSlot and break out of the loop.

Now, we move on to the if statement, and if there is a value assigned to badInputSlot we return an elicit slot directive for the specific slot that had a bad value.

Then, after the user supplies a new value, we repeat the process until every slot in handlerInput.requestEnvelope.request.intent.slots has a value property that passes our isNaN validation check. Once that happens, badInputSlot will be undefined, and our if statement will go to the else block and return a delegate directive to finish off the intent.

I also answered you on the Alexa Slack, however I will post it here again for others to see:

You still have to do error handling in code, this is mentioned multiple times in the docs. You have the following in your code to retrieve the slot values:

const filledSlots = handlerInput.requestEnvelope.request.intent.slots;
const slotValues = getSlotValues(filledSlots);
const startingValue = slotValues.startingValue.synonym;

What you have to do is check in your code for the correct format, e.g.:

if (!startingValue || startingValue === '?') {
    return handlerInput.responseBuilder
        .speak('This is not a number, please try again')
        .reprompt('Please try again.')
        .addElicitSlotDirective('SLOTNAMEGOESHERE')
        .getResponse();
}

This will elicit the slot again, in case userInput is undefined (which means we are still missing that slot in the dialog) or userInput equals the ?. Using above, you can very nicely design a conversation by eliciting slot after slot.

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