在Node.js和Bot框架V4.4中调试脚本记录中间件

时间:2019-07-27 19:06:10

标签: node.js debugging logging botframework middleware

我刚刚通过遵循此堆栈溢出答案here,将我的第一部分中间件添加到了聊天机器人中,用于记录脚本。

但是,该实现引发了一些错误,例如:

[onTurnError]: TypeError: this.logger.log is not a function
[onTurnError]: TypeError: Cannot read property 'role' of undefined
BotFrameworkAdapter.processActivity(): 500 ERROR - Error: BotFrameworkAdapter.sendActivity(): missing conversation id.

在我初始化会话并向用户发送第一条“ GET_STARTED”消息后,立即抛出这些错误。

与每个(简短!)对话的记录都发布到我的Azure Blob存储中的记录一起,记录记录工作正常。

但是,因为这是我第一次使用中间件,所以我不确定如何调试这些错误并使聊天机器人按预期工作。

用于记录脚本的onTurn函数与链接的示例非常相似,我刚刚在末尾添加了await next();

this.onTurn(async (turnContext, next) => {
// See https://aka.ms/about-bot-activity-message to learn more about the message and other activity types.
if (turnContext.activity.type === ActivityTypes.Message) {
   if (turnContext.activity.text === '!history') {
      // Retrieve the activities from the Transcript (blob store) and send them over to the channel when a request to upload history arrives. This could be an event or a special message activity as above.
      // Create the connector client to send transcript activities
      let connector = turnContext.adapter.createConnectorClient(turnContext.activity.serviceUrl);

      // Get all the message type activities from the Transcript.
      let continuationToken = '';
      var count = 0;

      // WebChat and Emulator require modifying the activity.Id to display the same activity again within the same chat window
      let updateActivities = [ 'webchat', 'emulator', 'directline' ].includes(turnContext.activity.channelId);
      let incrementId = 0;
      if (updateActivities && turnContext.activity.id.includes('|')) {
                    incrementId = parseInt(turnContext.activity.id.split('|')[1]) || 0;
      } do {
      // Transcript activities are retrieved in pages.  When the continuationToken is null, there are no more activities to be retireved for this conversation.
      var pagedTranscript = await this.transcriptStore.getTranscriptActivities(turnContext.activity.channelId, turnContext.activity.conversation.id, continuationToken);
      let activities = pagedTranscript.items.filter(item => item.type === ActivityTypes.Message);

         if (updateActivities) {
            activities.forEach(function(a) {
            incrementId++;
            a.id = `${ turnContext.activity.conversation.id }|${ incrementId.toString().padStart(7, '0') }`;
            a.timestamp = new Date().toISOString();
            a.channelData = []; // WebChat uses ChannelData for id comparisons, so we clear it here
            a.replyToId = '';
          });
         }

         // DirectLine only allows the upload of at most 500 activities at a time. The limit of 1500 below is arbitrary and up to the Bot author to decide.
         count += activities.length;
         if (activities.length > 500 || count > 1500) {
            throw new InvalidOperationException('Attempt to upload too many activities');
         }

         await connector.conversations.sendConversationHistory(turnContext.activity.conversation.id, { activities });
                    continuationToken = pagedTranscript.continuationToken;
         }
         while (continuationToken != null);

         console.log("Transcript sent");
         } else {
            // Echo back to the user whatever they typed.
            console.log(`User sent: ${ turnContext.activity.text }\n`);
         }
         } else if (turnContext.activity.type === ActivityTypes.ConversationUpdate) {
            // Send greeting when users are added to the conversation.
            console.log('Welcome Message');
         } else {
            // Generic message for all other activities
            console.log(`[${ turnContext.activity.type } event detected]`);
         }
     await next();
 });

下面也是我的onMessage函数:

