如何使用 Dialogflow 识别唯一身份用户

How to identify unique users with Diagflow

我正在尝试制作一个助手应用程序,并使用 firebase 的云 firestore 服务将响应发送回我的应用程序,使用 webhook 作为实现。我根据此 documentation 在请求 JSON 中使用了 'session' 参数,并发送 fulfilmentText 作为对用户的响应。但是每当用户启动该应用程序时,都会创建一个我不想要的新会话。我只是想要,我的数据库中的每个用户只有一个条目,所以如何使用 dialogflow 实现它。

在 Alexa Skill 中,我们将 deviceId 作为参数,无论会话 ID 是什么,我们都可以通过它唯一地标识用户,但是在 dialogflow 请求中是否有任何参数 JSON。如果没有,那么没有它如何完成这个任务。

我从 Dialogflow 获得的请求 JSON 中有一个 userID,所以我可以使用 userId 还是应该使用 userStorage,前提是 userStorage 参数在请求中不可用 JSON .

request.body.originalDetectIntentRequest { source: 'google',   version: '2',   payload:     { surface: { capabilities: [Object] },
     inputs: [ [Object] ],
     user: 
      { locale: 'en-US',
        userId: 'ABwppHG5OfRf2qquWWjI-Uy-MwfiE1DQlCCeoDrGhG8b0fHVg7GsPmaKehtxAcP-_ycf_9IQVtUISgfKhZzawL7spA' },
     conversation: 
      { conversationId: '1528790005269',
        type: 'ACTIVE',
        conversationToken: '["generate-number-followup"]' },
     availableSurfaces: [ [Object] ] } }

编辑:谢谢@Prisoner 的回答,但我无法发送在响应中生成并在有效负载中设置的随机 ID。下面是我生成 uuid 并将其存储在 firestore 中的代码。由于为返回的用户生成了新的 uuid,因此我在下面的代码中做错了什么,因此响应显示为在数据库中找不到文档。我想我没有适当地发送 uuid。请帮忙。

