Пользовательские поля с FormBuilder в Microsoft Bot Framework

Используя пример AlarmBot и улучшенный сэндвич-бот, я пытаюсь понять, как объединить FormBuilder с пользовательским поведением диалога. В частности, я хочу использовать метод Alarm Bot SetAlarm

SetAlarm(IDialogContext context, LuisResult result)

и использовать тот же Chronic.Parser в SandwichBot для поля DeliveryTime. Как это будет сделано? Я смотрел на реализацию IField, но я не уверен, как это будет выглядеть.

2 ответа

После просмотра и просмотра исходного кода, самый простой ответ не о IFieldState. Ключевым интерфейсом является IRecognize. Правильное использование требует понимания того, что происходит под одеялом.

Начните с создания собственного настраиваемого поля. Фреймворк позволяет нам получить производные от FieldReflector, который выполняет большую часть работы.

public class BetterDateTimeField : FieldReflector<MyOrder> 
{
  public BetterDateTimeField(string name, bool ignoreAnnotations = false) 
          : base(name, ignoreAnnotations)  { }

   public override IForm<MyOrder> Form
   {
      set
      {
        base.Form = value;
        base.SetRecognizer(new BetterDateTimeRecognizer<MyOrder>(this, CultureInfo.CurrentCulture));
      }
    }
}

Основная идея здесь состоит в том, чтобы создать свой собственный распознаватель, поскольку именно эта часть получает исходный текст. Хитрость заключается в том, чтобы узнать, когда вы можете создать экземпляр распознавателя. Это должно быть сделано ПОСЛЕ поля формы было установлено. Базовый базовый класс Recognizer будет смотреть на форму полей в конструкторе. (Если вы полностью откажетесь от использования базовых классов Recognizer, это может не быть проблемой.)

Затем вы можете создать свою собственную реализацию IRecognize. К сожалению, среда ботов герметизирует многие классы распознавателя базовых / примитивных типов, поэтому наследование от RecognizeDateTime и перегрузка Parse не являются приемлемыми (надеюсь, когда-нибудь они их распечатают). Тем не менее, это достаточно легко скопировать и отредактировать в свой собственный класс.

using Chronic;
public class BetterDateTimeRecognizer<T> : RecognizePrimitive<T> where T : class
{
   private CultureInfo _culture;
   private Parser _parser;

   public BetterDateTimeRecognizer(IField<T> field, CultureInfo culture) 
          : base(field)
   {
      _culture = culture;
      _parser = new Chronic.Parser();
   }

   public override string Help(T state, object defaultValue)
   {
     var prompt = new Prompter<T>(_field.Template(TemplateUsage.DateTimeHelp), _field.Form, null);
     var args = HelpArgs(state, defaultValue);
     return prompt.Prompt(state, _field.Name, args.ToArray());

   }

   public override TermMatch Parse(string input)
   {
     TermMatch match = null;
     // the original code
     //DateTime dt;
     //if (DateTime.TryParse(input, out dt))
     //{
     //    match = new TermMatch(0, input.Length, 1.0, dt);
     //}

     var parse = _parser.Parse(input);
     if (parse != null && parse.Start.HasValue)
     {
         match = new TermMatch(0, input.Length, 1.0, parse.Start.Value);
     }

     return match;
  }

  public override IEnumerable<string> ValidInputs(object value)
  {
     yield return ValueDescription(value);
  }

  public override string ValueDescription(object value)
  {
     return ((DateTime)value).ToString(CultureInfo.CurrentCulture.DateTimeFormat);
  }
}

Наконец, вам просто нужно подключить его к конструктору форм в BuildForm():

var form = builder.Message("Hello there. What can I help you today")
           .Field(new BetterDateTimeField("<NAME of YOUR DateTime Field HERE>")
           .Build();

Первоначально мы использовали Chronic для полей DateTime в FormFlow, но когда мы перешли к подписанию нашей dll, мы больше не могли использовать неподписанную библиотеку C# Chronic. Я обратился к автору, хотя и попросил его подписать его, но пока не получил ответа - если он это сделает, мы сделаем это частью FormFlow.

Что касается реализации IField, если вы хотите, вы можете использовать Field и предоставить собственную реализацию IFieldState. Поле имеет структуры данных для всех декларативных вещей, и вы можете переопределить все методы. Это позволит вам использовать Chronic в вашей неподписанной DLL.

Другие вопросы по тегам