嵌套对话框:消息被发送两次

时间:2017-04-07 20:33:08

标签: botframework luis

我有一个机器人,我正在做这样的事情:

1)新的活动(消息)到达。

2)我将消息发送到RootDialog。

3)根据某些逻辑,RootDialog可以:

 a) Call a LuisDialog (handling natural language)

 b) Call a CustomDialog (handles some business logic).

但是当重置用户状态,并且流程导致LuisDialog内部的意图时,它会调用意图方法两次。只是第一次状态为空,然后它才能正常工作。

让我告诉你代码:

MessagesController:

   public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
    {
        if (activity.Type == ActivityTypes.Message)
        {
            ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
            try
            {
                await Conversation.SendAsync(activity, () => new RootDialog());
            }
            catch (HttpRequestException e)
            {
             ...
            }
     }

RootDialog:

 public class RootDialog : IDialog<object>
 {
    public async Task StartAsync(IDialogContext context)
    {
        await MessageReceivedAsync(context, Awaitable.FromItem(context.Activity.AsMessageActivity()));
    }

    private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> awaitable)
    {
        bool value = DoSomeCustomLogic();
        if (value) 
        {
            string message = DoSomething();
            await context.PostAsync(message);
        } else {
            bool value2 = DoSomeCustomLogic2();
            if (value2) 
            {
                var answerValidationDialog = new ValidateAnswerWithUserDialog();
                context.Call(answerValidationDialog, ValidateAnswerWithUserDialogCompletedCallback);
            } else {
                var luisDialog = new LuisDialog();
                await context.Forward(luisDialog,LuisDialogCompletedCallback, context.Activity, CancellationToken.None);
            }
        }
    }

回调仅执行 context.Done(true);

LuisDialog的意图如下:

  [LuisIntent(LuisUtils.INTENT_MENU_SALUTE)]
    public async Task SaluteOrMenu(IDialogContext context, LuisResult result)
    {
        if (LuisUtils.IntentScoreIsHighEnough(result))
        {
            string userName = context.Activity.From.Name;
            ContextHelper helper = new ContextHelper(MessageReceived);
            await helper.AskUserToDoSomeInitialAction(context, saluteWord, userName);
            context.Done(true);
        }
        else
        {
            await None(context, result);
        }
    }

最后上课了ContextHelper:

public class ContextHelper
{
    private Func<IDialogContext, IAwaitable<IMessageActivity>, Task> MessageReceived;

    public ContextHelper(Func<IDialogContext, IAwaitable<IMessageActivity>, Task> messageReceived)
    {
        MessageReceived = messageReceived;
    }

    public async Task AskUserToDoSomeInitialAction(IDialogContext context, string saluteWord, string userName)
    {
        var reply = context.MakeMessage();
        List<CardAction> buttons = BuildInitialOptionActions();
        List<CardImage> images = BuildInitialOptionImages();
        string initialText = $"Hi stranger!"
        var card = new HeroCard
        {
            Title = "Hello!"
            Text = initialText,
            Buttons = buttons,
            Images = images
        };
        reply.Attachments = new List<Attachment> { card.ToAttachment() };
        await context.PostAsync(reply);
        context.Wait(AfterUserChoseOptionInSalute);
    }

    private async Task AfterUserChoseOptionInSalute(IDialogContext context, IAwaitable<IMessageActivity> result)
    {
        await ReDispatchMessageReceivedToDialog(context);
    }

    private async Task ReDispatchMessageReceivedToDialog(IDialogContext context)
    {
        await MessageReceived(context, Awaitable.FromItem(context.Activity.AsMessageActivity()));
    }

}

SaluteOrMenu意图被调用两次(仅在我第一次与机器人交互时或者当我删除状态时。调试后我看到在执行context.Wait(AfterUserChoseOptionInSalute);之后,机器人调用该函数(而不是等待事件称之为)

有什么想法吗?

提前致谢。

1 个答案:

答案 0 :(得分:3)

我发现这条线错了。它出现在第一个对话框(RootDialog)上:

public async Task StartAsync(IDialogContext context)
{
   await MessageReceivedAsync(context, Awaitable.FromItem(context.Activity.AsMessageActivity()));
}

这是一条重新调度带有传入活动的消息的行。我把它放在了一些代码中的某个地方(并且不知道为什么),认为在StartAsync上使用它是个好主意。所以,正因为如此,正在进行两次调用。

愚蠢的我。

我刚把它改成了这个并且工作了:

public async Task StartAsync(IDialogContext context)
{
    context.Wait(MessageReceivedAsync);
}