【问题标题】:Alexa skill testing error: Error handled: Cannot read property 'value' of undefinedAlexa 技能测试错误:错误处理:无法读取未定义的属性“值”
【发布时间】:2020-01-09 23:52:14
【问题描述】:

如果有人解决了这个问题,请帮助我,下面是我的 lambda 函数代码。 当我在exports.handler 功能中评论所有功能并执行/测试单个功能时,它正在工作,但是如果我们启用所有功能,那么我会收到错误,因为错误处理:无法读取未定义的属性'值'

Node JS code for alexa skill kit for different intents created.

GetNewFactHandler,
    CreateJIRAIssueHandler,
    UpdateJIRAIssueHandler,
    GetJIRAIssueHandler,
    GetJIRAIssueCountHandler,


/* eslint-disable  func-names */
/* eslint-disable  no-console */
var http = require('http');
var https = require('https');

var projectKey='';
var iType='';
var keyValueID='';
var userName='';
var IssueNumber='';

const Alexa = require('ask-sdk');

const GetNewFactHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'LaunchRequest'
      || (request.type === 'IntentRequest'
        && request.intent.name === 'GetNewFactIntent');
  },
  handle(handlerInput) {
    const factArr = data;
    const factIndex = Math.floor(Math.random() * factArr.length);
    const randomFact = factArr[factIndex];
    const speechOutput = GET_FACT_MESSAGE + randomFact;

    return handlerInput.responseBuilder
      .speak(speechOutput)
      .withSimpleCard(SKILL_NAME, randomFact)
      .getResponse();
  },
};


var reqTimeout = 3000;

const CreateJIRAIssueHandler = {
    canHandle(handlerInput) {
        const request = handlerInput.requestEnvelope.request;
        const proKey = request.intent.slots.PROJECTKEY.value;
        const issueType = request.intent.slots.ISSUETYPE.value;
        iType = capitalize_Words(issueType);
        projectKey = proKey.toUpperCase();
        return request.type === 'IntentRequest' &&
            request.intent.name === 'CreateJIRAIssue';
    },
    async handle(handlerInput) {
        const createIssue = await createJiraIssue(projectKey, iType);
        const speechOutput = JSON.parse(createIssue).key;
        return handlerInput.responseBuilder
            .speak('Issue ' + speechOutput + ' created')
            .getResponse();
    },
};

function capitalize_Words(str) {
    return str.replace(/\w\S*/g, function(txt) {
        return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
    });
};

//mule real time server
var muleCreateIssuePath = '/jira/createissue';
var muleProtocol = 'https';
var createIssueMethod = 'POST';
var muleUpdateIssuePath = '/jira/issue/';
var updateIssueMethod = 'PUT';
var getIssueMethod = 'GET';

var MuleReqOpts = {
    host: '',
    port: 443,
    path: undefined, // To be set.
    method: undefined,
    headers: {
        'Content-Type': 'application/json'
    },
    agent: false,
    // auth: jiraUsername + ':' + jiraPassword
    auth: ''

};

var MuleHttp = muleProtocol === 'https' ? https : http;

function createJiraIssue(projectKey, iType) {

    MuleReqOpts.path = muleCreateIssuePath;
    MuleReqOpts.method = createIssueMethod;

    var MuleReqBody = {
        'fields': {
            'project': {
                'key': projectKey
            },
            'summary': 'Test Message',
            'description': 'Issue created for alexa skill kit from Integration alexa to jira',
            'issuetype': {
                'name': iType // Make sure your JIRA project configuration(s) supports this Issue Type.
            }
        }
    };

    return doApiCall(MuleHttp, MuleReqOpts, MuleReqBody, 'creating issue', 201);
};

function doApiCall(httplib, reqOpts, reqBody, happening, successCode) {
    return new Promise(((resolve, reject) => {
        var req = httplib.request(reqOpts, (res) => {
            res.setEncoding('utf8');
            let returnData = '';
            res.on('data', (chunk) => {
                returnData += chunk;
            });
            res.on('end', () => {
                resolve(returnData);
            });
            res.on('error', (error) => {
                reject(error);
            });
        });
        req.write(JSON.stringify(reqBody));
        req.end();

        req.on('error', function(err) {
            context.done(new Error(' request error: ' + err.message));
        });
        req.setTimeout(reqTimeout, function() {
            context.done(new Error(' request timeout after ' + reqTimeout + ' milliseconds.'));
        });
    }));
};

