使用 Alexa 查询调用 DynamoDB

Recall DynamoDB with Alexa query

我正在尝试使用 Alexa 创建一项技能,以使用扫描或查询功能(或两者)从我的 DynamoDB table 读取数据。

我的 table 中的列是日期、时间和电影名称。

我是新手,但我已经设法 link 我的 Lambda 函数到 Alexa。我还创建了一个单独的 Lambda 函数,当我配置测试事件时,它会从我的 table 中调用数据,因此当我输入特定日期时,它会调用相应的电影和时间。但是现在我想将它实现到 Alexa 中,但我不确定如何实现。

这是我当前的代码

console.log('Loading function');

var AWSregion = 'us-east-1';  // us-east-1
var AWS = require('aws-sdk');
var dclient = new AWS.DynamoDB.DocumentClient();

var getItems = (event, context, callback)=>{
    
    dclient.get(event.params,(error,data)=>{
        if(error){
            callback(null,"error occurerd");
        }
        else{
            callback(null,data);
        }
    });
};

exports.handler = getItems;

exports.handler = (event, context, callback) => {
    try {

        var request = event.request;

        if (request.type === "LaunchRequest") {
            context.succeed(buildResponse({
                speechText: "Welcome to H.S.S.M.I skill, what would you like to find",
                repromptText: "I repeat, Welcome to my skill, what would you like to find",
                endSession: false
            }));
        }
        else if (request.type === "IntentRequest") {
            let options = {};         


            if (request.intent.name === "cinema") {
            } else if (request.intent.name === "AMAZON.StopIntent" || request.intent.name === "AMAZON.CancelIntent") {
                options.speechText = "ok, good bye.";
                options.endSession = true;
                context.succeed(buildResponse(options));
            }
             else if (request.intent.name === "AMAZON.HelpIntent") {
                options.speechText = "My skill will read your table depending on what is asked. For example, you can ask what about a specific date. Please refer to skill description for all possible utterences.";
                options.repromptText = "What is the data sign you want to know  about today? If you want to exit from my  skill please say stop or cancel.";
                options.endSession = false;
                context.succeed(buildResponse(options));
            }
            else {
                context.fail("Unknown Intent");
            }
        }

        else if (request.type === "SessionEndedRequest") {
            options.endSession = true;
            context.succeed();
        }
        else {
            context.fail("Unknown Intent type");
        }




    } catch (e) {

    }


};

function buildResponse(options) {
    var response = {
        version: "1.0",
        response: {
            outputSpeech: {
                "type": "SSML",
                "ssml": `<speak><prosody rate="slow">${options.speechText}</prosody></speak>`
            },

            shouldEndSession: options.endSession
        }
    };

    if (options.repromptText) {
        response.response.reprompt = {
            outputSpeech: {
                "type": "SSML",
                "ssml": `<speak><prosody rate="slow">${options.repromptText}</prosody></speak>`
            }
        };
    }

    return response;
}

function readDynamoItem(params, callback) {
    
    var AWS = require('aws-sdk');
    AWS.config.update({region: AWSregion});
    var dynamodb = new AWS.DynamoDB();
    console.log('reading item from DynamoDB table');

    dynamodb.scan(params, function(err, data) {
        if (err) console.log(err, err.stack); // an error occurred
        else{
            console.log(data); // successful response
            callback(JSON.stringify(data));
        }
    });
    var docClient = new AWS.DynamoDB.DocumentClient();
    //Get item by key
    docClient.get(params, (err, data) => {
        if (err) {
            console.error("Unable to read item. Error JSON:", JSON.stringify(err, null, 2));
        } else {
            console.log("GetItem succeeded:", JSON.stringify(data, null, 2));

            callback(data.Item.message);  // this particular row has an attribute called message

        }
    });

}

///////////////////////////////////////////////////////////////////////////////

这是我的 DBHandler

var AWS = require('aws-sdk');
AWS.config.update({
    region: "'us-east-1'"
});

let docClient = new AWS.DynamoDB.DocumentClient();

var table = "Cinema";

let getItems = (Id,callback) => {   
  
    var params = {
        TableName: "cinema",
        Key: {
            "date": "2018-01-04",
            "filmname": "rugrats"
        }
    };

    docClient.get(params, function (err, data) {
        callback(err, data);
    });

};
module.exports = {
    getItems
};

我可以启动该应用程序,并且当我配置测试事件以查找某个日期的电影时,我有一个 Lambda 函数可以自行运行,但我无法让它与 Alexa 一起工作。

任何人都可以帮助我或指出我哪里出错了

更新***************

这是我的意图架构的设置方式

