Краткое руководство. Распознавание и проверка говорящего

Справочная документация | Пакет (NuGet) | Дополнительные примеры в GitHub

В этом руководстве показаны базовые конструктивные шаблоны для распознавания говорящего с помощью пакета SDK службы "Речь". В статье рассматриваются следующие темы:

  • Проверка, зависящая от текста и не зависящая от текста.
  • Идентификация говорящего для идентификации образца голоса в группе голосов.
  • Удаление речевых профилей.

Общие сведения о концепциях распознавания говорящего см. в статье Обзор. Список поддерживаемых платформ см. на узле ссылки на панели навигации слева.

Важно!

Корпорация Майкрософт ограничивает доступ к распознаванию говорящего. Примените его с помощью формы azure AI Speaker Recognition Limited Access Review( Проверка ограниченного доступа). После утверждения можно получить доступ к API Распознавания говорящего.

Предварительные требования

Установка пакета SDK службы "Речь"

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

Импорт зависимостей

Чтобы выполнить примеры из этой статьи, добавьте в начале скрипта следующие инструкции using:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.CognitiveServices.Speech;
using Microsoft.CognitiveServices.Speech.Audio;

Создание конфигурации службы "Речь"

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

Важно!

Не забудьте удалить ключ из кода, когда закончите, и никогда не публикуйте его в открытом доступе. Для рабочей среды используйте безопасный способ хранения и доступа к учетным данным, например Azure Key Vault. Дополнительные сведения см. в статье о безопасности служб ИИ Azure.

public class Program 
{
    static async Task Main(string[] args)
    {
        // replace with your own subscription key 
        string subscriptionKey = "YourSubscriptionKey";
        // replace with your own subscription region 
        string region = "YourSubscriptionRegion";
        var config = SpeechConfig.FromSubscription(subscriptionKey, region);
    }
}

Проверка, зависящая от текста

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

Начните с создания следующей функции в классе Program, чтобы зарегистрировать речевой профиль:

public static async Task VerificationEnroll(SpeechConfig config, Dictionary<string, string> profileMapping)
{
    using (var client = new VoiceProfileClient(config))
    using (var profile = await client.CreateProfileAsync(VoiceProfileType.TextDependentVerification, "en-us"))
    {
        var phraseResult = await client.GetActivationPhrasesAsync(VoiceProfileType.TextDependentVerification, "en-us");
        using (var audioInput = AudioConfig.FromDefaultMicrophoneInput())
        {
            Console.WriteLine($"Enrolling profile id {profile.Id}.");
            // give the profile a human-readable display name
            profileMapping.Add(profile.Id, "Your Name");

            VoiceProfileEnrollmentResult result = null;
            while (result is null || result.RemainingEnrollmentsCount > 0)
            {
                Console.WriteLine($"Speak the passphrase, \"${phraseResult.Phrases[0]}\"");
                result = await client.EnrollProfileAsync(profile, audioInput);
                Console.WriteLine($"Remaining enrollments needed: {result.RemainingEnrollmentsCount}");
                Console.WriteLine("");
            }
            
            if (result.Reason == ResultReason.EnrolledVoiceProfile)
            {
                await SpeakerVerify(config, profile, profileMapping);
            }
            else if (result.Reason == ResultReason.Canceled)
            {
                var cancellation = VoiceProfileEnrollmentCancellationDetails.FromResult(result);
                Console.WriteLine($"CANCELED {profile.Id}: ErrorCode={cancellation.ErrorCode} ErrorDetails={cancellation.ErrorDetails}");
            }
        }
    }
}

В этой функции await client.CreateProfileAsync() — то, что фактически создает новый речевой профиль. После ее создания вы указываете, как будут вводиться звуковые образцы. В данном примере для записи звука с устройства ввода по умолчанию используется AudioConfig.FromDefaultMicrophoneInput(). Затем вы регистрируете звуковые образцы в цикле while, отслеживающем количество оставшихся образцов, которые должны быть зарегистрированы. В каждой итерации client.EnrollProfileAsync(profile, audioInput) предлагает произнести парольную фразу в микрофон и добавляет этот образец в речевой профиль.

После завершения регистрации вызывается await SpeakerVerify(config, profile, profileMapping) для проверки только что созданного профиля. Добавьте еще одну функцию для определения SpeakerVerify.

public static async Task SpeakerVerify(SpeechConfig config, VoiceProfile profile, Dictionary<string, string> profileMapping)
{
    var speakerRecognizer = new SpeakerRecognizer(config, AudioConfig.FromDefaultMicrophoneInput());
    var model = SpeakerVerificationModel.FromProfile(profile);

    Console.WriteLine("Speak the passphrase to verify: \"My voice is my passport, please verify me.\"");
    var result = await speakerRecognizer.RecognizeOnceAsync(model);
    Console.WriteLine($"Verified voice profile for speaker {profileMapping[result.ProfileId]}, score is {result.Score}");
}

В этой функции вы передаете только что созданный объект VoiceProfile, чтобы инициализировать модель для проверки. Затем await speakerRecognizer.RecognizeOnceAsync(model) предлагает еще раз произнести парольную фразу. На этот раз она будет проверяться на соответствие речевому профилю, после чего будет возвращаться показатель подобия от 0,0 до 1,0. Объект result также возвращает Accept или Reject в зависимости от того, соответствует ли парольная фраза.

Затем измените функцию Main() для вызова новых созданных функций. Кроме того, обратите внимание, что вы создаете Dictionary<string, string> для передачи по ссылке через вызовы функции. Это связано с тем, что для обеспечения конфиденциальности служба не позволяет хранить удобное для восприятия человеком имя с созданным VoiceProfile и сохраняет только идентификационный номер. В функции VerificationEnroll вы добавляете в этот словарь запись с только что созданным идентификатором и текстовым именем. В сценариях разработки приложений, где необходимо отображать удобное для восприятия имя, необходимо хранить это сопоставление где-нибудь еще, так как служба не может его хранить.

static async Task Main(string[] args)
{
    string subscriptionKey = "YourSubscriptionKey";
    string region = "westus";
    var config = SpeechConfig.FromSubscription(subscriptionKey, region);

    // persist profileMapping if you want to store a record of who the profile is
    var profileMapping = new Dictionary<string, string>();
    await VerificationEnroll(config, profileMapping);

    Console.ReadLine();
}

Выполните скрипт. Вам будет предложено произнести фразу "Мой голос — мой паспорт, проверьте меня" три раза для регистрации и еще один раз для проверки. Возвращаемый результат является показателем подобия, который можно использовать для создания собственных настраиваемых порогов для проверки.

Enrolling profile id 87-2cef-4dff-995b-dcefb64e203f.
Speak the passphrase, "My voice is my passport, verify me."
Remaining enrollments needed: 2

Speak the passphrase, "My voice is my passport, verify me."
Remaining enrollments needed: 1

Speak the passphrase, "My voice is my passport, verify me."
Remaining enrollments needed: 0

Speak the passphrase to verify: "My voice is my passport, verify me."
Verified voice profile for speaker Your Name, score is 0.915581

Проверка, не зависящая от текста

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

Внесите несколько простых изменений в функцию VerificationEnroll, чтобы переключиться на проверку, не зависящую от текста. Сначала измените тип проверки на VoiceProfileType.TextIndependentVerification. Затем измените цикл while, чтобы он отслеживал result.RemainingEnrollmentsSpeechLength и запрос на произнесение речи выводился до тех пор, пока не будут записаны 20 секунд.

public static async Task VerificationEnroll(SpeechConfig config, Dictionary<string, string> profileMapping)
{
    using (var client = new VoiceProfileClient(config))
    using (var profile = await client.CreateProfileAsync(VoiceProfileType.TextIndependentVerification, "en-us"))
    {
        var phraseResult = await client.GetActivationPhrasesAsync(VoiceProfileType.TextIndependentVerification, "en-us");
        using (var audioInput = AudioConfig.FromDefaultMicrophoneInput())
        {
            Console.WriteLine($"Enrolling profile id {profile.Id}.");
            // give the profile a human-readable display name
            profileMapping.Add(profile.Id, "Your Name");

            VoiceProfileEnrollmentResult result = null;
            while (result is null || result.RemainingEnrollmentsSpeechLength > TimeSpan.Zero)
            {
                Console.WriteLine($"Speak the activation phrase, \"${phraseResult.Phrases[0]}\"");
                result = await client.EnrollProfileAsync(profile, audioInput);
                Console.WriteLine($"Remaining enrollment audio time needed: {result.RemainingEnrollmentsSpeechLength}");
                Console.WriteLine("");
            }
            
            if (result.Reason == ResultReason.EnrolledVoiceProfile)
            {
                await SpeakerVerify(config, profile, profileMapping);
            }
            else if (result.Reason == ResultReason.Canceled)
            {
                var cancellation = VoiceProfileEnrollmentCancellationDetails.FromResult(result);
                Console.WriteLine($"CANCELED {profile.Id}: ErrorCode={cancellation.ErrorCode} ErrorDetails={cancellation.ErrorDetails}");
            }
        }
    }
}