const UpdateJIRAIssueHandler = {

    canHandle(handlerInput) {
            console.log('1');

        const request = handlerInput.requestEnvelope.request;
                    console.log('2');

        userName = request.intent.slots.USER.value;

        var keyValue = request.intent.slots.PROJECTKEY.value;
        console.log('keyValue : ' + keyValue);

        keyValueID = keyValue.toUpperCase();
        IssueNumber = request.intent.slots.ISSUENUMBER.value;
        let INumber = Number(IssueNumber);
            console.log('IssueNumber value: '+INumber);

        console.log('key value id: ' + keyValueID);
        return request.type === 'IntentRequest' &&
            request.intent.name === 'UpdateJIRAIssue';
    },
    async handle(handlerInput) {
        const updateIssue = await updateJiraIssue(userName);
        console.log('updateIssue log: ' + updateIssue);

        const speechOutput = JSON.parse(updateIssue).responseMessage;
        console.log('speechOutput log: ' + speechOutput);
        return handlerInput.responseBuilder
            .speak(speechOutput)
            .getResponse();
    },
};


function updateJiraIssue(userName) {
    console.log('inside method: ' +userName);
    MuleReqOpts.method = updateIssueMethod;

    var postdata = {
        "fields": {
            "assignee": {
                "name": userName
            }
        }
    }

    return doApiUpdateCall(MuleHttp, MuleReqOpts, postdata, 'updating issue', 201);
};

function doApiUpdateCall(httplib, options, postdata, happening, successCode) {

    options.path = muleUpdateIssuePath + keyValueID +'-'+IssueNumber ;

    return new Promise(((resolve, reject) => {

        var req = httplib.request(options, (res) => {
            console.log(options);

            res.setEncoding('utf8');
            let returnData = '';
            res.on('data', (body) => {
                returnData += body;
                console.log(returnData);

            });
            res.on('end', () => {
                resolve(returnData);
            });
            console.log('1');
            console.log('Body: ');
        });

        req.on('error', function(e) {
            console.log('problem with request: ' + e.message);
        });

        var jirapostString = JSON.stringify(postdata);
        console.log(jirapostString);
        req.write(jirapostString);
        req.end();
    }));
};

const GetJIRAIssueHandler = {
    canHandle(handlerInput) {
        console.log('1');
        const request = handlerInput.requestEnvelope.request;
        var keyValue = request.intent.slots.Issue.value;
        console.log('keyValue: ' + keyValue);

        keyValueID = keyValue.toUpperCase();
        return request.type === 'IntentRequest' &&
            request.intent.name === 'GetJIRAIssue';
    },
    async handle(handlerInput) {
        const getIssue = await GetJIRAIssue();
        console.log('getIssue log: ' + getIssue);

        const assigneeName = JSON.parse(getIssue).fields.assignee.name;
        const key = JSON.parse(getIssue).fields.assignee.key;
        const reporterName = JSON.parse(getIssue).fields.reporter.name;
        const issueType = JSON.parse(getIssue).fields.issuetype.name;
        const projectName = JSON.parse(getIssue).fields.project.name;
        const summaryDetails = JSON.parse(getIssue).fields.summary;

        const speechOutput = 'Here are the issue details summary: Assignee : ' + assigneeName.concat(' ,reporter : ' + reporterName, ' ,Issue Key : ' + key, ' ,IssueType : ' + issueType, ' ,ProjectName : ' + projectName, ' ,Summary : ' + summaryDetails);

        console.log('speechOutput log: ' + speechOutput);

        return handlerInput.responseBuilder
            .speak(speechOutput)
            .getResponse();
    },
};


function GetJIRAIssue() {
    MuleReqOpts.method = getIssueMethod;

    return doApiGetIssueCall(MuleHttp, MuleReqOpts, 'get issue details', 201);

};

function doApiGetIssueCall(httplib, options, happening, successCode) {

    options.path = muleUpdateIssuePath + keyValueID;

    return new Promise(((resolve, reject) => {

        https.get(options, (res) => {
            console.log(options);

            res.setEncoding('utf8');
            let returnData = '';
            res.on('data', (body) => {
                returnData += body;
                console.log('response :', returnData);

            });
            res.on('end', () => {
                resolve(returnData);
            });
        });

    }));
};

const GetJIRAIssueCountHandler = {
    canHandle(handlerInput) {
        const request = handlerInput.requestEnvelope.request;
        userName = request.intent.slots.USER.value;
        console.log('userName Value: ' + userName);
        const issueType = request.intent.slots.ISSUETYPE.value;
        iType = capitalize_Words(issueType);
        return request.type === 'IntentRequest' &&
            request.intent.name === 'GetJIRAIssueCount';
    },
    async handle(handlerInput) {
        const getIssueCount = await GetJIRAIssueCount();
        console.log('getIssue log: ' + getIssueCount);
        const total = JSON.parse(getIssueCount).total;

        const speechOutput = ('Here is the '+iType+' count details: ' +total );

        console.log('speechOutput log: ' + speechOutput);

        return handlerInput.responseBuilder
            .speak(speechOutput)
            .getResponse();
    },
};

function GetJIRAIssueCount() {
    MuleReqOpts.method = getIssueMethod;

    return doApiGetIssueCountCall(MuleHttp, MuleReqOpts, 'get issue count details', 201);

};

