빠른 시작: 말하는 사람 인식 및 확인

참조 설명서 | 패키지(NuGet) | GitHub의 추가 샘플

이 빠른 시작에서는 다음을 포함하여 음성 SDK를 사용하는 화자 인식에 대한 기본적인 디자인 패턴을 알아봅니다.

  • 텍스트 종속 및 텍스트 독립 확인.
  • 음성 그룹 간의 음성 샘플을 식별하는 화자 식별.
  • 음성 프로필 삭제.

화자 인식 개념에 대한 간략한 설명은 개요 문서를 참조하세요. 지원되는 플랫폼 목록은 왼쪽 창의 참조 노드를 참조하세요.

Important

Microsoft에서는 화자 인식에 대한 액세스를 제한합니다. Azure AI Speaker Recognition 제한된 액세스 검토 양식을 통해 사용을 신청합니다. 승인 후에는 Speaker Recognition API에 액세스할 수 있습니다.

필수 조건

Speech SDK 설치

시작하기 전에 음성 SDK를 설치해야 합니다. 플랫폼에 따라 다음 지침을 사용합니다.

종속성 가져오기

이 문서의 예제를 실행하려면 다음 using 문을 스크립트 위쪽에 포함시킵니다.

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

음성 구성 만들기

음성 SDK를 사용하여 Speech Service를 호출하려면 SpeechConfig 인스턴스를 만들어야 합니다. 이 예제에서는 구독 키와 지역을 사용하여 SpeechConfig 인스턴스를 만듭니다. 또한 이 문서의 나머지 부분에 사용할 몇 가지 기본 상용구 코드를 만들 수 있습니다. 이 문서의 나머지 부분에서는 사용자 지정을 위해 수정합니다.

Important

완료되면 코드에서 키를 제거하고 공개적으로 게시하지 마세요. 프로덕션의 경우 Azure Key Vault와 같은 자격 증명을 안전하게 저장하고 액세스하는 방법을 사용합니다. 자세한 내용은 Azure AI 서비스 보안 문서를 참조하세요.

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);
    }
}

텍스트 종속 확인

화자 검증은 화자가 알려진 또는 등록된 음성으로 일치하는지 확인하는 행위입니다. 첫 번째 단계는 음성 프로필을 등록하는 것입니다. 따라서 서비스에 향후 음성 샘플과 비교할 내용이 있습니다. 다음 예제에서는 텍스트 종속 전략을 사용하여 프로필을 등록합니다. 이 전략에서는 특정 암호를 등록 및 검증에 사용해야 합니다. 지원되는 암호 목록은 참조 문서를 확인하세요.

먼저 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에 저장할 수 없고 개인 정보 취급 방침에 대해서만 ID 번호를 저장하기 때문입니다. VerificationEnroll 함수에서는 텍스트 이름과 함께 새로 만든 ID가 있는 항목을 이 사전에 추가합니다. 사람이 읽을 수 있는 이름을 표시해야 하는 애플리케이션 개발 시나리오에서는 이 매핑을 서비스가 저장할 수 없으므로 이 매핑을 사용자가 어딘가에 저장해야 합니다.

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();
}

스크립트를 실행합니다. 등록을 위해 "My voice is my passport, verify me"라는 구절을 세 번 말하고 확인을 위해 한 번 더 말하라는 메시지가 표시됩니다. 반환된 결과는 유사성 점수이며, 이를 사용하여 확인을 위한 사용자 지정 임계값을 만들 수 있습니다.

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

텍스트 독립적 확인

텍스트 종속 확인과 달리 텍스트 독립 확인에는 3개의 오디오 샘플이 필요하지 않지만 총 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() . IdentificationEnroll() 함수에 전달하는 profileNames문자열 목록을 만듭니다. 이 목록에 있는 각 이름에 대해 새 음성 프로필을 만들라는 메시지가 표시되므로 친구나 동료를 위한 추가 프로필을 만들기 위해 더 많은 이름을 추가할 수 있습니다.

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 목록의 각 이름에 대해 이 프로세스를 반복하라는 메시지가 표시됩니다. 등록이 완료될 때마다 아무나 말하라는 메시지가 표시됩니다. 그런 다음, 서비스는 등록된 음성 프로필 중에서 이 사용자를 식별하려고 시도합니다.

이 예제에서는 가장 일치하는 항목과 유사성 점수만 반환합니다. 상위 5개의 유사성 점수를 포함하는 전체 응답을 가져오려면 SpeakerIdentification 함수에 string json = result.Properties.GetProperty(PropertyId.SpeechServiceResponse_JsonResult)를 추가합니다.

