오디오 녹음에서 화자 구분하기

이 페이지에서는 Speech-to-Text를 통해 텍스트로 변환된 오디오 데이터에서 여러 화자의 라벨을 가져오는 방법을 설명합니다.

오디오 데이터에 두 명 이상이 이야기하는 샘플이 포함되어 있는 경우가 있습니다. 예를 들어 전화 통화 오디오는 대개 두 명 이상의 음성이 포함되어 있습니다. 통화 내용을 텍스트로 변환할 때 누가 언제 이야기하는지 알 수 있습니다.

화자 분할

Speech-to-Text는 같은 오디오 클립에서 화자를 여러 명 인식할 수 있습니다. Speech-to-Text에 오디오 텍스트 변환 요청을 보낼 때 Speech-to-Text가 오디오 샘플에서 다른 화자를 식별하도록 지시하는 매개변수를 포함할 수 있습니다. 화자 분할이라고 하는 이 기능은 화자가 바뀌는 시점을 감지하고 오디오에서 감지된 개별 음성에 숫자로 라벨을 지정합니다.

텍스트 변환 요청에서 화자 분할을 사용 설정하면 Speech-to-Text는 오디오 샘플에 포함된 여러 음성을 구별하려고 시도합니다. 텍스트 변환 결과에는 개별 화자마다 지정된 숫자와 함께 각 단어에 태그가 지정됩니다. 같은 화자가 말한 단어는 같은 숫자가 지정됩니다. 텍스트 변환 결과에는 Speech-to-Text가 오디오 샘플에서 고유하게 식별할 수 있는 최대 화자 수가 모두 포함될 수 있습니다.

화자 분할을 사용할 경우 Speech-to-Text는 텍스트 변환에서 제공되는 모든 결과의 누적 집계를 산출합니다. 각 결과에는 이전 결과의 단어가 포함됩니다. 따라서 최종 결과의 words 배열은 텍스트 변환의 완전한 분할 결과를 제공합니다.

이 기능이 사용 중인 언어로 지원되는지 알아보려면 언어 지원 페이지를 확인하세요.

요청에 화자 분할 사용 설정

화자 분할을 사용 설정하려면 RecognitionFeatures에서 diarization_config 필드를 설정해야 합니다. 스크립트에서 예상되는 화자 수에 따라 min_speaker_count 값과 max_speaker_count 값을 설정해야 합니다.

Speech-to-Text는 speech:recognize, 스트리밍 등 모든 음성 인식 메서드의 화자 분할을 지원합니다.

로컬 파일 사용

다음 코드 스니펫은 로컬 파일을 사용하여 Speech-to-Text에 대한 텍스트 변환 요청에서 화자 분할을 사용 설정하는 방법을 보여줍니다.

프로토콜

자세한 내용은 speech:recognize API 엔드포인트를 참조하세요.

동기 음성 인식을 수행하려면 POST 요청을 하고 적절한 요청 본문을 제공합니다. 다음은 curl을 사용한 POST 요청의 예시입니다. 이 예시에서는 Google Cloud CLI를 사용하여 액세스 토큰을 생성합니다. gcloud CLI 설치에 대한 안내는 빠른 시작을 참조하세요.

curl -s -H "Content-Type: application/json" \
    -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
    https://speech.googleapis.com/v2/projects/{project}/locations/{location}/recognizers/{recognizer}:recognize \
    --data '{
    "config": {
        "features": {
            "diarizationConfig": {
              "minSpeakerCount": 2,
              "maxSpeakerCount": 2
            },
        }
    },
    "uri": "gs://cloud-samples-tests/speech/commercial_mono.wav"
}' > speaker-diarization.txt

요청이 성공하면 서버는 200 OK HTTP 상태 코드와 응답을 JSON 형식으로 반환하여 speaker-diarization.txt라는 파일에 저장합니다.

{
  "results": [
    {
      "alternatives": [
        {
          "transcript": "hi I'd like to buy a Chromecast and I was wondering whether you could help me with that certainly which color would you like we have blue black and red uh let's go with the black one would you like the new Chromecast Ultra model or the regular Chrome Cast regular Chromecast is fine thank you okay sure we like to ship it regular or Express Express please terrific it's on the way thank you thank you very much bye",
          "confidence": 0.92142606,
          "words": [
            {
              "startOffset": "0s",
              "endOffset": "1.100s",
              "word": "hi",
              "speakerLabel": "2"
            },
            {
              "startOffset": "1.100s",
              "endOffset": "2s",
              "word": "I'd",
              "speakerLabel": "2"
            },
            {
              "startOffset": "2s",
              "endOffset": "2s",
              "word": "like",
              "speakerLabel": "2"
            },
            {
              "startOffset": "2s",
              "endOffset": "2.100s",
              "word": "to",
              "speakerLabel": "2"
            },
            ...
            {
              "startOffset": "6.500s",
              "endOffset": "6.900s",
              "word": "certainly",
              "speakerLabel": "1"
            },
            {
              "startOffset": "6.900s",
              "endOffset": "7.300s",
              "word": "which",
              "speakerLabel": "1"
            },
            {
              "startOffset": "7.300s",
              "endOffset": "7.500s",
              "word": "color",
              "speakerLabel": "1"
            },
            ...
          ]
        }
      ],
      "languageCode": "en-us"
    }
  ]
}

