【问题标题】:Log the conversation to Azure CosmosDB with nodejs使用 nodejs 将对话记录到 Azure CosmosDB
【发布时间】:2019-12-09 10:17:19
【问题描述】:

我们正在尝试保存对话以用于分析目的,并且由于我们使用 CosmosDB 来存储用户和对话状态,因此我们也希望在其中记录对话。

我已经能够找到使用 BlobStorage 的方法,但这对我们来说是不可能的。

我们可以遵循/使用任何方式或实现来登录 CosmosDB?

谢谢

【问题讨论】:

    标签: node.js botframework


    【解决方案1】:

    我创建了一个自定义记录器来执行此操作。这是通过 TranscriptLoggerMiddleware(botbuilderlibrary 的一部分)在 index.js 中实现的。这里对 index.js 的主要补充是:

    const { TranscriptLoggerMiddleware } = require('botbuilder')
    const { CustomLogger } = require('./helpers/CustomLogger');
    
    const logger = new TranscriptLoggerMiddleware(new CustomLogger());
    adapter.use(logger);
    

    对于记录器本身,由于请求/响应的速度,我们发现通常只有一部分对话被记录下来。所以我们创建了一个for循环延迟函数。我尝试了其他方法,例如等待承诺,但并没有解决问题。添加延迟后,这已经坚如磐石。这是完整的自定义记录器代码:

    // Copyright (c) Microsoft Corporation. All rights reserved.
    // Licensed under the MIT License.
    
    const { CosmosDbStorage } = require('botbuilder-azure');
    
    class CustomLogger {
    
        // Set up Cosmos Storage
        constructor() {
            this.transcriptStorage = new CosmosDbStorage({
                serviceEndpoint: process.env.ACTUAL_SERVICE_ENDPOINT,
                authKey: process.env.ACTUAL_AUTH_KEY,
                databaseId: process.env.DATABASE,
                collectionId: 'bot-transcripts'
            });
    
            this.conversationLogger = {};
    
            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') {
    
                // Check if activity contains a card
                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);
    
                    // Prep object for CosmosDB logging
                    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);
    
                    // Write to CosmosDB
                    try {
                        let result = await this.transcriptStorage.write(updateObj);
                        console.log(`Transcript written successfully to DB\n\n`);
                    } catch(err) {
                        console.log(`There was an error writing the transcript to DB`);
                        console.log(err);
                    }
                }
            }
        }
        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;
    

    【讨论】:

    • 尽管您的示例很有帮助,但当机器人更新或重新启动时,我发现该记录器存在一些并发和覆盖问题,这不是我们想要发生的事情。如果我能够形成更完整的解决方案,我会回复你。感谢您的回复。
    • 这很有趣...我在添加延迟功能后没有任何问题。您是否在更新代码(或只是重新启动服务)时重新启动服务后遇到问题,或者是否有其他原因导致这些重新启动?您可以尝试增加延迟计时器。我不知道为什么这会起作用,但它为我解决了并发问题。我将它减少到对我来说仍然有效的最低延迟,但对于您的设置来说,这个数字可能更高。
    • 重现是一个相当复杂的问题,但是在重新启动的情况下,并且用户继续与机器人的新实例进行先前的对话,该对话的日志也将被覆盖延迟工作对我们不起作用,因为响应时间可能因位置和请求数量而异。
    猜你喜欢
    • 2019-07-22
    • 1970-01-01
    • 2019-05-17
    • 1970-01-01
    • 2019-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多