Alexa input validation for type AMAZON.NUMBER using dialog model

試著忘記壹切 提交于 2019-12-22 10:37:47

问题


I am using the ASK SDK 2.0 for Node.js. I have a skill that uses a dialog model to prompt the user for a series of inputs, all of which are required slots with the type AMAZON.NUMBER. When a user gives a numerical response, everything works fine. However, if the user gives a non-numeric response, such as "yellow", the slot value is filled in with:

"value": "?"

and moves on to propmpt the user for the input for the next slot. How can I get it to reprompt the user for that slot again if they provide an invalid response? I've poured over the documentation and can't find anything. Ideally I would want the skill to reprompt the user until a valid input is given (i.e., the value isn't "?")

(Strangely, if i set the type to AMAZON.DATE, it will automatically reprompt once, and then if an invalid type is provided a second time the skill will just quit out.)

My response looks like this:

"response": {
    "directives": [{
        "type": "Dialog.Delegate",
        "updatedIntent": {
            "name": "MRRIntent",
            "confirmationStatus": "NONE",
            "slots": {
                "growthValue": {
                    "name": "growthValue",
                    "value": "?",
                    "confirmationStatus": "NONE"
                },
                "churnValue": {
                    "name": "churnValue",
                    "value": "?",
                    "confirmationStatus": "NONE"
                },
                "startingValue": {
                    "name": "startingValue",
                    "value": "10",
                    "confirmationStatus": "NONE"
                }
            }
        }
    }]
}

Where in this example startingValue was given a numerical response, but the other two (growthValue and churnValue) were given non-number responses.

Where in the intent handler would I be able to check for this value and reprompt on the particular slots that are failing? I am using the Dialog.Directive which the docs say not to use reprompt with ( https://developer.amazon.com/docs/custom-skills/dialog-interface-reference.html#details ), unless I am misunderstanding it.

My handlers look like this:

const InProgressPlanMyTripHandler = {
    canHandle(handlerInput) {
        const request = handlerInput.requestEnvelope.request;
        return request.type === 'IntentRequest' &&
            request.intent.name === 'MRRIntent' &&
            request.dialogState !== 'COMPLETED';
    },
    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 === 'MRRIntent';
    },
    handle(handlerInput) {

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

        let speechOutput = `Your values are: startingValue: ${slotValues.startingValue.synonym} growthValue: ${slotValues.growthValue.synonym}, and churnValue: ${slotValues.churnValue.synonym}`

        return responseBuilder
            .speak(speechOutput)
            .getResponse();
    },
};

I used the Plan My Trip example as my starting point, so the vast majority of my code is going to be identical to it: https://github.com/alexa/alexa-cookbook/tree/master/feature-demos/skill-demo-plan-my-trip

What am I missing / not understanding? Thanks


回答1:


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




回答2:


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.




回答3:


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.



来源:https://stackoverflow.com/questions/51992393/alexa-input-validation-for-type-amazon-number-using-dialog-model

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