Снова запустите программу. Возвращается показатель подобия.

Enrolling profile id 4tt87d4-f2d3-44ae-b5b4-f1a8d4036ee9.
Speak the activation phrase, "<FIRST ACTIVATION PHRASE>"
Remaining enrollment audio time needed: 00:00:15.3200000

Speak the activation phrase, "<FIRST ACTIVATION PHRASE>"
Remaining enrollment audio time needed: 00:00:09.8100008

Speak the activation phrase, "<FIRST ACTIVATION PHRASE>"
Remaining enrollment audio time needed: 00:00:05.1900000

Speak the activation phrase, "<FIRST ACTIVATION PHRASE>"
Remaining enrollment audio time needed: 00:00:00.8700000

Speak the activation phrase, "<FIRST ACTIVATION PHRASE>"
Remaining enrollment audio time needed: 00:00:00

Speak the passphrase to verify: "My voice is my passport, please verify me."
Verified voice profile for speaker Your Name, score is 0.849409

Идентификация говорящего

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

Создайте функцию IdentificationEnroll для регистрации нескольких речевых профилей. Процесс регистрации каждого профиля аналогичен процессу регистрации при проверке, не зависящей от текста, и для каждого профиля требуется 20 секунд речи. Эта функция принимает список строк profileNames и создает новый речевой профиль для каждого имени в списке. Функция возвращает список объектов VoiceProfile, которые используются в следующей функции для определения говорящего.

public static async Task<List<VoiceProfile>> IdentificationEnroll(SpeechConfig config, List<string> profileNames, Dictionary<string, string> profileMapping)
{
    List<VoiceProfile> voiceProfiles = new List<VoiceProfile>();
    using (var client = new VoiceProfileClient(config))
    {
        var phraseResult = await client.GetActivationPhrasesAsync(VoiceProfileType.TextIndependentVerification, "en-us");
        foreach (string name in profileNames)
        {
            using (var audioInput = AudioConfig.FromDefaultMicrophoneInput())
            {
                var profile = await client.CreateProfileAsync(VoiceProfileType.TextIndependentIdentification, "en-us");
                Console.WriteLine($"Creating voice profile for {name}.");
                profileMapping.Add(profile.Id, name);

                VoiceProfileEnrollmentResult result = null;
                while (result is null || result.RemainingEnrollmentsSpeechLength > TimeSpan.Zero)
                {
                    Console.WriteLine($"Speak the activation phrase, \"${phraseResult.Phrases[0]}\" to add to the profile enrollment sample for {name}.");
                    result = await client.EnrollProfileAsync(profile, audioInput);
                    Console.WriteLine($"Remaining enrollment audio time needed: {result.RemainingEnrollmentsSpeechLength}");
                    Console.WriteLine("");
                }
                voiceProfiles.Add(profile);
            }
        }
    }
    return voiceProfiles;
}

Создайте следующую функцию SpeakerIdentification, чтобы отправить запрос на идентификацию. Основное отличие этой функции от запроса проверки говорящего заключается в использовании метода SpeakerIdentificationModel.FromProfiles(), который принимает список объектов VoiceProfile.

public static async Task SpeakerIdentification(SpeechConfig config, List<VoiceProfile> voiceProfiles, Dictionary<string, string> profileMapping) 
{
    var speakerRecognizer = new SpeakerRecognizer(config, AudioConfig.FromDefaultMicrophoneInput());
    var model = SpeakerIdentificationModel.FromProfiles(voiceProfiles);

    Console.WriteLine("Speak some text to identify who it is from your list of enrolled speakers.");
    var result = await speakerRecognizer.RecognizeOnceAsync(model);
    Console.WriteLine($"The most similar voice profile is {profileMapping[result.ProfileId]} with similarity score {result.Score}");
}

Измените функцию Main() следующим образом. Вы создаете список строк profileNames, который передаете в функцию IdentificationEnroll(). Появится запрос на создание нового речевого профиля для каждого имени в этом списке, поэтому можно добавить дополнительные имена для создания дополнительных профилей для друзей или коллег.

static async Task Main(string[] args)
{
    // replace with your own subscription key 
    string subscriptionKey = "YourSubscriptionKey";
    // replace with your own subscription region 
    string region = "YourSubscriptionRegion";
    var config = SpeechConfig.FromSubscription(subscriptionKey, region);

    // persist profileMapping if you want to store a record of who the profile is
    var profileMapping = new Dictionary<string, string>();
    var profileNames = new List<string>() { "Your name", "A friend's name" };
    
    var enrolledProfiles = await IdentificationEnroll(config, profileNames, profileMapping);
    await SpeakerIdentification(config, enrolledProfiles, profileMapping);

    foreach (var profile in enrolledProfiles)
    {
        profile.Dispose();
    }
    Console.ReadLine();
}

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

В этом примере возвращается только ближайшее соответствие и показатель подобия, но можно получить полный ответ, включающий пять главных показателей подобия, добавив string json = result.Properties.GetProperty(PropertyId.SpeechServiceResponse_JsonResult) в вашу функцию SpeakerIdentification.

Изменение типа входных звуковых данных

В примерах, приведенных в этой статье, для записи образцов звука используется микрофон устройства по умолчанию. Если же необходимо использовать звуковые файлы вместо ввода с микрофона, измените любой экземпляр AudioConfig.FromDefaultMicrophoneInput() на AudioConfig.FromWavFileInput(path/to/your/file.wav), чтобы переключиться на ввод файлов. Можно также использовать смешанные входные данные, например микрофон для регистрации и файлы для проверки.

Удаление регистраций речевых профилей

Чтобы удалить зарегистрированный профиль, используйте функцию DeleteProfileAsync() в объекте VoiceProfileClient. В следующем примере функции показано, как удалить речевой профиль для известного идентификатора речевого профиля:

public static async Task DeleteProfile(SpeechConfig config, string profileId) 
{
    using (var client = new VoiceProfileClient(config))
    {
        var profile = new VoiceProfile(profileId);
        await client.DeleteProfileAsync(profile);
    }
}

Справочная документация | Пакет (NuGet) | Дополнительные примеры в GitHub

В этом руководстве показаны базовые конструктивные шаблоны для распознавания говорящего с помощью пакета SDK службы "Речь". В статье рассматриваются следующие темы:

  • Проверка, зависящая от текста и не зависящая от текста.
  • Идентификация говорящего для идентификации образца голоса в группе голосов.
  • Удаление речевых профилей.

Общие сведения о концепциях распознавания говорящего см. в статье Обзор. Список поддерживаемых платформ см. на узле ссылки на панели навигации слева.

Важно!

Корпорация Майкрософт ограничивает доступ к распознаванию говорящего. Примените его с помощью формы azure AI Speaker Recognition Limited Access Review( Проверка ограниченного доступа). После утверждения можно получить доступ к API Распознавания говорящего.

Предварительные требования

Установка пакета SDK службы "Речь"

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

Импорт зависимостей

Чтобы выполнить примеры из этой статьи, добавьте в начале CPP-файла следующие инструкции:

#include <iostream>
#include <stdexcept>
// Note: Install the NuGet package Microsoft.CognitiveServices.Speech.
#include <speechapi_cxx.h>

using namespace std;
using namespace Microsoft::CognitiveServices::Speech;

// Note: Change the locale if desired.
auto profile_locale = "en-us";
auto audio_config = Audio::AudioConfig::FromDefaultMicrophoneInput();
auto ticks_per_second = 10000000;

Создание конфигурации службы "Речь"

Чтобы вызвать службу "Речь" с помощью пакета SDK для службы "Речь", создайте класс SpeechConfig. Этот класс содержит сведения о вашей подписке, такие как ключ и связанный регион, конечная точка, узел или маркер авторизации.

Важно!

Не забудьте удалить ключ из кода, когда закончите, и никогда не публикуйте его в открытом доступе. Для рабочей среды используйте безопасный способ хранения и доступа к учетным данным, например Azure Key Vault. Дополнительные сведения см. в статье о безопасности служб ИИ Azure.