{
  "intents": [
    {
      "slots": [
        {
          "name": "sincedate",
          "type": "AMAZON.DATE"
        }
      ],
      "intent": "date"
    },
    {
      "intent": "AMAZON.CancelIntent"
    },
    {
      "intent": "AMAZON.HelpIntent"
    },
    {
      "intent": "AMAZON.StopIntent"
    },
    {
      "slots": [
        {
          "name": "sincedate",
          "type": "AMAZON.DATE"
        }
      ],
      "intent": "cinema"
    },
    {
      "intent": "MyIntent"
    }
  ]
}

第 1 部分 - 权限

您可能无法在技能中读取 DynamoDB 的一个可能原因是权限问题。

您应该仔细检查分配给技能 lambda 的 IAM 角色,以确保它具有从 DynamoDB 读取的权限。

一些参考资料:

第 2 部分 - 实际的技能处理程序 Lambda

我 re-read 你的问题,我对你谈论设置第二个 Lambda 以从 Dynamo 读取数据的部分感到困惑。您不应该有两个 Lambda 函数 - 只有一个可以处理来自 Alexa 的请求,在那个函数中,您应该 return 在调用 Dynamo 后对 Alexa 做出响应。

现在,具体来说。在您的第一个代码片段中,您有:

exports.handler = getItems;

exports.handler = (event, context, callback) => {
    // here you have your handler to handle alexa responses 
}

立即突出的一件事是您首先将处理程序设置为 getItems,然后重置回应该响应 Alexa 的处理程序。

我猜的另一件事是有时技能会起作用,比如当你第一次启动它时,可能如果你说帮助但在其他情况下它不会,比如当你发送"cinema" 意图。

这是因为从 Alexa 请求到您的技能的入口点是 exports.handler,它基本上被定义为具有三个参数的函数(就像 void main(int argc,char *argv[] ) 的 c 程序)。

第一个参数——event是你技能的输入。 Alexa 将在此处提供信息,例如请求类型(如果是意图)、意图名称、会话信息等。

第二个和第三个参数 - contextcallback 是您用来 return 从 lambda 函数进行控制的参数,具体取决于节点运行时。对于 Note v4 和更新版本,您使用回调,对于您使用上下文的旧版本。

您可以使用类似这样的方式发送成功响应:

if(typeof callback === 'undefined') {
     context.succeed("successful response message");
} else {
     callback(null, "successful response message");
}

还有这样的东西来发送失败响应

if(typeof callback === 'undefined') {
     context.fail("failure response message");
} else {
     callback("failure response message", null);
}

总而言之,这是一个始终响应您的技能调用的基本 Lambda 处理程序:

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. what do you want to find?",
        endSession: false
      });
    }
    else if (request.type === "IntentRequest") {
      let options = {};         
      if (request.intent.name === "cinema") {
        // this is where we will wire up the dynamo call
        // for now, just send a simple response and end the session
        sendResponse(context, callback, {
          output: "cinema not implemented yet!",
          endSession: true
        });
      } 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 films",
          reprompt: "what can I help you with?"
          endSession: false
        });
      }
      else {
        sendResponse(context, callback, {
          output: "I don't know that one! Good bye!",
          endSession: true
        });
      }
    }
    else if (request.type === "SessionEndedRequest") {
      sendResponse(context, callback, ""); // no response needed
    }
    else {
      // un unexpected request type received.. just say I don't know..
      sendResponse(context, callback, {
          output: "I don't know that one! Good bye!",
          endSession: true
      });
    }
  } 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");
    }
  }
};

至此,该技能应该可以正常使用,并且应该能够处理您的所有请求。假设您已正确配置交互模型并且 cinema 意图已发送到您的技能,那么您可以使用 dynamo 客户端响应来自 table 的数据。

var AWSregion = 'us-east-1';  // us-east-1
var AWS = require('aws-sdk');
var dbClient = new AWS.DynamoDB.DocumentClient();

let handleCinemaIntent = (context, callback) => {    
  let params = {
    TableName: "cinema",
    Key: {
        "date": "2018-01-04",
        "filmname": "rugrats"
    }
  };
  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 Dynamo",
          endSession: true
       });
    } else {
       console.log('loaded data item:\n' + JSON.stringify(data.Item, null, 2))
       // assuming the item has an attribute called "message"..
       sendResponse(context, callback, {
          output: data.Item.message,
          endSession: true
       });
    }
  });
};


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. what do you want to find?",
        endSession: false
      });
    }
    else if (request.type === "IntentRequest") {
      let options = {};         
      if (request.intent.name === "cinema") {
        handleCinemaIntent(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 films",
          reprompt: "what can I help you with?"
          endSession: false
        });
      }
      else {
        sendResponse(context, callback, {
          output: "I don't know that one! Good bye!",
          endSession: true
        });
      }
    }
    else if (request.type === "SessionEndedRequest") {
      sendResponse(context, callback, ""); // no response needed
    }
    else {
      // un unexpected request type received.. just say I don't know..
      sendResponse(context, callback, {
          output: "I don't know that one! Good bye!",
          endSession: true
      });
    }
  } 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");
    }
  }
};