오디오 입력 형식 변경

이 문서의 예제에서는 기본 장치 마이크를 오디오 샘플에 대한 입력으로 사용합니다. 마이크 입력 대신 오디오 파일을 사용해야 하는 경우에는 AudioConfig.FromDefaultMicrophoneInput()의 인스턴스를 AudioConfig.FromWavFileInput(path/to/your/file.wav)로 변경하여 파일 입력으로 전환합니다. 예를 들어 등록용 마이크와 확인용 파일을 사용하여 입력을 혼합할 수 있습니다.

음성 프로필 등록 삭제

등록된 프로필을 삭제하려면 개체의 DeleteProfileAsync() 함수를 VoiceProfileClient 사용합니다. 다음 예제 함수는 알려진 음성 프로필 ID에서 음성 프로필을 삭제하는 방법을 보여줍니다.

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를 사용하는 화자 인식에 대한 기본적인 디자인 패턴을 알아봅니다.

  • 텍스트 종속 및 텍스트 독립 확인.
  • 음성 그룹 간의 음성 샘플을 식별하는 화자 식별.
  • 음성 프로필 삭제.

화자 인식 개념에 대한 간략한 설명은 개요 문서를 참조하세요. 지원되는 플랫폼 목록은 왼쪽 창의 참조 노드를 참조하세요.

Important

Microsoft에서는 화자 인식에 대한 액세스를 제한합니다. Azure AI Speaker Recognition 제한된 액세스 검토 양식을 통해 사용을 신청합니다. 승인 후에는 Speaker Recognition API에 액세스할 수 있습니다.

필수 조건

Speech 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를 사용하여 Speech Service를 호출하려면 SpeechConfig 클래스를 만듭니다. 이 클래스에는 키 및 연결된 지역, 엔드포인트, 호스트 또는 권한 부여 토큰과 같은 구독에 대한 정보가 포함됩니다.

Important

완료되면 코드에서 키를 제거하고 공개적으로 게시하지 마세요. 프로덕션의 경우 Azure Key Vault와 같은 자격 증명을 안전하게 저장하고 액세스하는 방법을 사용합니다. 자세한 내용은 Azure AI 서비스 보안 문서를 참조하세요.

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;
}

텍스트 종속 확인

화자 검증은 화자가 알려진 또는 등록된 음성으로 일치하는지 확인하는 행위입니다. 첫 번째 단계는 음성 프로필을 등록하는 것입니다. 따라서 서비스에 향후 음성 샘플과 비교할 내용이 있습니다. 다음 예제에서는 텍스트 종속 전략을 사용하여 프로필을 등록합니다. 이 전략에서는 특정 암호를 등록 및 검증에 사용해야 합니다. 지원되는 암호 목록은 참조 문서를 확인하세요.

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);
}

이 함수는 CreateProfileAsync 메서드를 사용하여 VoiceProfile 개체를 만듭니다. VoiceProfile에는 다음 세 가지 형식이 있습니다.

  • TextIndependentIdentification
  • TextDependentVerification
  • TextIndependentVerification

이 경우 VoiceProfileType::TextDependentVerificationCreateProfileAsync에 전달합니다.

그런 다음, 다음에 정의할 두 개의 도우미 함수(AddEnrollmentsToTextDependentProfileSpeakerVerify)를 호출합니다. 마지막으로 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";
}

이 함수에서는 이전에 만든 VoiceProfile 개체를 전달하여 SpeakerVerificationModel::FromProfile 메서드를 사용하여 SpeakerVerificationModel 개체를 만듭니다.

다음으로 SpeechRecognizer::RecognizeOnceAsync에서 암호를 다시 말하라는 메시지를 표시합니다. 이번에는 음성 프로필을 기준으로 유효성을 검사하고 0.0~1.0 범위의 유사성 점수를 반환합니다. 또한 SpeakerRecognitionResult 개체에서 암호가 일치하는지 여부에 따라 Accept 또는 Reject를 반환합니다.

텍스트 독립적 확인

텍스트 종속 확인과 달리 텍스트 독립 확인에는 3개의 오디오 샘플이 필요하지 않지만 총 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 마찬가지로 이 함수는 CreateProfileAsync 메서드를 사용하여 VoiceProfile 개체를 만듭니다.

이 경우 VoiceProfileType::TextIndependentVerificationCreateProfileAsync에 전달합니다.

