我想在向用户发送主动消息时启动“提醒对话框”。对话框已发布。但在处理答案时,它会返回主对话框。
目前我创建的机器人如下:
const conversationState = new ConversationState(mongoStorage);
const userState = new UserState(memoryStorage);
const bot = new DialogAndWelcomeBot(conversationState, userState, logger);
// Listen for incoming activities and route them to your bot main dialog.
server.post("/api/messages", (req, res) => {
adapter.use(new GraphQLMiddleware(bot.getAuthState()));
// Route received a request to adapter for processing
adapter.processActivity(req, res, async turnContext => {
await bot.run(turnContext);
});
});
并发送这样的主动消息:
await adapter.createConversation(conversationReferenceAdapted, bot.remind);
其中DialogAndWelcomeBot
具有以下功能:
remind = async turnContext => {
const reminderDialog = new ReminderDialog(this.logger);
await reminderDialog.run(turnContext, this.dialogState);
await this.conversationState.saveChanges(turnContext, false);
await this.userState.saveChanges(turnContext, false);
};
但是,ReminderDialog 会正确触发(带有"is"和“否”按钮)。但是当我按下任何一个按钮时我得到:
[onTurnError]: Error: DialogContext.continue(): Can't continue dialog. A dialog with an id of 'ReminderDialog' wasn't found.
这让我怀疑它不知道原始流程中的ReminderDialog
(通过实例化MainDialog
的DialogAndWelcomeBot
的构造函数)并运行)。
关于如何解决这个问题有什么想法吗?
所需功能
我有一个询问有关用户的一些详细信息的主流程。可以通过向机器人发送任何短信来调用此流程。然后它会回复请求一些输入。
我尝试实现的流程是主要流程的替代流程。它应该与用户联系(例如每天)。因此,它应该开始一个(不同于主要的)对话,要求输入他运动的时间,然后确认。
简而言之:
主流程:用户输入 hi -> 机器人回复“你的年龄” -> 用户输入 28 -> 机器人回复“好的,谢谢”
主动流程:机器人询问用户“您今天运动了多长时间?” -> 用户输入 1 小时 -> 机器人回复“好的,1 小时正确吗?” -> 用户点击"is"按钮 -> 机器人回复“谢谢,明天见”
最佳答案
您将需要为此工作设置一个 cron 作业以及主动消息传递。幸运的是,您已经可以引用一些帖子来了解如何执行这两项操作。
cron 作业将允许您设置一天中执行主动消息的时间。此堆栈溢出post讨论如何创建一个可以与您的机器人一起运行的简单项目。或者,您也可以在 Azure Function 内运行 cron 作业。同样,它会按照设定的时间表调用您的主动消息 API。
关于主动消息,请查看此 Stack Overflow post这详细介绍了设置此服务。特定于该用户问题的某些要点不适用于您,可以忽略。这个sample BotBuilder-Samples 存储库中的内容也可以作为一个很好的引用点。
希望得到帮助!
<小时/>[编辑]
以下是调用 API 发送主动消息的基本设置,该消息还会启动特定的对话流。显然,您需要进行更改以满足您的需求,但这应该会让您走上正确的道路。
简而言之,会针对您的机器人公开的 API 进行调用,其中包含 conversationId
作为参数。当调用 API 时,会创建一个 conversationReference
并用于发送英雄卡。 Hero 卡会询问用户是否接受过训练(是/否),并在用户响应时发送 PostBack
。 PostBack 是通过中断方法在组件对话框中监视的触发器。当匹配成功后,“主动”对话框就会开始。当用户结束时,“主动”对话框将从堆栈中弹出,然后用户返回到对话停止的地方(如果他们在对话中)。
请注意,主动消息需要 token 和对话 ID。用户之前需要与机器人进行过对话,或者您需要事先通过机器人生成 token 和对话 ID,然后将其与用户的 Slack user.id
一起发送以开始。
索引.js
const conversationReferences = {};
const dialog = new MainDialog( 'MainDialog', userState, conversationState );
const bot = new WelcomeBot( conversationState, userState, dialog, conversationReferences );
server.post( '/api/message', async ( req, res ) => {
[...]
}
server.get( '/api/notify/:conversationID', async ( req, res ) => {
const { conversationID, query } = req.params;
const conversationReference = conversationReferences[ conversationID ];
await adapter.continueConversation( conversationReference, async turnContext => {
var reply = { type: ActivityTypes.Message };
const yesBtn = { type: ActionTypes.PostBack, title: 'Yes', value: 'Yes' };
const noBtn = { type: ActionTypes.PostBack, title: 'No', value: 'No' };
const card = CardFactory.heroCard(
'Have you trained today?',
null,
[ yesBtn, noBtn ]
);
reply.attachments = [ card ];
await turnContext.sendActivity( reply );
return { status: DialogTurnStatus.waiting };
} );
res.setHeader( 'Content-Type', 'text/html' );
res.writeHead( 200 );
res.write( '<html><body><h1>Proactive messages have been sent.</h1></body></html>' );
res.end();
} );
mainDialog.js
const { DialogSet } = require( 'botbuilder-dialogs' );
const { InterruptionDialog} = require( './interruptionDialog' );
const MAIN_WATERFALL_DIALOG = 'MainWaterfallDialog';
const ADAPTIVE_CARD = 'AdaptiveCard';
class MainDialog extends CancelAndHelpDialog {
constructor ( id, userState, conversationState ) {
this.mainId = id;
this.userState = userState;
this.conversationState = conversationState;
[...]
};
async run ( turnContext, accessor ) {
const dialogSet = new DialogSet( accessor );
this.id = this.mainId;
dialogSet.add( this );
const dialogContext = await dialogSet.createContext( turnContext );
const results = await dialogContext.continueDialog();
if ( results.status === DialogTurnStatus.empty ) {
return await dialogContext.beginDialog( this.id );
}
};
[...]
};
interruptionDialog.js
const { ProactiveDialog, PROACTIVE_DIALOG } = require( './proactiveDialog' );
class InterruptionDialog extends ComponentDialog {
constructor ( id ) {
super( id );
this.addDialog( new ConfirmPrompt( 'ConfirmPrompt' ) );
this.addDialog( new ProactiveDialog() );
}
async onBeginDialog ( innerDc, options ) {
const result = await this.interrupt( innerDc );
if ( result ) {
return result;
}
return await super.onBeginDialog( innerDc, options );
}
async onContinueDialog ( innerDc ) {
const result = await this.interrupt( innerDc );
if ( result ) {
return result;
}
return await super.onContinueDialog( innerDc );
}
async onEndDialog ( innerDc ) {
const result = await this.interrupt( innerDc );
if ( result ) {
return result;
}
return await super.onEndDialog( innerDc );
}
async interrupt ( innerDc, next ) {
if ( innerDc.context.activity.type === 'message' ) {
if ( activity.channelId === 'slack' && activity.channelData.Payload ) {
if ( activity.channelData.Payload.actions[ 0 ].name === 'postBack' ) {
return await innerDc.beginDialog( PROACTIVE_DIALOG );
}
}
}
}
}
module.exports.InterruptionDialog = InterruptionDialog;
proactiveDialog.js
const {
NumberPrompt,
ComponentDialog,
DialogTurnStatus,
WaterfallDialog
} = require( 'botbuilder-dialogs' );
const PROACTIVE_DIALOG = 'proactiveDialog';
const WATERFALL_DIALOG = 'WATERFALL_DIALOG';
const NUMBER_PROMPT = 'NUMBER_PROMPT';
class ProactiveDialog extends ComponentDialog {
constructor () {
super( PROACTIVE_DIALOG );
this.addDialog( new NumberPrompt( NUMBER_PROMPT ) );
this.addDialog( new WaterfallDialog( WATERFALL_DIALOG, [
this.didTrainStep.bind( this ),
this.trainingStep.bind( this )
] ) );
this.initialDialogId = WATERFALL_DIALOG;
}
async didTrainStep ( stepContext ) {
const activity = stepContext.context.activity;
const response = activity.channelData.Payload.actions[ 0 ].value.toLowerCase();
if ( response === 'yes' ) {
return await stepContext.prompt( NUMBER_PROMPT, 'Fantastic! How many minutes?' )
} else if ( response === 'no' ) {
await stepContext.context.sendActivity( 'Rubbish...serious rubbish.' )
}
return await stepContext.next();
}
async trainingStep ( stepContext ) {
const activity = stepContext.context.activity;
const stepResult = stepContext.result;
const textResponse = activity.text.toLowerCase();
if ( textResponse === 'no' ) {
await stepContext.context.sendActivity( "I would recommend at least 5-10 mins of training." )
} else
if ( typeof ( stepResult ) === 'number' && stepResult > 0 ) {
await stepContext.context.sendActivity( "I'll log that for you." );
} else if ( stepResult <= 0 ) {
await stepContext.context.sendActivity( "I can't log that value." )
}
return { status: DialogTurnStatus.complete }
}
}
module.exports.ProactiveDialog = ProactiveDialog;
module.exports.PROACTIVE_DIALOG = PROACTIVE_DIALOG;
关于javascript - 处理提醒对话框的答案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57715944/