【问题标题】:Calling a FormDialog and starting it right away调用 FormDialog 并立即启动它
【发布时间】:2017-04-11 21:04:35
【问题描述】:

我正在使用 Microsoft 的 Bot Builder 和 LUIS,但对于非常基本的东西我遇到了一些困难。

我有响应 LUIS 意图的简单方法,其中一个我想调用 FormDialog(因此基于我拥有的一个非常简单的模型),仅此而已。当意图被识别时,我正确输入了正确的方法,并且我还看到我的模型的 BuildForm 方法被调用,但是机器人没有通过字段向用户询问值。

这是我的intent方法的代码(代码做的不多,还没有真正的目的):

[LuisIntent("SendMessage")]
public async Task SendMessage(IDialogContext context, LuisResult result)
{
    // Check if the user has already configured its message box
    bool isBoxConfigured = false;
    context.UserData.TryGetValue<bool>(Constants.UserData.IsBoxConfigured, out isBoxConfigured);

    if (!isBoxConfigured)
    {
        // Configure box
        context.Call(new FormDialog<MessageBox>(new MessageBox(), this._configureMessageBox, FormOptions.PromptInStart), async (c, r) =>
        {
            await c.PostAsync("Message Box configurée !");
        });
    }
    else
    {
        // Send message
        await context.PostAsync("Votre Message Box est déjà configurée. Le message a été envoyé !");
    }
     context.Wait(MessageReceived);
}

这是我的 LUIS 对话框类的构造函数和 _configureMessageBox 属性:

public readonly BuildFormDelegate<MessageBox> _configureMessageBox;
public LUISDialog(BuildFormDelegate<MessageBox> configureMessageBox)
{
    _configureMessageBox = configureMessageBox;
}

这是我的模型(表格):

[Serializable]
public class MessageBox
{
    [Describe("numéro d'identification")]
    [Prompt("Quel est le {&} de votre Message Box ?")]
    public int Id { get; set; }

    [Describe("surnom")]
    [Prompt("Quel {&} voulez-vous lui donner ?")]
    public string BoxName { get; set; }

    public static IForm<MessageBox> BuildForm()
    {
        return new FormBuilder<MessageBox>()
            .Message("Mmmh... Je ne connais pas votre Message Box. J'ai besoin de quelques informations.")
            .Build();
    }
}

当我向机器人发送消息“envoie un message”时,它会识别 SendMessage 意图,但会立即回复“消息框配置!”,这应该在 之后发送用户浏览表单。

有人知道我应该怎么做吗?

谢谢:)

【问题讨论】:

  • 请出示您的表单,context.Wait(MessageReceived) 应该在表单的 else 和“ResumeAfter”方法中。
  • 我在原始帖子中添加了表单代码。正如你所说,我还移动了context.Wait(...) 调用,现在我得到了表单的开头(消息+第一个字段提示),但立即出现错误:Exception: anonymous method closures that capture the environment are not serializable, consider removing environment capture or using a reflection serialization surrogate: BotTest.Dialogs.LUISDialog+&lt;&gt;c__DisplayClass4_0
  • 对,那是因为 async (c, r) =>。将其移至方法并让我知道。一旦你确认我可以制定一个答案。
  • 完美!现在可以用了,谢谢!但似乎在整个对话框类中经常需要回调。好像不太实用。这是一个好习惯吗?
  • 我刚刚添加了正式答案。请投票并标记为已回答。您可以使用匿名方法,但您需要确保它们是可序列化的,否则它将因错误而失败。详情请参阅我的回答。

标签: botframework azure-language-understanding


【解决方案1】:

为了解决这个问题,您需要更改两件事:

  1. context.Wait(MessageReceived) 调用移到else 子句和表单的ResumeAfter&lt;T&gt; 方法内。这是必需的,因为使用您当前的代码,您在调用错误的表单后正在等待。如果您调用对话框/表单,则无需等待
  2. ResumeAfter&lt;T&gt; 方法作为匿名函数会导致序列化问题,因此我建议改为创建一个方法。根据docs

    确保所有对话框都是可序列化的。 这可以像在 IDialog 实现上使用 [Serializable] 属性一样简单。 但请注意,如果匿名方法闭包引用其外部环境来捕获变量,则它们是不可序列化的。我们还支持基于反射的序列化代理,以帮助序列化未标记为可序列化的类型。

【讨论】:

  • 感谢您的解释 :-)
【解决方案2】:

我遇到了同样的问题,尽管当我将FormOptions.PromptInStart 添加到我的代码中时,表单会立即启动。这是我的代码和表单。

从 LUIS 意图调用:

var searchForm = new SearchForm();
var form = new FormDialog<SearchForm>(searchForm, SearchForm.BuildTestForm, FormOptions.PromptInStart);
context.Call(form, async (dialogContext, awaitable) =>
{
     var r = await awaitable;
     //handle result.
});

SearchForm 类:

public static IForm<SearchForm> BuildTestForm()
{
     return new FormBuilder<SearchForm>()
         .Message("Start of form message.")
         .Field(...)
         ...
         .Build()
}

我希望这会有所帮助。

PS:我的 LUIS 意图填充了我班级中的一些字段,这就是我在创建表单之前创建它的原因。

【讨论】:

    猜你喜欢
    • 2021-11-24
    • 2022-07-06
    • 1970-01-01
    • 1970-01-01
    • 2017-01-08
    • 1970-01-01
    • 2016-09-19
    • 1970-01-01
    • 2012-09-24
    相关资源
    最近更新 更多