그런 다음, 다음SpeakerVerify으로 정의하고 이미 정의한 두 개의 도우미 함수AddEnrollmentsToTextIndependentProfile를 호출합니다. 마지막으로 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);
}

함수와 TextIndependentVerification 마찬가지로 이 함수는 CreateProfileAsync 메서드를 사용하여 VoiceProfile 개체를 만듭니다.TextDependentVerification

이 경우 VoiceProfileType::TextIndependentIdentificationCreateProfileAsync에 전달합니다.

그런 다음, 이미 정의한 도우미 함수와 SpeakerIdentify다음에 정의할 두 개의 도우미 함수AddEnrollmentsToTextIndependentProfile를 호출합니다. 마지막으로 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::FromProfiles 메서드를 사용하여 SpeakerIdentificationModel 개체를 만듭니다. 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::AudioConfig::FromWavFileInput으로 모든 사용을 audio_config 대체합니다. 예를 들어 등록용 마이크와 확인용 파일을 사용하여 입력을 혼합할 수 있습니다.

참조 설명서 | 패키지(Go) | GitHub의 추가 샘플

이 빠른 시작에서는 다음을 포함하여 음성 SDK를 사용하는 화자 인식에 대한 기본적인 디자인 패턴을 알아봅니다.

  • 텍스트 종속 및 텍스트 독립 확인.
  • 음성 그룹 간의 음성 샘플을 식별하는 화자 식별.
  • 음성 프로필 삭제.

화자 인식 개념에 대한 간략한 설명은 개요 문서를 참조하세요. 지원되는 플랫폼 목록은 왼쪽 창의 참조 노드를 참조하세요.

Important

Microsoft에서는 화자 인식에 대한 액세스를 제한합니다. Azure AI Speaker Recognition 제한된 액세스 검토 양식을 통해 사용을 신청합니다. 승인 후에는 Speaker Recognition API에 액세스할 수 있습니다.

필수 조건

환경 설정

Go용 Speech SDK를 설치합니다. 추가 요구 사항은 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을 음성 리소스 지역으로 바꿉니다.

    Important

    완료되면 코드에서 키를 제거하고 공개적으로 게시하지 마세요. 프로덕션의 경우 Azure Key Vault와 같은 자격 증명을 안전하게 저장하고 액세스하는 방법을 사용합니다. 자세한 내용은 Azure AI 서비스 보안 문서를 참조하세요.

다음 명령을 실행하여 GitHub에서 호스팅되는 구성 요소에 연결되는 go.mod 파일을 만듭니다.

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을 음성 리소스 지역으로 바꿉니다.

다음 명령을 실행하여 GitHub에서 호스팅되는 구성 요소에 연결되는 go.mod 파일을 만듭니다.

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

이제 코드를 빌드하고 실행합니다.

go build
go run independent-verification

리소스 정리

Azure Portal 또는 Azure CLI(명령줄 인터페이스)를 사용하여 생성된 음성 리소스를 제거할 수 있습니다.

참조 설명서 | GitHub의 추가 샘플

Java용 Speech SDK는 화자 인식을 지원하지만 아직 가이드가 여기에 포함되지 않았습니다. 다른 프로그래밍 언어를 선택해서 작업을 시작하고 개념을 알아보거나 이 문서의 앞 부분에 링크된 Java 참조 및 샘플을 참조하세요.

참조 설명서 | 패키지(npm) | GitHub의 추가 샘플 | 라이브러리 소스 코드

이 빠른 시작에서는 다음을 포함하여 음성 SDK를 사용하는 화자 인식에 대한 기본적인 디자인 패턴을 알아봅니다.

  • 텍스트 종속 및 텍스트 독립 확인.
  • 음성 그룹 간의 음성 샘플을 식별하는 화자 식별.
  • 음성 프로필 삭제.

화자 인식 개념에 대한 간략한 설명은 개요 문서를 참조하세요. 지원되는 플랫폼 목록은 왼쪽 창의 참조 노드를 참조하세요.

Important

Microsoft에서는 화자 인식에 대한 액세스를 제한합니다. Azure AI Speaker Recognition 제한된 액세스 검토 양식을 통해 사용을 신청합니다. 승인 후에는 Speaker Recognition API에 액세스할 수 있습니다.

필수 조건

Speech SDK 설치

시작하기 전에 JavaScript용 Speech SDK를 설치해야 합니다.

대상 환경에 따라 다음 중 하나를 사용합니다.

JavaScript용 Speech SDK 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;

