在 MS BotFramework 中使用 PromptDialog 开始对话

Start conversation with a PromptDialog in MS BotFramework

机器人是否有合适的方式在 Direct Line 频道中与 PromptDialog.Choice 开始对话?

我正在尝试一个丑陋的 hack,抓住拳头 ConversationUpdate activity 并创建一条来自用户的虚假消息来初始化对话框,如下所示:

IMessageActivity greetingMessage = Activity.CreateMessageActivity();
greetingMessage.From = message.Recipient;//from bot
greetingMessage.Recipient = userAccount;//to user
greetingMessage.Conversation = message.Conversation;
greetingMessage.Text = "Hello, I am a bot";
greetingMessage.Locale = "en-us";
greetingMessage.Id = Guid.NewGuid().ToString();

await connector.Conversations.SendToConversationAsync((Activity)greetingMessage);

IMessageActivity dialogEntryMessage = Activity.CreateMessageActivity();
dialogEntryMessage.Recipient = message.Recipient;//to bot
dialogEntryMessage.From = message.From;//from user
dialogEntryMessage.Conversation = message.Conversation;
dialogEntryMessage.Text = "any text";
dialogEntryMessage.Locale = "en-us";
dialogEntryMessage.ChannelId = message.ChannelId;
dialogEntryMessage.ServiceUrl = message.ServiceUrl;
dialogEntryMessage.Id = Guid.NewGuid().ToString();
dialogEntryMessage.ReplyToId = greetingMessage.Id;

await Conversation.SendAsync(dialogEntryMessage, () => new Dialogs.RootDialog());

其中 message 是来自的 ConversationUpdate 消息。在 RootDialog 中,我从 PromptDialog.Choice.

开始

它在模拟器中工作,但在 Direct Line 通道中机器人不记得对话状态,当用户选择一个对话选项并发送他的第一条真实消息时,根对话再次从 PromptDialog.Choice 开始, 所以它出现了两次。

更新

我找到了 Microsoft 的相关博文:https://blog.botframework.com/2018/07/12/how-to-properly-send-a-greeting-message-and-common-issues-from-customers/

in Direct Line channel bot doesn't remember the dialog state and when user choose one of dialog options and send his first real message, root dialog starts again from the PromptDialog.Choice, so it appears twice.

我可以在我这边重现同样的问题,我发现当机器人和用户都被添加到对话中时,ConversationUpdate 处理程序将被执行。

解决问题,您可以参考下面的代码示例。

在 MessagesController 中:

else if (message.Type == ActivityTypes.ConversationUpdate)
{
    // Handle conversation state changes, like members being added and removed
    // Use Activity.MembersAdded and Activity.MembersRemoved and Activity.Action for info
    // Not available in all channels

    if (update.MembersAdded != null && update.MembersAdded.Any())
    {
        foreach (var newMember in update.MembersAdded)
        {
            if (newMember.Name == "{your_botid_here}")
            {
                IMessageActivity greetingMessage = Activity.CreateMessageActivity();

                //...
                //your code logic
                //...

                IMessageActivity dialogEntryMessage = Activity.CreateMessageActivity();
                dialogEntryMessage.Recipient = message.Recipient;//to bot
                dialogEntryMessage.From = message.From;//from user
                dialogEntryMessage.Conversation = message.Conversation;
                dialogEntryMessage.Text = "show choices";
                dialogEntryMessage.Locale = "en-us";
                dialogEntryMessage.ChannelId = message.ChannelId;
                dialogEntryMessage.ServiceUrl = message.ServiceUrl;
                dialogEntryMessage.Id = System.Guid.NewGuid().ToString();
                dialogEntryMessage.ReplyToId = greetingMessage.Id;

                await Conversation.SendAsync(dialogEntryMessage, () => new Dialogs.RootDialog());
            }
        }
    }
}

在 RootDialog 中:

private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
    var activity = await result as Activity;

    var mes = activity.Text.ToLower();

    string[] choices = new string[] { "choice 1", "choice 2" };

    if (Array.IndexOf(choices, mes) > -1)
    {
        await context.PostAsync($"You selected {mes}");
    }
    else if(mes == "show choices")
    {
        PromptDialog.Choice(context, resumeAfterPrompt, choices, "please choose an option.");
    }
    else
    {
        await context.PostAsync($"You sent {activity.Text} which was {length} characters.");
        context.Wait(MessageReceivedAsync);
    }

}

private async Task resumeAfterPrompt(IDialogContext context, IAwaitable<string> result)
{
    string choice = await result;

    await context.PostAsync($"You selected {choice}");
}

测试结果: