1
votes

I have created one skill and code is as below with my test case.

(1) I am facing issue for the Invalid input after 3-4 times input given by user for both intents.

(2) If user call CustomerWiseProductPriceIntent it working fine but if user enter "No" or "go back" it should prompt for the LaunchRequest and start everything again but it prompts for "please, provide customer name or account number".

Currently this is happening:
When the user enters CustomerWiseProductPriceIntent it prompts for Account no. and product name and after that it elicits slot: confirmation (YES/NO/GO BACK)

If the user enters YES:
It is working fine and again asks for account no. and product name.

If user enters NO:
Then it enters inside No and console logs "Inside No ....." but the next line: this.emit('AMAZON.StopIntent'); does not execute. It then again asks for account no. and product name.

If user enters GO BACK: Then it enters inside go back but but the next line: this.emit('LaunchRequest'); does not execute. It then again asks for account no. and product name.

Here is my code :

Lambda function :

'use strict';
const Alexa = require('alexa-sdk');
const APP_ID = undefined;
const SKILL_NAME = 'CustomerSupportVA';
const HELP_MESSAGE = 'You can say Item name to get On hand quantity or stop to exit';
const HELP_REPROMPT = 'What can I help you with?';
const STOP_MESSAGE = 'Thank for using EBS, Goodbye!';
const WELCOME_MESSAGE = "Welcome to EBS Speech Assistance, what do you like to know about <break time=\"1s\"/>  On hand stock , past due or customer wise product price";

const handlers = {
    'LaunchRequest': function() {
        this.response.speak(WELCOME_MESSAGE).listen("Please provide input");
        this.response.shouldEndSession(false);
        this.emit(':responseReady');
    },
    'OnHandQuantityIntent': function() {
        var intentObj = this.event.request.intent;
        var self = this;
        var slotToElicit = "";
        console.log("this.event.request  : "+JSON.stringify(this.event.request))
        var promptForProductName = "please, provide Product name";
        var confirmationStr = "<break time=\"1s\"/> " + " Would you like to know for other product on hand quantity?";
        console.log("Request Object  : "+JSON.stringify( this.event.request));
        if (this.event.request.dialogState == "STARTED") {
            slotToElicit = "productName";
            this.emit(':elicitSlot', slotToElicit, promptForProductName, promptForProductName, intentObj);
        }else if (this.event.request.dialogState == "IN_PROGRESS") {
            console.log("=============>>>>>>>>>>>>0000000  "+intentObj.slots.productName.value)
            if (intentObj.slots.productName.value) {
                var productName = intentObj.slots.productName.value;
                productName = productName.replace(' ', '');
                getOnHandQuatitySrv(productName, function(result) {
                    intentObj.slots.productName.value = undefined;
                    slotToElicit = "confirmation";
                    self.response.shouldEndSession(false);
                    self.emit(':elicitSlot', slotToElicit, result + confirmationStr, confirmationStr, intentObj);
                });

            }else if ("yes" == intentObj.slots.confirmation.value) {
                console.log("Inside Yes .....");
                intentObj = this.event.request.intent;
                slotToElicit = "productName";
                this.emit(':elicitSlot', slotToElicit, promptForProductName, promptForProductName, intentObj);
                intentObj.slots.confirmation.value = undefined;
            }else if ("no" == intentObj.slots.confirmation.value) {
                console.log("Inside No .....");
                this.emit('AMAZON.StopIntent');
            }else if ("go back" == intentObj.slots.confirmation.value) {
                this.emit('LaunchRequest');
            }
        }    
    },
    'CustomerWiseProductPriceIntent': function() {
        var intentObj = this.event.request.intent;
        var self = this;
        var promptForCustomerName = "please, provide customer name or account number";
        var promptForProductName = "please, provide product name";
        var confirmationStr = "<break time=\"1s\"/> " + "Would you like to know for product price for other customer?";
        var slotToElicit = "custAccountNameNo";
        var slotToElicitProd = "productName";

        if (this.event.request.dialogState == "STARTED") {
            console.log("Inside STARTED .....");
            if (!intentObj.slots.custAccountNameNo.value) {
                this.emit(':elicitSlot', slotToElicit, promptForCustomerName, promptForCustomerName, intentObj);
            }
        }else if (this.event.request.dialogState == "IN_PROGRESS") {
            console.log("Inside IN PROGRESS .....");
            if(""==intentObj.slots.custAccountNameNo.value || intentObj.slots.custAccountNameNo.value==undefined){
                this.emit(':elicitSlot', slotToElicit, promptForCustomerName, promptForCustomerName, intentObj);
            }else if (""==intentObj.slots.productName.value || intentObj.slots.productName.value==undefined) {
                this.emit(':elicitSlot', slotToElicitProd, promptForProductName, promptForProductName, intentObj);
            }

             if (intentObj.slots.custAccountNameNo.value!="" && intentObj.slots.productName.value!="") { 
                var custAccountNameNo = intentObj.slots.custAccountNameNo.value;
                var productName = intentObj.slots.productName.value;
                var speechOut="";
                getCustomerWiseProductPriceSrv(custAccountNameNo, productName,      function(itemPrice) {
                    if (itemPrice == undefined) {
                        itemPrice = 0;
                    }
                    else {
                        if (itemPrice == -333) {
                            speechOut = "Please provide valid Product Name";
                            slotToElicit="productName";
                        }
                        else if (itemPrice == -666) {
                            speechOut = "Please provide valid Account Number";
                            slotToElicit="custAccountNameNo";
                        }
                        else {
                            speechOut = "Price of " + productName + " is  " + itemPrice + " for " + custAccountNameNo + " customer  " + confirmationStr;
                            console.log("resultStr  : " + speechOut);
                            slotToElicit = "confirmation";
                            intentObj.slots.productName.value = "";
                            intentObj.slots.custAccountNameNo.value = "";
                        }

                    }
                    slotToElicit = "confirmation";
                    intentObj.slots.productName.value = "";
                    intentObj.slots.custAccountNameNo.value="";
                    self.response.shouldEndSession(false);
                    intentObj = self.event.request.intent;
                    self.emit(':elicitSlot', slotToElicit, speechOut, speechOut, intentObj);
                });

            }else if ("yes" == intentObj.slots.confirmation.value) {
                console.log("Inside Yes .....");
                slotToElicit = "custAccountNameNo";
                slotToElicitProd = "productName";
                intentObj.slots.confirmation.value = "";
                intentObj = this.event.request.intent;
                this.response.shouldEndSession(false);              
            }
            else if ("no" == intentObj.slots.confirmation.value) {
                console.log("Inside No .....");
                this.response.shouldEndSession(false);
                this.emit('AMAZON.StopIntent');
            }
            else if ("go back" == intentObj.slots.confirmation.value) {
                this.emit('LaunchRequest');
            }
        }    
    },
    'AMAZON.HelpIntent': function() {
        const speechOutput = HELP_MESSAGE;
        const reprompt = HELP_REPROMPT;

        this.response.speak(speechOutput).listen(reprompt);
        this.emit(':responseReady');
    },
    'AMAZON.CancelIntent': function() {
        this.response.speak(STOP_MESSAGE);
        this.emit(':responseReady');
    },
    'AMAZON.StopIntent': function() {
        this.response.speak(STOP_MESSAGE);
        this.emit(':responseReady');
    },
    'Unhandled': function() {
        this.response.speak("Invalid Input");
        console.log("this.event.request  :  "+JSON.stringify(this.event.request))
        this.emit(':responseReady');
    },
};

