Преодоление языковых барьеров, один бот за раз

Создание многоязычного чат-бота с помощью C# и MS Bot Framework v4

Как глобализировать ваше бот-приложение

В этой статье мы создадим чат-бота с помощью Microsoft Bot Framework и научимся адаптировать его под разные языки.

Глава 1. Настройка проекта

Мы собираемся создать простой проект чат-бота, который изначально будет предлагать пользователям два языковых варианта. Итак, приступим!

Шаг 1: Инициируйте проект

Первый шаг — создать новый пустой проект ASP.NET Core в Visual Studio и настроить его на .NET 6.0. Обязательно добавьте в проект следующий пакет NuGet:

Microsoft.Bot.Builder.Integration.AspNet.Core --version 4.20.0

Шаг 2: Создайте логику бота

Мозг нашего бота будет помещен в MainBot.cs файл:

using Microsoft.Bot.Builder;
using Microsoft.Bot.Schema;

namespace MultilingualChatBot.Bots
{
    public class MainBot : ActivityHandler
    {
        protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersAdded, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
        {
            foreach (var member in membersAdded)
            {
                if (member.Id == turnContext.Activity.Recipient.Id)
                    continue;

                var reply = MessageFactory.Text("Please choose your language");
                reply.SuggestedActions = new SuggestedActions
                {
                    Actions = new List<CardAction>
                    {
                        new() { Title = "English", Type = ActionTypes.ImBack, Value = "English" },
                        new() { Title = "Українська", Type = ActionTypes.ImBack, Value = "Українська" }
                    }
                };
                await turnContext.SendActivityAsync(reply, cancellationToken);
            }
        }

        protected override Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
        {
            var replyText = $"Your language is **{turnContext.Activity.Text}**";
            return turnContext.SendActivityAsync(MessageFactory.Text(replyText, replyText), cancellationToken);
        }
    }
}

Бот просит пользователей выбрать язык: английский или украинский. После этого всякий раз, когда пользователь отправляет сообщение, бот будет повторять выбранный язык.

Шаг 3: Создайте адаптер

Чтобы настроить стратегию обработки ошибок для чат-бота, мы реализуем класс AdapterWithErrorHandler.cs:

using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Connector.Authentication;

namespace MultilingualChatBot
{
    public class AdapterWithErrorHandler : CloudAdapter
    {
        public AdapterWithErrorHandler(BotFrameworkAuthentication auth, ILogger<IBotFrameworkHttpAdapter> logger)
            : base(auth, logger)

        {
            OnTurnError = async (turnContext, exception) =>
            {
                // Log any leaked exception from the application.
                logger.LogError(exception, $"[OnTurnError] unhandled error : {exception.Message}");

                // Send a message to the user
                await turnContext.SendActivityAsync("The bot encountered an error or bug.");
                await turnContext.SendActivityAsync("To continue to run this bot, please fix the bot source code.");
            };
        }
    }
}

В инфраструктуре MS Bot Framework класс адаптера действует как мост между ботом и каналом связи (например, Telegram, Teams, Slack и т. д.). Для более подробного объяснения общей структуры бота обратитесь к официальной документации.

Шаг 4: Настройте зависимости

Чтобы все заработало, нам нужно настроить все зависимости в Program.cs file:

using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Connector.Authentication;
using MultilingualChatBot;
using MultilingualChatBot.Bots;

var builder = WebApplication.CreateBuilder(args);

// Create the Bot Framework Authentication to be used with the Bot Adapter
builder.Services.AddSingleton<BotFrameworkAuthentication, ConfigurationBotFrameworkAuthentication>();

// Create the Bot Adapter with error handling enabled
builder.Services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>();

// Add the main bot to the container
builder.Services.AddTransient<IBot, MainBot>();

var app = builder.Build();

app.UseHttpsRedirection();

app.MapPost("api/messages", (IBotFrameworkHttpAdapter adapter, IBot bot, HttpContext context) =>
    adapter.ProcessAsync(context.Request, context.Response, bot));

app.Run();

Шаг 5: протестируйте бота

Теперь, когда у нас есть начальная настройка бота, пришло время протестировать его. Вот как выглядит начальный диалог в Эмуляторе Bot Framework:

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

Глава 2. Локализация и многоязычная поддержка

В этом разделе мы собираемся интегрировать многоязычную поддержку в наш чат-бот. Мы будем использовать файлы ресурсов (. resx) и интерфейс IStringLocalizer, чтобы обеспечить локализацию для английского и украинского языков.