this.onMessage(async (context, next) => {
     await sendTyping(context);
     this.logger.log('Processing a Message Activity');
     // await logMessageText(storageBlob, context);

     const qnaResults = await this.qnaMaker.getAnswers(context);

     // Show choices if the Facebook Payload from ChannelData is not handled
     if (!await fbBot.processFacebookPayload(context, context.activity.channelData)) {
         // detect if Facebook Messenger is the channel being used
         if (context.activity.channelId === 'facebook') {
             let facebookPayload = context.activity.channelData;
             let fbSender = facebookPayload.sender;
             var fbPSID = fbSender.id;
             if (qnaResults[0]) {
                 const { answer, context: { prompts } } = qnaResults[0];

                 // set a variable for the prompts array from QnA
                 var qnaPrompts = null;
                 if (qnaResults[0].context != null) {
                     qnaPrompts = qnaResults[0].context.prompts;
                 }

                 // map the prompts to the required format for quick_replies channelData
                 var qnaPromptsArray = qnaPrompts.map(obj => {
                     return { content_type: 'text', title: obj.displayText, payload: obj.displayText };
                 });

                 let reply;
                 if (prompts.length) {
                     const quickReply = {
                         channelData: {
                         text: answer,
                         quick_replies: qnaPromptsArray
                         }
                     };
                     reply = quickReply;
                 } else {
                     reply = {
                         channelData: {
                         text: answer
                         }
                     };
                 }

                 await context.sendActivity(reply);

             // If no answers were returned from QnA Maker, reply with help.
             } else {
                 let errorCardFB = await fbCards.getErrorCardFB(fbPSID);
                 await context.sendActivity(errorCardFB);
             }
         } else {
         // If an answer was received from QnA Maker, send the answer back to the user.
             if (qnaResults[0]) {
                 const { answer, context: { prompts } } = qnaResults[0];

                 let reply;
                 if (prompts.length) {
                     const card = {
                         'type': 'AdaptiveCard',
                         'body': [
                             {
                             'type': 'TextBlock',
                             'text': answer,
                              wrap: true
                             }
                         ],
                         'actions': prompts.map(({ displayText }) => ({ type: 'Action.Submit', title: displayText, data: displayText })),
                         '$schema': 'http://adaptivecards.io/schemas/adaptive-card.json',
                         'version': '1.1'
                     };

                 reply = { attachments: [CardFactory.adaptiveCard(card)] };
                 } else {
                     reply = answer;
                 }

                 await context.sendActivity(reply);

             // If no answers were returned from QnA Maker, reply with help.
             } else {
                 await context.sendActivity('I\'m sorry, I don\'t have an answer for that. Please ask me something else, such as: \n\n "What Is Mental Health?" \n\n "What Is NeuroDiversity" \n\n "Help"');
             }
         }
     }

     // By calling next() you ensure that the next BotHandler is run.
     await next();
 });

由于我不确定如何调试中间件,并且由于我将Facebook Messenger用作Chatbot通道,所以我不确定如何找出导致这些错误的原因。

有人能指出我正确的方向吗?

1 个答案:

答案 0 :(得分:0)

如果您打算将记录记录器用作中间件,则需要在index.js文件中实现它。中间件已附加到您的适配器上,并且不存在于“对话框”代码中。

您的代码应如下所示:

const {
  [...],
  ConsoleTranscriptLogger,
  TranscriptLoggerMiddleware,
  [...]
} = require( 'botbuilder' );

// The bot.
const { WelcomeBot } = require( './bots/welcomeBot' );
const { MainDialog } = require( './dialogs/mainDialog' );

const ENV_FILE = path.join( __dirname, '.env' );
require( 'dotenv' ).config( { path: ENV_FILE } );

// Create HTTP server
let server = restify.createServer();
server.listen( process.env.port || process.env.PORT || 3978, function () {
  console.log( `\n${ server.name } listening to ${ server.url }` );
} );

// configure middleware
const logstore = new ConsoleTranscriptLogger();
const logActivity = new TranscriptLoggerMiddleware( logstore );
[...other middleware...]

// Create adapter.
const adapter = new BotFrameworkAdapter( {
  appId: process.env.MicrosoftAppId,
  appPassword: process.env.MicrosoftAppPassword
} )
  .use( logActivity );

[...other bot code...]

这时,您应该很好。记录器将解析通过适配器传递的所有消息,并将其呈现在控制台中。

您可以阅读有关中间件here的更多信息。

希望有帮助!