Распознавание намерений в речи с помощью пакета SDK службы "Речь" для C#

Пакет SDK службы искусственного интеллекта Azure интегрируется с службой Распознавание речи (LUIS), чтобы обеспечить распознавание намерений. Намерение — это действие, которое хочет выполнить пользователь, например забронировать билет на самолет, проверить прогноз погоды или совершить звонок. Пользователь может использовать любые термины, которые кажутся естественными. LUIS сопоставляет запросы пользователей с заданными намерениями.

Примечание.

Приложение LUIS используется для определения намерений и сущностей, которые требуется распознать. Оно работает отдельно от приложения C#, в котором используется служба "Речь". В этой статье под словом "приложение" подразумевается приложение LUIS, а под "программа" — код C#.

В данном руководстве для разработки консольного приложения C#, извлекающего намерения пользователя из речевых фрагментов, полученных через микрофон устройства, будет использован пакет SDK для службы "Речь". Узнайте следующие темы:

  • создать проект в Visual Studio, ссылающийся на пакет SDK для службы "Речь" для NuGet;
  • выполнить настройки речи и получить распознаватель намерений;
  • создать модель для приложения LUIS и добавить необходимые намерения;
  • указать язык распознавания речи;
  • по распознаванию речи из файла
  • использовать асинхронное непрерывное распознавание при определенном событии.

Необходимые компоненты

Перед началом работы с этим руководством необходимо убедиться в наличии следующих элементов:

LUIS и речь

Чтобы распознать намерения в речи LUIS интегрируется в службу "Речь". Подписка на службу "Речь" не требуется.

В LUIS используются два типа ключей.

Тип ключа Характер использования
Разработка Позволяет программно создавать и изменять приложения LUIS.
Прогноз Используется для доступа к приложению LUIS в среде выполнения

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

Ключ разработки автоматически создается при создании приложения LUIS. Это позволяет тестировать приложение с использованием текстовых запросов. Этот ключ не включает интеграцию службы "Речь" и не работает с этим руководством. На панели мониторинга Azure создайте ресурс LUIS и назначьте его приложению LUIS. Для данного руководства можно использовать бесплатную подписку.

После создания ресурса LUIS на панели мониторинга Azure необходимо войти на портал LUIS и выбрать свою программу на странице Мои приложения, а затем перейти на страницу Управление. Наконец, выберите ресурсы Azure на боковой панели.

Shows a screenshot of the LUIS portal keys and endpoint settings.

На странице ресурсов Azure:

Чтобы скопировать ее в буфер обмена, выберите значок рядом с ключом. (Вы можете использовать любой ключ.)

Создание проекта и добавление рабочей нагрузки

Чтобы создать проект Visual Studio для разработки Windows, необходимо создать проект, настроить Visual Studio для разработки рабочего стола .NET, установить пакет SDK для службы "Речь" и выбрать целевую архитектуру.

Для начала создайте проект в Visual Studio и убедитесь, что Visual Studio настроена на разработку рабочего стола.NET :

  1. Откройте Visual Studio 2019.

  2. В окне "Период запуска" выберите Создать новый проект.

  3. В окне Создание проекта выберите Консольное приложение (.NET Framework) и нажмите кнопку Далее.

  4. В окне Настройка нового проекта введите helloworld в Имя проекта, выберите или создайте путь каталога в Расположение, а затем выберите Создать.

  5. В строке меню Visual Studio выберите Инструменты>Get Tools and Features (Получить инструменты и компоненты), открывающие Visual Studio Installer и показывающие диалоговое окно Идет изменение.

  6. Проверьте, доступна ли рабочая нагрузка разработки классического приложения .NET. Если рабочая нагрузка не установлена, выберите поле проверка рядом с ним и нажмите кнопку "Изменить", чтобы начать установку. Скачивание и установка могут занять несколько минут.

    Если флажок рядом с Разработка классических приложений .NET уже установлен, выберите Закрыть, чтобы выйти из диалогового окна.

    Enable .NET desktop development

  7. Закройте Visual Studio Installer.

