0

I have been trying to resolve this issue for the past couple of hours with no success. Here is my code:

Lambda code:

/*eslint-disable  func-names */
/* eslint quote-props: ["error", "consistent"]*/

// There are three sections, Text Strings, Skill Code, and Helper Function(s).
// You can copy and paste the contents as the code for a new Lambda function, using the alexa-skill-kit-sdk-factskill template.
// This code includes helper functions for compatibility with versions of the SDK prior to 1.0.9, which includes the dialog directives.



 // 1. Text strings =====================================================================================================
 //    Modify these strings and messages to change the behavior of your Lambda function


let speechOutput;
let reprompt;
let welcomeOutput = "Welcome to Tanpura! You can ask me to play at any pitch. How can I help you today?";
let welcomeReprompt = "sample re-prompt text";
// 2. Skill Code =======================================================================================================
"use strict";
const Alexa = require('alexa-sdk');
const APP_ID = undefined;  // TODO replace with your app ID (OPTIONAL).
speechOutput = '';
const handlers = {
    'LaunchRequest': function () {
        this.emit(':ask', welcomeOutput, welcomeReprompt);
    },
    'AMAZON.HelpIntent': function () {
        speechOutput = 'You can ask me to play at any pitch, such as C, C sharp, D, D sharp, and so on. How can I help you?';
        reprompt = '';
        this.emit(':ask', speechOutput, reprompt);
    },
   'AMAZON.CancelIntent': function () {
        speechOutput = 'Would you like me to play another pitch?';
        this.emit(':tell', speechOutput);
    },
   'AMAZON.StopIntent': function () {
        speechOutput = 'I hope I helped you. Goodbye!';
        this.emit(':tell', speechOutput);
   },
   'SessionEndedRequest': function () {
        speechOutput = '';
        //this.emit(':saveState',true);//uncomment to save attributes to db on session end
        this.emit(':tell', speechOutput);
   },
    'AMAZON.FallbackIntent': function () {
        speechOutput = '';

        //any intent slot variables are listed here for convenience


        //Your custom intent handling goes here
        speechOutput = "I currently do not support your request. However, you can ask me to play at any pitch, and I will do so. How can I help?";
        this.emit(":ask", speechOutput, speechOutput);
    },
    'AMAZON.NavigateHomeIntent': function () {
        speechOutput = '';

        //any intent slot variables are listed here for convenience


        //Your custom intent handling goes here
        speechOutput = "Welcome to Tanpura! You can ask me to play at any pitch. How can I help you today?";
        this.emit(":ask", speechOutput, speechOutput);
    },
    'PlayNoteIntent': function () {
        speechOutput = '';

        //any intent slot variables are listed here for convenience

        let noteSlot = resolveCanonical(this.event.request.intent.slots.note);
        console.log("User selected pitch: " + noteSlot);

        let accidentalSlot = resolveCanonical(this.event.request.intent.slots.accidental);
        console.log("User selected accidental: " + accidentalSlot);
        var notes = {
            'a': {
                'flat': 'https://s3.amazonaws.com/tanpuranew/tanpura_Gsharp.mp3',
                'natural': 'https://s3.amazonaws.com/tanpuranew/tanpura_A.mp3',
                'sharp': 'https://s3.amazonaws.com/tanpuranew/tanpura_Asharp.mp3'
            },
            'b': {
                'flat': 'https://s3.amazonaws.com/tanpuranew/tanpura_Asharp.mp3',
                'natural': 'https://s3.amazonaws.com/tanpuranew/tanpura_B.mp3',
                'sharp': 'https://s3.amazonaws.com/tanpuranew/tanpura_C.mp3'
            },
            'c': {
                'flat': 'https://s3.amazonaws.com/tanpuranew/tanpura_B.mp3',
                'natural': 'https://s3.amazonaws.com/tanpuranew/tanpura_C.mp3',
                'sharp': 'https://s3.amazonaws.com/tanpuranew/tanpura_Csharp.mp3'
            },
            'd': {
                'flat': 'https://s3.amazonaws.com/tanpuranew/tanpura_Csharp.mp3',
                'natural': 'https://s3.amazonaws.com/tanpuranew/tanpura_D.mp3',
                'sharp': 'https://s3.amazonaws.com/tanpuranew/tanpura_Dsharp.mp3'
            },
            'e': {
                'flat': 'https://s3.amazonaws.com/tanpuranew/tanpura_Dsharp.mp3',
                'natural': 'https://s3.amazonaws.com/tanpuranew/tanpura_E.mp3',
                'sharp': 'https://s3.amazonaws.com/tanpuranew/tanpura_F.mp3'
            },
            'f': {
                'flat': 'https://s3.amazonaws.com/tanpuranew/tanpura_E.mp3',
                'natural': 'https://s3.amazonaws.com/tanpuranew/tanpura_F.mp3',
                'sharp': 'https://s3.amazonaws.com/tanpuranew/tanpura_Fsharp.mp3'
            },
            'g': {
                'flat': 'https://s3.amazonaws.com/tanpuranew/tanpura_Fsharp.mp3',
                'natural': 'https://s3.amazonaws.com/tanpuranew/tanpura_G.mp3',
                'sharp': 'https://s3.amazonaws.com/tanpuranew/tanpura_Gsharp.mp3'
            }

        }
        var note = noteSlot.toLowerCase();
            var speechReprompt = "";
        if (noteSlot && notes[note]){
            var audio = '';
            var accidental = 'natural';

            if(accidentalSlot && accidental.indexOf(accidentalSlot) > -1){
                accidental = accidentalSlot;
            }

            var audioSrc = notes[note][accidental];
            speechOutput = "Ok. I will play " + noteSlot + accidental + <audio src="' + audioSrc + '" />;
            speechReprompt = "Would you like me to continue playing?";

        }

        else{
            speechOutput = "The note you have requested is not supported yet.";
            speechReprompt = "However, Tanpura does support A, B, C, D, E, F, G, and all of the accidentals in between.";
        }

        //Your custom intent handling goes here

        this.emit(":ask", speechOutput, speechOutput);
    },  
    'Unhandled': function () {
        speechOutput = "Tanpura didn't quite understand what you wanted. Please try rephrasing your request.";
        this.emit(':ask', speechOutput, speechOutput);
    }
};

exports.handler = (event, context) => {
    const alexa = Alexa.handler(event, context);
    alexa.appId = APP_ID;
    // To enable string internationalization (i18n) features, set a resources object.
    //alexa.resources = languageStrings;
    alexa.registerHandlers(handlers);
    //alexa.dynamoDBTableName='DYNAMODB_TABLE_NAME';//uncomment this line to save attributes to DB
    alexa.execute();
};

//    END of Intent Handlers {} ========================================================================================
// 3. Helper Function  =================================================================================================

function resolveCanonical(slot){
    //this function looks at the entity resolution part of request and returns the slot value if a synonyms is provided
    let canonical;
    try{
        canonical = slot.resolutions.resolutionsPerAuthority[0].values[0].value.name;
    }catch(err){
        console.log(err.message);
        canonical = slot.value;
    };
    return canonical;
};

function delegateSlotCollection(){
  console.log("in delegateSlotCollection");
  console.log("current dialogState: "+this.event.request.dialogState);
    if (this.event.request.dialogState === "STARTED") {
      console.log("in Beginning");
      let updatedIntent= null;
      // updatedIntent=this.event.request.intent;
      //optionally pre-fill slots: update the intent object with slot values for which
      //you have defaults, then return Dialog.Delegate with this updated intent
      // in the updatedIntent property
      //this.emit(":delegate", updatedIntent); //uncomment this is using ASK SDK 1.0.9 or newer

      //this code is necessary if using ASK SDK versions prior to 1.0.9 
      if(this.isOverridden()) {
            return;
        }
        this.handler.response = buildSpeechletResponse({
            sessionAttributes: this.attributes,
            directives: getDialogDirectives('Dialog.Delegate', updatedIntent, null),
            shouldEndSession: false
        });
        this.emit(':responseReady', updatedIntent);

    } else if (this.event.request.dialogState !== "COMPLETED") {
      console.log("in not completed");
      // return a Dialog.Delegate directive with no updatedIntent property.
      //this.emit(":delegate"); //uncomment this is using ASK SDK 1.0.9 or newer

      //this code necessary is using ASK SDK versions prior to 1.0.9
        if(this.isOverridden()) {
            return;
        }
        this.handler.response = buildSpeechletResponse({
            sessionAttributes: this.attributes,
            directives: getDialogDirectives('Dialog.Delegate', null, null),
            shouldEndSession: false
        });
        this.emit(':responseReady');

    } else {
      console.log("in completed");
      console.log("returning: "+ JSON.stringify(this.event.request.intent));
      // Dialog is now complete and all required slots should be filled,
      // so call your normal intent handler.
      return this.event.request.intent;
    }
}


