首页 > 解决方案 > 如何使用 dialogflow Fulfillment Inline Editor 将用户名和心情保存在实时数据库中?

问题描述

我使用 dialogflow 在 google 上构建操作以进行体验采样。它的想法是:它每天 3 次询问特定用户的心情。在研究人员分析之后,它会每周向这些用户发送一份关于他们情绪的每周概览。

因此,我需要将每个用户信息与他的情绪条目一起保存在数据库中,以便研究人员以后可以访问、分析并发送回用户。

我正在使用带有 index.js 的对话流实现来连接到 Firebase 数据库以保存条目。该代理应作为对 google 的操作进行集成

在数据库中,我得到了用户名和心情,但它们彼此不相关,所以我不知道哪个用户输入了哪种心情,而且我也无法进行用户 ID 检查。

如果有人可以帮助我完成这些功能,我将不胜感激,因为我完全不熟悉 node.js 或数据库,但我必须这样做。

这是我的代码。

// See https://github.com/dialogflow/dialogflow-fulfillment-nodejs
// for Dialogflow fulfillment library docs, samples, and to report issues
'use strict';
 
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card, Suggestion} = require('dialogflow-fulfillment');
 
 
 //initialise DB connection
 const admin = require('firebase-admin');
 admin.initializeApp();
 
 
process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements
 
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
  const agent = new WebhookClient({ request, response });
  console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
  console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
 
   function saveName(agent) {
       const nameParam = agent.parameters.name;
       const context = agent.getContext('awaiting_name_confirm');
       const name = nameParam || context.parameters.name;
       agent.add('Hi ' + name + ' Are you ready to answer my question?' || 'Hi' + name + 'Have you got a moment for me? '  );
       //agent.add('Hi' + name + 'Have you got a minute for me? ');
       
       return admin.database().ref('/names').push({name: name}).then((snapshot)=>
       {
       
           console.log('database write sucessful: ' + snapshot.ref.toString());
       });
   }
 
  function saveMood(agent) {
       const moodParam = agent.parameters.mood;
       const mood = moodParam; 
       
       agent.add('That is good! keep it up. Thanks for sharing with me! Bye ');
       //agent.add('Hi' + name + 'Have you got a minute for me? ');
       
       return admin.database().ref('/moods').push({mood: mood}).then((snapshot)=>
       {
       
           console.log('database write sucessful: ' + snapshot.ref.toString());
       });
  }
   
  // Run the proper function handler based on the matched Dialogflow intent name
  let intentMap = new Map();
  intentMap.set('Get Name', saveName);
  intentMap.set('Confirm Name Yes', saveName);
  // intentMap.set('Confirm Name Yes', getName);
  intentMap.set('attentiveness', saveMood);

  agent.handleRequest(intentMap);
});

标签: firebasefirebase-realtime-databasedialogflow-esfulfillment

解决方案


您的代码和方法中有一些问题需要解决:

  • 您需要设计您的数据库,以便您可以将用户的心情与他们的帐户相关联。(可能还有其他用户信息,例如他们的姓名或电子邮件地址,而您正在使用它。)
  • 您需要此人的唯一身份。
    • 一个人的名字不是唯一的身份。两个人可能有相同的名字,或者系统每次听到的名字都不同,所以你需要有办法知道你在和谁说话。
    • 您还需要知道他们的电子邮件地址和可能的其他信息,以便您可以在周末向他们发送报告。
  • 您需要确保在同一对话期间对您的操作的调用之间具有他们的身份。

幸运的是,您做了一件通常会错过的事情——使用 Promises 调用数据库。所以那部分有效。

唯一身份

您的示例代码向用户询问他们的姓名,听起来您打算将其用作他们的身份。不幸的是,这是一个坏主意,原因如下:

  • 名字不是身份。如果两个同名的人访问您的操作会怎样?

  • 名称很容易被发现,因此其他人可以使用它并报告误导性信息。在您的情况下,这可能不是太严重,但它仍然可能具有可信度影响。

  • 姓名可以是个人身份信息 (PII),因此可能受到其他隐私法的保护。

  • 用户可能想要终止他们的帐户,并且如果不“更改”他们的名字就无法做到这一点。

此外,您以后可能需要其他身份信息,例如他们的电子邮件地址,并且每次都要求提供这些信息可能会很麻烦。

你有几种方法可以解决这个问题:

  • 如果您正在为 Google Assistant 开发,您还可以使用Google Sign In for Assistant,它会告诉您用户的 Google 标识符,您可以将其用作唯一 ID。您还可以将他们的电子邮件地址和姓名作为他们个人资料的一部分。

  • 您可以询问此信息(姓名、电子邮件等)并将其保存在您生成的用户 ID 或用户提供的用户名中。此 ID 成为标识符。如果您正在为 Google 助理进行开发,您可以将此 ID 保存在用户的私人存储空间中 - 只有您和用户才能访问或删除它。如果没有,您可能需要使用数据库来查找 ID。稍后再谈。

  • 您可能希望在稍后使用变体,具体取决于您获得的信息以及您希望用户每次如何识别自己。但重要的是,他们需要用一些独特的东西来识别自己,并且你可以轻松地捕捉到这些东西。

在同一会话中使用身份

如果您使用的是 Google 登录,则不必担心这一点。您将在每次会话和会话期间的每次呼叫中获得相同的 ID。

如果您将用户的私人存储与 Google 助理一起使用,您将把它作为 userStore 对象的一部分。

但如果不是,则需要确保在早期意图中获取用户 ID,并将其保存为Context的一部分,以便在调用 webhook 之间保留它。在后续处理程序中,您可以从上下文中获取 ID,然后使用它来访问其他信息。

此时您不需要将其存储在数据库中。您所拥有的只是一个标识符 - 这将成为您将用于其他信息的密钥。你只需要记住它,以便在以后的对话中使用。

所以在你的saveName()函数中,它可能看起来像

   function saveName(agent) {
       const nameParam = agent.parameters.name;
       agent.add('Hi ' + nameParam + ' Are you ready to answer my question?');
       agent.setContext({
         name: 'user',
         lifespan: 99,
         parameters: {
           id: nameParam
         }
       };
   }

顺便说一句 - 您的处理程序似乎试图确定这是用户说出他们的名字还是确认他们的名字。这可能作为单独的意图和单独的处理程序更好地处理。试图将它们结合起来会使事情变得混乱。

构建和访问您的数据库

我们有身份证。我们让用户报告数据。我们如何将两者联系起来?

有很多方法可以构建数据,Firebase 会根据您打算如何使用、访问它以及将其提供给用户或其他人的方式来详细介绍。

在这种情况下,您想要存储有关用户的记录似乎很简单。每条记录都可以使用他们的 ID 作为键,然后包含有关用户的一些信息,包括他们的心情。

Firebase 数据库的一个优点是您可以(大部分)将其视为 Javascript 对象。如果我们这样想,它可能看起来像

{
  "user": {
    "id1":{...},
    "id2":{...},
    "id3":{
       "moods": [
         {"mood":"good"},
         {"mood":"tired"}
       ]
    },
    "id4":{...}
  }
}

等等。使用 Firebase,我们将使用诸如user/id3/moods. 如果我们在变量中有用户标识name,我们可以使用以下代码来获取该引用

var ref = admin.database().ref('user').ref(name).ref('moods');

然后使用这样的代码将带有心情的对象推送到数组上(并返回我们需要做的 Promise):

var obj = {
  mood: mood
};
return ref.push( obj ).then( snapshot => {
  // Do stuff, including acknowledge to the user you saved it.
});

请记住,您可能还希望使用它在用户级别存储有关每个用户的更多信息(例如他们的姓名或电子邮件),或者在心情对象中存储有关心情(例如时间戳)的更多信息。


推荐阅读