exports.handler = function(event, context, callback) {
    const alexa = Alexa.handler(event, context, callback);
    alexa.APP_ID = APP_ID;
    alexa.registerHandlers(handlers);
    alexa.execute();
};

var getOnHandQuatitySrv = function(productName, callback) {
    var totalOnHandQuanity = Math.floor(Math.random() * Math.floor(999))    
    //web service call 
    var resultStr = "Total " + totalOnHandQuanity + " available for Product    " + productName + "<break time=\"1s\"/> " + resultStr;
    callback(resultStr);
}
var getCustomerWiseProductPriceSrv = function(customerAccountNameNo, ProductName, callback) {
    var custWiseItemPrice = Math.floor(Math.random() * Math.floor(999));
    //web service call 
    callback(custWiseItemPrice);
}

Here is my Model JSON :

{
"interactionModel": {
    "languageModel": {
        "invocationName": "product details",
        "intents": [
            {
                "name": "AMAZON.FallbackIntent",
                "samples": []
            },
            {
                "name": "AMAZON.CancelIntent",
                "samples": []
            },
            {
                "name": "AMAZON.HelpIntent",
                "samples": []
            },
            {
                "name": "AMAZON.StopIntent",
                "samples": []
            },
            {
                "name": "OnHandQuantityIntent",
                "slots": [
                    {
                        "name": "productName",
                        "type": "ProductName",
                        "samples": [
                            "on hand stock for {productName}",
                            "{productName}"
                        ]
                    },
                    {
                        "name": "confirmation",
                        "type": "AMAZON.Genre",
                        "samples": [
                            "go back",
                            "No",
                            "yes"
                        ]
                    }
                ],
                "samples": [
                    "provide me on hand stock ",
                    "on hand quantity  ",
                    "on hand stock "
                ]
            },
            {
                "name": "CustomerWiseProductPriceIntent",
                "slots": [
                    {
                        "name": "custAccountNameNo",
                        "type": "CustomerAccountNameNo",
                        "samples": [
                            "{custAccountNameNo}"
                        ]
                    },
                    {
                        "name": "productName",
                        "type": "ProductName",
                        "samples": [
                            "{productName}"
                        ]
                    },
                    {
                        "name": "confirmation",
                        "type": "AMAZON.Genre",
                        "samples": [
                            "go back",
                            "No",
                            "Yes"
                        ]
                    }
                ],
                "samples": [
                    "customer wise product price "
                ]
            }
        ],
        "types": [
            {
                "name": "ProductName",
                "values": [
                    {
                        "id": "CM080901",
                        "name": {
                            "value": "CM080901",
                            "synonyms": [
                                "CM o eight o nine o one",
                                "CM zero eight zero nine zero one",
                                "CM080901"
                            ]
                        }
                    },
                    {
                        "id": "f30000",
                        "name": {
                            "value": "f30000",
                            "synonyms": [
                                "F three O O O O",
                                "F thirty thousand",
                                "F three zero zero zero zero"
                            ]
                        }
                    },
                    {
                        "id": "AT23808",
                        "name": {
                            "value": "AT23808",
                            "synonyms": [
                                "A T two three eight zero eight",
                                "AT twentythree thousand and eight hundred and eight",
                                "AT two three eight zero eight"
                            ]
                        }
                    }
                ]
            },
            {
                "name": "CustomerAccountNameNo",
                "values": [
                    {
                        "id": "1004",
                        "name": {
                            "value": "1004",
                            "synonyms": [
                                "one o o four",
                                "one zero zero four",
                                "One thousand four"
                            ]
                        }
                    },
                    {
                        "name": {
                            "value": "AT&T Universal Card",
                            "synonyms": [
                                "A T and T Universal Card",
                                "atandt Universal Card",
                                "AT&T Universal Card",
                                "AT and T Universal Card"
                            ]
                        }
                    },
                    {
                        "name": {
                            "value": "hilman and associates",
                            "synonyms": [
                                "hilman and associates",
                                "hilman  associates"
                            ]
                        }
                    },
                    {
                        "name": {
                            "value": "American Telephone & Telegraph - GOLD",
                            "synonyms": [
                                "american telephone and telegraph dash gold",
                                "american telephone and telegraph   gold",
                                "american telephone and telegraph - gold"
                            ]
                        }
                    },
                    {
                        "name": {
                            "value": "A. C. NETWORKS",
                            "synonyms": [
                                "A CNetworks",
                                "ACNETWORKS",
                                "A C Networks"
                            ]
                        }
                    },
                    {
                        "name": {
                            "value": "1001",
                            "synonyms": [
                                "one zero zero one",
                                "one o o one",
                                "one thousand one",
                                "1001"
                            ]
                        }
                    }
                ]
            }
        ]
    },
    "dialog": {
        "intents": [
            {
                "name": "OnHandQuantityIntent",
                "confirmationRequired": false,
                "prompts": {},
                "slots": [
                    {
                        "name": "productName",
                        "type": "ProductName",
                        "confirmationRequired": false,
                        "elicitationRequired": true,
                        "prompts": {
                            "elicitation": "Elicit.Slot.979240528726.539427738586"
                        }
                    },
                    {
                        "name": "confirmation",
                        "type": "AMAZON.Genre",
                        "confirmationRequired": false,
                        "elicitationRequired": true,
                        "prompts": {
                            "elicitation": "Elicit.Slot.979240528726.1367676676111"
                        }
                    }
                ]
            },
            {
                "name": "CustomerWiseProductPriceIntent",
                "confirmationRequired": false,
                "prompts": {},
                "slots": [
                    {
                        "name": "custAccountNameNo",
                        "type": "CustomerAccountNameNo",
                        "confirmationRequired": false,
                        "elicitationRequired": true,
                        "prompts": {
                            "elicitation": "Elicit.Slot.160438293908.60972362882"
                        }
                    },
                    {
                        "name": "productName",
                        "type": "ProductName",
                        "confirmationRequired": false,
                        "elicitationRequired": true,
                        "prompts": {
                            "elicitation": "Elicit.Slot.160438293908.513106626751"
                        }
                    },
                    {
                        "name": "confirmation",
                        "type": "AMAZON.Genre",
                        "confirmationRequired": false,
                        "elicitationRequired": true,
                        "prompts": {
                            "elicitation": "Elicit.Slot.160438293908.1422666600589"
                        }
                    }
                ]
            }
        ]
    },
    "prompts": [
        {
            "id": "Elicit.Slot.979240528726.539427738586",
            "variations": [
                {
                    "type": "PlainText",
                    "value": "Please provide product name"
                }
            ]
        },
        {
            "id": "Elicit.Slot.979240528726.1367676676111",
            "variations": [
                {
                    "type": "PlainText",
                    "value": "would you like to know for other product on hand quantity?"
                }
            ]
        },
        {
            "id": "Elicit.Slot.160438293908.1422666600589",
            "variations": [
                {
                    "type": "PlainText",
                    "value": "DO you like to continue?"
                }
            ]
        },
        {
            "id": "Elicit.Slot.160438293908.60972362882",
            "variations": [
                {
                    "type": "PlainText",
                    "value": "provide customer account name or number"
                }
            ]
        },
        {
            "id": "Elicit.Slot.160438293908.513106626751",
            "variations": [
                {
                    "type": "PlainText",
                    "value": "provide product name"
                }
            ]
        }
    ]
}
} 

