I am trying to create a skill in Alexa dev console which will respond to a command by returning information found from API queries. My other commands work, such as “help”, status of elevator xxx, etc. Just this one command doesn’t return correct results.
The expected outcome:
Me: what is going on
.
Alexa: Greetings. There are currently XXX elevators deployed in the XXX buildings of your XXX customers Currently, XXX elevators are not in Running Status and are being serviced XXX Batteries are deployed across XXX cities On another note you currently have XXX quotes awaiting processing You also have XXX leads in your contact requests
.
Actual result:
Me: what is going on
.
Alexa:Sorry, I can't understand the command. Please say again.
JSON Input 1 from the command:
{ "version": "1.0", "session": { "new": false, "sessionId": "amzn1.echo-api.session.b7c275c5-a4d6-40a0-a905-2c767181ef14", "application": { "applicationId": "amzn1.ask.skill.a6415548-f2a7-4098-8d6b-62a74c41fb60" }, "attributes": {}, "user": { "userId": "amzn1.ask.account.AEI2SJB7LJZYKBWBT23GK4W4WGU2NYIWO7YG5UG3PRXRVICLXOHYB33PZXP63NNBIW4ZIIJF63XTT32CKBGKJDIIMNH32DD6VTFUYE4MW3D72OVKZ52UGSGVDKDD4TDAK3Q2AXBAKQHZ5R3XZDLXFWC3OAY5HMV3BL47NG7YKS43WR3RLM4UEMQBC2EQM6OPSWJIWALUGSYVO7A" } }, "context": { "Viewports": [ { "type": "APL", "id": "main", "shape": "RECTANGLE", "dpi": 213, "presentationType": "STANDARD", "canRotate": false, "configuration": { "current": { "mode": "HUB", "video": { "codecs": [ "H_264_42", "H_264_41" ] }, "size": { "type": "DISCRETE", "pixelWidth": 1280, "pixelHeight": 800 } } } } ], "Viewport": { "experiences": [ { "arcMinuteWidth": 346, "arcMinuteHeight": 216, "canRotate": false, "canResize": false } ], "mode": "HUB", "shape": "RECTANGLE", "pixelWidth": 1280, "pixelHeight": 800, "dpi": 213, "currentPixelWidth": 1280, "currentPixelHeight": 800, "touch": [ "SINGLE" ], "video": { "codecs": [ "H_264_42", "H_264_41" ] } }, "Extensions": { "available": { "aplext:backstack:10": {} } }, "System": { "application": { "applicationId": "amzn1.ask.skill.a6415548-f2a7-4098-8d6b-62a74c41fb60" }, "user": { "userId": "amzn1.ask.account.AEI2SJB7LJZYKBWBT23GK4W4WGU2NYIWO7YG5UG3PRXRVICLXOHYB33PZXP63NNBIW4ZIIJF63XTT32CKBGKJDIIMNH32DD6VTFUYE4MW3D72OVKZ52UGSGVDKDD4TDAK3Q2AXBAKQHZ5R3XZDLXFWC3OAY5HMV3BL47NG7YKS43WR3RLM4UEMQBC2EQM6OPSWJIWALUGSYVO7A" }, "device": { "deviceId": "amzn1.ask.device.AG7VS7XSFW5VZ73I6A7HFTJPUO56OU4TAM2ICF2KIU75TSD3U53KGGOIYR4IUUUPMRC7AR3KY3X5JT3IDBJ5VADVZLQTWLXFNPSJC3BKM6QOH4IYJLGB3HZOKXMD5XTYZPQILBUHROBVAYAOQ7ZNJRSFFR62DW3G2ZCG3MEMBT45MIRT56F44", "supportedInterfaces": {} }, "apiEndpoint": "https://api.amazonalexa.com", "apiAccessToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IjEifQ.eyJhdWQiOiJodHRwczovL2FwaS5hbWF6b25hbGV4YS5jb20iLCJpc3MiOiJBbGV4YVNraWxsS2l0Iiwic3ViIjoiYW16bjEuYXNrLnNraWxsLmE2NDE1NTQ4LWYyYTctNDA5OC04ZDZiLTYyYTc0YzQxZmI2MCIsImV4cCI6MTY0MTM0Nzk4NiwiaWF0IjoxNjQxMzQ3Njg2LCJuYmYiOjE2NDEzNDc2ODYsInByaXZhdGVDbGFpbXMiOnsiY29udGV4dCI6IkFBQUFBQUFBQUFBdUVDMVZqR1IvSklqOXR4VDJqMXljS3dFQUFBQUFBQUNpSlhzaGQ3eXhVUEViZjNnMWk2c1JiYmMwTENQN2hnUm5OZXlmTnNKdldWWHE5QWg3ajdkNC8raEJxYnB6THpoYzJiR0dNeHdLdFlQZ3FDK08xdWh0b3dGcFBaaEE0RElnN1FFNXE5dDBaalR0M0VnejdCeDhOWDloYm9mVG1TOHc0VWZ5NGc0dVA1RVducHYvQUtzNGlRSzdNbmh0a3hEdm8vMzNycmRWZ0JzTm5wM1l5bDBNSHE4QTBkVS85VUdZUlZ5Q0FyaTJqeFBVMTZIVTJhWFJZTWZuN2FDeTBEa0FWUk81TXliYUJDWklxSjhxaWtUUURoOUE5NlAxNTREc3hrK0FkMnVyRUVrN1E2VC84a0grYVkyVjQ3dVRFM1h4cWppVCt1KzBsR0M5N3JpdXpSU2Z5MGtXVlpwNFBLTGZpU0dlRzJIbHNtRE5HRFFwNUJRZy8yaittVHNYdXEweDlkR3QrYUpNYTh0VkFHTzd6RVBHelZxMlFydllFRXA2aHNPdWxoaTlQc1I0aXc9PSIsImNvbnNlbnRUb2tlbiI6bnVsbCwiZGV2aWNlSWQiOiJhbXpuMS5hc2suZGV2aWNlLkFHN1ZTN1hTRlc1Vlo3M0k2QTdIRlRKUFVPNTZPVTRUQU0ySUNGMktJVTc1VFNEM1U1M0tHR09JWVI0SVVVVVBNUkM3QVIzS1kzWDVKVDNJREJKNVZBRFZaTFFUV0xYRk5QU0pDM0JLTTZRT0g0SVlKTEdCM0haT0tYTUQ1WFRZWlBRSUxCVUhST0JWQVlBT1E3Wk5KUlNGRlI2MkRXM0cyWkNHM01FTUJUNDVNSVJUNTZGNDQiLCJ1c2VySWQiOiJhbXpuMS5hc2suYWNjb3VudC5BRUkyU0pCN0xKWllLQldCVDIzR0s0VzRXR1UyTllJV083WUc1VUczUFJYUlZJQ0xYT0hZQjMzUFpYUDYzTk5CSVc0WklJSkY2M1hUVDMyQ0tCR0tKRElJTU5IMzJERDZWVEZVWUU0TVczRDcyT1ZLWjUyVUdTR1ZES0RENFREQUszUTJBWEJBS1FIWjVSM1haRExYRldDM09BWTVITVYzQkw0N05HN1lLUzQzV1IzUkxNNFVFTVFCQzJFUU02T1BTV0pJV0FMVUdTWVZPN0EifX0.YxsDZNDIU69YvWX7RmjTF6UzeoMSp8fTK6jlhTe4qoS-JAfXUxPkzjygs3QMKfphu7B-a5Ht8zkXybuGR1S_rny3-46UiehOJHRdrYoyf46K_9pCNCehFsOjsPf7sH5-QgqSetDHcy9qgbGUs1MSnh5oAN0tZdpXBdYtopjcW6h2N0GFnaeNGVi2iuhQgkO-qz4FXlB1rfbAPWXzfxKMI6GLNAdLMusjXpgqVeFJasyg-a6OXr_9cHfkIKJZsYSEtfRrOYJkQUcgnYLfvwqKdmVcORrL2bUuRvFYb4YQa49K6d2vcwJg8Y2mHtomCzElIr9N-4tdPwgU5LvrFWv75A" } }, "request": { "type": "IntentRequest", "requestId": "amzn1.echo-api.request.3ed6b0ec-ef10-4816-bb17-ecdd18dccdac", "locale": "en-US", "timestamp": "2022-01-05T01:54:47Z", "intent": { "name": "GetRemoteDataIntent", "confirmationStatus": "NONE" } } }
JSON Output 1:
{ "body": { "version": "1.0", "response": { "outputSpeech": { "type": "SSML", "ssml": "<speak>Sorry, I can't understand the command. Please say again.</speak>" }, "reprompt": { "outputSpeech": { "type": "SSML", "ssml": "<speak>Sorry, I can't understand the command. Please say again.</speak>" } }, "shouldEndSession": false, "type": "_DEFAULT_RESPONSE" }, "sessionAttributes": {}, "userAgent": "ask-node/2.11.0 Node/v12.22.7" } }
Index.js:
/* eslint-disable func-names */ /* eslint-disable no-console */ const Alexa = require("ask-sdk-core"); const http = require("https"); // greating message hello there. const GetLaunchHandler = { canHandle(handlerInput) { return handlerInput.requestEnvelope.request.type === "LaunchRequest"; }, handle(handlerInput) { const speechText = "Hello there. How can i help you today?"; return handlerInput.responseBuilder .speak(speechText) .reprompt() .getResponse(); } }; // ----- find the elevator status of a elevator specific----- const GetStatusHandler = { canHandle(handlerInput) { return ( handlerInput.requestEnvelope.request.intent.name === "GetStatusIntent" ); }, async handle(handlerInput) { let outputSpeech = "This is the default message."; const id = handlerInput.requestEnvelope.request.intent.slots.id.value; if (id > 200) { outputSpeech = "Please enter a valid number"; return handlerInput.responseBuilder .speak(outputSpeech) .reprompt() .getResponse(); } //need to add elevator status endpoint const elevatorStatus = await getRemoteElevatorData( "https://jakerocket.azurewebsites.net/elevator/" + id ); const elevator = JSON.parse(elevatorStatus); outputSpeech = `The status of elevator ${id} is ${elevator} `; return handlerInput.responseBuilder .speak(outputSpeech) .reprompt() .getResponse(); } }; // ----- make all get for the big sentence ----- const GetRemoteDataHandler = { canHandle(handlerInput) { return ( handlerInput.requestEnvelope.request.type === "IntentRequest" && handlerInput.requestEnvelope.request.intent.name === "GetRemoteDataIntent" ); }, async handle(handlerInput) { let outputSpeech = "This is the default message."; //elevators that are not in running status and are being serviced const elevatorData = await getRemoteElevatorData( "https://jakerocket.azurewebsites.net/elevator/inactive" ); const elevatorAllData = await getRemoteElevatorAllData( "https://jakerocket.azurewebsites.net/elevator" ); const buildingData = await getRemoteBuildingData( "https://jakerocket.azurewebsites.net/buildings" ); const customerData = await getRemoteCustomerData( "https://jakerocket.azurewebsites.net/customer" ); const batteryData = await getRemoteBatteryData( "https://jakerocket.azurewebsites.net/battery" ); const AddressCityData = await getRemoteCityData( "https://jakerocket.azurewebsites.net/address" ); const QuoteData = await getQuoteData( "https://jakerocket.azurewebsites.net/quote" ); const LeadData = await getLeadData( "https://jakerocket.azurewebsites.net/leads" ); const elevator = JSON.parse(elevatorData); const elevatorAll = JSON.parse(elevatorAllData); const building = JSON.parse(buildingData); const customer = JSON.parse(customerData); const batteries = JSON.parse(batteryData); const cities = JSON.parse(AddressCityData); const quotes = JSON.parse(QuoteData); const leads = JSON.parse(LeadData); outputSpeech = `Hi Sir welcome to Rocket Elevator Statistic. There are currently ${ elevatorAll.length } elevators deployed in the ${building.length} buildings of your ${ customer.length } customers . Currently, ${ elevator.length } elevators are not in Running Status and are being serviced. ${batteries.length} Batteries are deployed across ${ cities.length } cities. On another note you currently have ${ quotes.length } quotes awaiting processing. You also have ${ leads.length } leads in your contact requests `; return handlerInput.responseBuilder .speak(outputSpeech) .reprompt() .getResponse(); } }; // ----- help commands ----- const HelpIntentHandler = { canHandle(handlerInput) { return ( handlerInput.requestEnvelope.request.type === "IntentRequest" && handlerInput.requestEnvelope.request.intent.name === "AMAZON.HelpIntent" ); }, handle(handlerInput) { const speechText = `Here is the list of all commands : what is the status of elevator {id},Can you tell me the status of elevator {id}, how is rocket elevators going, what is happening at rocket elevators, what is going on`; return handlerInput.responseBuilder .speak(speechText) .reprompt(speechText) .getResponse(); } }; const CancelAndStopIntentHandler = { canHandle(handlerInput) { return ( handlerInput.requestEnvelope.request.type === "IntentRequest" && (handlerInput.requestEnvelope.request.intent.name === "AMAZON.CancelIntent" || handlerInput.requestEnvelope.request.intent.name === "AMAZON.StopIntent") ); }, handle(handlerInput) { const speechText = "Goodbye!"; return handlerInput.responseBuilder.speak(speechText).getResponse(); } }; const SessionEndedRequestHandler = { canHandle(handlerInput) { return handlerInput.requestEnvelope.request.type === "SessionEndedRequest"; }, handle(handlerInput) { console.log( `Session ended with reason: ${ handlerInput.requestEnvelope.request.reason }` ); return handlerInput.responseBuilder.getResponse(); } }; const ErrorHandler = { canHandle() { return true; }, handle(handlerInput, error) { console.log(`Error handled: ${error.message}`); return handlerInput.responseBuilder .speak("Sorry, I can't understand the command. Please say again.") .reprompt("Sorry, I can't understand the command. Please say again.") .getResponse(); } }; const getLeadData = function(url) { return new Promise((resolve, reject) => { const client = url.startsWith("https") ? require("https") : require("http"); const request = client.get(url, response => { if (response.statusCode < 200 || response.statusCode > 299) { reject(new Error("Failed with status code: " + response.statusCode)); } const body = []; response.on("data", chunk => body.push(chunk)); response.on("end", () => resolve(body.join(""))); }); request.on("error", err => reject(err)); }); }; const getRemoteElevatorData = function(url) { return new Promise((resolve, reject) => { const client = url.startsWith("https") ? require("https") : require("http"); const request = client.get(url, response => { if (response.statusCode < 200 || response.statusCode > 299) { reject(new Error("Failed with status code: " + response.statusCode)); } const body = []; response.on("data", chunk => body.push(chunk)); response.on("end", () => resolve(body.join(""))); }); request.on("error", err => reject(err)); }); }; const getRemoteElevatorAllData = function(url) { return new Promise((resolve, reject) => { const client = url.startsWith("https") ? require("https") : require("http"); const request = client.get(url, response => { if (response.statusCode < 200 || response.statusCode > 299) { reject(new Error("Failed with status code: " + response.statusCode)); } const body = []; response.on("data", chunk => body.push(chunk)); response.on("end", () => resolve(body.join(""))); }); request.on("error", err => reject(err)); }); }; const getQuoteData = function(url) { return new Promise((resolve, reject) => { const client = url.startsWith("https") ? require("https") : require("http"); const request = client.get(url, response => { if (response.statusCode < 200 || response.statusCode > 299) { reject(new Error("Failed with status code: " + response.statusCode)); } const body = []; response.on("data", chunk => body.push(chunk)); response.on("end", () => resolve(body.join(""))); }); request.on("error", err => reject(err)); }); }; const getRemoteBuildingData = function(url) { return new Promise((resolve, reject) => { const client = url.startsWith("https") ? require("https") : require("http"); const request = client.get(url, response => { if (response.statusCode < 200 || response.statusCode > 299) { reject(new Error("Failed with status code: " + response.statusCode)); } const body = []; response.on("data", chunk => body.push(chunk)); response.on("end", () => resolve(body.join(""))); }); request.on("error", err => reject(err)); }); }; const getRemoteCityData = function(url) { return new Promise((resolve, reject) => { const client = url.startsWith("https") ? require("https") : require("http"); const request = client.get(url, response => { if (response.statusCode < 200 || response.statusCode > 299) { reject(new Error("Failed with status code: " + response.statusCode)); } const body = []; response.on("data", chunk => body.push(chunk)); response.on("end", () => resolve(body.join(""))); }); request.on("error", err => reject(err)); }); }; const getRemoteCustomerData = function(url) { return new Promise((resolve, reject) => { const client = url.startsWith("https") ? require("https") : require("http"); const request = client.get(url, response => { if (response.statusCode < 200 || response.statusCode > 299) { reject(new Error("Failed with status code: " + response.statusCode)); } const body = []; response.on("data", chunk => body.push(chunk)); response.on("end", () => resolve(body.join(""))); }); request.on("error", err => reject(err)); }); }; const getRemoteBatteryData = function(url) { return new Promise((resolve, reject) => { const client = url.startsWith("https") ? require("https") : require("http"); const request = client.get(url, response => { if (response.statusCode < 200 || response.statusCode > 299) { reject(new Error("Failed with status code: " + response.statusCode)); } const body = []; response.on("data", chunk => body.push(chunk)); response.on("end", () => resolve(body.join(""))); }); request.on("error", err => reject(err)); }); }; const skillBuilder = Alexa.SkillBuilders.custom(); exports.handler = skillBuilder .addRequestHandlers( GetLaunchHandler, GetRemoteDataHandler, HelpIntentHandler, CancelAndStopIntentHandler, SessionEndedRequestHandler, GetStatusHandler ) .addErrorHandlers(ErrorHandler) .lambda();
And lastly, the JSON for the interaction model:
{ "interactionModel": { "languageModel": { "invocationName": "rocket elevators", "intents": [ { "name": "GetLaunchIntent", "slots": [], "samples": [ "hi", "hello" ] }, { "name": "AMAZON.CancelIntent", "samples": [] }, { "name": "AMAZON.HelpIntent", "samples": [ "help" ] }, { "name": "AMAZON.StopIntent", "samples": [] }, { "name": "GetStatusIntent", "slots": [ { "name": "id", "type": "AMAZON.NUMBER" } ], "samples": [ "what is the status of elevator {id}", "Can you tell me the status of elevator {id}" ] }, { "name": "GetRemoteDataIntent", "slots": [], "samples": [ "how is rocket elevators going", "what is happening at rocket elevators", "what is going on" ] }, { "name": "AMAZON.NavigateHomeIntent", "samples": [] } ], "types": [] } } }
I’m quite new to Alexa skills development, and am just following a tutorial that may be a bit outdated. Any help would be greatly appreciated!
Advertisement
Answer
Add AMAZON.FallbackIntent in your interaction model.
“Sorry, I can’t understand the command. Please say again. ” This speech output should be sent when AMAZON.FallbackIntent is requested, not on an error.
I don’t know how javascript works, but I think there is some error in your code which triggers errorHandler which then gives that output.