function randomPhrase(array) {
    // the argument is an array [] of words or phrases
    let i = 0;
    i = Math.floor(Math.random() * array.length);
    return(array[i]);
}
function isSlotValid(request, slotName){
        let slot = request.intent.slots[slotName];
        //console.log("request = "+JSON.stringify(request)); //uncomment if you want to see the request
        let slotValue;

        //if we have a slot, get the text and store it into speechOutput
        if (slot && slot.value) {
            //we have a value in the slot
            slotValue = slot.value.toLowerCase();
            return slotValue;
        } else {
            //we didn't get a value in the slot.
            return false;
        }
}

//These functions are here to allow dialog directives to work with SDK versions prior to 1.0.9
//will be removed once Lambda templates are updated with the latest SDK

function createSpeechObject(optionsParam) {
    if (optionsParam && optionsParam.type === 'SSML') {
        return {
            type: optionsParam.type,
            ssml: optionsParam['speech']
        };
    } else {
        return {
            type: optionsParam.type || 'PlainText',
            text: optionsParam['speech'] || optionsParam
        };
    }
}

function buildSpeechletResponse(options) {
    let alexaResponse = {
        shouldEndSession: options.shouldEndSession
    };

    if (options.output) {
        alexaResponse.outputSpeech = createSpeechObject(options.output);
    }

    if (options.reprompt) {
        alexaResponse.reprompt = {
            outputSpeech: createSpeechObject(options.reprompt)
        };
    }

    if (options.directives) {
        alexaResponse.directives = options.directives;
    }

    if (options.cardTitle && options.cardContent) {
        alexaResponse.card = {
            type: 'Simple',
            title: options.cardTitle,
            content: options.cardContent
        };

        if(options.cardImage && (options.cardImage.smallImageUrl || options.cardImage.largeImageUrl)) {
            alexaResponse.card.type = 'Standard';
            alexaResponse.card['image'] = {};

            delete alexaResponse.card.content;
            alexaResponse.card.text = options.cardContent;

            if(options.cardImage.smallImageUrl) {
                alexaResponse.card.image['smallImageUrl'] = options.cardImage.smallImageUrl;
            }

            if(options.cardImage.largeImageUrl) {
                alexaResponse.card.image['largeImageUrl'] = options.cardImage.largeImageUrl;
            }
        }
    } else if (options.cardType === 'LinkAccount') {
        alexaResponse.card = {
            type: 'LinkAccount'
        };
    } else if (options.cardType === 'AskForPermissionsConsent') {
        alexaResponse.card = {
            type: 'AskForPermissionsConsent',
            permissions: options.permissions
        };
    }

    let returnResult = {
        version: '1.0',
        response: alexaResponse
    };

    if (options.sessionAttributes) {
        returnResult.sessionAttributes = options.sessionAttributes;
    }
    return returnResult;
}

function getDialogDirectives(dialogType, updatedIntent, slotName) {
    let directive = {
        type: dialogType
    };

    if (dialogType === 'Dialog.ElicitSlot') {
        directive.slotToElicit = slotName;
    } else if (dialogType === 'Dialog.ConfirmSlot') {
        directive.slotToConfirm = slotName;
    }

    if (updatedIntent) {
        directive.updatedIntent = updatedIntent;
    }
    return [directive];
}

Alexa Developer JSON Input:

