0

我正在使用具有多语言的 botframework 作曲家,并希望每个用户都能够选择首选语言/区域设置。在使用选择对话框解决他的选择的本地代码后,我如何在对话中设置它,以便他在设备中的区域设置将被否决以进行其余的对话?

在模拟器中更改语言环境可以正常工作,希望在用户选择后具有相同的行为。

设置 turn.locale 工作一回合,但在下一回合重置。

4

1 回答 1

1

假设您无法控制客户端,那将是最好的。

您可以在不断增长的未标记为已弃用的 bot 适配器层次结构上诉诸旧的重载。

您必须在以下控制器中使用PostAsync方法(api/post-messages端点)(显示由当前一组机器人框架模板创建的只是为了比较):

    [Route("api")]
    [ApiController]
    public class BotController : ControllerBase
    {
        private readonly IBotFrameworkHttpAdapter StreamingAdapter;
        private readonly BotFrameworkAdapter PostAdapter;
        private readonly ConversationLocales ConversationLocales;
        private readonly IBot Bot;

        public BotController(
            IBotFrameworkHttpAdapter streamingAdapter,
            BotFrameworkAdapter postAdapter,
            ConversationLocales conversationLocales,
            IBot bot)
        {
            StreamingAdapter = streamingAdapter;
            PostAdapter = postAdapter;
            Bot = bot;
        }

        [HttpPost("messages"), HttpGet("messages")]
        public async Task PostOrStreamingAsync()
        {
            // Delegate the processing of the HTTP POST to the adapter.
            // The adapter will invoke the bot.
            await StreamingAdapter.ProcessAsync(Request, Response, Bot);
        }

        [HttpPost("post-messages")]
        public async Task<InvokeResponse> PostAsync([FromBody] Activity activity)
        {
            var savedLocale = ConversationLocales.GetLocaleForConversation(activity.Conversation.Id);

            activity.Locale = savedLocale ?? activity.Locale;

            return await PostAdapter.ProcessActivityAsync(string.Empty, activity, Bot.OnTurnAsync, default);
        }
    }

假设您实现了一项ConversationLocales服务,该服务允许您为每个对话 id 保留选定的语言环境。

在上面的代码中,我们使用BotFrameworkAdapter适配器而不是IBotFrameworkHttpAdapter,但是AdapterWithErrorHandler模板中使用的 间接继承自BotFrameworkAdapter,因此您可以执行以下操作ConfigureServices来注册“两个”适配器:


services.AddSingleton<AdapterWithErrorHandler>();
services.AddSingleton<IBotFrameworkHttpAdapter>(sp => sp.GetRequiredService<AdapterWithErrorHandler>());
services.AddSingleton<BotFrameworkAdapter>(sp => sp.GetRequiredService<AdapterWithErrorHandler>());

拥有一个适配器实例。

使用此方法,适配器将无法使用机器人通道流式传输端点,但这应该不是什么大问题,只要您不使用语音客户端即可。

您还可以在我的博客文章Bot Builder v4 机器人如何工作?,它有点过时但仍然有效。

更新- 找到了更好的解决方案

这个适用于当前的适配器浪潮并使用消息管道,因此它是“现代的”。

它还要求您使用自定义运行时,您将按如下方式进行自定义。

1 - 创建以下中间件

public class LocaleSelectionMiddleware : IMiddleware
{
    private readonly IStatePropertyAccessor<string> _userLocale;

    public LocaleSelectionMiddleware(UserState userState)
    {
        _userLocale = userState.CreateProperty<string>("locale");
    }

    public async Task OnTurnAsync(ITurnContext turnContext, NextDelegate next, CancellationToken cancellationToken = default)
    {
        if (turnContext is null)
        {
            throw new ArgumentNullException(nameof(turnContext));
        }

        var userLocale = await _userLocale.GetAsync(turnContext, () => turnContext.Activity.Locale);

        turnContext.Activity.Locale = userLocale;
        (turnContext as TurnContext).Locale = userLocale;

        await next(cancellationToken).ConfigureAwait(false);
    }
}

2 - 在适配器中配置GetBotAdapter()中间件Startup.cs

public class Startup
{
    public Startup(IWebHostEnvironment env, IConfiguration configuration)
    {
        this.HostingEnvironment = env;
        this.Configuration = configuration;
    }

    //...
    public BotFrameworkHttpAdapter GetBotAdapter(IStorage storage, BotSettings settings, UserState userState, ConversationState conversationState, IServiceProvider s)
    {
        var adapter = IsSkill(settings)
            ? new BotFrameworkHttpAdapter(new ConfigurationCredentialProvider(this.Configuration), s.GetService<AuthenticationConfiguration>())
            : new BotFrameworkHttpAdapter(new ConfigurationCredentialProvider(this.Configuration));

        adapter
            .UseStorage(storage)
            .UseBotState(userState, conversationState)
            .Use(new RegisterClassMiddleware<IConfiguration>(Configuration))
            .Use(new LocaleSelectionMiddleware(userState)) // <-- Add the middleware here
            .Use(s.GetService<TelemetryInitializerMiddleware>());

        //...
        return adapter;
    }

    //...
}

3 - 在任何对话框中设置 user.locale 属性

从任何对话框设置user.locale属性,下一轮将具有所需的语言环境,并将保持在用户状态,直到他们再次更改它。

于 2021-05-02T11:21:17.403 回答