我刚刚通过遵循此堆栈溢出答案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通道,所以我不确定如何找出导致这些错误的原因。
有人能指出我正确的方向吗?
答案 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的更多信息。
希望有帮助!