используя слоты в навыке намерения искать DynamodB - PullRequest
0 голосов
/ 01 мая 2018

Я новичок в alexa, nodejs и кодировании в целом, но в настоящее время я пытаюсь создать навык для поиска состояний машины из моей таблицы DynamodB, используя дату и время.

В настоящее время я настроил свой навык, чтобы заставить alexa и lambda понимать значения моего слота, но я не уверен, как я могу использовать эти значения для запроса динамодаба и заставить 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.log('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.log('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.log('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"
	}
}

1 Ответ

0 голосов
/ 06 мая 2018

Пара наблюдений:

Первый В ветке кода, которая обрабатывает 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.log('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.log('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.log('Unexpected error occurred in the skill handler!', e);
    if(typeof callback === 'undefined') {
       context.fail("Unexpected error");
    } else {
       callback("Unexpected error");
    }
  }
};
...