Sometimes For both intent if user do multi turn conversation than dialogue states changes to "Started" and gives response "Invalid Input". For CustomerWiseProductPriceIntent if user enter "NO" it must message for stop and if user enter "go back" it prompt message like Launch Request.

1
I've updated your question from your comments to my attempted answer, and removed my answer.Jay A. Little

1 Answers

0
votes

It's because your slots, namely custAccountNameNo, productName and confirmation are compulsory to fulfil the intent. This is a problem because just after you display the result, you empty the first two slot values.

speechOut = "Price of " + productName + " is  " + itemPrice + " for " + custAccountNameNo + " customer  " + confirmationStr;
console.log("resultStr  : " + speechOut);
slotToElicit = "confirmation";
intentObj.slots.productName.value = "";
intentObj.slots.custAccountNameNo.value = "";

And again a few lines later,

slotToElicit = "confirmation";
intentObj.slots.productName.value = "";
intentObj.slots.custAccountNameNo.value="";
self.response.shouldEndSession(false);
intentObj = self.event.request.intent;
self.emit(':elicitSlot', slotToElicit, speechOut, speechOut, intentObj);

What is happening is when you are asking for a confirmation, the slot values for productName and custAccountNameNo are empty, so Alexa needs you to fill these values before it continues with whatever you want.