{
    "version": "1.0",
    "session": {
        "new": true,
        "sessionId": "amzn1.echo-api.session.1456bfda-a9d3-457f-88a7-bc5387d774db",
        "application": {
            "applicationId": "amzn1.ask.skill.0c237132-8815-4025-a23f-ca6df688bcd2"
        },
        "user": {
            "userId": "amzn1.ask.account.AGD7V7GZTLU4DQH623OMU5MUBR2FGWXKDVW2OPNYYRWKIYJCHQBCSKVNQHEPOEXQWO33Q4OTJ6LSIRLYT3TN33OAK3W7LLNNYPU5S3MVKPMPNH2XDWYJ7DBWCFZRXY4STCPFKVL2FADYZE4TXS53Z5AXBPN6344R6VG6GD365TFQTCPPKABC5IKM46UZXUX3BPR4TQ4KEYO6LTA"
        }
    },
    "context": {
        "System": {
            "application": {
                "applicationId": "amzn1.ask.skill.0c237132-8815-4025-a23f-ca6df688bcd2"
            },
            "user": {
                "userId": "amzn1.ask.account.AGD7V7GZTLU4DQH623OMU5MUBR2FGWXKDVW2OPNYYRWKIYJCHQBCSKVNQHEPOEXQWO33Q4OTJ6LSIRLYT3TN33OAK3W7LLNNYPU5S3MVKPMPNH2XDWYJ7DBWCFZRXY4STCPFKVL2FADYZE4TXS53Z5AXBPN6344R6VG6GD365TFQTCPPKABC5IKM46UZXUX3BPR4TQ4KEYO6LTA"
            },
            "device": {
                "deviceId": "amzn1.ask.device.AFHBRIBVUWYIR2ESXPKWP3G3PHYK4W5VW4NF55KH5ZXD27WMSPBPU7YLJQJWM2YQDZBH7VWGXCLNQKESUNWWGI6CJUWUUSWUKVBZWZC5LBNXMCDY2IOZAZUYWHYXT5VLLA7XC3OP2WY7RXE2LPRHM5E4BIMR662M5MZKJH4WRPUFS3HVIFRDK",
                "supportedInterfaces": {}
            },
            "apiEndpoint": "https://api.amazonalexa.com",
            "apiAccessToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IjEifQ.eyJhdWQiOiJodHRwczovL2FwaS5hbWF6b25hbGV4YS5jb20iLCJpc3MiOiJBbGV4YVNraWxsS2l0Iiwic3ViIjoiYW16bjEuYXNrLnNraWxsLjBjMjM3MTMyLTg4MTUtNDAyNS1hMjNmLWNhNmRmNjg4YmNkMiIsImV4cCI6MTUzOTU1MzE2NywiaWF0IjoxNTM5NTQ5NTY3LCJuYmYiOjE1Mzk1NDk1NjcsInByaXZhdGVDbGFpbXMiOnsiY29uc2VudFRva2VuIjpudWxsLCJkZXZpY2VJZCI6ImFtem4xLmFzay5kZXZpY2UuQUZIQlJJQlZVV1lJUjJFU1hQS1dQM0czUEhZSzRXNVZXNE5GNTVLSDVaWEQyN1dNU1BCUFU3WUxKUUpXTTJZUURaQkg3VldHWENMTlFLRVNVTldXR0k2Q0pVV1VVU1dVS1ZCWldaQzVMQk5YTUNEWTJJT1pBWlVZV0hZWFQ1VkxMQTdYQzNPUDJXWTdSWEUyTFBSSE01RTRCSU1SNjYyTTVNWktKSDRXUlBVRlMzSFZJRlJESyIsInVzZXJJZCI6ImFtem4xLmFzay5hY2NvdW50LkFHRDdWN0daVExVNERRSDYyM09NVTVNVUJSMkZHV1hLRFZXMk9QTllZUldLSVlKQ0hRQkNTS1ZOUUhFUE9FWFFXTzMzUTRPVEo2TFNJUkxZVDNUTjMzT0FLM1c3TExOTllQVTVTM01WS1BNUE5IMlhEV1lKN0RCV0NGWlJYWTRTVENQRktWTDJGQURZWkU0VFhTNTNaNUFYQlBONjM0NFI2Vkc2R0QzNjVURlFUQ1BQS0FCQzVJS000NlVaWFVYM0JQUjRUUTRLRVlPNkxUQSJ9fQ.KAHvIOOUP4k-73lNMxRnOToYjrUbeHuLRDQGzMFi9dVEiwc2QpvpMZpLNpG5rCtoqB2-OfC48KbK5u67nW6X9QO6DSoNTBfPKUatIHB6pUWbArdv-FliUO69SQMomjLtLzC86_jnZ8TqvNavjb5I5hOGnmCe5Fv2IY5HgBw0h07Dq3ZT4i_4edcnhX9zYJretTEydF0L3JA7GTithgtAGFxbBqbiDTKRMlaGUGBWAkZkHy8FPWsAmvfTwRaNL7F3LAEbGH2QJlyoPQR7jYij7CsnlRAEv-3Ur1kFaMEdhDNA9fcn2JI4TVf1umy0fL66dHWq3omk2p5I4FyrJ3a8SQ"
        }
    },
    "request": {
        "type": "IntentRequest",
        "requestId": "amzn1.echo-api.request.80cc2899-2fa2-4828-99ba-1c25d8cce05b",
        "timestamp": "2018-10-14T20:39:27Z",
        "locale": "en-US",
        "intent": {
            "name": "PlayNoteIntent",
            "confirmationStatus": "NONE",
            "slots": {
                "note": {
                    "name": "note",
                    "value": "an",
                    "resolutions": {
                        "resolutionsPerAuthority": [
                            {
                                "authority": "amzn1.er-authority.echo-sdk.amzn1.ask.skill.0c237132-8815-4025-a23f-ca6df688bcd2.Note",
                                "status": {
                                    "code": "ER_SUCCESS_NO_MATCH"
                                }
                            }
                        ]
                    },
                    "confirmationStatus": "NONE",
                    "source": "USER"
                },
                "accidental": {
                    "name": "accidental",
                    "value": "e",
                    "resolutions": {
                        "resolutionsPerAuthority": [
                            {
                                "authority": "amzn1.er-authority.echo-sdk.amzn1.ask.skill.0c237132-8815-4025-a23f-ca6df688bcd2.accidental",
                                "status": {
                                    "code": "ER_SUCCESS_NO_MATCH"
                                }
                            }
                        ]
                    },
                    "confirmationStatus": "NONE",
                    "source": "USER"
                }
            }
        }
    }
}