Шаг 1. Добавьте ресурсы (.resx)

Мы создадим класс BotMessages.cs и два файла ресурсов, BotMessages.en-US.resx для английского и BotMessages.uk-UA.resx для украинского. В этих файлах будут храниться локализованные строки, которые наш бот будет использовать для связи. Вот как файлы выглядят в Visual Studio:

Шаг 2. Измените логику бота

Мы обновим MainBot.cs, чтобы использовать интерфейс IStringLocalizer. Это позволит боту извлекать и отображать правильные локализованные строки в зависимости от выбранного пользователем языка:

using System.Globalization;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Localization;
using MultilingualChatBot.Resources;

namespace MultilingualChatBot.Bots
{
    public class MainBot : ActivityHandler
    {
        private readonly IStringLocalizer<BotMessages> _localizer;

        public MainBot(IStringLocalizer<BotMessages> localizer) =>
            _localizer = localizer;

        protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersAdded, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
        {
            foreach (var member in membersAdded)
            {
                if (member.Id == turnContext.Activity.Recipient.Id)
                    continue;

                var reply = MessageFactory.Text("Please choose your language");
                reply.SuggestedActions = new SuggestedActions
                {
                    Actions = new List<CardAction>
                    {
                        new() { Title = "English", Type = ActionTypes.ImBack, Value = "English" },
                        new() { Title = "Українська", Type = ActionTypes.ImBack, Value = "Українська" }
                    }
                };
                await turnContext.SendActivityAsync(reply, cancellationToken);
            }
        }

        protected override Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
        {
            var language = turnContext.Activity.Text;

            var culture = language switch
            {
                "English" => "en-US",
                "Українська" => "uk-UA",
                _ => "en-US"
            };

            CultureInfo.CurrentCulture = new CultureInfo(culture);
            CultureInfo.CurrentUICulture = new CultureInfo(culture);

            var welcomeMsg = _localizer["WelcomeMessage", language];

            return turnContext.SendActivityAsync(MessageFactory.Text(welcomeMsg, welcomeMsg), cancellationToken);
        }
    }
}

Метод OnMessageActivityAsync обрабатывает пользовательские сообщения как выбор языка, сопоставляет их с соответствующей культурой и возвращает локализованное приветственное сообщение на выбранном языке с помощью IStringLocalizer. Имейте в виду, что IStringLocalizerзависит от установленного языка и региональных параметров, чтобы найти правильный файл ресурсов, поэтому необходимо вручную определить язык и региональные параметры.

Шаг 3: Добавьте зависимость от локализации

В последнем разделе мы настроим Program.cs, чтобы установить необходимые зависимости. Это позволит нам использовать IStringLocalizer для локализации в нашем боте. Все, что нам нужно сделать, это добавить следующую строку:

builder.Services.AddLocalization();

К концу этой главы наш многоязычный чат-бот работает без сбоев. Но давайте не будем останавливаться на достигнутом — в следующей главе мы рассмотрим способы его дальнейшего улучшения.

Глава 3: Легкий выбор языка

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

Шаг 1. Внедрите промежуточное ПО

Здесь мы создадим класс LocalizationMiddleware.cs, автоматический компонент для определения языкового контекста для ответов нашего бота.

using System.Globalization;
using Microsoft.Bot.Builder;
using IMiddleware = Microsoft.Bot.Builder.IMiddleware;

namespace MultilingualChatBot
{
    public class LocalizationMiddleware : IMiddleware
    {
        public Task OnTurnAsync(ITurnContext turnContext, NextDelegate next, CancellationToken cancellationToken = new())
        {
            var culture = turnContext.Activity.Text switch
            {
                "English" => "en-US",
                "Українська" => "uk-UA",
                _ => "en-US"
            };

            CultureInfo.CurrentCulture = new CultureInfo(culture);
            CultureInfo.CurrentUICulture = new CultureInfo(culture);
            
            return next(cancellationToken);
        }
    }
}

Наше промежуточное ПО определяет язык текущего взаимодействия с ботом на основе выбора пользователя. Это означает, что бот будет автоматически использовать правильные языковые ресурсы при отправке сообщений, избавляя от необходимости вручную устанавливать культуру каждый раз, когда мы используем IStringLocalizer interface.

