有没有什么方法可以使用 SDK V4 Nodedjs 在 bot 框架中捕获端到端对话数据并将其保存到 blob 存储或 cosmos DB 中
Is there any way to capture and save end-to-end conversation data into blob storage or cosmos DB in bot framework using SDK V4 Nodedjs
我想将对话数据存储到存储账户或cosmos DB。通过尝试这个 https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-howto-v4-storage?view=azure-bot-service-4.0&tabs=javascript#using-blob-storage
我能够将话语日志发送到 blob 存储中。但是我想存储端到端的对话数据,其中包括两个用户的数据以及使用 javascript.
的机器人响应
我尝试使用保存用户状态和对话状态,但没有达到预期的输出。
我创建了一个自定义记录器(基于不再存在的旧 botduilder-samples 示例),它使用 TranscriptLoggerMiddleware 完成此操作。我选择 CosmosDB 而不是 Blob 存储,因为我觉得它更容易存储(和检索)为 JSON 文档。但是您可以调整这个概念以使用任何数据库。这是我所做的。
首先,创建您的自定义记录器代码。如前所述,我使用的是 CosmosDB,因此如果您使用的是不同的数据库,则可能需要更改一些内容。这些活动的时间安排造成了并发问题,因此我没有解决这个问题,而是在本地存储转录对象,并在每个回合 覆盖 DB 对象。也许不是最优雅的,但它确实有效。此外,我发现我的等待函数是 必需的 。否则你只能站在谈话的一边。我被告知这种类型的等待功能不是最佳实践,但等待承诺或其他创建延迟的方法对我不起作用。这是代码:
customerLogger.js
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
const { CosmosDbStorage } = require('botbuilder-azure');
const path = require('path');
/**
* CustomLogger, takes in an activity and saves it for the duration of the conversation, writing to an emulator compatible transcript file in the transcriptsPath folder.
*/
class CustomLogger {
/**
* Log an activity to the log file.
* @param activity Activity being logged.
*/
// Set up Cosmos Storage
constructor(appInsightsClient) {
this.transcriptStorage = new CosmosDbStorage({
serviceEndpoint: process.env.COSMOS_SERVICE_ENDPOINT,
authKey: process.env.COSMOS_AUTH_KEY,
databaseId: process.env.DATABASE,
collectionId: 'bot-transcripts'
});
this.conversationLogger = {};
this.appInsightsClient = appInsightsClient;
this.msDelay = 250;
}
async logActivity(activity) {
if (!activity) {
throw new Error('Activity is required.');
}
// Log only if this is type message
if (activity.type === 'message') {
if (activity.attachments) {
var logTextDb = `${activity.from.name}: ${activity.attachments[0].content.text}`;
} else {
var logTextDb = `${activity.from.name}: ${activity.text}`;
}
if (activity.conversation) {
var id = activity.conversation.id;
if (id.indexOf('|') !== -1) {
id = activity.conversation.id.replace(/\|.*/, '');
}
// Get today's date for datestamp
var currentDate = new Date();
var day = currentDate.getDate();
var month = currentDate.getMonth()+1;
var year = currentDate.getFullYear();
var datestamp = year + '-' + month + '-' + day;
var fileName = `${datestamp}_${id}`;
var timestamp = Math.floor(Date.now()/1);
// CosmosDB logging (JK)
if (!(fileName in this.conversationLogger)) {
this.conversationLogger[fileName] = {};
this.conversationLogger[fileName]['botName'] = process.env.BOTNAME;
}
this.conversationLogger[fileName][timestamp] = logTextDb;
let updateObj = {
[fileName]:{
...this.conversationLogger[fileName]
}
}
// Add delay to ensure messages logged sequentially
await this.wait(this.msDelay);
try {
let result = await this.transcriptStorage.write(updateObj);
} catch(err) {
this.appInsightsClient.trackTrace({message: `Logger ${err.name} - ${path.basename(__filename)}`,severity: 3,properties: {'botName': process.env.BOTNAME, 'error':err.message,'callStack':err.stack}});
}
}
}
}
async wait(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds) {
break;
}
}
}
}
exports.CustomLogger = CustomLogger;
现在您需要将其附加到 index.js 文件中的 botframework 适配器。相关代码为:
index.js
const { TranscriptLoggerMiddleware } = require('botbuilder');
const { CustomLogger } = require('./helpers/CustomLogger');
//
//Your code to create your adapter, etc.
//
const transcriptLogger = new TranscriptLoggerMiddleware(new CustomLogger(appInsightsClient));
adapter.use(transcriptLogger);
我在这里假设您已经弄清楚了 index.js 文件,但是如果您需要任何帮助来设置它并让转录记录器使用它,请告诉我。
编辑:根据要求,这是对象在 CosmosDB 中的样子。通常我会显示 "from name",但由于我测试机器人的方式,它通过 "undefined".
{
"id": "2020-3-21_IfHK46rZV42KH5g3dIUgKu-j",
"realId": "2020-3-21_IfHK46rZV42KH5g3dIUgKu-j",
"document": {
"botName": "itInnovationBot",
"1584797671549": "Innovation Bot: Hi! I'm the IT Innovation Bot. I can answer questions about the innovation team and capture your innovation ideas. Let me know how I can help!",
"1584797692355": "undefined: Hello",
"1584797692623": "Innovation Bot: Hello.",
"1584797725223": "undefined: Tell me about my team",
"1584797725490": "Innovation Bot: The innovation team is responsible for investigating, incubating, and launching new technologies and applications. The innovation focus areas are:\n\n* Chatbots\n\n* Augmented Reality/Virtual Reality\n\n* Blockchain\n\n* Robotic Process Automation\n\n* AI & Machine Learning\n\nLet me know if you want to learn more about any of these technologies!",
"1584797746279": "undefined: Thanks",
"1584797746531": "Innovation Bot: You're welcome."
},
"_rid": "OsYpALLrTn2TAwAAAAAAAA==",
"_self": "dbs/OsYpAA==/colls/OsYpALLrTn0=/docs/OsYpALLrTn2TAwAAAAAAAA==/",
"_etag": "\"a4008d12-0000-0300-0000-5e7618330000\"",
"_attachments": "attachments/",
"_ts": 1584797747
}
要回读对话(即使仍在对话中间),您只需在机器人中创建一个连接器,重新创建密钥,然后读取文件下面(在这种情况下,id 被传递到我的函数中,并且是对话 id):
const transcriptStorage = new CosmosDbStorage({
serviceEndpoint: process.env.COSMOS_SERVICE_ENDPOINT,
authKey: process.env.COSMOS_AUTH_KEY,
databaseId: process.env.DATABASE,
collectionId: 'bot-transcripts',
partitionKey: process.env.BOTNAME
});
// Get today's date for datestamp
var currentDate = new Date();
var day = currentDate.getDate();
var month = currentDate.getMonth()+1;
var year = currentDate.getFullYear();
var datestamp = year + '-' + month + '-' + day;
var filename = `${datestamp}_${id}`;
var transcript = await transcriptStorage.read([filename]);
我想将对话数据存储到存储账户或cosmos DB。通过尝试这个 https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-howto-v4-storage?view=azure-bot-service-4.0&tabs=javascript#using-blob-storage
我能够将话语日志发送到 blob 存储中。但是我想存储端到端的对话数据,其中包括两个用户的数据以及使用 javascript.
的机器人响应我尝试使用保存用户状态和对话状态,但没有达到预期的输出。
我创建了一个自定义记录器(基于不再存在的旧 botduilder-samples 示例),它使用 TranscriptLoggerMiddleware 完成此操作。我选择 CosmosDB 而不是 Blob 存储,因为我觉得它更容易存储(和检索)为 JSON 文档。但是您可以调整这个概念以使用任何数据库。这是我所做的。
首先,创建您的自定义记录器代码。如前所述,我使用的是 CosmosDB,因此如果您使用的是不同的数据库,则可能需要更改一些内容。这些活动的时间安排造成了并发问题,因此我没有解决这个问题,而是在本地存储转录对象,并在每个回合 覆盖 DB 对象。也许不是最优雅的,但它确实有效。此外,我发现我的等待函数是 必需的 。否则你只能站在谈话的一边。我被告知这种类型的等待功能不是最佳实践,但等待承诺或其他创建延迟的方法对我不起作用。这是代码:
customerLogger.js
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
const { CosmosDbStorage } = require('botbuilder-azure');
const path = require('path');
/**
* CustomLogger, takes in an activity and saves it for the duration of the conversation, writing to an emulator compatible transcript file in the transcriptsPath folder.
*/
class CustomLogger {
/**
* Log an activity to the log file.
* @param activity Activity being logged.
*/
// Set up Cosmos Storage
constructor(appInsightsClient) {
this.transcriptStorage = new CosmosDbStorage({
serviceEndpoint: process.env.COSMOS_SERVICE_ENDPOINT,
authKey: process.env.COSMOS_AUTH_KEY,
databaseId: process.env.DATABASE,
collectionId: 'bot-transcripts'
});
this.conversationLogger = {};
this.appInsightsClient = appInsightsClient;
this.msDelay = 250;
}
async logActivity(activity) {
if (!activity) {
throw new Error('Activity is required.');
}
// Log only if this is type message
if (activity.type === 'message') {
if (activity.attachments) {
var logTextDb = `${activity.from.name}: ${activity.attachments[0].content.text}`;
} else {
var logTextDb = `${activity.from.name}: ${activity.text}`;
}
if (activity.conversation) {
var id = activity.conversation.id;
if (id.indexOf('|') !== -1) {
id = activity.conversation.id.replace(/\|.*/, '');
}
// Get today's date for datestamp
var currentDate = new Date();
var day = currentDate.getDate();
var month = currentDate.getMonth()+1;
var year = currentDate.getFullYear();
var datestamp = year + '-' + month + '-' + day;
var fileName = `${datestamp}_${id}`;
var timestamp = Math.floor(Date.now()/1);
// CosmosDB logging (JK)
if (!(fileName in this.conversationLogger)) {
this.conversationLogger[fileName] = {};
this.conversationLogger[fileName]['botName'] = process.env.BOTNAME;
}
this.conversationLogger[fileName][timestamp] = logTextDb;
let updateObj = {
[fileName]:{
...this.conversationLogger[fileName]
}
}
// Add delay to ensure messages logged sequentially
await this.wait(this.msDelay);
try {
let result = await this.transcriptStorage.write(updateObj);
} catch(err) {
this.appInsightsClient.trackTrace({message: `Logger ${err.name} - ${path.basename(__filename)}`,severity: 3,properties: {'botName': process.env.BOTNAME, 'error':err.message,'callStack':err.stack}});
}
}
}
}
async wait(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds) {
break;
}
}
}
}
exports.CustomLogger = CustomLogger;
现在您需要将其附加到 index.js 文件中的 botframework 适配器。相关代码为:
index.js
const { TranscriptLoggerMiddleware } = require('botbuilder');
const { CustomLogger } = require('./helpers/CustomLogger');
//
//Your code to create your adapter, etc.
//
const transcriptLogger = new TranscriptLoggerMiddleware(new CustomLogger(appInsightsClient));
adapter.use(transcriptLogger);
我在这里假设您已经弄清楚了 index.js 文件,但是如果您需要任何帮助来设置它并让转录记录器使用它,请告诉我。
编辑:根据要求,这是对象在 CosmosDB 中的样子。通常我会显示 "from name",但由于我测试机器人的方式,它通过 "undefined".
{
"id": "2020-3-21_IfHK46rZV42KH5g3dIUgKu-j",
"realId": "2020-3-21_IfHK46rZV42KH5g3dIUgKu-j",
"document": {
"botName": "itInnovationBot",
"1584797671549": "Innovation Bot: Hi! I'm the IT Innovation Bot. I can answer questions about the innovation team and capture your innovation ideas. Let me know how I can help!",
"1584797692355": "undefined: Hello",
"1584797692623": "Innovation Bot: Hello.",
"1584797725223": "undefined: Tell me about my team",
"1584797725490": "Innovation Bot: The innovation team is responsible for investigating, incubating, and launching new technologies and applications. The innovation focus areas are:\n\n* Chatbots\n\n* Augmented Reality/Virtual Reality\n\n* Blockchain\n\n* Robotic Process Automation\n\n* AI & Machine Learning\n\nLet me know if you want to learn more about any of these technologies!",
"1584797746279": "undefined: Thanks",
"1584797746531": "Innovation Bot: You're welcome."
},
"_rid": "OsYpALLrTn2TAwAAAAAAAA==",
"_self": "dbs/OsYpAA==/colls/OsYpALLrTn0=/docs/OsYpALLrTn2TAwAAAAAAAA==/",
"_etag": "\"a4008d12-0000-0300-0000-5e7618330000\"",
"_attachments": "attachments/",
"_ts": 1584797747
}
要回读对话(即使仍在对话中间),您只需在机器人中创建一个连接器,重新创建密钥,然后读取文件下面(在这种情况下,id 被传递到我的函数中,并且是对话 id):
const transcriptStorage = new CosmosDbStorage({
serviceEndpoint: process.env.COSMOS_SERVICE_ENDPOINT,
authKey: process.env.COSMOS_AUTH_KEY,
databaseId: process.env.DATABASE,
collectionId: 'bot-transcripts',
partitionKey: process.env.BOTNAME
});
// Get today's date for datestamp
var currentDate = new Date();
var day = currentDate.getDate();
var month = currentDate.getMonth()+1;
var year = currentDate.getFullYear();
var datestamp = year + '-' + month + '-' + day;
var filename = `${datestamp}_${id}`;
var transcript = await transcriptStorage.read([filename]);