이러한 문은 필수 라이브러리를 가져오고, 환경 변수에서 Speech Service 구독 키 및 지역을 가져옵니다. 또한 다음 작업에서 사용할 오디오 파일의 경로를 지정합니다.

Important

완료되면 코드에서 키를 제거하고 공개적으로 게시하지 마세요. 프로덕션의 경우 Azure Key Vault와 같은 자격 증명을 안전하게 저장하고 액세스하는 방법을 사용합니다. 자세한 내용은 Azure AI 서비스 보안 문서를 참조하세요.

도우미 함수 만들기

Speech Service에서 사용할 오디오 파일을 스트림으로 읽어 들이기 위해 다음 도우미 함수를 추가합니다.

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

이 함수에서는 AudioInputStream.createPushStream 및 AudioConfig.fromStreamInput 메서드를 사용하여 AudioConfig 개체를 만듭니다. 이 AudioConfig 개체는 오디오 스트림을 나타냅니다. 다음 작업 중에 이러한 AudioConfig 개체 중 몇 가지를 사용합니다.

텍스트 종속 확인

화자 검증은 화자가 알려진 또는 등록된 음성으로 일치하는지 확인하는 행위입니다. 첫 번째 단계는 음성 프로필을 등록하는 것입니다. 따라서 서비스에 향후 음성 샘플과 비교할 내용이 있습니다. 다음 예제에서는 텍스트 종속 전략을 사용하여 프로필을 등록합니다. 이 전략에서는 특정 암호를 등록 및 검증에 사용해야 합니다. 지원되는 암호 목록은 참조 문서를 확인하세요.

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);
        }
    }
}

이 함수는 VoiceProfileClient.createProfileAsync 메서드를 사용하여 VoiceProfile 개체를 만듭니다. VoiceProfile에는 다음 세 가지 형식이 있습니다.

  • TextIndependentIdentification
  • TextDependentVerification
  • TextIndependentVerification

이 경우 VoiceProfileType.TextDependentVerificationVoiceProfileClient.createProfileAsync에 전달합니다.

그런 다음, 다음에 정의할 두 개의 도우미 함수(AddEnrollmentsToTextDependentProfileSpeakerVerify)를 호출합니다. 마지막으로 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.FromProfile 메서드를 사용하여 SpeakerVerificationModel 개체를 만들고 이전에 만든 VoiceProfile 개체를 전달합니다.

다음으로 SpeechRecognizer.recognizeOnceAsync 메서드를 호출하여 이전에 등록한 오디오 샘플과 동일한 암호를 포함하는 오디오 샘플의 유효성을 검사합니다. SpeechRecognizer.recognizeOnceAsyncscore 속성에 0.0~1.0 범위의 유사성 점수가 포함된 SpeakerRecognitionResult 개체를 반환합니다. 또한 SpeakerRecognitionResult 개체에는 ResultReason 형식의 reason 속성이 포함되어 있습니다. 검증에 성공하면 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 마찬가지로 이 함수는 VoiceProfileClient.createProfileAsync 메서드를 사용하여 VoiceProfile 개체를 만듭니다.

이 경우 VoiceProfileType.TextIndependentVerificationcreateProfileAsync에 전달합니다.

그런 다음, 다음SpeakerVerify으로 정의하고 이미 정의한 두 개의 도우미 함수AddEnrollmentsToTextIndependentProfile를 호출합니다. 마지막으로 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);
        }
    }
}

함수와 TextIndependentVerification 마찬가지로 이 함수는 VoiceProfileClient.createProfileAsync 메서드를 사용하여 VoiceProfile 개체를 만듭니다.TextDependentVerification

이 경우 VoiceProfileType.TextIndependentIdentificationVoiceProfileClient.createProfileAsync에 전달합니다.

그런 다음, 이미 정의한 도우미 함수와 SpeakerIdentify다음에 정의할 두 개의 도우미 함수AddEnrollmentsToTextIndependentProfile를 호출합니다. 마지막으로 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);
    }
}

이 함수에서는 이전에 만든 VoiceProfile 개체를 전달하여 SpeakerIdentificationModel.fromProfiles 메서드를 사용하여 SpeakerIdentificationModel 개체를 만듭니 다.

다음으로 SpeechRecognizer.recognizeOnceAsync 메서드를 호출하고 오디오 샘플을 전달합니다. SpeechRecognizer.recognizeOnceAsync 를 만들 때 사용한 개체를 기반으로 이 오디오 샘플의 VoiceProfile 음성을 식별하려고 SpeakerIdentificationModel합니다. 이는 profileId 속성에서 일치하는 VoiceProfile을 식별하지만(있는 경우) score 속성에 0.0~1.0 범위의 유사성 점수가 포함된 SpeakerRecognitionResult 개체를 반환합니다.

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의 추가 샘플