shared_ptr<SpeechConfig> GetSpeechConfig()
{
    auto subscription_key = 'PASTE_YOUR_SPEECH_SUBSCRIPTION_KEY_HERE';
    auto region = 'PASTE_YOUR_SPEECH_ENDPOINT_REGION_HERE';
    auto config = SpeechConfig::FromSubscription(subscription_key, region);
    return config;
}

Проверка, зависящая от текста

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

Функция TextDependentVerification

Начните с создания функции TextDependentVerification:

void TextDependentVerification(shared_ptr<VoiceProfileClient> client, shared_ptr<SpeakerRecognizer> recognizer)
{
    std::cout << "Text Dependent Verification:\n\n";
    // Create the profile.
    auto profile = client->CreateProfileAsync(VoiceProfileType::TextDependentVerification, profile_locale).get();
    std::cout << "Created profile ID: " << profile->GetId() << "\n";
    AddEnrollmentsToTextDependentProfile(client, profile);
    SpeakerVerify(profile, recognizer);
    // Delete the profile.
    client->DeleteProfileAsync(profile);
}

Эта функция создает объект VoiceProfile с помощью метода CreateProfileAsync. Здесь возможны три вариантаVoiceProfile:

  • TextIndependentIdentification
  • TextDependentVerification
  • TextIndependentVerification

В этом примере VoiceProfileType::TextDependentVerification передается в CreateProfileAsync.

Затем нужно вызвать две вспомогательные функции AddEnrollmentsToTextDependentProfile и SpeakerVerify, которые вы определяете далее. Наконец, вызовите DeleteProfileAsync, чтобы очистить профиль.

Функция AddEnrollmentsToTextDependentProfile

Определите следующую функцию, чтобы зарегистрировать речевой профиль:

void AddEnrollmentsToTextDependentProfile(shared_ptr<VoiceProfileClient> client, shared_ptr<VoiceProfile> profile)
{
    shared_ptr<VoiceProfileEnrollmentResult> enroll_result = nullptr;
    auto phraseResult = client->GetActivationPhrasesAsync(profile->GetType(), profile_locale).get();
    auto phrases = phraseResult->GetPhrases();
    while (enroll_result == nullptr || enroll_result->GetEnrollmentInfo(EnrollmentInfoType::RemainingEnrollmentsCount) > 0)
    {
        if (phrases != nullptr && phrases->size() > 0)
        {
            std::cout << "Please say the passphrase, \"" << phrases->at(0) << "\"\n";
            enroll_result = client->EnrollProfileAsync(profile, audio_config).get();
            std::cout << "Remaining enrollments needed: " << enroll_result->GetEnrollmentInfo(EnrollmentInfoType::RemainingEnrollmentsCount) << ".\n";
        }
        else
        {
            std::cout << "No passphrases received, enrollment not attempted.\n\n";
        }
    }
    std::cout << "Enrollment completed.\n\n";
}

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

Функция SpeakerVerify

Определите SpeakerVerify следующим образом:

void SpeakerVerify(shared_ptr<VoiceProfile> profile, shared_ptr<SpeakerRecognizer> recognizer)
{
    shared_ptr<SpeakerVerificationModel> model = SpeakerVerificationModel::FromProfile(profile);
    std::cout << "Speak the passphrase to verify: \"My voice is my passport, verify me.\"\n";
    shared_ptr<SpeakerRecognitionResult> result = recognizer->RecognizeOnceAsync(model).get();
    std::cout << "Verified voice profile for speaker: " << result->ProfileId << ". Score is: " << result->GetScore() << ".\n\n";
}

В этой функции вы создаете объект SpeakerVerificationModel с помощью метода SpeakerVerificationModel::FromProfile, передавая ранее созданный объект VoiceProfile.

Затем SpeechRecognizer::RecognizeOnceAsync предлагает снова произнести парольную фразу. На этот раз она будет проверяться на соответствие речевому профилю, после чего будет возвращаться показатель подобия от 0,0 до 1,0. Объект SpeakerRecognitionResult также возвращает Accept или Reject в зависимости от того, соответствует ли парольная фраза.

Проверка, не зависящая от текста

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

Функция TextIndependentVerification

Начните с создания функции TextIndependentVerification:

void TextIndependentVerification(shared_ptr<VoiceProfileClient> client, shared_ptr<SpeakerRecognizer> recognizer)
{
    std::cout << "Text Independent Verification:\n\n";
    // Create the profile.
    auto profile = client->CreateProfileAsync(VoiceProfileType::TextIndependentVerification, profile_locale).get();
    std::cout << "Created profile ID: " << profile->GetId() << "\n";
    AddEnrollmentsToTextIndependentProfile(client, profile);
    SpeakerVerify(profile, recognizer);
    // Delete the profile.
    client->DeleteProfileAsync(profile);
}

Как и функция TextDependentVerification, эта функция создает объект VoiceProfile с помощью метода CreateProfileAsync.

В этом примере VoiceProfileType::TextIndependentVerification передается в CreateProfileAsync.

Затем нужно вызвать две вспомогательные функции: AddEnrollmentsToTextIndependentProfile (определяется далее) и SpeakerVerify (уже определена). Наконец, вызовите DeleteProfileAsync, чтобы очистить профиль.

AddEnrollmentsToTextIndependentProfile

Определите следующую функцию, чтобы зарегистрировать речевой профиль:

void AddEnrollmentsToTextIndependentProfile(shared_ptr<VoiceProfileClient> client, shared_ptr<VoiceProfile> profile)
{
    shared_ptr<VoiceProfileEnrollmentResult> enroll_result = nullptr;
    auto phraseResult = client->GetActivationPhrasesAsync(profile->GetType(), profile_locale).get();
    auto phrases = phraseResult->GetPhrases();
    while (enroll_result == nullptr || enroll_result->GetEnrollmentInfo(EnrollmentInfoType::RemainingEnrollmentsSpeechLength) > 0)
    {
        if (phrases != nullptr && phrases->size() > 0)
        {
            std::cout << "Please say the activation phrase, \"" << phrases->at(0) << "\"\n";
            enroll_result = client->EnrollProfileAsync(profile, audio_config).get();
            std::cout << "Remaining audio time needed: " << enroll_result->GetEnrollmentInfo(EnrollmentInfoType::RemainingEnrollmentsSpeechLength) / ticks_per_second << " seconds.\n";
        }
        else
        {
            std::cout << "No activation phrases received, enrollment not attempted.\n\n";
        }
    }
    std::cout << "Enrollment completed.\n\n";
}

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

Идентификация говорящего

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

Функция TextIndependentIdentification

Начните с создания функции TextIndependentIdentification:

void TextIndependentIdentification(shared_ptr<VoiceProfileClient> client, shared_ptr<SpeakerRecognizer> recognizer)
{
    std::cout << "Speaker Identification:\n\n";
    // Create the profile.
    auto profile = client->CreateProfileAsync(VoiceProfileType::TextIndependentIdentification, profile_locale).get();
    std::cout << "Created profile ID: " << profile->GetId() << "\n";
    AddEnrollmentsToTextIndependentProfile(client, profile);
    SpeakerIdentify(profile, recognizer);
    // Delete the profile.
    client->DeleteProfileAsync(profile);
}

Как и функции TextDependentVerification и TextIndependentVerification, эта функция создает объект VoiceProfile с помощью метода CreateProfileAsync.

В этом примере VoiceProfileType::TextIndependentIdentification передается в CreateProfileAsync.

Затем нужно вызвать две вспомогательные функции: уже определенную вами AddEnrollmentsToTextIndependentProfile и SpeakerIdentify, которую вы определите. Наконец, вызовите DeleteProfileAsync, чтобы очистить профиль.

Функция SpeakerIdentify

Определите функцию SpeakerIdentify следующим образом:

void SpeakerIdentify(shared_ptr<VoiceProfile> profile, shared_ptr<SpeakerRecognizer> recognizer)
{
    shared_ptr<SpeakerIdentificationModel> model = SpeakerIdentificationModel::FromProfiles({ profile });
    // Note: We need at least four seconds of audio after pauses are subtracted.
    std::cout << "Please speak for at least ten seconds to identify who it is from your list of enrolled speakers.\n";
    shared_ptr<SpeakerRecognitionResult> result = recognizer->RecognizeOnceAsync(model).get();
    std::cout << "The most similar voice profile is: " << result->ProfileId << " with similarity score: " << result->GetScore() << ".\n\n";
}

