我正在Facebook Messenger中创建一个聊天机器人。我显然希望聊天机器人能够支持多个用户。用户首次访问聊天机器人时,应该创建一个用户帐户。创建用户帐户的过程如下:
这是当任何用户与聊天机器人进行交互时正常发生的事情:
问题是,这种情况没有发生。当多个用户尝试同时设置其个人资料时,将会发生以下情况(假设有两个用户-“用户A”和“用户B”:
对于人A:
聊天机器人获得用户的名字,并说“你好(A人)”,并说明他们需要创建用户个人资料。
然后,聊天机器人会询问用户他们想要被叫什么。它提供的选项是(人B)或“其他”。
无论用户选择什么,他们都无法继续前进,因为聊天机器人不断重复第二阶段。
所以,我的代码:
用户数据存储在名为user.js
的文件中的“数据”对象中:
data: {
fbID: undefined, // senderID (user's Facebook PSID)
firstName: undefined, // User's first name (only used during user profile creation)
userID: undefined, // User ID (i.e. first name or nickname)
gender: undefined, // Gender
age: undefined, // Age
}
User.js还包含用于重新加载用户的“重新加载”功能。稍后您将了解其工作原理:
reload: function(data) {
self.data.fbID = data.fbid; /** @namespace data.fbid */
self.data.userID = data.userid; /** @namespace data.userid */
self.data.gender = data.gender; /** @namespace data.gender */
self.data.age = data.age; /** @namespace data.age */
console.log("Profile reloaded for user '%s'.", self.data.fbID);
},
当用户向聊天机器人发送消息时,这会触发app.js
内的webhook事件:
// Accept POST requests to webhook
app.post('/webhook/', function (req, res) {
// Parse the request body from the POST
let body = req.body;
// Check the webhook event is from a Page subscription
if (body.object === 'page') {
body.entry.forEach(function(entry) { /** @namespace body.entry */
// Gets the body of the webhook event
let webhookEvent = entry.messaging[0]; /** @param entry.messaging[] */
// Get sender ID
let senderID = webhookEvent.sender.id;
// Set session ID
session.set(senderID);
// Handle webhook event
handler.handleWebhookEvent(senderID, webhookEvent);
});
// Return a '200 OK' response to all events
res.status(200).send('EVENT_RECEIVED');
} else {
// Return a '404 Not Found' if event is not from a page subscription
res.sendStatus(404);
}
});
webhook事件传递到handler.js
,由handleWebhookEvent
函数处理:
handleWebhookEvent: function(senderID, webhookEvent) {
let greetingText, delay;
let handleEvent = function() {
/**
* @param webhookEvent
* @param webhookEvent.message
* @param webhookEvent.optin
* @param webhookEvent.delivery
* @param webhookEvent.postback
* @param webhookEvent.read
* @param webhookEvent.account_linking
* */
if (webhookEvent.optin) {
handleOptIn(webhookEvent);
} else if (webhookEvent.message) {
handleMessage(senderID, webhookEvent.message);
} else if (webhookEvent.delivery) {
handleDelivery(webhookEvent);
} else if (webhookEvent.postback) {
handlePostback(senderID, webhookEvent.postback);
} else if (webhookEvent.read) {
handleRead(webhookEvent);
} else if (webhookEvent.account_linking) {
handleAccountLink(senderID, webhookEvent.account_linking);
} else {
console.log("Webhook received unknown event: ", webhookEvent);
}
};
if (common.isDefined(user.data.fbID) && user.data.fbID === senderID) {
// User is loaded - handle events as normal
console.log("User '%s' is loaded.", senderID);
//logging.logEvent(senderID, webhookEvent, function() {
handleEvent();
//});
} else { // User is not loaded
getUser(senderID, function(result) { // First try and load user
if (common.isDefined(result)) { // Result returned
user.reload(result);
//logging.logEvent(senderID, webhookEvent, function() {
handleEvent();
//});
} else {
// User was not found in database. We need to
create a new profile for the user
common.getFBUser(senderID, function(name) {
console.log("User '%s' was not found in database.", senderID);
user.data.fbID = senderID;
user.data.firstName = name; // Stores user's first name
in the user object
greetingText = strings.initialGreeting.replace("%USER",
user.data.firstName);
delay = common.setDelay(greetingText);
messaging.sendTextMessage(senderID, greetingText);
setTimeout(function() {
// Pause before kicking off the 'uprofile' intent
dialogflow.sendRequest(session.getIDs(), senderID,
strings.createUser);
}, delay);
});
}
});
}
}
我认为这里的问题是我认为通过使用user.js
中的一个对象,聊天机器人将只创建该对象的多个实例,每个用户一个。显然我弄错了。创建多个实例并防止多个用户共享用户数据对象的最佳方法是什么?还是我应该完全放弃对象,而每次都只是从数据库中读取?我想避免这样做,因为这需要大量的读/写操作。
答案 0 :(得分:0)
好的,所以我最终使用了Map()
。
我的user.js
文件现在包含以下内容:
loadedUsers: new Map()
当我想创建一个新用户(数据库中不存在该用户)时,我使用以下对象:
newUser: {
firstName: undefined,
userID: undefined,
gender: undefined,
age: undefined,
},
当我想重新加载现有用户时,我使用以下对象:
user: {
userID: undefined,
gender: undefined,
age: undefined,
},
我使用add()
和addNewUser()
函数在地图上创建用户:
add: function(senderID, data) {
self.loadedUsers.set(senderID, self.user);
self.setProperty(senderID, 1, data.userid); /**@namespace data.userid */
self.setProperty(senderID, 2, data.gender);
self.setProperty(senderID, 3, data.age);
console.log ("User '%s' added to map", senderID);
},
addNewUser: function(senderID, name) {
self.loadedUsers.set(senderID, self.newUser);
self.setProperty(senderID, 0, name);
console.log("New User '%s' created", senderID);
},
如果要设置用户属性,请使用setter函数:
setProperty: function(senderID, property, value) {
switch (property) {
case 0: {
// First Name
self.loadedUsers.get(senderID).firstName = value;
break;
} case 1: {
// UserID
self.loadedUsers.get(senderID).userID = value;
break;
} case 2: {
// Gender
self.loadedUsers.get(senderID).gender = value;
break;
} case 3: {
// Age
self.loadedUsers.get(senderID).age = value
}
}
},
我使用getter函数获取属性:
getProperty: function(senderID, property) {
switch (property) {
case 0: {
// First Name
return self.loadedUsers.get(senderID).firstName;
} case 1: {
// UserID
return self.loadedUsers.get(senderID).userID;
} case 2: {
// Gender
return self.loadedUsers.get(senderID).gender;
} case 3: {
// Age
return self.loadedUsers.get(senderID).age
}
}
},
最后,如果要查看是否已加载用户(在尝试从数据库读取之前),请使用以下方法:
isLoaded(senderID) {
return self.loadedUsers.has(senderID);
},