Передача сущностей с Luis в FormFlow

Я использую Luis, чтобы определить, запускает ли пользователь поток с некоторыми объектами, например: он может сказать «Отчет» или «Я хочу сообщить в Лондоне» или "Я хочу сообщить о месте x в Лондоне"

    [LuisIntent("Report")]
    public async Task ReportCompleteIntent(IDialogContext context, LuisResult result)
    {
        EntityRecommendation location;
        EntityRecommendation POS;

        result.TryFindEntity("Weather.Location", out location);
        result.TryFindEntity("POS", out POS);

        //I tried with passing entities (it doesn't recognize the entities in formBuild)
        context.Call(Chain.From(() => new FormDialog<OutOfStockReport>(new OutOfStockReport(), buildForm: OutOfStockReport.BuildForm, options: FormOptions.PromptInStart, entities: result.Entities)), OOSDialogComplete);
        //Also tried prepopulating the state
        context.Call(Chain.From(() => new FormDialog<OutOfStockReport>(new OutOfStockReport() { LocalizationId = location?.Entity }, buildForm: OutOfStockReport.BuildForm, options: FormOptions.PromptInStart)), OOSDialogComplete);
    }

Это класс и форма сборки:

[Serializable]
[Template(TemplateUsage.NavigationFormat, "{&}")]
public class OutOfStockReport
{
    public string LocalizationId;
    public string PositionId;     

    public static IForm<OutOfStockReport> BuildForm()
    {
        return FormBuilderHelper.CreateCustomForm<OutOfStockReport>()
            .Message("Welcome!")         
            .Field(new FieldReflector<OutOfStockReport>(nameof(LocalizationId))
                .SetType(null)
                .SetActive(hasLocation)
                .SetDefine(async (state, field) =>
                {
                    var cities = new City().GetCities();

                    foreach (var option in cities)
                    {
                        var description = new DescribeAttribute($"{option.Name}", message: $"{option.Name}", title: $"{option.Name}");
                        field.AddDescription(option.Id, description);
                        field.AddTerms(option.Id, Language.GenerateTerms(Language.CamelCase(option.Name), 3));
                    }

                    return true;
                })
                .SetValidate(async (state, response) =>
                {
                    state.PositionId = null;

                    var result = new ValidateResult { IsValid = true, Value = response };

                    return result;

                }))
            .Field(new FieldReflector<OutOfStockReport>(nameof(PositionId))
                .SetType(null)
                .SetActive((state) => !string.IsNullOrEmpty(state.LocalizationId))
                .SetDefine(async (state, field) =>
                {
                    field.RemoveValues();

                    var localizedOptions = new Position().GetPositions(state.LocalizationId);

                    foreach (var option in localizedOptions)
                    {
                        var description = new DescribeAttribute($"{option.Name}", message: $"{option.Name}", title: $"{option.Name}");
                        field.AddDescription(option.Id, description);
                        field.AddTerms(option.Id, Language.GenerateTerms(Language.CamelCase($"{option.Id} {option.Name} {option.Direction}"), 3));
                    }

                    return true;
                }))
            .AddRemainingFields()       
            .Confirm("Are you sure of your selection?{||}")
            .OnCompletion(async (context, state) => await context.PostAsync($"Thanks, the task is complete."))                    
            .Build();

При добавлении ActiveDelegate hasLocation я могу контролировать, должно ли отображаться поле LocationId или нет. Это работает, но после этого бот прерывается с сообщением «Извините, в коде моего бота возникла проблема».

Пример с неправильным текстом пример с неправильным текстом

Пример с правильным текстом пример с правильным текстом

РЕДАКТИРОВАТЬ

Классы, которые используются в форме:

Базовая модель класса

public class BaseModel
{
    public string Id{ get; set; }
}

Класс Город

public class City : BaseModel
{
    public string Name { get; set; }
}

Позиция в классе

public class Position : BaseModel
{
    public string Name { get; set; }
    public string Direction { get; set; }
    public string CityId { get; set; }
}

person StubbornElio    schedule 21.06.2018    source источник
comment
Вы хотите передать полный список сущностей или хотите заполнить форму сущностью, полученной от Луиса?   -  person Anita George    schedule 21.06.2018
comment
В идеале было бы передать объекты luis в поток форм в качестве ответов (чтобы использовать собственную проверку и функциональность потока форм), но я не знаю, возможно ли это.   -  person StubbornElio    schedule 21.06.2018


Ответы (1)


Простым подходом было бы проанализировать результат Luis, получить значение сущности из результата и передать результат в formflow.

ЛуисДиалог

[LuisIntent("Report")]
public async Task ReportCompleteIntent(IDialogContext context, LuisResult result)
{
        OutOfStockReport form = new OutOfStockReport();
        EntityRecommendation location;
        EntityRecommendation POS;

        if(result.TryFindEntity("Weather.Location", out location))
        {
        //Here you are initializing the form with values.
        //If you have written any validation code for this field then
        //formflow will check the validation when the form is called

             form.Location = location.Entity;
        }
        if(result.TryFindEntity("POS", out POS))
        {
             form.POS = POS.Entity;
        }

        context.Call(form,OutOfStockReport.BuildForm, FormOptions.PromptInStart,OOSDialogComplete);

}

Если вам нужно обработать Entity, прежде чем назначать ее полю в formflow, вам придется сделать это в самом методе Luis Dialog.

person Anita George    schedule 21.06.2018
comment
невозможно сделать так, чтобы диалог обрабатывал объекты так, как он будет делать регулярно, если пользователь вставит его один к одному? - person StubbornElio; 21.06.2018
comment
не могли бы вы объяснить, что вы получаете в Луисе и что вы заполняете в форме? - person Anita George; 21.06.2018
comment
Например, Луис получает Я хочу сообщить в Лондоне и передает Лондон в FormFlow. Луис не может знать, является ли город правильным или нет, и потоку формы требуется идентификатор города для продолжения (форма знает, что London является описанием, и заполняет это поле идентификатором). Поле для города использует класс City, который имеет Name и Id, для заполнения параметров. - person StubbornElio; 21.06.2018
comment
Итак, насколько я понимаю, объекты сразу переходят в состояние без какой-либо привязки или проверки, как FormFlow запускается в случае ответа пользователя. Таким образом, хотя обычно Лондон проверяется и в конечном итоге регистрируется как идентификатор в LocalizationId, при передаче предварительно заполненного состояния LocalizationId оказывается просто Лондоном. Я прав? Я не знаю, возможно ли добиться такого поведения. @АнитаДжордж - person Imartin; 21.06.2018
comment
@StubbornElio Каков ваш городской класс? - person Anita George; 22.06.2018
comment
@StubbornElio Вы извлекаете значения из базы данных? .. у меня есть обходной путь с перечислениями .. - person Anita George; 22.06.2018
comment
@Imartin да, это невозможно. Я пытаюсь найти альтернативный метод - person Anita George; 22.06.2018
comment
@AnitaGeorge да, значения взяты из базы данных. На данный момент значения проверяются перед отправкой их в FormFlow, и теперь это работает. Было бы неплохо использовать валидатор FormFlow, так как сейчас это все равно, что писать один и тот же код два раза. - person StubbornElio; 25.06.2018