В этой функции вы создаете объект SpeakerIdentificationModel с помощью метода SpeakerIdentificationModel::FromProfiles. Метод SpeakerIdentificationModel::FromProfiles принимает список объектов VoiceProfile. В этом случае вы передадите ранее созданный объект VoiceProfile. При необходимости можно передать несколько объектов VoiceProfile, каждый из которых зарегистрирован с помощью звуковых примеров другого голоса.

Затем SpeechRecognizer::RecognizeOnceAsync предлагает говорить снова. На этот раз он сравнивает ваш голос с зарегистрированными речевыми профилями и возвращает самый похожий речевой профиль.

Функция main

Наконец, определите функцию main следующим образом:

int main()
{
    auto speech_config = GetSpeechConfig();
    auto client = VoiceProfileClient::FromConfig(speech_config);
    auto recognizer = SpeakerRecognizer::FromConfig(speech_config, audio_config);
    TextDependentVerification(client, recognizer);
    TextIndependentVerification(client, recognizer);
    TextIndependentIdentification(client, recognizer);
    std::cout << "End of quickstart.\n";
}

Эта функция вызывает ранее определенные функции. Сначала она создает объекты VoiceProfileClient и SpeakerRecognizer.

auto speech_config = GetSpeechConfig();
auto client = VoiceProfileClient::FromConfig(speech_config);
auto recognizer = SpeakerRecognizer::FromConfig(speech_config, audio_config);

Объект VoiceProfileClient используется для создания, регистрации и удаления речевых профилей. Объект SpeakerRecognizer используется для проверки примеров речи по одному или нескольким зарегистрированным речевым профилям.

Изменение типа входных звуковых данных

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

auto audio_config = Audio::AudioConfig::FromDefaultMicrophoneInput();

на:

auto audio_config = Audio::AudioConfig::FromWavFileInput("path/to/your/file.wav");

Или замените audio_config на Audio::AudioConfig::FromWavFileInput. Можно также использовать смешанные входные данные, например микрофон для регистрации и файлы для проверки.

Справочная документация | Пакет (Go) | Дополнительные примеры в GitHub

В этом руководстве показаны базовые конструктивные шаблоны для распознавания говорящего с помощью пакета SDK службы "Речь". В статье рассматриваются следующие темы:

  • Проверка, зависящая от текста и не зависящая от текста.
  • Идентификация говорящего для идентификации образца голоса в группе голосов.
  • Удаление речевых профилей.

Общие сведения о концепциях распознавания говорящего см. в статье Обзор. Список поддерживаемых платформ см. на узле ссылки на панели навигации слева.

Важно!

Корпорация Майкрософт ограничивает доступ к распознаванию говорящего. Примените его для использования с помощью формы Azure AI Speaker Recognition Limited Access Review . После утверждения можно получить доступ к API Распознавания говорящего.

Предварительные требования

Настройка среды

Установите пакет SDK службы "Речь" для Go. Сначала ознакомьтесь со статьей Руководство по установке пакета SDK, чтобы узнать о дополнительных требованиях.

Выполнение независимой идентификации

Выполните следующие действия, чтобы создать новый модуль GO.

  1. Откройте командную строку, в которой должен быть создан новый модуль, и создайте новый файл с именем independent-identification.go.

  2. Замените все содержимое independent-identification.go следующим кодом:

    package main
    
    import (
        "bufio"
        "fmt"
        "os"
        "time"
    
        "github.com/Microsoft/cognitive-services-speech-sdk-go/audio"
        "github.com/Microsoft/cognitive-services-speech-sdk-go/common"
        "github.com/Microsoft/cognitive-services-speech-sdk-go/speaker"
        "github.com/Microsoft/cognitive-services-speech-sdk-go/speech"
    )
    
    func GetNewVoiceProfileFromClient(client *speaker.VoiceProfileClient, expectedType common.VoiceProfileType) *speaker.VoiceProfile {
        future := client.CreateProfileAsync(expectedType, "en-US")
        outcome := <-future
        if outcome.Failed() {
            fmt.Println("Got an error creating profile: ", outcome.Error.Error())
            return nil
        }
        profile := outcome.Profile
        _, err := profile.Id()
        if err != nil {
            fmt.Println("Unexpected error creating profile id: ", err)
            return nil
        }
        profileType, err := profile.Type();
        if err != nil {
            fmt.Println("Unexpected error getting profile type: ", err)
            return nil
        }
        if profileType != expectedType {
            fmt.Println("Profile type does not match expected type")
            return nil
        }
        return profile
    }
    
    func EnrollProfile(client *speaker.VoiceProfileClient, profile *speaker.VoiceProfile, audioConfig *audio.AudioConfig) {
        enrollmentReason, currentReason := common.EnrollingVoiceProfile, common.EnrollingVoiceProfile
        var currentResult *speaker.VoiceProfileEnrollmentResult
        expectedEnrollmentCount := 1
        for currentReason == enrollmentReason {
            fmt.Println(`Please speak the following phrase: "I'll talk for a few seconds so you can recognize my voice in the future."`)
            enrollFuture := client.EnrollProfileAsync(profile, audioConfig)
            enrollOutcome := <-enrollFuture
            if enrollOutcome.Failed() {
                fmt.Println("Got an error enrolling profile: ", enrollOutcome.Error.Error())
                return
            }
            currentResult = enrollOutcome.Result
            currentReason = currentResult.Reason
            if currentResult.EnrollmentsCount != expectedEnrollmentCount {
                fmt.Println("Unexpected enrollments for profile: ", currentResult.RemainingEnrollmentsCount)
            }
            expectedEnrollmentCount += 1
        }
        if currentReason != common.EnrolledVoiceProfile {
            fmt.Println("Unexpected result enrolling profile: ", currentResult)
        }
    }
    
    func DeleteProfile(client *speaker.VoiceProfileClient, profile *speaker.VoiceProfile) {
        deleteFuture := client.DeleteProfileAsync(profile)
        deleteOutcome := <-deleteFuture
        if deleteOutcome.Failed() {
            fmt.Println("Got an error deleting profile: ", deleteOutcome.Error.Error())
            return
        }
        result := deleteOutcome.Result
        if result.Reason != common.DeletedVoiceProfile {
            fmt.Println("Unexpected result deleting profile: ", result)
        }
    }
    
    func main() {
        subscription :=  "YourSubscriptionKey"
        region := "YourServiceRegion"
        config, err := speech.NewSpeechConfigFromSubscription(subscription, region)
        if err != nil {
            fmt.Println("Got an error: ", err)
            return
        }
        defer config.Close()
        client, err := speaker.NewVoiceProfileClientFromConfig(config)
        if err != nil {
            fmt.Println("Got an error: ", err)
            return
        }
        defer client.Close()
        audioConfig, err := audio.NewAudioConfigFromDefaultMicrophoneInput()
        if err != nil {
            fmt.Println("Got an error: ", err)
            return
        }
        defer audioConfig.Close()
        <-time.After(10 * time.Second)
        expectedType := common.VoiceProfileType(1)
    
        profile := GetNewVoiceProfileFromClient(client, expectedType)
        if profile == nil {
            fmt.Println("Error creating profile")
            return
        }
        defer profile.Close()
    
        EnrollProfile(client, profile, audioConfig)
    
        profiles := []*speaker.VoiceProfile{profile}
        model, err := speaker.NewSpeakerIdentificationModelFromProfiles(profiles)
        if err != nil {
            fmt.Println("Error creating Identification model: ", err)
        }
        if model == nil {
            fmt.Println("Error creating Identification model: nil model")
            return
        }
        identifyAudioConfig, err := audio.NewAudioConfigFromDefaultMicrophoneInput()
        if err != nil {
            fmt.Println("Got an error: ", err)
            return
        }
        defer identifyAudioConfig.Close()
        speakerRecognizer, err := speaker.NewSpeakerRecognizerFromConfig(config, identifyAudioConfig)
        if err != nil {
            fmt.Println("Got an error: ", err)
            return
        }
        identifyFuture := speakerRecognizer.IdentifyOnceAsync(model)
        identifyOutcome := <-identifyFuture
        if identifyOutcome.Failed() {
            fmt.Println("Got an error identifying profile: ", identifyOutcome.Error.Error())
            return
        }
        identifyResult := identifyOutcome.Result
        if identifyResult.Reason != common.RecognizedSpeakers {
            fmt.Println("Got an unexpected result identifying profile: ", identifyResult)
        }
        expectedID, _ := profile.Id()
        if identifyResult.ProfileID != expectedID {
            fmt.Println("Got an unexpected profile id identifying profile: ", identifyResult.ProfileID)
        }
        if identifyResult.Score < 1.0 {
            fmt.Println("Got an unexpected score identifying profile: ", identifyResult.Score)
        }
    
        DeleteProfile(client, profile)
        bufio.NewReader(os.Stdin).ReadBytes('\n')
    }
    
  3. В independent-identification.go замените YourSubscriptionKey на ключ ресурса службы "Речь" и замените YourServiceRegion на регион ресурса службы "Речь".

    Важно!

    Не забудьте удалить ключ из кода, когда закончите, и никогда не публикуйте его в открытом доступе. Для рабочей среды используйте безопасный способ хранения и доступа к учетным данным, например Azure Key Vault. Дополнительные сведения см. в статье о безопасности служб ИИ Azure.

