0
votes

I am working on a simple skill to retrieve ifsc code for a bank from bank name and branch. I have implemented multiturn dialogs meaning that there is a conversation involved before the slots are getting filled. I have two slots in the interaction model. They are BANK and BRANCH. Both the slots required. I have provided 200 utterances for BANK slot.

The skill first prompts the user for bank name. If the user provides invalid bank name, lets say for example "I don't know". It identifies that its not a valid bank name and prompts the user back again for bank name. But in this process it fills the BRANCH slot with "I don't know". I want to maintain the order in which slots are filled. The BRANCH slot should not be filled unless and until BANK slot is filled. I want to make sure that BRANCH is a valid street address(which is the slotType for BRANCH). How do I enforce the order in filling the slot values ? Please find the lambda code below:

const InProgressIfscCodeIntentHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'IntentRequest' &&
            handlerInput.requestEnvelope.request.intent.name === 'ifscCode' &&
            handlerInput.requestEnvelope.request.dialogState !== 'COMPLETED'
    },
    handle(handlerInput) {
        const currentIntent = handlerInput.requestEnvelope.request.intent;
        return handlerInput.responseBuilder
            .addDelegateDirective(currentIntent)
            .getResponse();
    }
};

const CompletedIfscCodeIntentHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'IntentRequest' &&
            handlerInput.requestEnvelope.request.intent.name === 'ifscCode'
    },
    async handle(handlerInput) {

        if (!handlerInput.requestEnvelope.request.intent.slots.BANK.value) {
            return handlerInput.responseBuilder
                .speak("Let me know which IFSC code for which bank are you looking for ?")
                .reprompt("Let me know which IFSC code for which bank are you looking for ?")
                .addElicitSlotDirective('BANK')
                .getResponse();
        } else {

            const bankName = handlerInput.requestEnvelope.request.intent.slots.BANK.value;
            const branch = handlerInput.requestEnvelope.request.intent.slots.BRANCH.value;

            // retrieve the bank details by calling the API
            const bankDetails = await getBankDetails(bankName, branch);

            console.log('--- length of the bank ---', bankDetails.banks.length);
            if (bankDetails.banks.length > 0) {
                console.log('-- bank details --', bankDetails);
                const speechText = `IFSC code of the ${bankName}, ${branch} is
                <break time="2s"/>
                <emphasis level="strong"><say-as interpret-as='spell-out'>${bankDetails.banks[0].IFSC}</say-as></emphasis>.
                <break time="2s"/>Try again for different bank by invoking open ifsc code finder.`;

                return handlerInput.responseBuilder
                    .speak(speechText)
                    .reprompt(speechText)
                    .withShouldEndSession(true)
                    .getResponse();
            } else {
                const speechText = "We were not able to get the bank details. Please try again by invoking open ifsc code finder.";
                return handlerInput.responseBuilder
                    .speak(speechText)
                    .reprompt(speechText)
                    .withShouldEndSession(true)
                    .getResponse();
            }

        }
    }
};

Also, the string "I don't know" is not a valid street address. Training the model for 1 million addresses is not feasible option as of now. My problem is that invalid value for BANK slot should not be used as branch. I want to add validation here. Please help me understanding things here.

Thanks

1

1 Answers

0
votes

With Dialog.Delegate directive you give the control to Alexa and you don't have any control on which slot will Alexa ask for. Also you cannot send outputSpeech or reprompt from your code as response. Instead those defined in interaction model will be used.

So in your InProgressIfscCodeIntentHandler, instead of delegating the control to Alexa you can actually elicit a slot that you want. If you want BANK slot to be filled first, then elicit BANK slot first and validate it. And if it's a proper bank name, then ask for BRANCH and then validate it.

If any of the validation fails, like if the user says "I don't know". Then elicit that particular slot again with a proper error message.

const InProgressIfscCodeIntentHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'IntentRequest' &&
            handlerInput.requestEnvelope.request.intent.name === 'ifscCode' &&
            handlerInput.requestEnvelope.request.dialogState !== 'COMPLETED'
    },
    handle(handlerInput) {
        const currentIntent = handlerInput.requestEnvelope.request.intent;

        // write a function to validate BANK name
        if (isBankNameValid(handlerInput)) {
            return handlerInput.responseBuilder
                .speak("Let me know which IFSC code for which bank are you looking for ?")
                .reprompt("Let me know which IFSC code for which bank are you looking for ?")
                .addElicitSlotDirective('BANK')
                .getResponse();
        }
        // write a function to validate BRANCH name
        if (isBranchNameValid(handlerInput)) {
            return handlerInput.responseBuilder
                .speak("Let me know the branch ?")
                .reprompt("Let me know the branch ?")
                .addElicitSlotDirective('BRANCH')
                .getResponse();

        }

        //Do your stuff

        return handlerInput.responseBuilder
            .speak("Your speech here")
            .reprompt("Your reprompt here")
            .getResponse();
    }

};