Alexa使用对话框模型输入AMAZON.NUMBER类型的输入验证

时间:2018-08-23 18:44:22

标签: node.js alexa alexa-skills-kit

我正在使用ASK SDK 2.0 forNode.js。 我的技能是使用对话框模型提示用户输入一系列输入,所有这些都是AMAZON.NUMBER类型的必需插槽。当用户给出数值响应时,一切正常。但是,如果用户给出了非数字的响应,例如“黄色”,则插槽值将填充为:

"value": "?"

,然后继续提示用户输入下一个广告位。如果他们提供了无效的响应,我如何才能再次提示用户该插槽?我已经翻阅了文档,找不到任何东西。理想情况下,我希望该技能可以提示用户,直到给出有效输入为止(即值不是"?"

(奇怪的是,如果我将类型设置为AMAZON.DATE,它将自动再次提示一次,然后如果第二次提供了无效的类型,则该技能将退出。)

我的回答如下:

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

在此示例中,startingValue得到了数值响应,而其他两个变量(growthValuechurnValue)得到了非数字响应。

我可以在intent处理程序中的哪个位置检查该值并在出现故障的特定插槽上重新提示?我使用的是Dialog.Directive,除非我误解了文档,否则文档说不要将reprompt与(https://developer.amazon.com/docs/custom-skills/dialog-interface-reference.html#details)一起使用。

我的处理程序如下:

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

我以“计划我的旅行”示例作为起点,因此我的绝大多数代码都将与之相同:https://github.com/alexa/alexa-cookbook/tree/master/feature-demos/skill-demo-plan-my-trip

我缺少/不了解什么?谢谢

3 个答案:

答案 0 :(得分:2)

始终验证后端中的插槽,并且每当您的数字插槽不返回数字值时,就不要委托,而是使用Dialog.ElicitSlot指令让Alexa询问该特定插槽。

例如:

// if number-slot validation fails

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

使用Dialog.Delegate指令,您无法从代码中发送outputSpeechreprompt。而是将使用在交互模型中定义的那些。但是,在任何时候,您都可以接管对话框,而不必继续委托给Alexa。

有关对话框指令here

的更多信息

答案 1 :(得分:1)

我相信我已经找到了解决方案-我不确定这是否是最好的解决方案,但是它似乎有效。

CompletedPlanMyTripHandler中,我向handle方法添加了以下检查:

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

它的作用是在for循环中检查意图上的插槽,查看每个插槽是否具有value属性(仅在提供响应后才添加),然后执行{ {1}}检查该值是否实际上有效。如果不是,那么我们需要再次询问用户该值,因此我们将插槽的名称存储在isNaN中并退出循环。

现在,我们继续执行if语句,如果有一个赋值给badInputSlot的值,我们将为具有错误值的特定插槽返回一个引发的插槽指令。

然后,在用户提供新值之后,我们重复该过程,直到badInputSlot中的每个插槽都具有handlerInput.requestEnvelope.request.intent.slots属性,该属性通过我们的value验证检查。一旦发生这种情况,isNaN将是未定义的,并且我们的if语句将进入badInputSlot块并返回委托指令以结束意图。

答案 2 :(得分:1)

我也在Alexa Slack上回答了您,但是我将其再次发布在这里,供其他人查看:

您仍然必须在代码中进行错误处理,这在文档中多次提到。您的代码中包含以下内容以检索广告位值:

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

您需要做的是检查代码中的正确格式,例如:

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

如果userInputundefined(这意味着我们在对话框中仍缺少该插槽)或userInput等于?,这将再次引发该插槽。使用上面的方法,您可以通过在插槽之间引出一个插槽来很好地设计对话。