2017-04-07 70 views
1

我有一個機器人,我正在做這樣的事情:嵌套對話框:消息被髮送兩次

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(真);

而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);後,機器人調用該函數(ins tead等待一個事件來稱呼它)

任何想法?

在此先感謝。

+0

你可以創建一個小樣本,其中這可以重現? –

+0

0)正如我在帖子中所說的,當機器人狀態爲空(第一次用戶使用它或當我執行/刪除配置文件時)時會發生這種情況。 1)用戶類型「hi」。 2)我說的邏輯是評估的(在我的情況下,DoSomeLogic()調用QnA服務,並根據分數回答問題或不)。由於「嗨」不是一個有效的問題,它將msg轉發給LuisDialog。 3)致敬意向被調用並顯示一個小的英雄卡。它完成一個context.Wait(AfterUserChoseOptionInSalute); 4)本身,AfterUserChoseOption被調用,並重新分派活動(導致另一個調用)。 –

+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); 
}