Выполните приведенные ниже команды, чтобы создать файл go.mod со ссылкой на компоненты, размещенные в GitHub:

go mod init independent-identification
go get github.com/Microsoft/cognitive-services-speech-sdk-go

Теперь можно приступить к сборке и выполнению кода:

go build
go run independent-identification

Выполнение независимой проверки

Выполните следующие действия, чтобы создать новый модуль GO.

  1. Откройте командную строку, в которой должен быть создан новый модуль, и создайте новый файл с именем independent-verification.go.

  2. Замените все содержимое independent-verification.go следующим кодом:

    package main
    
    import (
        "bufio"
        "fmt"
        "os"
        "time"
    
        "github.com/Microsoft/cognitive-services-speech-sdk-go/audio"
        "github.com/Microsoft/cognitive-services-speech-sdk-go/common"
        "github.com/Microsoft/cognitive-services-speech-sdk-go/speaker"
        "github.com/Microsoft/cognitive-services-speech-sdk-go/speech"
    )
    
    func GetNewVoiceProfileFromClient(client *speaker.VoiceProfileClient, expectedType common.VoiceProfileType) *speaker.VoiceProfile {
        future := client.CreateProfileAsync(expectedType, "en-US")
        outcome := <-future
        if outcome.Failed() {
            fmt.Println("Got an error creating profile: ", outcome.Error.Error())
            return nil
        }
        profile := outcome.Profile
        _, err := profile.Id()
        if err != nil {
            fmt.Println("Unexpected error creating profile id: ", err)
            return nil
        }
        profileType, err := profile.Type();
        if err != nil {
            fmt.Println("Unexpected error getting profile type: ", err)
            return nil
        }
        if profileType != expectedType {
            fmt.Println("Profile type does not match expected type")
            return nil
        }
        return profile
    }
    
    func EnrollProfile(client *speaker.VoiceProfileClient, profile *speaker.VoiceProfile, audioConfig *audio.AudioConfig) {
        enrollmentReason, currentReason := common.EnrollingVoiceProfile, common.EnrollingVoiceProfile
        var currentResult *speaker.VoiceProfileEnrollmentResult
        expectedEnrollmentCount := 1
        for currentReason == enrollmentReason {
            fmt.Println(`Please speak the following phrase: "I'll talk for a few seconds so you can recognize my voice in the future."`)
            enrollFuture := client.EnrollProfileAsync(profile, audioConfig)
            enrollOutcome := <-enrollFuture
            if enrollOutcome.Failed() {
                fmt.Println("Got an error enrolling profile: ", enrollOutcome.Error.Error())
                return
            }
            currentResult = enrollOutcome.Result
            currentReason = currentResult.Reason
            if currentResult.EnrollmentsCount != expectedEnrollmentCount {
                fmt.Println("Unexpected enrollments for profile: ", currentResult.RemainingEnrollmentsCount)
            }
            expectedEnrollmentCount += 1
        }
        if currentReason != common.EnrolledVoiceProfile {
            fmt.Println("Unexpected result enrolling profile: ", currentResult)
        }
    }
    
    func DeleteProfile(client *speaker.VoiceProfileClient, profile *speaker.VoiceProfile) {
        deleteFuture := client.DeleteProfileAsync(profile)
        deleteOutcome := <-deleteFuture
        if deleteOutcome.Failed() {
            fmt.Println("Got an error deleting profile: ", deleteOutcome.Error.Error())
            return
        }
        result := deleteOutcome.Result
        if result.Reason != common.DeletedVoiceProfile {
            fmt.Println("Unexpected result deleting profile: ", result)
        }
    }
    
    func main() {
        subscription :=  "YourSubscriptionKey"
        region := "YourServiceRegion"
        config, err := speech.NewSpeechConfigFromSubscription(subscription, region)
        if err != nil {
            fmt.Println("Got an error: ", err)
            return
        }
        defer config.Close()
        client, err := speaker.NewVoiceProfileClientFromConfig(config)
        if err != nil {
            fmt.Println("Got an error: ", err)
            return
        }
        defer client.Close()
        audioConfig, err := audio.NewAudioConfigFromDefaultMicrophoneInput()
        if err != nil {
            fmt.Println("Got an error: ", err)
            return
        }
        defer audioConfig.Close()
        <-time.After(10 * time.Second)
        expectedType := common.VoiceProfileType(3)
    
        profile := GetNewVoiceProfileFromClient(client, expectedType)
        if profile == nil {
            fmt.Println("Error creating profile")
            return
        }
        defer profile.Close()
    
        EnrollProfile(client, profile, audioConfig)
    
        model, err := speaker.NewSpeakerVerificationModelFromProfile(profile)
        if err != nil {
            fmt.Println("Error creating Verification model: ", err)
        }
        if model == nil {
            fmt.Println("Error creating Verification model: nil model")
            return
        }
        verifyAudioConfig, err := audio.NewAudioConfigFromDefaultMicrophoneInput()
        if err != nil {
            fmt.Println("Got an error: ", err)
            return
        }
        defer verifyAudioConfig.Close()
        speakerRecognizer, err := speaker.NewSpeakerRecognizerFromConfig(config, verifyAudioConfig)
        if err != nil {
            fmt.Println("Got an error: ", err)
            return
        }
        verifyFuture := speakerRecognizer.VerifyOnceAsync(model)
        verifyOutcome := <-verifyFuture
        if verifyOutcome.Failed() {
            fmt.Println("Got an error verifying profile: ", verifyOutcome.Error.Error())
            return
        }
        verifyResult := verifyOutcome.Result
        if verifyResult.Reason != common.RecognizedSpeaker {
            fmt.Println("Got an unexpected result verifying profile: ", verifyResult)
        }
        expectedID, _ := profile.Id()
        if verifyResult.ProfileID != expectedID {
            fmt.Println("Got an unexpected profile id verifying profile: ", verifyResult.ProfileID)
        }
        if verifyResult.Score < 1.0 {
            fmt.Println("Got an unexpected score verifying profile: ", verifyResult.Score)
        }
    
        DeleteProfile(client, profile)
        bufio.NewReader(os.Stdin).ReadBytes('\n')
    }
    
  3. В independent-verification.go замените YourSubscriptionKey на ключ ресурса службы "Речь" и замените YourServiceRegion на регион ресурса службы "Речь".

Выполните приведенные ниже команды, чтобы создать файл go.mod со ссылкой на компоненты, размещенные в GitHub:

go mod init independent-verification
go get github.com/Microsoft/cognitive-services-speech-sdk-go

Теперь можно приступить к сборке и выполнению кода:

go build
go run independent-verification

Очистка ресурсов

Для удаления созданного ресурса службы "Речь" можно использовать портал Azure или интерфейс командной строки (CLI) Azure.

Справочная документация | Дополнительные примеры в GitHub

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

Справочная документация | Пакет (npm) | Дополнительные примеры в GitHub | Исходный код библиотеки

В этом руководстве показаны базовые конструктивные шаблоны для распознавания говорящего с помощью пакета SDK службы "Речь". В статье рассматриваются следующие темы:

  • Проверка, зависящая от текста и не зависящая от текста.
  • Идентификация говорящего для идентификации образца голоса в группе голосов.
  • Удаление речевых профилей.

Общие сведения о концепциях распознавания говорящего см. в статье Обзор. Список поддерживаемых платформ см. на узле ссылки на панели навигации слева.

Важно!

Корпорация Майкрософт ограничивает доступ к распознаванию говорящего. Примените его для использования с помощью формы Azure AI Speaker Recognition Limited Access Review . После утверждения можно получить доступ к API Распознавания говорящего.