Установка пакета SDK Речи

Следующим шагом является установка Speech SDK NuGet package (Речевой пакет SDK NuGet), чтобы вы могли ссылаться на него в коде.

  1. В Обозревателе решений щелкните правой кнопкой мыши на проект helloworld и выберите Управление пакетами NuGet, чтобы отобразить Диспетчер пакетов NuGet.

    NuGet Package Manager

  2. В правом верхнем углу найдите раскрывающийся список Источник пакета и убедитесь, что выбран параметр NuGet.org.

  3. В левом верхнем углу нажмите кнопку Просмотреть.

  4. В поле поиска введите Microsoft.CognitiveServices.Speech и выберите Ввести.

  5. В результатах поиска выберите пакет Microsoft.CognitiveServices.Speech, а затем выберите Установить для установки последней стабильной версии.

    Install Microsoft.CognitiveServices.Speech NuGet package

  6. Примите все соглашения и лицензии для запуска установки.

    После установки пакета на Консоли диспетчера пакетов появится подтверждение.

Выбор целевой архитектуры

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

  1. В строке меню выберите Сборка>Configuration Manager (Диспетчер конфигураций). Откроется диалоговое окноConfigurationManager (Диспетчер конфигураций).

    Configuration Manager dialog box

  2. В раскрывающемся списке Активная платформа решения выберите команду Новый. Откроется диалоговое окно Создание платформы решения.

  3. В раскрывающемся списке Введите или выберите новую платформу.

    • Если вы используете 64-разрядную версию Windows, выберите x64.
    • Если вы используете 32-разрядную версию Windows, выберите x86.
  4. Нажмите ОК, а затем Закрыть.

Добавление кода

