Доступ к состоянию пользователя/разговора перед отправкой первого сообщения

В Bot Framework V4 объясняется, что можно получить доступ к состоянию пользователя или состоянию диалога, создав диалоговый контекст в OnTurnAsync

var dc = await Dialogs.CreateContextAsync(turnContext);

или используя аксессор в классе контекста диалога

var state = await HogehogeSettingAccessor.GetAsync(stepContext.Context);

однако, как мне получить к ним доступ перед отправкой сообщения в диалог?

В настоящее время я разрабатываю Directline API и хотел бы обратиться к настройке языка перед отправкой первого сообщения (например, игнорировать ввод пользователя, если письменный язык не соответствует настройке).

private async Task OnMessageReceive(SocketMessage socketMessage)
{
    if (IsLanguageMatch(socketMessage)){
        await channel.SendMessageAsync(response);
    }
}

Как мне этого добиться?


person kemakino    schedule 19.02.2019    source источник


Ответы (1)


Вы можете сделать так, чтобы OnTurnAsync запускал первый/основной диалог только при выполнении вашего условия. Когда пользователь отправляет сообщение боту в первый раз, активного диалога не будет. Вы можете воспользоваться этим условием и добавить туда свое, запустив диалоговое окно только в том случае, если выполняются оба условия:

 // Getting the bot accessor state you want to use   

LanguageAccessor languageAccessor = await _accessors.LanguageAccessor.GetAsync(turnContext, () => new LanguageAccessor(), cancellationToken);

    // Every step sends a response. If no dialog is active, no response is sent and turnContext.Responded is null
    //where turnContext.Activity.Text is the message sent by the user

 if (!turnContext.Responded && ((languageAccessor.property)turnContext.Activity.Text))

OnTurnAsync должен выглядеть примерно так:

        public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
                {

                    if (turnContext.Activity.Type == ActivityTypes.Message)
                    {
        // Establish dialog state from the conversation state.
                        DialogContext dc = await _dialogs.CreateContextAsync(turnContext, cancellationToken);

                        // Get the user's info.
                       LanguageAccessor languageAccessor = await _accessors.LanguageAccessor.GetAsync(turnContext, () => new LanguageAccessor(), cancellationToken);

                        await _accessors.UserInfoAccessor.SetAsync(turnContext, userInfo, cancellationToken);

                        // Continue any current dialog.
                        DialogTurnResult dialogTurnResult = await dc.ContinueDialogAsync();    

                        // Every dialog step sends a response, so if no response was sent,
                        // then no dialog is currently active and the Else if is entered.

                        if (!turnContext.Responded && ((languageAccessor.property)turnContext.Activity.Text))
                        {

                            //This starts the MainDialog if there's no active dialog when the user sends a message
                            await dc.BeginDialogAsync(MainDialogId, null, cancellationToken);


                        }

                       //Else if the validation is not passed
                       else if (!turnContext.Responded && ! 
                       ((languageAccessor.property)turnContext.Activity.Text))
                          { await turnContext.SendActivityAsync("Thank you, see you next time"); }
                          }
            }

Другим вариантом было бы отправить объект доступа в диалоговое окно, где вы хотите его использовать, и использовать первый шаг водопада диалогового окна, чтобы либо продолжить диалоговое окно, если проверка выполнена, либо завершить его, если нет.

Шаг водопада должен выглядеть примерно так:

     private async Task<DialogTurnResult> ValidationFirstStepAsync(
                WaterfallStepContext stepContext,
                CancellationToken cancellationToken = default(CancellationToken))
            {
                // Access the bot UserInfo accessor so it can be used to get state info.
                LanguageAccessor languageAccessor = await 
                _accessors.LanguageAccessor.GetAsync(stepContext.Context, null, 
                cancellationToken);

               if ((languageAccessor)stepContext.Context.Activity.Text)
               {             
                  await stepContext.Context.SendActivityAsync(
                            "Hi!");
                  return await stepContext.NextAsync();
               }
               else
               { 
                  await stepContext.Context.SendActivityAsync("Sorry, your language is not supported");
                  return await stepContext.EndDialogAsync(); }
               }
}
person Dante Nahuel Ciai    schedule 20.02.2019
comment
Спасибо за решение. Нужно ли мне вставлять этот шаг для проверки либо в OnTurnAsync, либо в контекст диалога? Несмотря на то, что это все еще будет работать, я изначально хотел просто просмотреть состояние во внешнем классе, прежде чем бот начнет обрабатывать сообщение. - person kemakino; 21.02.2019
comment
Я никогда не пытался сделать что-то подобное вне бота. Я думаю, это было бы слишком сложно. По какой-то конкретной причине вы не хотите обрабатывать проверку внутри бота с помощью OnTurnAsync? Платформа бота готова постоянно выполнять проверки, особенно в V4 с циклом OnTurnAsync каждый раз, когда происходит действие. - person Dante Nahuel Ciai; 21.02.2019
comment
Я подумал, что сокращение входящих сообщений для бота упрощает обработку всего. Однако, как вы указали, кажется, что приложение запутано. Я пойду по варианту, который вы предложили. Спасибо. - person kemakino; 25.02.2019
comment
Я пытаюсь изменить свой диалог, но не совсем понимаю (languageAccessor)stepContext.Context.Activity.Text это условие. Что тут происходит? - person kemakino; 28.02.2019