Я новичок в alexa, nodejs и кодировании в целом, но в настоящее время я пытаюсь создать навык для поиска состояний машины из моей таблицы Dynamodb с использованием даты и времени.
В настоящее время я настроил свои навыки, чтобы заставить alexa и lambda понимать значения моих слотов, но я не уверен, как я могу использовать эти значения для запроса Dynamodb и заставить alexa вызывать состояние для этого соответствующего времени
Моя таблица настроена с первичным ключом и ключом сортировки, которые являются датой и временем, и у меня есть третий столбец для состояния машины.
Я не уверен, следует ли мне настраивать пользовательский слот для состояния машины, поскольку это было бы легко сделать, поскольку есть только 4 возможных состояния.
Вот код, который у меня есть в настоящее время. Не стесняйтесь очищать части или объяснять, как вы пришли к моему решению.
const awsSDK = require('aws-sdk');
const updatedincident = 'updatedincident';
const docClient = new awsSDK.DynamoDB.DocumentClient();
var AWSregion = 'us-east-1'; // us-east-1
var AWS = require('aws-sdk');
var dbClient = new AWS.DynamoDB.DocumentClient();
AWS.config.update({
region: "'us-east-1'"
});
const params = {
TableName: "updatedincident",
Key:{ date: "2018-03-28",
time: "04:23",
state: "Blocked Primary"
}
};
let GetMachineStateIntent = (context, callback) => {
var params = {
TableName: "updatedincident",
Key: {
date: "2018-03-28",
time: "04:23",
state: "Blocked Primary"
}
};
dbClient.get(params, function (err, data) {
if (err) {
// failed to read from table for some reason..
console.info('failed to load data item:\n' + JSON.stringify(err, null, 2));
// let skill tell the user that it couldn't find the data
sendResponse(context, callback, {
output: "the data could not be loaded from your database",
endSession: false
});
} else {
console.info('loaded data item:\n' + JSON.stringify(data.Item, null, 2));
// assuming the item has an attribute called "state"..
sendResponse(context, callback, {
output: data.Item.state,
endSession: false
});
}
});
};
function sendResponse(context, callback, responseOptions) {
if (typeof callback === 'undefined') {
context.succeed(buildResponse(responseOptions));
} else {
callback(null, buildResponse(responseOptions));
}
}
function buildResponse(options) {
var alexaResponse = {
version: "1.0",
response: {
outputSpeech: {
"type": "SSML",
"ssml": `<speak><prosody rate = "slow">${options.output}</prosody></speak>`
},
shouldEndSession: options.endSession
}
};
if (options.repromptText) {
alexaResponse.response.reprompt = {
outputSpeech: {
"type": "SSML",
"ssml": `<speak><prosody rate = "slow">${options.reprompt}</prosody></speak>`
}
};
}
return alexaResponse;
}
exports.handler = (event, context, callback) => {
try {
var request = event.request;
if (request.type === "LaunchRequest") {
sendResponse(context, callback, {
output: "welcome to my skill, I can tell you about the status of machines at different times. what data are you looking for?",
endSession: false
});
}
else if (request.type === "IntentRequest") {
if (request.type === "IntentRequest"
// make sure the name of the intent matches the one in interaction model
&& request.intent.name == "GetMachineStateIntent") {
var dateSlot = request.intent.slots.Date != null ?
request.intent.slots.Date.value : "unknown date";
var timeSlot = request.intent.slots.Time != null ?
request.intent.slots.Time.value : "unknown time";
// respond with speech saying back what the skill thinks the user requested
sendResponse(context, callback, {
output: "You wanted the machine state at "
+ timeSlot + " on " + dateSlot,
endSession: false
});
var ConfirmationHandlers = Alexa.CreateStateHandler(states.CONFIRMATIONMODE, {
'YesIntent': function () {
this.emit("GetMachineStateIntent");
},
'AMAZON.NoIntent': function () {
this.response.speak(GetMachineStateIntent);
this.emit(':responseReady');
}
});
}
let options = {};
if (request.intent.name === "GetMachineStateIntent") {
GetMachineStateIntent(context, callback);
} else if (request.intent.name === "AMAZON.StopIntent" || request.intent.name === "AMAZON.CancelIntent") {
sendResponse(context, callback, {
output: "ok. good bye!",
endSession: true
});
}
else if (request.intent.name === "AMAZON.HelpIntent") {
sendResponse(context, callback, {
output: "you can ask me about incidents that have happened or states of machines in the past",
reprompt: "what can I help you with?",
endSession: false
});
}
else {
sendResponse(context, callback, {
output: "I don't know that one! please try again!",
endSession: false
});
}
}
else if (request.type === "SessionEndedRequest") {
sendResponse(context, callback, ""); // no response needed
}
else {
// an unexpected request type received.. just say I don't know..
sendResponse(context, callback, {
output: "I don't know that one! please try again!",
endSession: false
});
}
} catch (e) {
// handle the error by logging it and sending back an failure
console.info('Unexpected error occurred in the skill handler!', e);
if (typeof callback === 'undefined') {
context.fail("Unexpected error");
} else {
callback("Unexpected error");
}
}
};
Обновлять ************
Ответ я получаю в настоящее время в Skill I / O в alexa
"request": {
"type": "IntentRequest",
"requestId": "amzn1.echo-api.request.c515c39e-4ce1-4f28-97ed-30536fa593b9",
"timestamp": "2018-05-15T08:55:25Z",
"locale": "en-GB",
"intent": {
"name": "GetMachineStateIntent",
"confirmationStatus": "NONE",
"slots": {
"Time": {
"name": "Time",
"value": "04:23",
"confirmationStatus": "NONE"
},
"Date": {
"name": "Date",
"value": "2018-03-28",
"confirmationStatus": "NONE"
}
}
},
"dialogState": "STARTED"
}
}
Пара наблюдений:
Первый
В ветви кода, которая обрабатывает GetMachineStateIntent
, вы добавили код для создания обработчиков состояния, но они не были правильно подключены. В лучшем случае этот код ничего не сделает, в худшем - может вызвать некоторые проблемы. Удалите это.
// take the following lines of code out
var ConfirmationHandlers = Alexa.CreateStateHandler(states.CONFIRMATIONMODE, {
'YesIntent': function () {
this.emit("GetMachineStateIntent");
},
'AMAZON.NoIntent': function () {
this.response.speak(GetMachineStateIntent);
this.emit(':responseReady');
}
});
Второй Параметры запроса, которые вы передаете в свой запрос DynamoDB, жестко запрограммированы. Это означает, что вы всегда будете получать один и тот же результат. Вам необходимо передать значения слотов, которые вы получаете в намерении, в параметры запроса.
var params = {
TableName: "updatedincident",
Key: {
date: "2018-03-28",
time: "04:23",
state: "Blocked Primary"
}
};
Они жестко запрограммированы. Вам нужно только указать первичный ключ (date
) и ключ сортировки («время»), чтобы вы могли удалить state
. А для date
и time
вы должны изменить значения, которые будут динамически передаваться из dateSlot
и timeSlot
.
В третьих В ветви кода, которая обрабатывает запросы типа IntentRequest
, вы дважды обрабатываете GetMachineStateIntent
, и этот код немного избыточен. Перепишите это следующим образом:
...
} else if (request.type === "IntentRequest") {
if (request.intent.name === "GetMachineStateIntent") {
GetMachineStateIntent(context, callback);
} else if (request.intent.name === "AMAZON.StopIntent" || request.intent.name === "AMAZON.CancelIntent") {
sendResponse(context, callback, {
output: "ok. good bye!",
endSession: true
});
}
else if (request.intent.name === "AMAZON.HelpIntent") {
sendResponse(context, callback, {
output: "you can ask me about incidents that have happened or states of machines in the past",
reprompt: "what can I help you with?",
endSession: false
});
}
else {
sendResponse(context, callback, {
output: "I don't know that one! please try again!",
endSession: false
});
}
} else if (request.type === "SessionEndedRequest") {
Четвертый Объяснить это труднее всего. Когда вы запрашиваете состояние машины, вы указываете дату и время, но, предположительно, состояние машины может не храниться в базе данных с отметкой времени, которая точно соответствует значению времени в вашем запросе. Таким образом, вы должны выполнить запрос, который по сути эквивалентен «каково состояние машины на дату X, в самое последнее время до или равное Y».
Сложность заключается в том, что «самое последнее время до или равное Y». Вы должны создать запрос в своей таблице, который выражает это, и вам также придется изменить способ хранения временных меток в таблице со строки на числовой формат, чтобы вы могли легко выразить это неравенство.
Я собираюсь показать здесь, как передать dateSlot и timeSlot для выполнения запроса, но я рекомендую вам изучить, как заставить это работать (возможно, задайте конкретные вопросы, если вы застряли).
Вот ваш код с упомянутыми мною модификациями:
const awsSDK = require('aws-sdk');
const updatedincident = 'updatedincident';
const docClient = new awsSDK.DynamoDB.DocumentClient();
var AWSregion = 'us-east-1'; // us-east-1
var AWS = require('aws-sdk');
var dbClient = new AWS.DynamoDB.DocumentClient();
AWS.config.update({
region: "'us-east-1'"
});
let GetMachineStateIntent = (context, callback, dateSlot, timeSlot) => {
var params = {
TableName: "updatedincident",
KeyConditionExpression: '#d = :dVal and #t < :tVal',
ExpressionAttributeValues: {
':dVal': dateSlot,
':tVal': timeSlot
},
ExpressionAttributeNames: {
'#d': 'date',
'#t': 'time'
},
ScanIndexForward: false // gets values in reverse order by time
};
dbClient.query(params, function (err, data) {
if (err) {
// failed to read from table for some reason..
console.info('failed to load data item:\n' + JSON.stringify(err, null, 2));
// let skill tell the user that it couldn't find the data
sendResponse(context, callback, {
output: "the data could not be loaded from your database",
endSession: false
});
} else {
let dataItem = data.Items[0];
console.info('loaded data item:\n' + JSON.stringify(dataItem, null, 2));
// assuming the item has an attribute called "state"..
sendResponse(context, callback, {
output: dataItem.state,
endSession: false
});
}
});
};
function sendResponse(context, callback, responseOptions) {
if (typeof callback === 'undefined') {
context.succeed(buildResponse(responseOptions));
} else {
callback(null, buildResponse(responseOptions));
}
}
function buildResponse(options) {
var alexaResponse = {
version: "1.0",
response: {
outputSpeech: {
"type": "SSML",
"ssml": `<speak><prosody rate = "slow">${options.output}</prosody></speak>`
},
shouldEndSession: options.endSession
}
};
if (options.repromptText) {
alexaResponse.response.reprompt = {
outputSpeech: {
"type": "SSML",
"ssml": `<speak><prosody rate = "slow">${options.reprompt}</prosody></speak>`
}
};
}
return alexaResponse;
}
exports.handler = (event, context, callback) => {
try {
var request = event.request;
if (request.type === "LaunchRequest") {
sendResponse(context, callback, {
output: "welcome to my skill, I can tell you about the status of machines at different times. what data are you looking for?",
endSession: false
});
} else if (request.type === "IntentRequest") {
if (request.intent.name === "GetMachineStateIntent") {
var dateSlot = request.intent.slots.Date != null
? request.intent.slots.Date.value : null;
var timeSlot = request.intent.slots.Time != null
? request.intent.slots.Time.value : null;
// pass the slot values to the GetMachineStateIntent function
GetMachineStateIntent(context, callback, dateSlot, timeSlot);
} else if (request.intent.name === "AMAZON.StopIntent" || request.intent.name === "AMAZON.CancelIntent") {
sendResponse(context, callback, {
output: "ok. good bye!",
endSession: true
});
}
else if (request.intent.name === "AMAZON.HelpIntent") {
sendResponse(context, callback, {
output: "you can ask me about incidents that have happened or states of machines in the past",
reprompt: "what can I help you with?",
endSession: false
});
}
else {
sendResponse(context, callback, {
output: "I don't know that one! please try again!",
endSession: false
});
}
}
else if (request.type === "SessionEndedRequest") {
sendResponse(context, callback, ""); // no response needed
}
else {
// an unexpected request type received.. just say I don't know..
sendResponse(context, callback, {
output: "I don't know that one! please try again!",
endSession: false
});
}
} catch (e) {
// handle the error by logging it and sending back an failure
console.info('Unexpected error occurred in the skill handler!', e);
if (typeof callback === 'undefined') {
context.fail("Unexpected error");
} else {
callback("Unexpected error");
}
}
};
Просто хотел добавить элемент, который я хочу вызвать, это dataItem.State.
Кажется, не может получить никакого ответа от Alexa, кроме «данные не могут быть загружены из вашей базы данных». Моя дата и время отформатированы правильно, и я вижу по Алексе, что мои время и дата вводятся правильно.
Я добавил то, что в настоящее время получаю от ввода / вывода навыков alexa, когда я ввожу дату и время
также посмотрите мой последний пост, чтобы узнать, что я получаю в CloudWatch
@zuba Я посмотрел на другой вопрос, который вы разместили, и да, возникла проблема с параметрами запроса; Я опубликовал ответ там, но я обновил и этот здесь
Привет, я добавил ваши изменения, но теперь я получаю «данные не могут быть загружены из вашей базы данных». Я вижу, что вводятся мои значения даты и времени, но не получаю ответа. Мне нужно будет изменить мою модель взаимодействия? Также можно добавить подтверждение, например: «Вы хотите, чтобы состояние было в (время) в (дата)?» когда пользователь отвечает "да" или "нет"?