And finally the Skill's JSON:

{
    "interactionModel": {
        "languageModel": {
            "invocationName": "tanpura",
            "intents": [
                {
                    "name": "AMAZON.FallbackIntent",
                    "samples": []
                },
                {
                    "name": "AMAZON.CancelIntent",
                    "samples": []
                },
                {
                    "name": "AMAZON.HelpIntent",
                    "samples": []
                },
                {
                    "name": "AMAZON.StopIntent",
                    "samples": []
                },
                {
                    "name": "AMAZON.NavigateHomeIntent",
                    "samples": []
                },
                {
                    "name": "PlayNoteIntent",
                    "slots": [
                        {
                            "name": "note",
                            "type": "Note"
                        },
                        {
                            "name": "accidental",
                            "type": "accidental"
                        }
                    ],
                    "samples": [
                        "for an {note} {accidental}",
                        "for a {note} {accidental}",
                        "play {note} {accidental}",
                        "Start an {note} {accidental}",
                        "Give me an {note} {accidental}",
                        "Make an {note} {accidental}",
                        "Put on an {note} {accidental}",
                        "Sing at an {note} {accidental}",
                        "Sing at a {note} {accidental}",
                        "Create an {note} {accidental}",
                        "Lets hear an {note} {accidental}",
                        "Play an {note} {accidental}",
                        "Lets hear a {note} {accidental}",
                        "Sing at {note} {accidental}",
                        "Create a {note} {accidental}",
                        "Make a {note} {accidental}",
                        "Put on a {note} {accidental}",
                        "Initiate a {note} {accidental}",
                        "Give me a {note} {accidental}",
                        "Start a {note} {accidental}",
                        "Play a {note} {accidental}"
                    ]
                }
            ],
            "types": [
                {
                    "name": "Note",
                    "values": [
                        {
                            "name": {
                                "value": "B"
                            }
                        },
                        {
                            "name": {
                                "value": "A#"
                            }
                        },
                        {
                            "name": {
                                "value": "A"
                            }
                        },
                        {
                            "name": {
                                "value": "G#"
                            }
                        },
                        {
                            "name": {
                                "value": "G"
                            }
                        },
                        {
                            "name": {
                                "value": "F"
                            }
                        },
                        {
                            "name": {
                                "value": "E"
                            }
                        },
                        {
                            "name": {
                                "value": "D#"
                            }
                        },
                        {
                            "name": {
                                "value": "D"
                            }
                        },
                        {
                            "name": {
                                "value": "C#"
                            }
                        },
                        {
                            "name": {
                                "value": "C"
                            }
                        }
                    ]
                },
                {
                    "name": "accidental",
                    "values": [
                        {
                            "name": {
                                "value": "natural"
                            }
                        },
                        {
                            "name": {
                                "value": "flat"
                            }
                        },
                        {
                            "name": {
                                "value": "sharp"
                            }
                        }
                    ]
                }
            ]
        }
    }
}

The code was working initially, but after I made a couple of edits to the Lambda code, I was getting the same reply again and again, which made no sense. I think that the problem may lie in the fact that I added an extra value for the accidental value, and I added a natural value before rebuilding my Lambda code in the skillinator.io site. Any help would be much appreciated as I have been struggling with this code all day.

JJJ
  • 32,902
  • 20
  • 89
  • 102

1 Answers1

0

"There was a problem with the requested skill's response” means that there is something wrong with the response json. It might be null or invalid.

In your case, this line throws an error because your string concatenation is not right.

speechOutput = "Ok. I will play " + noteSlot + accidental + <audio src="' + audioSrc + '" />;

Change it to :

speechOutput = "Ok. I will play " + noteSlot + accidental + "<audio src=\"" + audioSrc + "\" />";
johndoe
  • 4,387
  • 2
  • 25
  • 40