Go

Speech-to-Text용 클라이언트 라이브러리를 설치하고 사용하는 방법은 Speech-to-Text 클라이언트 라이브러리를 참조하세요. 자세한 내용은 Speech-to-Text Go API 참조 문서를 확인하세요.

Speech-to-Text에 인증하려면 애플리케이션 기본 사용자 인증 정보를 설정합니다. 자세한 내용은 로컬 개발 환경의 인증 설정을 참조하세요.


import (
	"context"
	"fmt"
	"io"
	"os"
	"strings"

	speech "cloud.google.com/go/speech/apiv1"
	"cloud.google.com/go/speech/apiv1/speechpb"
)

// transcribe_diarization_gcs_beta Transcribes a remote audio file using speaker diarization.
func transcribe_diarization(w io.Writer, filename string) error {
	// filename := "path-to-an-audio-file"

	ctx := context.Background()
	client, err := speech.NewClient(ctx)
	if err != nil {
		return fmt.Errorf("NewClient: %w", err)
	}
	defer client.Close()

	diarizationConfig := &speechpb.SpeakerDiarizationConfig{
		EnableSpeakerDiarization: true,
		MinSpeakerCount:          2,
		MaxSpeakerCount:          2,
	}

	recognitionConfig := &speechpb.RecognitionConfig{
		Encoding:          speechpb.RecognitionConfig_LINEAR16,
		SampleRateHertz:   8000,
		LanguageCode:      "en-US",
		DiarizationConfig: diarizationConfig,
	}

	// Get the contents of the local audio file
	content, err := os.ReadFile(filename)
	if err != nil {
		return fmt.Errorf("error reading file %v", err)
	}
	audio := &speechpb.RecognitionAudio{
		AudioSource: &speechpb.RecognitionAudio_Content{Content: content},
	}

	longRunningRecognizeRequest := &speechpb.LongRunningRecognizeRequest{
		Config: recognitionConfig,
		Audio:  audio,
	}

	operation, err := client.LongRunningRecognize(ctx, longRunningRecognizeRequest)
	if err != nil {
		return fmt.Errorf("error running recognize %v", err)
	}

	response, err := operation.Wait(ctx)
	if err != nil {
		return err
	}

	// Speaker Tags are only included in the last result object, which has only one
	// alternative.
	alternative := response.Results[len(response.Results)-1].Alternatives[0]

	wordInfo := alternative.GetWords()[0]
	currentSpeakerTag := wordInfo.GetSpeakerTag()

	var speakerWords strings.Builder

	speakerWords.WriteString(fmt.Sprintf("Speaker %d: %s", wordInfo.GetSpeakerTag(), wordInfo.GetWord()))

	// For each word, get all the words associated with one speaker, once the speaker changes,
	// add a new line with the new speaker and their spoken words.
	for i := 1; i < len(alternative.Words); i++ {
		wordInfo := alternative.Words[i]
		if currentSpeakerTag == wordInfo.GetSpeakerTag() {
			speakerWords.WriteString(" ")
			speakerWords.WriteString(wordInfo.GetWord())
		} else {
			speakerWords.WriteString(fmt.Sprintf("\nSpeaker %d: %s",
				wordInfo.GetSpeakerTag(), wordInfo.GetWord()))
			currentSpeakerTag = wordInfo.GetSpeakerTag()
		}
	}
	fmt.Fprintf(w, speakerWords.String())
	return nil
}

Python

Speech-to-Text용 클라이언트 라이브러리를 설치하고 사용하는 방법은 Speech-to-Text 클라이언트 라이브러리를 참조하세요. 자세한 내용은 Speech-to-Text Python API 참조 문서를 확인하세요.

Speech-to-Text에 인증하려면 애플리케이션 기본 사용자 인증 정보를 설정합니다. 자세한 내용은 로컬 개발 환경의 인증 설정을 참조하세요.

from google.cloud import speech_v1p1beta1 as speech

client = speech.SpeechClient()

speech_file = "resources/commercial_mono.wav"

with open(speech_file, "rb") as audio_file:
    content = audio_file.read()

audio = speech.RecognitionAudio(content=content)

diarization_config = speech.SpeakerDiarizationConfig(
    enable_speaker_diarization=True,
    min_speaker_count=2,
    max_speaker_count=10,
)

config = speech.RecognitionConfig(
    encoding=speech.RecognitionConfig.AudioEncoding.LINEAR16,
    sample_rate_hertz=8000,
    language_code="en-US",
    diarization_config=diarization_config,
)

print("Waiting for operation to complete...")
response = client.recognize(config=config, audio=audio)

# The transcript within each result is separate and sequential per result.
# However, the words list within an alternative includes all the words
# from all the results thus far. Thus, to get all the words with speaker
# tags, you only have to take the words list from the last result:
result = response.results[-1]

words_info = result.alternatives[0].words

# Printing out the output:
for word_info in words_info:
    print(f"word: '{word_info.word}', speaker_tag: {word_info.speaker_tag}")

return result