Подтвердить что ты не робот

Завершите все диалоги и завершите разговор в MS Bot Framework, когда пользователь вводит "exit", "quit" и т.д.

Я не могу понять, как сделать очень простую вещь в MS Bot Framework: позволить пользователю вырваться из любой беседы, оставить текущие диалоги и вернуться в главное меню, набрав "quit" , "exit" или "начать все".

Здесь, как мой основной разговор настроен:

    public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
    {
        try
        {
            if (activity.Type == ActivityTypes.Message)
            {
                UserActivityLogger.LogUserBehaviour(activity);

                if (activity.Text.ToLower() == "start over")
                {
                    //Do something here, but I don't have the IDialogContext here!
                }
                BotUtils.SendTyping(activity); //send "typing" indicator upon each message received
                await Conversation.SendAsync(activity, () => new RootDialog());
            }
            else
            {
                HandleSystemMessage(activity);
            }
        }

Я знаю, как завершить диалог с context.Done<DialogType>(this);, но в этом методе у меня нет доступа к объекту IDialogContext, поэтому я не могу позвонить .Done().

Есть ли другой способ завершить весь стек диалогового окна, когда пользователь вводит определенное сообщение, кроме добавления проверки для этого на каждом шаге всех диалогов?

Добавлено баунти:

Мне нужен способ прервать все IDialog без использования возмутительного взлома, который я разместил здесь (который удаляет все пользовательские данные, которые мне нужны, например, пользовательские настройки и предпочтения).

В принципе, когда пользователь набирает "quit" или "exit", мне нужно выйти из того, что в настоящий момент выполняется IDialog, и вернуться в новое состояние, как будто пользователь только что начал разговор.

Мне нужно иметь возможность сделать это из MessageController.cs,, где я до сих пор не имею доступа к IDialogContext. Единственными полезными данными, которые у меня есть, является объект Activity. Я буду счастлив, если кто-то укажет на другие способы сделать это.

Еще один способ приблизиться к этому - найти другой способ проверить ключевые слова "exit" и "quit" в каком-либо другом месте бота, а не в методе Post.

Но это не должно быть проверкой, которая выполняется на каждом шаге IDialog, потому что слишком много кода и даже не всегда возможно (при использовании PromptDialog у меня нет доступа к тексту, который пользователь набрал).

Два возможных способа, которых я не исследовал:

  • Вместо завершения всех текущих IDialog s, запустите новый диалог с пользователем (новый ConversationId)
  • Получите объект IDialogStack и сделайте что-нибудь с ним для управления стеке диалога.

Документы Microsoft молчат об этом объекте, поэтому я понятия не имею, как его получить. Я не использую объект Chain, который позволяет .Switch() находиться в любом месте бота, но если вы считаете, что его можно переписать для его использования, это может быть одним из способов его решения. Однако я не нашел, как делать разветвление между различными типами диалогов (FormFlow и обычный IDialog), которые, в свою очередь, вызывают их собственные дочерние диалоги и т.д.

4b9b3361

Ответ 1

ПРОБЛЕМА BREAKDOWN

Из моего понимания вашего вопроса, чего вы хотите достичь, это reset стек диалога без полного уничтожения состояния бота.


ФАКТЫ (из того, что я читал из репозитория github)

  • Как сохранить структуру диалогового стека, как показано ниже:

BotDataStore > BotData > DialogStack

  1. BotFramework использует AutoFac в качестве контейнера DI
  2. DialogModule - это модуль Autofac для компонентов диалога

КАК ДЕЛАТЬ

Зная ФАКТЫ сверху, мое решение будет

  • Зарегистрируйте зависимости, чтобы мы могли использовать наш контроллер:

// in Global.asax.cs
var builder = new ContainerBuilder();
builder.RegisterModule(new DialogModule());
builder.RegisterModule(new ReflectionSurrogateModule());
builder.RegisterModule(new DialogModule_MakeRoot());

var config = GlobalConfiguration.Configuration;
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterWebApiFilterProvider(config);
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
  1. Получите Контейнер Autofac (не стесняйтесь размещать где-нибудь в своем коде, который вам нравится)
private static ILifetimeScope Container
{
    get
    {
        var config = GlobalConfiguration.Configuration;
        var resolver = (AutofacWebApiDependencyResolver)config.DependencyResolver;
        return resolver.Container;
    }
}
  1. Загрузите BotData​​strong > в область
  2. Загрузите DialogStack
  3. reset DialogStack
  4. Верните новый BotData​​strong > обратно в BotDataStore
using (var scope = DialogModule.BeginLifetimeScope(Container, activity))
{
    var botData = scope.Resolve<IBotData>();
    await botData.LoadAsync(default(CancellationToken));
    var stack = scope.Resolve<IDialogStack>();
    stack.Reset();
    await botData.FlushAsync(default(CancellationToken));
}

Надеюсь, что это поможет.


ОБНОВЛЕНИЕ 1 (27/08/2016)

Благодаря @ejadib, чтобы указать, Контейнер уже отображается в классе беседы.

Мы можем удалить шаг 2 в ответе выше, в конце код будет выглядеть как

using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, activity))
{
    var botData = scope.Resolve<IBotData>();
    await botData.LoadAsync(default(CancellationToken));
    var stack = scope.Resolve<IDialogStack>();
    stack.Reset();
    await botData.FlushAsync(default(CancellationToken));
}