Предварительные требования

Установка пакета SDK службы "Речь"

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

В зависимости от целевой среды используйте один из следующих параметров:

Скачайте пакет SDK службы "Речь" для JavaScript, извлеките из него файл microsoft.cognitiveservices.speech.sdk.bundle.js. Поместите этот файл в папку, доступную для HTML-файла.

<script src="microsoft.cognitiveservices.speech.sdk.bundle.js"></script>;

Совет

Если в качестве платформы вы используете веб-браузер и применяете тег <script>, использовать префикс sdk не нужно. Префикс sdk является псевдонимом для присвоения имени модулю require.

Импорт зависимостей

Чтобы выполнить примеры из этой статьи, добавьте в начале JS-файла следующие инструкции:

"use strict";

/* To run this sample, install:
npm install microsoft-cognitiveservices-speech-sdk
*/
var sdk = require("microsoft-cognitiveservices-speech-sdk");
var fs = require("fs");

// Note: Change the locale if desired.
const profile_locale = "en-us";

/* Note: passphrase_files and verify_file should contain paths to audio files that contain \"My voice is my passport, verify me.\"
You can obtain these files from:
https://github.com/Azure-Samples/cognitive-services-speech-sdk/tree/fa6428a0837779cbeae172688e0286625e340942/quickstart/javascript/node/speaker-recognition/verification
*/ 
const passphrase_files = ["myVoiceIsMyPassportVerifyMe01.wav", "myVoiceIsMyPassportVerifyMe02.wav", "myVoiceIsMyPassportVerifyMe03.wav"];
const verify_file = "myVoiceIsMyPassportVerifyMe04.wav";
/* Note: identify_file should contain a path to an audio file that uses the same voice as the other files, but contains different speech. You can obtain this file from:
https://github.com/Azure-Samples/cognitive-services-speech-sdk/tree/fa6428a0837779cbeae172688e0286625e340942/quickstart/javascript/node/speaker-recognition/identification
*/
const identify_file = "aboutSpeechSdk.wav";

var subscription_key = 'PASTE_YOUR_SPEECH_SUBSCRIPTION_KEY_HERE';
var region = 'PASTE_YOUR_SPEECH_ENDPOINT_REGION_HERE';

const ticks_per_second = 10000000;

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

Важно!

Не забудьте удалить ключ из кода, когда закончите, и никогда не публикуйте его в открытом доступе. Для рабочей среды используйте безопасный способ хранения и доступа к учетным данным, например Azure Key Vault. Дополнительные сведения см. в статье о безопасности служб ИИ Azure.

Создание вспомогательной функции

Добавьте следующую вспомогательную функцию для чтения аудиофайлов в потоках, используемых службой "Речь":

function GetAudioConfigFromFile (file)
{
    return sdk.AudioConfig.fromWavFileInput(fs.readFileSync(file));
}

В этой функции для создания объекта AudioConfig используются методы AudioInputStream.createPushStream и AudioConfig.fromStreamInput. Этот объект AudioConfig представляет звуковой поток. Некоторые из этих объектов AudioConfig понадобятся в следующих задачах.

Проверка, зависящая от текста

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

Функция TextDependentVerification

Начните с создания функции TextDependentVerification.

async function TextDependentVerification(client, speech_config)
{
    console.log ("Text Dependent Verification:\n");
    var profile = null;
    try {
        const type = sdk.VoiceProfileType.TextDependentVerification;
        // Create the profile.
        profile = await client.createProfileAsync(type, profile_locale);
        console.log ("Created profile ID: " + profile.profileId);
        // Get the activation phrases
        await GetActivationPhrases(type, profile_locale);
        await AddEnrollmentsToTextDependentProfile(client, profile, passphrase_files);
        const audio_config = GetAudioConfigFromFile(verify_file);
        const recognizer = new sdk.SpeakerRecognizer(speech_config, audio_config);
        await SpeakerVerify(profile, recognizer);
    }
    catch (error) {
        console.log ("Error:\n" + error);
    }
    finally {
        if (profile !== null) {
            console.log ("Deleting profile ID: " + profile.profileId);
            const deleteResult = await client.deleteProfileAsync (profile);
        }
    }
}

Эта функция создает объект VoiceProfile с помощью метода VoiceProfileClient.createProfileAsync. Здесь возможны три вариантаVoiceProfile:

  • TextIndependentIdentification
  • TextDependentVerification
  • TextIndependentVerification

В этом примере VoiceProfileType.TextDependentVerification передается в VoiceProfileClient.createProfileAsync.

Затем нужно вызвать две вспомогательные функции AddEnrollmentsToTextDependentProfile и SpeakerVerify, которые вы определяете далее. Наконец, для удаления профиля вызовите VoiceProfileClient.deleteProfileAsync.

Функция AddEnrollmentsToTextDependentProfile

Определите следующую функцию, чтобы зарегистрировать речевой профиль:

async function AddEnrollmentsToTextDependentProfile(client, profile, audio_files)
{
    try {
        for (const file of audio_files) {
            console.log ("Adding enrollment to text dependent profile...");
            const audio_config = GetAudioConfigFromFile(file);
            const result = await client.enrollProfileAsync(profile, audio_config);
            if (result.reason === sdk.ResultReason.Canceled) {
                throw(JSON.stringify(sdk.VoiceProfileEnrollmentCancellationDetails.fromResult(result)));
            }
            else {
                console.log ("Remaining enrollments needed: " + result.privDetails["remainingEnrollmentsCount"] + ".");
            }
        };
        console.log ("Enrollment completed.\n");
    } catch (error) {
        console.log ("Error adding enrollments: " + error);
    }
}

В этой функции вы вызываете функцию GetAudioConfigFromFile, определенную ранее, для создания объектов AudioConfig из примеров звуковых данных. Эти примеры звуковых данных содержат парольную фразу, например "Мой голос — мой паспорт, проверь меня". Затем вы зарегистрируете эти примеры звуковых данных, используя метод VoiceProfileClient.enrollProfileAsync.

Функция SpeakerVerify

Определите SpeakerVerify следующим образом:

async function SpeakerVerify(profile, recognizer)
{
    try {
        const model = sdk.SpeakerVerificationModel.fromProfile(profile);
        const result = await recognizer.recognizeOnceAsync(model);
        console.log ("Verified voice profile for speaker: " + result.profileId + ". Score is: " + result.score + ".\n");
    } catch (error) {
        console.log ("Error verifying speaker: " + error);
    }
}

В этой функции вы создаете объект SpeakerVerificationModel с помощью метода SpeakerVerificationModel.FromProfile, передавая ранее созданный объект VoiceProfile.

Далее вызовите метод SpeechRecognizer.recognizeOnceAsync, чтобы проверить пример звуковых данных, который содержит ту же парольную фразу, что и в ранее зарегистрированном примере звуковых данных. SpeechRecognizer.recognizeOnceAsync возвращает объект SpeakerRecognitionResult, свойство score которого содержит оценку схожести в диапазоне 0,0–1,0. Объект SpeakerRecognitionResult также содержит свойство reason типа ResultReason. Если проверка прошла успешно, тогда свойство reason должно иметь значение RecognizedSpeaker.

Проверка, не зависящая от текста

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

  • Определенная парольная фраза не требуется, можно произносить что угодно.
  • Не требуются три примера звуковых данных, но требуется, чтобы длительность звуковых данных составляла 20 секунд.

Функция TextIndependentVerification

Начните с создания функции TextIndependentVerification.

async function TextIndependentVerification(client, speech_config)
{
    console.log ("Text Independent Verification:\n");
    var profile = null;
    try {
        const type = sdk.VoiceProfileType.TextIndependentVerification;
        // Create the profile.
        profile = await client.createProfileAsync(type, profile_locale);
        console.log ("Created profile ID: " + profile.profileId);
        // Get the activation phrases
        await GetActivationPhrases(type, profile_locale);
        await AddEnrollmentsToTextIndependentProfile(client, profile, [identify_file]);
        const audio_config = GetAudioConfigFromFile(passphrase_files[0]);
        const recognizer = new sdk.SpeakerRecognizer(speech_config, audio_config);
        await SpeakerVerify(profile, recognizer);
    }
    catch (error) {
        console.log ("Error:\n" + error);
    }
    finally {
        if (profile !== null) {
            console.log ("Deleting profile ID: " + profile.profileId);
            const deleteResult = await client.deleteProfileAsync (profile);
        }
    }
}

Как и функция TextDependentVerification, эта функция создает объект VoiceProfile с помощью метода VoiceProfileClient.createProfileAsync.