В потенциальных случаях использования такие каналы, как Telegram, Facebook Messenger и другие, могут передавать пользовательские локали, что делает приведенный ниже код жизнеспособным решением для автоматической настройки культуры для каждого взаимодействия:

using System.Globalization;
using Microsoft.Bot.Builder;
using IMiddleware = Microsoft.Bot.Builder.IMiddleware;

namespace MultilingualChatBot
{
    public class LocalizationMiddleware : IMiddleware
    {
        public Task OnTurnAsync(ITurnContext turnContext, NextDelegate next, CancellationToken cancellationToken = new())
        {
            // Get the actual user's locale
            var culture = turnContext.Activity.Locale ?? "en-US";

            CultureInfo.CurrentCulture = new CultureInfo(culture);
            CultureInfo.CurrentUICulture = new CultureInfo(culture);

            return next(cancellationToken);
        }
    }
}

Шаг 2: Интегрируйте ПО промежуточного слоя

Чтобы сделать наше промежуточное ПО полностью работоспособным, мы выполним два заключительных действия. Во-первых, мы интегрируем его в класс AdapterWithErrorHandler.cs:

using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Connector.Authentication;

namespace MultilingualChatBot
{
    public class AdapterWithErrorHandler : CloudAdapter
    {
        public AdapterWithErrorHandler(
            LocalizationMiddleware localizationMiddleware, 
            BotFrameworkAuthentication auth,
            ILogger<IBotFrameworkHttpAdapter> logger) : base(auth, logger)

        {
            // Add localization middleware
            Use(localizationMiddleware);

            OnTurnError = async (turnContext, exception) =>
            {
                // Log any leaked exception from the application.
                logger.LogError(exception, $"[OnTurnError] unhandled error : {exception.Message}");

                // Send a message to the user
                await turnContext.SendActivityAsync("The bot encountered an error or bug.");
                await turnContext.SendActivityAsync("To continue to run this bot, please fix the bot source code.");
            };
        }
    }
}

Во-вторых, мы убедимся, что он правильно настроен в файле Program.cs:

using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Connector.Authentication;
using MultilingualChatBot;
using MultilingualChatBot.Bots;

var builder = WebApplication.CreateBuilder(args);

// Add localization
builder.Services.AddLocalization();
builder.Services.AddSingleton<LocalizationMiddleware>();

// Create the Bot Framework Authentication to be used with the Bot Adapter
builder.Services.AddSingleton<BotFrameworkAuthentication, ConfigurationBotFrameworkAuthentication>();

// Create the Bot Adapter with error handling enabled
builder.Services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>();

// Add the main bot to the container
builder.Services.AddTransient<IBot, MainBot>();

var app = builder.Build();

app.UseHttpsRedirection();

app.MapPost("api/messages", (IBotFrameworkHttpAdapter adapter, IBot bot, HttpContext context) =>
    adapter.ProcessAsync(context.Request, context.Response, bot));

app.Run();

Теперь, когда промежуточное программное обеспечение локализации установлено, наш чат-бот может автоматически устанавливать языковые предпочтения на основе пользовательского ввода.

Шаг 4: Чат-бот в действии

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

Завершая эту главу, мы успешно автоматизировали процесс обработки языка в нашем чат-боте.

Глава 4. Изучение реального чат-бота

Давайте выйдем за рамки основ! Я создал практичный и многофункциональный двуязычный чат-бот для напоминаний.

Для пользователей это полезный инструмент с расширенными возможностями; не стесняйтесь протестировать его в Telegram.

Тем временем разработчики могут получить более глубокое представление о более сложных реализациях ботов на моем GitHub. Это отличная ссылка, чтобы увидеть, как сложные методы ботов применяются на практике. Наслаждаться!

Заключение

С помощью этого руководства мы создали чат-бота, способного поддерживать несколько языков, улучшая взаимодействие с пользователем и доступность. Мы также видели, как промежуточное ПО может автоматизировать выбор языка, делая бота более эффективным.

Хорошо, это все. Спасибо за прочтение! Исходный код проекта, использованного в статье, вы можете найти на моем GitHub.

Повышение уровня кодирования

Спасибо, что являетесь частью нашего сообщества! Перед тем, как ты уйдешь:

🔔 Подписывайтесь на нас: Twitter | ЛинкедИн | "Новостная рассылка"

🚀👉 Присоединяйтесь к коллективу талантов Level Up и найдите прекрасную работу