Ответ 2

Вот ужасно уродливый хак, который работает. Он в основном удаляет все пользовательские данные (которые вам действительно понадобятся), и это приводит к перезапуску сеанса.

Если кто-то знает лучший способ, не удаляя данные пользователя, пожалуйста, поделитесь.

    public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
    {
        try
        {
            if (activity.Type == ActivityTypes.Message)
            {
                //if the user types certain messages, quit all dialogs and start over
                string msg = activity.Text.ToLower().Trim();
                if (msg == "start over" || msg == "exit" || msg == "quit" || msg == "done" || msg =="start again" || msg == "restart" || msg == "leave" || msg == "reset")
                {
                    //This is where the conversation gets reset!
                    activity.GetStateClient().BotState.DeleteStateForUser(activity.ChannelId, activity.From.Id);
                }

                //and even if we reset everything, show the welcome message again
                BotUtils.SendTyping(activity); //send "typing" indicator upon each message received
                await Conversation.SendAsync(activity, () => new RootDialog());
            }
            else
            {
                HandleSystemMessage(activity);
            }
        }

Ответ 3

Я знаю, что это немного старо, но у меня была та же проблема, и опубликованные решения перестали быть лучшими подходами.

Я не уверен, с какой версией это доступно, но на 3.8.1 вы можете зарегистрировать службы IScorable, которые можно запускать в любом месте диалога.

Существует пример кода, который показывает, как он работает, и у него есть глобальный обработчик команд "cancel":

https://github.com/Microsoft/BotBuilder-Samples/tree/master/CSharp/core-GlobalMessageHandlers

Часть кода будет выглядеть так:

protected override async Task PostAsync(IActivity item, string state, CancellationToken token)
{
    this.task.Reset();
}

Ответ 4

Дополнительный код, который работал для кого-то другого:

private async Task _reset(Activity activity)
    {
        await activity.GetStateClient().BotState
            .DeleteStateForUserWithHttpMessagesAsync(activity.ChannelId, activity.From.Id);

        var client = new ConnectorClient(new Uri(activity.ServiceUrl));
        var clearMsg = activity.CreateReply();
        clearMsg.Text = $"Reseting everything for conversation: {activity.Conversation.Id}";
        await client.Conversations.SendToConversationAsync(clearMsg);
    }

Этот код опубликован пользователем mmulhearn здесь: https://github.com/Microsoft/BotBuilder/issues/101#issuecomment-316170517