function doApiGetIssueCountCall(httplib, options, happening, successCode) {

    options.path = muleUpdateIssuePath + userName +'/'+iType;

    return new Promise(((resolve, reject) => {

        https.get(options, (res) => {
            console.log(options);

            res.setEncoding('utf8');
            let returnData = '';
            res.on('data', (body) => {
                returnData += body;
                console.log('response :', returnData);

            });
            res.on('end', () => {
                resolve(returnData);
            });
        });

    }));
};

const HelpHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest'
      && request.intent.name === 'AMAZON.HelpIntent';
  },
  handle(handlerInput) {
    return handlerInput.responseBuilder
      .speak(HELP_MESSAGE)
      .reprompt(HELP_REPROMPT)
      .getResponse();
  },
};

const ExitHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest'
      && (request.intent.name === 'AMAZON.CancelIntent'
        || request.intent.name === 'AMAZON.StopIntent');
  },
  handle(handlerInput) {
    return handlerInput.responseBuilder
      .speak(STOP_MESSAGE)
      .getResponse();
  },
};

const SessionEndedRequestHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return 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, an error occurred.')
      .reprompt('Sorry, an error occurred.')
      .getResponse();
  },
};

const SKILL_NAME = 'Space Facts';
const GET_FACT_MESSAGE = 'Here\'s your fact: ';
const HELP_MESSAGE = 'You can say tell me a space fact, or, you can say exit... What can I help you with?';
const HELP_REPROMPT = 'What can I help you with?';
const STOP_MESSAGE = 'Goodbye!';

const data = [
  'A year on Mercury is just 88 days long.',
  'Despite being farther from the Sun, Venus experiences higher temperatures than Mercury.',
  'Venus rotates counter-clockwise, possibly because of a collision in the past with an asteroid.',
  'On Mars, the Sun appears about half the size as it does on Earth.',
  'Earth is the only planet not named after a god.',
  'Jupiter has the shortest day of all the planets.',
  'The Milky Way galaxy will collide with the Andromeda Galaxy in about 5 billion years.',
  'The Sun contains 99.86% of the mass in the Solar System.',
  'The Sun is an almost perfect sphere.',
  'A total solar eclipse can happen once every 1 to 2 years. This makes them a rare event.',
  'Saturn radiates two and a half times more energy into space than it receives from the sun.',
  'The temperature inside the Sun can reach 15 million degrees Celsius.',
  'The Moon is moving approximately 3.8 cm away from our planet every year.',
];

const skillBuilder = Alexa.SkillBuilders.custom();

exports.handler = skillBuilder
  .addRequestHandlers(
    GetNewFactHandler,
    CreateJIRAIssueHandler,
    UpdateJIRAIssueHandler,
    GetJIRAIssueHandler,
    GetJIRAIssueCountHandler,
    HelpHandler,
    ExitHandler,
    SessionEndedRequestHandler
  )
  .addErrorHandlers(ErrorHandler)
  .lambda();

【问题讨论】:

  • 即使一行有错误,Lambda 函数也不会执行代码,因此请检查是否有任何拼写错误,您是否还可以指定技能失败的意图。

标签: jira alexa


【解决方案1】:

检查所有代码以查找您正在寻找someObject.someNestedProperty.value 的实例。

我怀疑您在 Intent 中的插槽值与您在 model/some-LANG.json 文件中定义的不同。尝试在没有 someNestedProperty 的情况下从 someObject 访问 value 属性将导致您的错误(即 request.intent.slots.PROJECTKEY.value)。

如果这是 Alexa 托管的技能,则 CloudWatch 日志记录已内置。打开 Alexa 开发人员控制台,编辑您的技能,然后转到 代码 选项卡。在左下角,您应该会看到 Logs: Amazon CloudWatch 的链接。您可以使用简单的console.log() 语句记录您想要的任何内容。

另外,请注意ask-sdk-core npm 包包含获取 slotValues 的辅助方法(以及其他很棒的工具)。欲了解更多信息,请参阅此链接:https://developer.amazon.com/en-US/docs/alexa/alexa-skills-kit-sdk-for-nodejs/utilities.html

【讨论】:

    【解决方案2】:

    感谢大家的建议和及时回复。 现在问题已解决,解决方案是 addRequestHandlers 方法将按顺序执行方法,即使您执行/触发第三个处理程序,它将执行第一个和第二个处理程序并转到第三个处理程序。这里的问题是,当您从 alexa 触发第三个处理程序命令时,它将传递与第三个处理程序话语相关的槽值,因此具有槽值的第一个和第二个处理程序无法解析并失败。所以我在那边设置了一个条件来跳过第一个和第二个处理程序执行并且它起作用了。

    【讨论】:

      猜你喜欢
      • 2019-04-24
      • 2020-10-11
      • 1970-01-01
      • 1970-01-01
      • 2021-11-05
      • 1970-01-01
      • 2018-04-29
      • 2020-04-29
      相关资源
      最近更新 更多