exports.webhook = functions.https.onRequest((request, response) => {


    console.log("request.body.queryResult.parameters", request.body.queryResult.parameters);
    console.log("request.body.originalDetectIntentRequest.payload", request.body.originalDetectIntentRequest.payload);

    let userStorage = request.body.originalDetectIntentRequest.payload.user.userStorage || {};
    let userId;
    console.log("userStorage", userStorage);

    if (userId in userStorage) {
      userId = userStorage.userId;
    } else {
      var uuid = require('uuid/v4');
      userId = uuid();
      userStorage.userId = userId
    }

    console.log("userID", userId);

    switch (request.body.queryResult.action) {
      case 'FeedbackAction': {

            let params = request.body.queryResult.parameters;

            firestore.collection('users').doc(userId).set(params)
              .then(() => {

              response.send({
                'fulfillmentText' : `Thank You for visiting our ${params.resortLocation} hotel branch and giving us ${params.rating} and your comment as ${params.comments}.` ,
                'payload': {
                  'google': {
                    'userStorage': userStorage
                  }
                }

                });
                return console.log("resort location", params.resortLocation);
            })
            .catch((e => {

              console.log('error: ', e);

              response.send({
             'fulfillmentText' : `something went wrong when writing to database`,
             'payload': {
               'google': {
                 'userStorage': userStorage
               }
             }
                });
            }))

        break;
      }
        case 'countFeedbacks':{

          var docRef = firestore.collection('users').doc(userId);

          docRef.get().then(doc => {
              if (doc.exists) {
                  // console.log("Document data:", doc.data());
                  var dat = doc.data();
                  response.send({
                    'fulfillmentText' : `You have given feedback for ${dat.resortLocation} and rating as ${dat.rating}`,
                    'payload': {
                      'google': {
                        'userStorage': userStorage
                      }
                    }
                  });

              } else {
                  // doc.data() will be undefined in this case
                  console.log("No such document!");

                  response.send({
                    'fulfillmentText' : `No feedback found in our database`,
                    'payload': {
                      'google': {
                        'userStorage': userStorage
                      }
                    }
                  });

              }
              return console.log("userStorage_then_wala", userStorage);
          }).catch((e => {
              console.log("Error getting document:", error);
              response.send({
                'fulfillmentText' : `something went wrong while reading from the database`,
                'payload': {
                  'google': {
                    'userStorage': userStorage
                  }
                }
              })
          }));

          break;
        }

根据您的具体需要,您有多种选择。

简单:userStorage

Google提供了一个userStorage object which is persisted across conversations when it can identify a user。这使您可以在需要跟踪用户 returns.

时存储自己的标识符

最简单的方法是在调用 webhook 时检查 userStorage 对象的标识符。如果它不存在,请使用诸如 v4 UUID 之类的东西创建一个并将其保存在 userStorage 对象中。

如果您使用的是 actions-on-google 库,代码可能如下所示:

let userId;
// if a value for userID exists un user storage, it's a returning user so we can
// just read the value and use it. If a value for userId does not exist in user storage,
// it's a new user, so we need to generate a new ID and save it in user storage.
if (userId in conv.user.storage) {
  userId = conv.user.storage.userId;
} else {
  // Uses the "uuid" package. You can get this with "npm install --save uuid"
  var uuid = require('uuid/v4');
  userId = uuid();
  conv.user.storage.userId = userId
}

如果您使用的是 dialogflow 库,则可以使用上面的内容,但您首先需要这一行:

let conv = agent.conv();

如果您使用的是 multivocal 库,它会为您完成上述所有操作,并将在路径 User/Id.

下的环境中提供一个 UserID

如果您直接处理 JSON,并且您使用的是 Dialogflow v2 协议,则可以通过检查 JSON 请求对象中的 originalDetectIntentRequest.payload.user.userStorage 来获取 userStorage 对象。您将在 JSON 响应中设置 payload.google.userStorage 对象。代码与上面类似,可能看起来像这样:

let userStorage = body.originalDetectIntentRequest.payload.user.userStorage || {};
let userId;
// if a value for userID exists un user storage, it's a returning user so we can
// just read the value and use it. If a value for userId does not exist in user storage,
// it's a new user, so we need to generate a new ID and save it in user storage.
if (userId in userStorage) {
  userId = userStorage.userId;
} else {
  // Uses the "uuid" package. You can get this with "npm install --save uuid"
  var uuid = require('uuid/v4');
  userId = uuid();
  userStorage.userId = userId
}

// ... Do stuff with the userID

// Make sure you include the userStorage as part of the response
var responseBody = {
  payload: {
    google: {
      userStorage: JSON.stringify(userStorage),
      // ...
    }
  }
};

注意代码的第一行 - 如果 userStorage 不存在,则使用空对象。在您第一次发送包含在其中存储内容的响应之前,它不会存在,这将发生在这段代码的最后几行中。

高级:帐户链接

您可以请求用户sign in to your Action using Google Sign In。这可以在最简单的情况下使用语音来完成,并且只会在第一次中断流程。

在此之后,您的 Action 将获得一个 JWT,其中包含它们的 Google ID,您可以将其用作它们的标识符。

如果您使用的是 actions-on-google 库,您可以使用以下行从解码的 JWT 中获取 ID:

const userId = conv.user.profile.payload.sub;

在 multivocal 库中,来自解码 JWT 的 ID 在路径 User/Profile/sub

下的环境中可用

已弃用:匿名用户 ID

您会在 Whosebug 上看到一些引用匿名用户 ID 的答案。 Google 已弃用此标识符,这并非始终是验证返回用户的可靠方法,并将于 2019 年 6 月 1 日将其删除。

目前仍在发送此代码,但将从 2019 年 6 月 1 日起删除。