В этом примере VoiceProfileType.TextIndependentVerification передается в createProfileAsync.

Затем нужно вызвать две вспомогательные функции: AddEnrollmentsToTextIndependentProfile (определяется далее) и SpeakerVerify (уже определена). Наконец, для удаления профиля вызовите VoiceProfileClient.deleteProfileAsync.

AddEnrollmentsToTextIndependentProfile

Определите следующую функцию, чтобы зарегистрировать речевой профиль:

async function AddEnrollmentsToTextIndependentProfile(client, profile, audio_files)
{
    try {
        for (const file of audio_files) {
            console.log ("Adding enrollment to text independent profile...");
            const audio_config = GetAudioConfigFromFile(file);
            const result = await client.enrollProfileAsync (profile, audio_config);
            if (result.reason === sdk.ResultReason.Canceled) {
                throw(JSON.stringify(sdk.VoiceProfileEnrollmentCancellationDetails.fromResult(result)));
            }
            else {
                console.log ("Remaining audio time needed: " + (result.privDetails["remainingEnrollmentsSpeechLength"] / ticks_per_second) + " seconds.");
            }
        }
        console.log ("Enrollment completed.\n");
    } catch (error) {
        console.log ("Error adding enrollments: " + error);
    }
}

В этой функции вы вызываете функцию GetAudioConfigFromFile, определенную ранее, для создания объектов AudioConfig из примеров звуковых данных. Затем вы зарегистрируете эти примеры звуковых данных, используя метод VoiceProfileClient.enrollProfileAsync.

Идентификация говорящего

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

Функция TextIndependentIdentification

Начните с создания функции TextIndependentIdentification.

async function TextIndependentIdentification(client, speech_config)
{
    console.log ("Text Independent Identification:\n");
    var profile = null;
    try {
        const type = sdk.VoiceProfileType.TextIndependentIdentification;
        // Create the profile.
        profile = await client.createProfileAsync(type, profile_locale);
        console.log ("Created profile ID: " + profile.profileId);
        // Get the activation phrases
        await GetActivationPhrases(type, profile_locale);
        await AddEnrollmentsToTextIndependentProfile(client, profile, [identify_file]);
        const audio_config = GetAudioConfigFromFile(passphrase_files[0]);
        const recognizer = new sdk.SpeakerRecognizer(speech_config, audio_config);
        await SpeakerIdentify(profile, recognizer);
    }
    catch (error) {
        console.log ("Error:\n" + error);
    }
    finally {
        if (profile !== null) {
            console.log ("Deleting profile ID: " + profile.profileId);
            const deleteResult = await client.deleteProfileAsync (profile);
        }
    }
}

Как и функции TextDependentVerification и TextIndependentVerification, эта функция создает объект VoiceProfile с помощью метода VoiceProfileClient.createProfileAsync.

В этом примере VoiceProfileType.TextIndependentIdentification передается в VoiceProfileClient.createProfileAsync.

Затем нужно вызвать две вспомогательные функции: уже определенную вами AddEnrollmentsToTextIndependentProfile и SpeakerIdentify, которую вы определите. Наконец, для удаления профиля вызовите VoiceProfileClient.deleteProfileAsync.

Функция SpeakerIdentify

Определите функцию SpeakerIdentify следующим образом:

async function SpeakerIdentify(profile, recognizer)
{
    try {
        const model = sdk.SpeakerIdentificationModel.fromProfiles([profile]);
        const result = await recognizer.recognizeOnceAsync(model);
        console.log ("The most similar voice profile is: " + result.profileId + " with similarity score: " + result.score + ".\n");
    } catch (error) {
        console.log ("Error identifying speaker: " + error);
    }
}

В этой функции вы создаете объект SpeakerIdentificationModel с помощью метода SpeakerIdentificationModel.fromProfiles, передавая ранее созданный объект VoiceProfile.

Затем вызовите метод SpeechRecognizer.recognizeOnceAsync и передайте пример звуковых данных. Метод SpeechRecognizer.recognizeOnceAsync пытается определить речь для этого примера звуковых данных на основе объектов VoiceProfile, использованных для создания SpeakerIdentificationModel. Он возвращает объект SpeakerRecognitionResult, свойство profileId которого определяет совпадение с VoiceProfile, если таковое имеется, а свойство score содержит показатель подобия в диапазоне 0,0–1,0.

Функция main

Наконец, определите функцию main следующим образом:

async function main() {
    const speech_config = sdk.SpeechConfig.fromSubscription(subscription_key, region);
    const client = new sdk.VoiceProfileClient(speech_config);

    await TextDependentVerification(client, speech_config);
    await TextIndependentVerification(client, speech_config);
    await TextIndependentIdentification(client, speech_config);
    console.log ("End of quickstart.");
}
main();

Эта функция создает объект VoiceProfileClient, который используется при создании, регистрации и удалении голосовых профилей. Затем она вызывает функции, определенные ранее.

Справочная документация | Пакет (скачивание) | Дополнительные примеры в GitHub

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

Справочная документация | Пакет (скачивание) | Дополнительные примеры в GitHub

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

Справочная документация | Пакет (PyPi) | Дополнительные примеры в GitHub

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

Справочник | по REST API преобразования речи в текстRest API преобразования речи в текст для краткого справочника по звуку | Дополнительные примеры на GitHub

В этом руководстве показаны базовые конструктивные шаблоны для распознавания говорящего с помощью пакета SDK службы "Речь". В статье рассматриваются следующие темы:

  • Проверка, зависящая от текста и не зависящая от текста.
  • Идентификация говорящего для идентификации образца голоса в группе голосов.
  • Удаление речевых профилей.

Общие сведения о концепциях распознавания говорящего см. в статье Обзор. Список поддерживаемых платформ см. на узле ссылки на панели навигации слева.

Важно!

Корпорация Майкрософт ограничивает доступ к распознаванию говорящего. Примените его для использования с помощью формы Azure AI Speaker Recognition Limited Access Review . После утверждения можно получить доступ к API Распознавания говорящего.

Предварительные требования

Проверка, зависящая от текста

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

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

Важно!

Не забудьте удалить ключ из кода, когда закончите, и никогда не публикуйте его в открытом доступе. Для рабочей среды используйте безопасный способ хранения и доступа к учетным данным, например Azure Key Vault. Дополнительные сведения см. в статье о безопасности служб ИИ Azure.

# Note Change locale if needed.
curl --location --request POST 'INSERT_ENDPOINT_HERE/speaker-recognition/verification/text-dependent/profiles?api-version=2021-09-05' \
--header 'Ocp-Apim-Subscription-Key: INSERT_SUBSCRIPTION_KEY_HERE' \
--header 'Content-Type: application/json' \
--data-raw '{
    '\''locale'\'':'\''en-us'\''
}'

Существует три типа речевого профиля:

  • Текстозависимая проверка
  • Текстонезависимая проверка
  • Текстонезависимое распознавание

В этом случае вы создадите речевой профиль с зависимой от текста проверкой. Вы получите следующий ответ:

{
    "remainingEnrollmentsCount": 3,
    "locale": "en-us",
    "createdDateTime": "2020-09-29T14:54:29.683Z",
    "enrollmentStatus": "Enrolling",
    "modelVersion": null,
    "profileId": "714ce523-de76-4220-b93f-7c1cc1882d6e",
    "lastUpdatedDateTime": null,
    "enrollmentsCount": 0,
    "enrollmentsLength": 0.0,
    "enrollmentSpeechLength": 0.0
}

Затем вам нужно зарегистрировать речевой профиль. В качестве значения параметра --data-binary укажите звуковой файл на компьютере, который содержит одну из поддерживаемых парольных фраз, например "Мой голос — мой паспорт, проверь меня". Вы можете записать такой звуковой файл с помощью приложения, например Запись голоса Windows, Или вы можете создать его, используя текст для речи.

curl --location --request POST 'INSERT_ENDPOINT_HERE/speaker-recognition/verification/text-dependent/profiles/INSERT_PROFILE_ID_HERE/enrollments?api-version=2021-09-05' \
--header 'Ocp-Apim-Subscription-Key: INSERT_SUBSCRIPTION_KEY_HERE' \
--header 'Content-Type: audio/wav' \
--data-binary @'INSERT_FILE_PATH_HERE'

Вы получите следующий ответ:

