Я работаю над навыком Alexa (ASK-SDK v.2 для Node.js), который выполняет GET из базы данных Airtable.Пользователь запрашивает имя персонажа, а навык проверяет его по этой базе данных, чтобы в результате получить краткое описание.
Однако, когда я провожу некоторое тестирование в Skill Builder, даже если я говорю «Имя персонажа», которое делает ER_SUCCESS_MATCH в моем входе JSON, JSON OUTPUT возвращает разрешенное значение (фактически, любые действительные имена) как «НЕ УКАЗАНО»,Я слышу ответное сообщение: «Я не могу найти НЕ УКАЗАНО в своей базе данных», независимо от имени персонажа, о котором я спрашиваю.
Я считаю, что навыку не удается подключиться к моей базе Airtable, чтобы получить персонажа.Имя, даже если я считаю, что предоставил правильный код API и ключ AirtableGet в своем коде.Кроме того, я должен видеть запись «IN AIRTABLE GET» в моих лямбда-журналах AWS, прямо между 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();