了解为什么在Bot Builder框架示例中似乎要进行三遍翻译:MultiLingualBot

时间:2019-06-26 00:54:19

标签: c# azure botframework

Microsoft官方的示例在bot的中间件中提供语言翻译,似乎提供了在中间件中按3种不同的方式触发语言翻译。

我的问题是为什么3种不同类型/方式没有重叠。 (触发器如何互斥?)

有问题的代码存在here

似乎被触发了三遍:

1)  if (turnContext.Activity.Type == ActivityTypes.Message) //trigger translation
2) turnContext.OnSendActivities(async (newContext, activities, nextSend) => //trigger translation
3) turnContext.OnUpdateActivity(async (newContext, activity, nextUpdate) => //trigger translation

一个可能有助于提高清晰度的单独问题->文档说... "beware short circuiting",但是您不清楚我的(有意还是无意)短路了中间件。以下两个return语句之一会使中间件短路吗?

                return await nextSend(); //LINE 83 at time of writing
                return await nextUpdate(); //LINE 100 at time of writing

对于后代,参考代码为:


// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Schema;

namespace Microsoft.BotBuilderSamples.Translation
{
    /// <summary>
    /// Middleware for translating text between the user and bot.
    /// Uses the Microsoft Translator Text API.
    /// </summary>
    public class TranslationMiddleware : IMiddleware
    {
        private readonly MicrosoftTranslator _translator;
        private readonly IStatePropertyAccessor<string> _languageStateProperty;

        /// <summary>
        /// Initializes a new instance of the <see cref="TranslationMiddleware"/> class.
        /// </summary>
        /// <param name="translator">Translator implementation to be used for text translation.</param>
        /// <param name="languageStateProperty">State property for current language.</param>
        public TranslationMiddleware(MicrosoftTranslator translator, UserState userState)
        {
            _translator = translator ?? throw new ArgumentNullException(nameof(translator));
            if(userState == null)
            {
                throw new ArgumentNullException(nameof(userState));
            }

            _languageStateProperty = userState.CreateProperty<string>("LanguagePreference");
        }

        /// <summary>
        /// Processes an incoming activity.
        /// </summary>
        /// <param name="turnContext">Context object containing information for a single turn of conversation with a user.</param>
        /// <param name="next">The delegate to call to continue the bot middleware pipeline.</param>
        /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public async Task OnTurnAsync(ITurnContext turnContext, NextDelegate next, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (turnContext == null)
            {
                throw new ArgumentNullException(nameof(turnContext));
            }

            var translate = await ShouldTranslateAsync(turnContext, cancellationToken);

            if (translate)
            {
                if (turnContext.Activity.Type == ActivityTypes.Message)
                {
                    turnContext.Activity.Text = await _translator.TranslateAsync(turnContext.Activity.Text, TranslationSettings.DefaultLanguage, cancellationToken);
                }
            }

            turnContext.OnSendActivities(async (newContext, activities, nextSend) =>
            {
                string userLanguage = await _languageStateProperty.GetAsync(turnContext, () => TranslationSettings.DefaultLanguage) ?? TranslationSettings.DefaultLanguage;
                bool shouldTranslate = userLanguage != TranslationSettings.DefaultLanguage;

                // Translate messages sent to the user to user language
                if (shouldTranslate)
                {
                    List<Task> tasks = new List<Task>();
                    foreach (Activity currentActivity in activities.Where(a => a.Type == ActivityTypes.Message))
                    {
                        tasks.Add(TranslateMessageActivityAsync(currentActivity.AsMessageActivity(), userLanguage));
                    }

                    if (tasks.Any())
                    {
                        await Task.WhenAll(tasks).ConfigureAwait(false);
                    }
                }

                return await nextSend();
            });

            turnContext.OnUpdateActivity(async (newContext, activity, nextUpdate) =>
            {
                string userLanguage = await _languageStateProperty.GetAsync(turnContext, () => TranslationSettings.DefaultLanguage) ?? TranslationSettings.DefaultLanguage;
                bool shouldTranslate = userLanguage != TranslationSettings.DefaultLanguage;

                // Translate messages sent to the user to user language
                if (activity.Type == ActivityTypes.Message)
                {
                    if (shouldTranslate)
                    {
                        await TranslateMessageActivityAsync(activity.AsMessageActivity(), userLanguage);
                    }
                }

                return await nextUpdate();
            });

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

        private async Task TranslateMessageActivityAsync(IMessageActivity activity, string targetLocale, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (activity.Type == ActivityTypes.Message)
            {
                activity.Text = await _translator.TranslateAsync(activity.Text, targetLocale);
            }
        }

        private async Task<bool> ShouldTranslateAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
        {
            string userLanguage = await _languageStateProperty.GetAsync(turnContext, () => TranslationSettings.DefaultLanguage, cancellationToken) ?? TranslationSettings.DefaultLanguage;
            return userLanguage != TranslationSettings.DefaultLanguage;
        }
    }
}

1 个答案:

答案 0 :(得分:1)

当机器人接收到某些类型的活动时,需要进行消息翻译。某些类型的活动不需要翻译。该协议的活动类型可以在here

中找到
        "message",
        "contactRelationUpdate",
        "conversationUpdate",
        "typing",
        "endOfConversation",
        "event",
        "invoke",
        "deleteUserData",
        "messageUpdate",
        "messageDelete",
        "installationUpdate",
        "messageReaction",
        "suggestion",
        "trace",
        "handoff"

MultiLingualBot示例演示了翻译:

1)将传入的消息活动转换为TranslationSettings.DefaultLanguage,以供漫游器处理

2)将传出的消息活动转换回用户惯用的语言

3)messageUpdate活动


1)  if (turnContext.Activity.Type == ActivityTypes.Message) //trigger translation
2) turnContext.OnSendActivities(async (newContext, activities, nextSend) => //trigger translation
3) turnContext.OnUpdateActivity(async (newContext, activity, nextUpdate) => //trigger translation

短路中间件不会调用

await next(cancellationToken).ConfigureAwait(false);
or 
return await nextSend();
or
return await nextUpdate();

如果未调用它们,则消息处理停止。堆栈中的其他中间件将不会处理传入的消息。