无法从Airtable数据库检索值(Alexa Skill)

时间:2018-10-08 20:21:47

标签: node.js alexa alexa-skills-kit alexa-skill airtable

我正在研究一项Alexa技能(适用于Node.js的ASK-SDK v.2),该技能可以从Airtable数据库执行GET。用户要求输入角色名称,然后技能将对照此数据库进行检查以检索简短的描述。

但是,当我在Skill Builder上进行一些测试时,即使我说出在JSON INPUT中产生ER_SUCCESS_MATCH的角色名称,JSON OUTPUT也会将解析后的值(实际上是任何有效名称)返回为UNDEFINED。无论我查询的字符名称是什么,我都听到的消息是“我在数据库中找不到未定义的字符。”

即使我相信我在代码中提供了正确的API密钥和AirtableGet密钥,我仍然认为该技能无法连接到我的Airtable基地以获得角色名称。此外,我应该在我的AWS Lambda日志上看到一个“ IN AIRTABLE GET”条目,就在IN CHARACTER HANDLER和通常的END RequestID之间,但是到目前为止,我从IN CHARACTER HANDLER跳到了END RequestID,所以Airtable db似乎没有被调用。

这是完整的Index.js代码(减去技能编号,API密钥和角色名称列密钥)。你能发现任何错误吗?预先感谢您的帮助!

'use strict';
const Alexa = require('ask-sdk');
const https = require('https');

const APP_ID = "amzn1.ask.skill.xxxxxxxxxxxxxxxxxxxx";

const EmptyHandler = {
    canHandle(handlerInput) {
        return false;
    },
    handle(handlerInput, error) {
        return handlerInput.responseBuilder
                .speak()
                .reprompt()
                .getResponse();
    }
};

const LaunchRequestHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === "LaunchRequest";
    },
    handle(handlerInput, error) {
        console.log("IN LAUNCH REQUEST");
        return handlerInput.responseBuilder
            .speak("Accessing the Skill. Say any name.")
            .reprompt("Go on, start.")
            .getResponse();
  },
};

const CharacterHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === "IntentRequest" &&
               handlerInput.requestEnvelope.request.intent.name === "CharacterIntent";
    },
    handle(handlerInput, error) {
        console.log("IN CHARACTER HANDLER");

        var spokenValue = getSpokenValue(handlerInput.requestEnvelope, "character");
        var resolvedValues = getResolvedValues(handlerInput.requestEnvelope, "character");

        //NO MATCHES FOUND
        if (resolvedValues === undefined)
        {
            return handlerInput.responseBuilder
                   .speak("I can't find " + spokenValue + " in my database." + getRandomQuestion())
                   .reprompt("" + spokenValue + " is not in my database. " + getRandomQuestion())
                   .getResponse();
        }
        //ONLY ONE MATCH FOUND
        else if (resolvedValues.length === 1)
        {
            var filter = "&filterByFormula=%7BName%7D%3D%22" + encodeURIComponent(resolvedValues[0].value.name) + "%22";

            return new Promise((resolve) => {
                airtableGet("appXXXXXXXXXX", "Character", filter, (record) => {
                    console.log("AIRTABLE RECORD = " + JSON.stringify(record));
                    var speechText = "Accessing to " + spokenValue + "<break time='.5s'/>" + record.records[0].fields.VoiceDescription;

                    console.log("RESPONSE BUILDER = " + JSON.stringify(handlerInput.responseBuilder));

                    resolve(handlerInput.responseBuilder
                       .speak(speechText)
                       .reprompt(getRandomQuestion())
                       .getResponse());
                });
            });
        }
        //MORE THAN ONE MATCH FOUND.  DISAMBIGUATE.
        else if (resolvedValues.length > 1)
        {
            var valuesString = getValuesString(resolvedValues);

            return handlerInput.responseBuilder
                   .speak("You asked for " + spokenValue + ", but I have different matches for that name.  Do you mean " + valuesString + "?")
                   .reprompt("Do you want to talk about" + valuesString + "?")
                   .getResponse();
        }
  }
};

const HelpHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === "IntentRequest" &&
               handlerInput.requestEnvelope.request.intent.name === "AMAZON.HelpIntent";
    },
    handle(handlerInput, error) {
        console.log("IN " +  handlerInput.requestEnvelope.request.intent.name.toUpperCase())
        return handlerInput.responseBuilder
                .speak("I know a lot of things about these characters. Tell me something about them.")
                .reprompt("Go on.")
                .getResponse();
    }
};

const StopHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === "IntentRequest" &&
               (handlerInput.requestEnvelope.request.intent.name === "AMAZON.StopIntent" ||
                handlerInput.requestEnvelope.request.intent.name === "AMAZON.CancelIntent");
    },
    handle(handlerInput, error) {
        console.log("IN " + handlerInput.requestEnvelope.request.intent.name.toUpperCase())
        return handlerInput.responseBuilder
                .speak("Okey. See you!")
                .getResponse();
    }
};

const SessionEndedHandler = { 
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'SessionEndedRequest';
    },
    handle(handlerInput) {
      console.log("IN SESSIONENDEDHANDLER");
              return handlerInput.responseBuilder
                  .speak(getRandomGoodbye())
                  .getResponse();
     }
  };

function getRandomQuestion()
{
    var questions = ["Say another name when you're ready.", "Tell me another    name.", "Say another one.", "Any other names?"];
    var random = getRandom(0, questions.length-1);
    return "<break time='.5s'/>" + questions[random]; 
}

function getRandom(min, max)
{
    return Math.floor(Math.random() * (max-min+1)+min);
}

function getSpokenValue(envelope, slotName)
{
    if (envelope &&
        envelope.request &&
        envelope.request.intent &&
        envelope.request.intent.slots &&
        envelope.request.intent.slots[slotName] &&
        envelope.request.intent.slots[slotName].value)
    {
        return envelope.request.intent.slots[slotName].value;    
    }
    else return undefined;
}

function getResolvedValues(envelope, slotName)
{
    if (envelope &&
        envelope.request &&
        envelope.request.intent &&
        envelope.request.intent.slots &&
        envelope.request.intent.slots[slotName] &&
        envelope.request.intent.slots[slotName].resolutions &&
        envelope.request.intent.slots[slotName].resolutions.resolutionsPerAuthority &&
        envelope.request.intent.slots[slotName].resolutions.resolutionsPerAuthority[0] &&
        envelope.request.intent.slots[slotName].resolutions.resolutionsPerAuthority[0].values)
    {
        return envelope.request.intent.slots[slotName].resolutions.resolutionsPerAuthority[0].values;
    }
    else return undefined;
}

function getSlotName(envelope)
{
    if (envelope &&
        envelope.request &&
        envelope.request.intent &&
        envelope.request.intent.slots &&
        envelope.request.intent.slots[0] &&
        envelope.request.intent.slots[0].name)
    {
        return envelope.request.intent.slots[0].name;
    }
    else return undefined;
}

function getValuesString(values)
{
    var string = "";
    for (var i = 0;i<values.length; i++)
    {
        if (i != 0) string += ", ";
        if (i === (values.length-1)) string += " or ";
        string += values[i].value.name;
    }
    return string;
}

function airtableGet(base, table, filter, callback) {
    console.log("IN AIRTABLE GET");
    console.log("BASE = " + base);
    console.log("TABLE = " + table);
    console.log("FILTER = " + filter);

    var options = {
        host: "api.airtable.com",
        port: 443,
        path: "/v0/" + base + "/" + table + "?api_key=keyXXXXXXXXXX" + filter,
        method: 'GET',
    };

    console.log("PATH = https://" + options.host + options.path);

    var req = https.request(options, res => {
        res.setEncoding('utf8');
        var returnData = "";

        res.on('data', chunk => {
            returnData = returnData + chunk;
        });

        res.on('end', () => {
            var data = JSON.parse(returnData);
            console.log("DATA = " + JSON.stringify(data));
            callback(data);
        });
    });
    req.end();
}

const RequestLog = {
    process(handlerInput) {
        console.log("REQUEST ENVELOPE = " + JSON.stringify(handlerInput.requestEnvelope));    
        return;
    }
};

const ErrorHandler = {
    canHandle() {
        return true;
    },
    handle(handlerInput, error) {
        console.log("Error handled: " + JSON.stringify(error.message));
        console.log('handlerInput:' + JSON.stringify(handlerInput));
        return handlerInput.responseBuilder
            .speak('I am sorry, something went wrong on my side.')
            .getResponse();
  },
};

exports.handler = Alexa.SkillBuilders.standard() 
.addRequestHandlers(
    LaunchRequestHandler,
    CharacterHandler,
    HelpHandler,
    StopHandler,
    SessionEndedHandler    
  )
.addRequestInterceptors(RequestLog)
.addErrorHandlers(ErrorHandler)
.lambda();

0 个答案:

没有答案