If you comment the four lines when you are setting the slots to an empty string, Alexa will stop trying to fill the empty slots, and Alexa will not ask for the slot values.

However, since you are using the empty strings as a condition, i.e.

if (intentObj.slots.custAccountNameNo.value!="" && intentObj.slots.productName.value!=""){
}else{...}

you may have problems with failing this if condition to go to the no confirmation code.

A work around I found for this is checking the status of the confirmation slot. If it is undefined or empty, go to the if block, else skip to the yes/no/go-back code.

The problem with the above hack (keep slots non empty while asking for confirmation, and adding an extra condition) makes your skill work for the no and go-back scenarios.

There is a problem with the yes code now, though. You may have to restructure that to maintain the flow.

I recommend an alternate method.

Remove confirmation from your CustomerWiseProductPriceIntent, and make use of the Amazon's built-in YesIntent, NoIntent and PreviousIntent.

After you display the result, ask the user if they want to find the price for another user (like what you are doing now). If you remove the confirmation slot from your intent, the yes/no/go-back responses will trigger the YesIntent/NoIntent/PreviousIntent respectively. In these intents, copy the code you were using inside the else blocks.

For example. if the user says go back, Alexa goes to the PreviousIntent

'AMAZON.PreviousIntent': function(){
     this.emit('LaunchRequest');
 }

If the user says yes, simply use this.emit('CustomerWiseProductPriceIntent').

That way, when you ask for confirmation, Alexa does not require you to fill the compulsory slots over and over. This will also help you get rid of the if-else blocks in the CustomerWiseProductPriceIntent intent.

Since you have two intents which are using the confirmation slot, you may need to keep track of which intent you just came from. One solution is to keep a session attribute.

this.attributes.lastIntent = 'where you just came from'

Add this whenever you are logically asking for a confirmation, i.e. when you are showing your result.

This may require to shuffle your code around a bit, but it's the best solution I can think of.

Sorry for such a long answer! Bonus advice: when you are stopping an intent, like when you are going to StopIntent after no, do not set the shouldEndSession attribute to false. This will create an error when you try to exit. Either don't set it, or make it true.