Objective-C용 음성 SDK는 화자 인식을 지원하지 않습니다. 다른 프로그래밍 언어를 선택하거나 이 문서의 앞 부분에서 링크된 Objective-C 참조 및 샘플을 참조하세요.

참조 설명서 | 패키지(다운로드) | GitHub의 추가 샘플

Swift용 음성 SDK는 화자 인식을 지원하지 않습니다. 다른 프로그래밍 언어를 선택하거나 이 문서의 앞 부분에서 링크된 Swift 참조 및 샘플을 참조하세요.

참조 설명서 | 패키지(PyPi) | GitHub의 추가 샘플

Python용 음성 SDK는 화자 인식을 지원하지 않습니다. 다른 프로그래밍 언어를 선택하거나 이 문서의 앞 부분에서 링크된 Python 참조 및 샘플을 참조하세요.

음성을 텍스트로 변환하는 REST API 참조 | 짧은 오디오 참조를 위한 음성을 텍스트로 변환하는 REST API | GitHub의 추가 샘플

이 빠른 시작에서는 다음을 포함하여 음성 SDK를 사용하는 화자 인식에 대한 기본적인 디자인 패턴을 알아봅니다.

  • 텍스트 종속 및 텍스트 독립 확인.
  • 음성 그룹 간의 음성 샘플을 식별하는 화자 식별.
  • 음성 프로필 삭제.

화자 인식 개념에 대한 간략한 설명은 개요 문서를 참조하세요. 지원되는 플랫폼 목록은 왼쪽 창의 참조 노드를 참조하세요.

Important

Microsoft에서는 화자 인식에 대한 액세스를 제한합니다. Azure AI Speaker Recognition 제한된 액세스 검토 양식을 통해 사용을 신청합니다. 승인 후에는 Speaker Recognition API에 액세스할 수 있습니다.

필수 조건

텍스트 종속 확인

화자 검증은 화자가 알려진 또는 등록된 음성으로 일치하는지 확인하는 행위입니다. 첫 번째 단계는 음성 프로필을 등록하는 것입니다. 따라서 서비스에 향후 음성 샘플과 비교할 내용이 있습니다. 다음 예제에서는 텍스트 종속 전략을 사용하여 프로필을 등록합니다. 이 전략에서는 특정 암호를 등록 및 검증에 사용해야 합니다. 지원되는 암호 목록은 참조 문서를 확인하세요.

먼저 음성 프로필을 만듭니다. Speech Service 구독 키 및 지역을 이 문서의 각 curl 명령에 삽입해야 합니다.

Important

완료되면 코드에서 키를 제거하고 공개적으로 게시하지 마세요. 프로덕션의 경우 Azure Key Vault와 같은 자격 증명을 안전하게 저장하고 액세스하는 방법을 사용합니다. 자세한 내용은 Azure AI 서비스 보안 문서를 참조하세요.

# 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
}

이제 음성 프로필과 비교하여 오디오 샘플을 검증할 준비가 되었습니다. 다시 말하지만, 이 오디오 샘플은 암호를 포함할 필요가 없습니다. 어떤 음성도 포함할 수 있지만 총 4초 이상의 오디오가 포함되어야 합니다.

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
}

이제 음성 프로필을 사용하여 오디오 샘플을 식별할 준비가 되었습니다. 식별 명령은 가능한 음성 프로필 ID의 쉼표로 구분된 목록을 허용합니다. 이 경우 이전에 만든 음성 프로필의 ID를 전달합니다. 원하는 경우 각 음성 프로필이 다른 음성의 오디오 샘플에 등록된 여러 음성 프로필 ID를 전달할 수 있습니다.

# 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
        }
    ]
}

응답에는 제출한 오디오 샘플과 가장 밀접하게 일치하는 음성 프로필의 ID가 포함됩니다. 또한 유사성 순서로 순위가 지정된 후보 음성 프로필 목록이 포함되어 있습니다.

완료하려면 음성 프로필을 삭제합니다.

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'

응답이 없습니다.

Speech CLI는 화자 인식을 지원하지만 아직 가이드가 여기에 포함되지 않았습니다. 다른 프로그래밍 언어를 선택하여 작업을 시작하고 개념에 대해 알아보세요.

다음 단계