Далее добавьте код в проект.

  1. В Обозревателе решений откройте файл Program.cs.

  2. Замените блок операторов using, который находится в начале файла, следующими объявлениями.

    using System;
    using System.Threading.Tasks;
    using Microsoft.CognitiveServices.Speech;
    using Microsoft.CognitiveServices.Speech.Audio;
    using Microsoft.CognitiveServices.Speech.Intent;
    
  3. Замените предоставленный метод Main() следующим асинхронным эквивалентом:

    public static async Task Main()
    {
        await RecognizeIntentAsync();
        Console.WriteLine("Please press Enter to continue.");
        Console.ReadLine();
    }
    
  4. Создайте пустой асинхронный метод RecognizeIntentAsync(), как показано ниже.

    static async Task RecognizeIntentAsync()
    {
    }
    
  5. Добавьте следующий код в текст метода:

    // Creates an instance of a speech config with specified subscription key
    // and service region. Note that in contrast to other services supported by
    // the Cognitive Services Speech SDK, the Language Understanding service
    // requires a specific subscription key from https://www.luis.ai/.
    // The Language Understanding service calls the required key 'endpoint key'.
    // Once you've obtained it, replace with below with your own Language Understanding subscription key
    // and service region (e.g., "westus").
    // The default language is "en-us".
    var config = SpeechConfig.FromSubscription("YourLanguageUnderstandingSubscriptionKey", "YourLanguageUnderstandingServiceRegion");
    
    // Creates an intent recognizer using microphone as audio input.
    using (var recognizer = new IntentRecognizer(config))
    {
        // Creates a Language Understanding model using the app id, and adds specific intents from your model
        var model = LanguageUnderstandingModel.FromAppId("YourLanguageUnderstandingAppId");
        recognizer.AddIntent(model, "YourLanguageUnderstandingIntentName1", "id1");
        recognizer.AddIntent(model, "YourLanguageUnderstandingIntentName2", "id2");
        recognizer.AddIntent(model, "YourLanguageUnderstandingIntentName3", "any-IntentId-here");
    
        // Starts recognizing.
        Console.WriteLine("Say something...");
    
        // Starts intent recognition, and returns after a single utterance is recognized. The end of a
        // single utterance is determined by listening for silence at the end or until a maximum of 15
        // seconds of audio is processed.  The task returns the recognition text as result. 
        // Note: Since RecognizeOnceAsync() returns only a single utterance, it is suitable only for single
        // shot recognition like command or query. 
        // For long-running multi-utterance recognition, use StartContinuousRecognitionAsync() instead.
        var result = await recognizer.RecognizeOnceAsync().ConfigureAwait(false);
    
        // Checks result.
        if (result.Reason == ResultReason.RecognizedIntent)
        {
            Console.WriteLine($"RECOGNIZED: Text={result.Text}");
            Console.WriteLine($"    Intent Id: {result.IntentId}.");
            Console.WriteLine($"    Language Understanding JSON: {result.Properties.GetProperty(PropertyId.LanguageUnderstandingServiceResponse_JsonResult)}.");
        }
        else if (result.Reason == ResultReason.RecognizedSpeech)
        {
            Console.WriteLine($"RECOGNIZED: Text={result.Text}");
            Console.WriteLine($"    Intent not recognized.");
        }
        else if (result.Reason == ResultReason.NoMatch)
        {
            Console.WriteLine($"NOMATCH: Speech could not be recognized.");
        }
        else if (result.Reason == ResultReason.Canceled)
        {
            var cancellation = CancellationDetails.FromResult(result);
            Console.WriteLine($"CANCELED: Reason={cancellation.Reason}");
    
            if (cancellation.Reason == CancellationReason.Error)
            {
                Console.WriteLine($"CANCELED: ErrorCode={cancellation.ErrorCode}");
                Console.WriteLine($"CANCELED: ErrorDetails={cancellation.ErrorDetails}");
                Console.WriteLine($"CANCELED: Did you update the subscription info?");
            }
        }
    }
    
  6. Замените заполнители в этом методе ключом ресурса LUIS, регионом и идентификатором приложения следующим образом.

    Заполнитель Replace with
    YourLanguageUnderstandingSubscriptionKey Ключ ресурса LUIS. Опять же, вы должны получить этот элемент с панели мониторинга Azure. Его можно найти на странице приложения Ресурсы Azure (в разделе Manage (Управление) на портале LUIS.
    YourLanguageUnderstandingServiceRegion Короткий идентификатор для региона, в который находится ресурс LUIS, например westus для западной части США. См. статью Регионы и конечные точки службы "Речь".
    YourLanguageUnderstandingAppId Идентификатор приложения LUIS. Его можно найти на странице Параметры приложения на портале LUIS.

После выполнения этих изменений можно создать (Control+Shift+B) и запустить (F5) приложение. При появлении запроса в микрофон компьютера следует произнести фразу "выключить свет". Приложение отображает результат в окне консоли.

В следующих разделах приводится описание кода.

Создание распознавателя намерений

Во-первых, необходимо создать конфигурацию речи на основе ключа прогнозирования LUIS и данных о регионе. Конфигурации речи могут использоваться для создания распознавателей, обладающих различными возможностями, используемыми в пакете SDK службы "Речь". Конфигурация речи имеет несколько способов указать ресурс, который требуется использовать; Здесь мы используем FromSubscriptionключ ресурса и регион.

Примечание.

Используйте ключ и регион ресурса LUIS, а не ресурс "Речь".

Затем с помощью new IntentRecognizer(config) создайте распознаватель намерений. Так как конфигурация уже знает, какой ресурс следует использовать, при создании распознавателя не нужно указывать ключ еще раз.

Добавление намерений и импорт модели

Теперь импортируйте модель из приложения LUIS с помощью идентификатора LanguageUnderstandingModel.FromAppId() и добавьте те намерения LUIS, которые требуется распознать, с помощью метода AddIntent(). С помощью двух приведенных шагов улучшается точность распознавания речи путем указания слов, которые пользователь может использовать в запросах. Если в программе не планируется распознавать все намерения приложений, их добавление не нужно.

Чтобы добавить намерения, необходимо указать три аргумента: модель LUIS (с именем model), имя намерения и идентификатор намерения. Разница между идентификатором и именем приведена в следующей таблице.

Аргумент AddIntent() Характер использования
intentName Имя намерения, определенного в приложении LUIS. Это значение должно совпадать с именем намерения LUIS.
intentID Идентификатор, присвоенный намерению, распознанному пакетом SDK для службы "Речь". Это значение может быть любым. Оно не обязательно должно соответствовать имени намерения, определенному в приложении LUIS. Для обработки нескольких намерений может использоваться один код, как и один идентификатор используется для всех намерений.

Приложение LUIS для системы домашней автоматики содержит два намерения. Первое — включение устройства, второе — выключение. С помощью приведенных ниже строк намерения будут добавлены в распознаватель. Замените приведенным ниже кодом три строки AddIntent в методе RecognizeIntentAsync().

recognizer.AddIntent(model, "HomeAutomation.TurnOff", "off");
recognizer.AddIntent(model, "HomeAutomation.TurnOn", "on");

Вместо добавления отдельных намерения можно также использовать метод AddAllIntents, чтобы добавить в распознаватель все намерения из модели.

Начало распознавания

После создания распознавателя и добавления намерений можно начать процесс распознавания. В пакете SDK для службы "Речь" поддерживается краткое и непрерывное распознавание.

Режим распознавания Вызываемые методы Результат
Одиночный RecognizeOnceAsync() Возвращает распознанное намерение, извлеченное из одного высказывания.
Непрерывные StartContinuousRecognitionAsync()
StopContinuousRecognitionAsync()
Распознает множественные речевые фрагменты; выдает события (например, IntermediateResultReceived), если результаты доступны.

В приложении используется "одиночный" режим, поэтому для запуска распознавания вызывается RecognizeOnceAsync(). Результат — объект IntentRecognitionResult, который содержит информацию о распознанном намерении. Ответ LUIS в формате JSON извлекается с помощью следующего выражения:

result.Properties.GetProperty(PropertyId.LanguageUnderstandingServiceResponse_JsonResult)

Приложение не выполняет разбор результата JSON. Оно только отображает текст JSON в окне консоли.

Single LUIS recognition results

Указание языка распознавания

По умолчанию язык распознавания намерений — английский (США) (en-us). Чтобы распознавать намерения на других языках, свойству SpeechRecognitionLanguage необходимо присвоить код языкового стандарта. Например, перед созданием распознавателя добавьте в приложение параметр config.SpeechRecognitionLanguage = "de-de";. Это позволит распознавать намерения на немецком языке. Дополнительные сведения см. в разделе Поддержка языков в приложении LUIS.

Непрерывное распознавание из файла

Следующий код иллюстрирует еще две возможности распознавания намерений с помощью пакета SDK службы "Речь". Первая из возможностей, которая была упомянута ранее, — непрерывное распознавание, используя которое распознаватель извлекает события при получении результата. Эти события обрабатываются предоставленными обработчиками событий. При непрерывном распознавании вызывается метод распознавания StartContinuousRecognitionAsync(), который начнет работать вместо RecognizeOnceAsync().

К другим возможностям можно отнести считывание звукового файла в формате WAV, содержащего речь, подлежащую обработке. Реализация включает создание конфигурации звука, которую можно использовать при создании распознавателя намерений. Файл должен состоять из одного канала (моно) с уровнем дискретизации 16 000 Гц.

Чтобы опробовать эти возможности, удалите или прокомментируйте текст метода RecognizeIntentAsync() и добавьте вместо него следующий код.

// Creates an instance of a speech config with specified subscription key
// and service region. Note that in contrast to other services supported by
// the Cognitive Services Speech SDK, the Language Understanding service
// requires a specific subscription key from https://www.luis.ai/.
// The Language Understanding service calls the required key 'endpoint key'.
// Once you've obtained it, replace with below with your own Language Understanding subscription key
// and service region (e.g., "westus").
var config = SpeechConfig.FromSubscription("YourLanguageUnderstandingSubscriptionKey", "YourLanguageUnderstandingServiceRegion");

// Creates an intent recognizer using file as audio input.
// Replace with your own audio file name.
using (var audioInput = AudioConfig.FromWavFileInput("YourAudioFile.wav"))
{
    using (var recognizer = new IntentRecognizer(config, audioInput))
    {
        // The TaskCompletionSource to stop recognition.
        var stopRecognition = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);

        // Creates a Language Understanding model using the app id, and adds specific intents from your model
        var model = LanguageUnderstandingModel.FromAppId("YourLanguageUnderstandingAppId");
        recognizer.AddIntent(model, "YourLanguageUnderstandingIntentName1", "id1");
        recognizer.AddIntent(model, "YourLanguageUnderstandingIntentName2", "id2");
        recognizer.AddIntent(model, "YourLanguageUnderstandingIntentName3", "any-IntentId-here");

        // Subscribes to events.
        recognizer.Recognizing += (s, e) =>
        {
            Console.WriteLine($"RECOGNIZING: Text={e.Result.Text}");
        };

        recognizer.Recognized += (s, e) =>
        {
            if (e.Result.Reason == ResultReason.RecognizedIntent)
            {
                Console.WriteLine($"RECOGNIZED: Text={e.Result.Text}");
                Console.WriteLine($"    Intent Id: {e.Result.IntentId}.");
                Console.WriteLine($"    Language Understanding JSON: {e.Result.Properties.GetProperty(PropertyId.LanguageUnderstandingServiceResponse_JsonResult)}.");
            }
            else if (e.Result.Reason == ResultReason.RecognizedSpeech)
            {
                Console.WriteLine($"RECOGNIZED: Text={e.Result.Text}");
                Console.WriteLine($"    Intent not recognized.");
            }
            else if (e.Result.Reason == ResultReason.NoMatch)
            {
                Console.WriteLine($"NOMATCH: Speech could not be recognized.");
            }
        };

        recognizer.Canceled += (s, e) =>
        {
            Console.WriteLine($"CANCELED: Reason={e.Reason}");

            if (e.Reason == CancellationReason.Error)
            {
                Console.WriteLine($"CANCELED: ErrorCode={e.ErrorCode}");
                Console.WriteLine($"CANCELED: ErrorDetails={e.ErrorDetails}");
                Console.WriteLine($"CANCELED: Did you update the subscription info?");
            }

            stopRecognition.TrySetResult(0);
        };

        recognizer.SessionStarted += (s, e) =>
        {
            Console.WriteLine("\n    Session started event.");
        };

        recognizer.SessionStopped += (s, e) =>
        {
            Console.WriteLine("\n    Session stopped event.");
            Console.WriteLine("\nStop recognition.");
            stopRecognition.TrySetResult(0);
        };


        // Starts continuous recognition. Uses StopContinuousRecognitionAsync() to stop recognition.
        await recognizer.StartContinuousRecognitionAsync().ConfigureAwait(false);

        // Waits for completion.
        // Use Task.WaitAny to keep the task rooted.
        Task.WaitAny(new[] { stopRecognition.Task });

        // Stops recognition.
        await recognizer.StopContinuousRecognitionAsync().ConfigureAwait(false);
    }
}

Пересмотрите код на наличие ключа прогнозирования LUIS, данных о регионе и идентификатора приложения и, как и в предыдущем примере, добавьте намерения системы домашней автоматики. Измените имя whatstheweatherlike.wav на имя вашего звукового файла. Затем выполните сборку, скопируйте звуковой файл в каталог сборки и запустите приложение.

Например, если вы произнесете слово "Отключить свет", приостановите и нажмите кнопку "Включить свет" в записанном звуковом файле, выходные данные консоли, аналогичные следующим:

Audio file LUIS recognition results

Группа разработки пакета SDK для службы "Речь" активно поддерживает большой набор примеров в репозитории с открытым кодом. Пример репозитория исходного кода см. в пакете SDK службы "Речь ИИ Azure" на сайте GitHub. Имеются примеры для таких языков, как C#, C++, Java, Python, Objective-C, Swift, JavaScript, UWP, Unity и Xamarin. Код, используемый в данной статье, можно найти в папке samples/csharp/sharedcontent/console.

Следующие шаги

Краткое руководство. Распознавание речи с микрофона