{
    "remainingEnrollmentsCount": 2,
    "passPhrase": "my voice is my passport verify me",
    "profileId": "714ce523-de76-4220-b93f-7c1cc1882d6e",
    "enrollmentStatus": "Enrolling",
    "enrollmentsCount": 1,
    "enrollmentsLength": 3.5,
    "enrollmentsSpeechLength": 2.88,
    "audioLength": 3.5,
    "audioSpeechLength": 2.88
}

Этот ответ указывает на то, что вам нужно зарегистрировать еще два примера звуковых данных.

После регистрации всех трех примеров звуковых данных вы получите следующий ответ:

{
    "remainingEnrollmentsCount": 0,
    "passPhrase": "my voice is my passport verify me",
    "profileId": "714ce523-de76-4220-b93f-7c1cc1882d6e",
    "enrollmentStatus": "Enrolled",
    "enrollmentsCount": 3,
    "enrollmentsLength": 10.5,
    "enrollmentsSpeechLength": 8.64,
    "audioLength": 3.5,
    "audioSpeechLength": 2.88
}

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

curl --location --request POST 'INSERT_ENDPOINT_HERE/speaker-recognition/verification/text-dependent/profiles/INSERT_PROFILE_ID_HERE:verify?api-version=2021-09-05' \
--header 'Ocp-Apim-Subscription-Key: INSERT_SUBSCRIPTION_KEY_HERE' \
--header 'Content-Type: audio/wav' \
--data-binary @'INSERT_FILE_PATH_HERE'

Вы получите следующий ответ:

{
    "recognitionResult": "Accept",
    "score": 1.0
}

Accept означает, что парольная фраза сопоставлена и проверка прошла успешно. Ответ также содержит показатель подобия в диапазоне от 0,0 до 1,0.

Чтобы завершить, удалите речевой профиль.

curl --location --request DELETE \
'INSERT_ENDPOINT_HERE/speaker-recognition/verification/text-dependent/profiles/INSERT_PROFILE_ID_HERE?api-version=2021-09-05' \
--header 'Ocp-Apim-Subscription-Key: INSERT_SUBSCRIPTION_KEY_HERE'

Нет ответа.

Проверка, не зависящая от текста

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

  • Определенная парольная фраза не требуется, можно произносить что угодно.
  • Не требуются три примера звуковых данных, но требуется, чтобы длительность звуковых данных составляла 20 секунд.

Начните с создания профиля проверки, не зависящего от текста.

curl --location --request POST 'INSERT_ENDPOINT_HERE/speaker-recognition/verification/text-independent/profiles?api-version=2021-09-05' \
--header 'Ocp-Apim-Subscription-Key: INSERT_SUBSCRIPTION_KEY_HERE' \
--header 'Content-Type: application/json' \
--data-raw '{
    '\''locale'\'':'\''en-us'\''
}'

Вы получите следующий ответ:

{
    "profileStatus": "Inactive",
    "remainingEnrollmentsSpeechLength": 20.0,
    "profileId": "3f85dca9-ffc9-4011-bf21-37fad2beb4d2",
    "locale": "en-us",
    "enrollmentStatus": "Enrolling",
    "createdDateTime": "2020-09-29T16:08:52.409Z",
    "lastUpdatedDateTime": null,
    "enrollmentsCount": 0,
    "enrollmentsLength": 0.0,
    "enrollmentSpeechLength": 0.0
    "modelVersion": null,
}

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

curl --location --request POST 'INSERT_ENDPOINT_HERE/speaker-recognition/verification/text-independent/profiles/INSERT_PROFILE_ID_HERE/enrollments?api-version=2021-09-05' \
--header 'Ocp-Apim-Subscription-Key: INSERT_SUBSCRIPTION_KEY_HERE' \
--header 'Content-Type: audio/wav' \
--data-binary @'INSERT_FILE_PATH_HERE'

Отправив достаточное количество примеров звуковых данных, вы получите следующий ответ:

{
    "remainingEnrollmentsSpeechLength": 0.0,
    "profileId": "3f85dca9-ffc9-4011-bf21-37fad2beb4d2",
    "enrollmentStatus": "Enrolled",
    "enrollmentsCount": 1,
    "enrollmentsLength": 33.16,
    "enrollmentsSpeechLength": 29.21,
    "audioLength": 33.16,
    "audioSpeechLength": 29.21
}

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

curl --location --request POST 'INSERT_ENDPOINT_HERE/speaker-recognition/verification/text-independent/profiles/INSERT_PROFILE_ID_HERE:verify?api-version=2021-09-05' \
--header 'Ocp-Apim-Subscription-Key: INSERT_SUBSCRIPTION_KEY_HERE' \
--header 'Content-Type: audio/wav' \
--data-binary @'INSERT_FILE_PATH_HERE'

Вы получите следующий ответ:

{
    "recognitionResult": "Accept",
    "score": 0.9196669459342957
}

Accept означает, что проверка прошла успешно. Ответ также содержит показатель подобия в диапазоне от 0,0 до 1,0.

Чтобы завершить, удалите речевой профиль.

curl --location --request DELETE 'INSERT_ENDPOINT_HERE/speaker-recognition/verification/text-independent/profiles/INSERT_PROFILE_ID_HERE?api-version=2021-09-05' \
--header 'Ocp-Apim-Subscription-Key: INSERT_SUBSCRIPTION_KEY_HERE'

Нет ответа.

Идентификация говорящего

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

Начните с создания профиля идентификации, не зависящего от текста.

# Note Change locale if needed.
curl --location --request POST 'INSERT_ENDPOINT_HERE/speaker-recognition/identification/text-independent/profiles?api-version=2021-09-05' \
--header 'Ocp-Apim-Subscription-Key: INSERT_SUBSCRIPTION_KEY_HERE' \
--header 'Content-Type: application/json' \
--data-raw '{
    '\''locale'\'':'\''en-us'\''
}'

Вы получите следующий ответ:

{
    "profileStatus": "Inactive",
    "remainingEnrollmentsSpeechLengthInSec": 20.0,
    "profileId": "de99ab38-36c8-4b82-b137-510907c61fe8",
    "locale": "en-us",
    "enrollmentStatus": "Enrolling",
    "createdDateTime": "2020-09-22T17:25:48.642Z",
    "lastUpdatedDateTime": null,
    "enrollmentsCount": 0,
    "enrollmentsLengthInSec": 0.0,
    "enrollmentsSpeechLengthInSec": 0.0,
    "modelVersion": null
}

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

curl --location --request POST 'INSERT_ENDPOINT_HERE/speaker-recognition/identification/text-independent/profiles/INSERT_PROFILE_ID_HERE/enrollments?api-version=2021-09-05' \
--header 'Ocp-Apim-Subscription-Key: INSERT_SUBSCRIPTION_KEY_HERE' \
--header 'Content-Type: audio/wav' \
--data-binary @'INSERT_FILE_PATH_HERE'

Отправив достаточное количество примеров звуковых данных, вы получите следующий ответ:

{
    "remainingEnrollmentsSpeechLength": 0.0,
    "profileId": "de99ab38-36c8-4b82-b137-510907c61fe8",
    "enrollmentStatus": "Enrolled",
    "enrollmentsCount": 2,
    "enrollmentsLength": 36.69,
    "enrollmentsSpeechLength": 31.95,
    "audioLength": 33.16,
    "audioSpeechLength": 29.21
}

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

# Profile ids comma seperated list
curl --location --request POST 'INSERT_ENDPOINT_HERE/speaker-recognition/identification/text-independent/profiles:identifySingleSpeaker?api-version=2021-09-05&profileIds=INSERT_PROFILE_ID_HERE' \
--header 'Ocp-Apim-Subscription-Key: INSERT_SUBSCRIPTION_KEY_HERE' \
--header 'Content-Type: audio/wav' \
--data-binary @'INSERT_FILE_PATH_HERE'

Вы получите следующий ответ:

Success:
{
    "identifiedProfile": {
        "profileId": "de99ab38-36c8-4b82-b137-510907c61fe8",
        "score": 0.9083486
    },
    "profilesRanking": [
        {
            "profileId": "de99ab38-36c8-4b82-b137-510907c61fe8",
            "score": 0.9083486
        }
    ]
}

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

Чтобы завершить, удалите речевой профиль.

curl --location --request DELETE \
'INSERT_ENDPOINT_HERE/speaker-recognition/identification/text-independent/profiles/INSERT_PROFILE_ID_HERE?api-version=2021-09-05' \
--header 'Ocp-Apim-Subscription-Key: INSERT_SUBSCRIPTION_KEY_HERE'

Нет ответа.

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

Дальнейшие действия