Différencier les locuteurs dans un enregistrement audio

Cette page explique comment attribuer des libellés aux différents locuteurs dans les données audio transcrites par Speech-to-Text.

Parfois, les données audio contiennent des échantillons où plusieurs locuteurs parlent. Par exemple, un fichier audio provenant d'un appel téléphonique comprend généralement les voix de deux personnes ou plus. Dans l'idéal, une transcription de l'appel indique qui parle et quand.

Identification du locuteur

Speech-to-Text peut reconnaître plusieurs locuteurs dans un même extrait audio. Lorsque vous envoyez une requête de transcription audio à Speech-to-Text, vous pouvez inclure un paramètre lui indiquant d'identifier les différents locuteurs de l'échantillon audio. Cette fonctionnalité, appelée identification du locuteur, permet de détecter le changement d'intervenant et attribue un numéro à chaque voix détectée dans le fichier audio.

Lorsque vous activez cette fonctionnalité dans votre requête de transcription, Speech-to-Text tente de distinguer les différentes voix incluses dans l'échantillon audio. Dans le résultat de la transcription, un libellé est attribué à chaque mot. Ce libellé contient un numéro correspondant à chaque locuteur. Les mots prononcés par un même locuteur portent le même numéro. Un résultat de transcription peut inclure autant de numéros que de locuteurs que Speech-to-Text peut identifier de manière unique dans l'échantillon audio.

Lorsque vous utilisez la fonctionnalité d'identification du locuteur, Speech-to-Text génère un agrégat mobile de l'ensemble des résultats fournis dans la transcription. Chaque résultat comprend les mots du résultat précédent. Ainsi, le tableau words compris dans le résultat final fournit les résultats complets identifiant les locuteurs de la transcription.

Consultez la page Langues acceptées pour savoir si cette fonctionnalité est disponible pour votre langue.

Activer l'identification du locuteur dans une requête

Pour activer l'identification du locuteur, vous devez définir le champ enableSpeakerDiarization sur true dans les paramètres RecognitionConfig de la requête. Pour améliorer les résultats de la transcription, vous devez également spécifier le nombre de locuteurs présents dans l'extrait audio en définissant le champ diarizationSpeakerCount dans les paramètres RecognitionConfig. Si vous n'indiquez pas la valeur du champ diarizationSpeakerCount, Speech-to-Text utilise une valeur par défaut.

Speech-to-Text permet d'utiliser la fonctionnalité d'identification du locuteur pour toutes les méthodes de reconnaissance vocale : speech:recognize, speech:longrunningrecognize et Streaming.

Utiliser un fichier local

L'extrait de code suivant montre comment activer l'identification du locuteur dans une requête de transcription envoyée à Speech-to-Text à l'aide d'un fichier local.

Protocole

Reportez-vous au point de terminaison speech:recognize de l'API pour obtenir des informations complètes.

Pour réaliser une reconnaissance vocale synchrone, exécutez une requête POST en fournissant le corps de requête approprié. Voici un exemple de requête POST utilisant curl. Cet exemple fait intervenir le jeton d'accès associé à un compte de service configuré pour le projet à l'aide du SDK Cloud de Google Cloud. Pour obtenir des instructions sur l'installation du SDK Cloud, la configuration d'un projet avec un compte de service et l'obtention d'un jeton d'accès, consultez le guide de démarrage rapide.

    curl -s -H "Content-Type: application/json" \
        -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
        https://speech.googleapis.com/v1p1beta1/speech:recognize \
        --data '{
        "config": {
            "encoding": "LINEAR16",
            "languageCode": "en-US",
            "enableSpeakerDiarization": true,
            "diarizationSpeakerCount": 2,
            "model": "phone_call"
        },
        "audio": {
            "uri": "gs://cloud-samples-tests/speech/commercial_mono.wav"
        }
    }' > speaker-diarization.txt
    

Si la requête aboutit, le serveur affiche un code d'état HTTP 200 OK et la réponse au format JSON, enregistrée dans un fichier nommé 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": [
                {
                  "startTime": "0s",
                  "endTime": "1.100s",
                  "word": "hi",
                  "speakerTag": 2
                },
                {
                  "startTime": "1.100s",
                  "endTime": "2s",
                  "word": "I'd",
                  "speakerTag": 2
                },
                {
                  "startTime": "2s",
                  "endTime": "2s",
                  "word": "like",
                  "speakerTag": 2
                },
                {
                  "startTime": "2s",
                  "endTime": "2.100s",
                  "word": "to",
                  "speakerTag": 2
                },
                ...
                {
                  "startTime": "6.500s",
                  "endTime": "6.900s",
                  "word": "certainly",
                  "speakerTag": 1
                },
                {
                  "startTime": "6.900s",
                  "endTime": "7.300s",
                  "word": "which",
                  "speakerTag": 1
                },
                {
                  "startTime": "7.300s",
                  "endTime": "7.500s",
                  "word": "color",
                  "speakerTag": 1
                },
                ...
              ]
            }
          ],
          "languageCode": "en-us"
        }
      ]
    }
    

Java

/**
     * Transcribe the given audio file using speaker diarization.
     *
     * @param fileName the path to an audio file.
     */
    public static void transcribeDiarization(String fileName) throws Exception {
      Path path = Paths.get(fileName);
      byte[] content = Files.readAllBytes(path);

      try (SpeechClient speechClient = SpeechClient.create()) {
        // Get the contents of the local audio file
        RecognitionAudio recognitionAudio =
            RecognitionAudio.newBuilder().setContent(ByteString.copyFrom(content)).build();

        SpeakerDiarizationConfig speakerDiarizationConfig =
            SpeakerDiarizationConfig.newBuilder()
                .setEnableSpeakerDiarization(true)
                .setMinSpeakerCount(2)
                .setMaxSpeakerCount(2)
                .build();

        // Configure request to enable Speaker diarization
        RecognitionConfig config =
            RecognitionConfig.newBuilder()
                .setEncoding(AudioEncoding.LINEAR16)
                .setLanguageCode("en-US")
                .setSampleRateHertz(8000)
                .setDiarizationConfig(speakerDiarizationConfig)
                .build();

        // Perform the transcription request
        RecognizeResponse recognizeResponse = speechClient.recognize(config, recognitionAudio);

        // Speaker Tags are only included in the last result object, which has only one alternative.
        SpeechRecognitionAlternative alternative =
            recognizeResponse.getResults(recognizeResponse.getResultsCount() - 1).getAlternatives(0);

        // The alternative is made up of WordInfo objects that contain the speaker_tag.
        WordInfo wordInfo = alternative.getWords(0);
        int currentSpeakerTag = wordInfo.getSpeakerTag();

        // 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.
        StringBuilder speakerWords =
            new StringBuilder(
                String.format("Speaker %d: %s", wordInfo.getSpeakerTag(), wordInfo.getWord()));

        for (int i = 1; i < alternative.getWordsCount(); i++) {
          wordInfo = alternative.getWords(i);
          if (currentSpeakerTag == wordInfo.getSpeakerTag()) {
            speakerWords.append(" ");
            speakerWords.append(wordInfo.getWord());
          } else {
            speakerWords.append(
                String.format("\nSpeaker %d: %s", wordInfo.getSpeakerTag(), wordInfo.getWord()));
            currentSpeakerTag = wordInfo.getSpeakerTag();
          }
        }

        System.out.println(speakerWords.toString());
      }
    }

Node.js

const fs = require('fs');

    // Imports the Google Cloud client library
    const speech = require('@google-cloud/speech').v1p1beta1;

    // Creates a client
    const client = new speech.SpeechClient();

    /**
     * TODO(developer): Uncomment the following lines before running the sample.
     */
    // const fileName = 'Local path to audio file, e.g. /path/to/audio.raw';

    const config = {
      encoding: 'LINEAR16',
      sampleRateHertz: 8000,
      languageCode: 'en-US',
      enableSpeakerDiarization: true,
      diarizationSpeakerCount: 2,
      model: 'phone_call',
    };

    const audio = {
      content: fs.readFileSync(fileName).toString('base64'),
    };

    const request = {
      config: config,
      audio: audio,
    };

    const [response] = await client.recognize(request);
    const transcription = response.results
      .map(result => result.alternatives[0].transcript)
      .join('\n');
    console.log(`Transcription: ${transcription}`);
    console.log('Speaker Diarization:');
    const result = response.results[response.results.length - 1];
    const wordsInfo = result.alternatives[0].words;
    // Note: 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:
    wordsInfo.forEach(a =>
      console.log(` word: ${a.word}, speakerTag: ${a.speakerTag}`)
    );

Python

from google.cloud import speech_v1p1beta1
    import io

    def sample_long_running_recognize(local_file_path):
        """
        Print confidence level for individual words in a transcription of a short audio
        file
        Separating different speakers in an audio file recording

        Args:
          local_file_path Path to local audio file, e.g. /path/audio.wav
        """

        client = speech_v1p1beta1.SpeechClient()

        # local_file_path = 'resources/commercial_mono.wav'

        # If enabled, each word in the first alternative of each result will be
        # tagged with a speaker tag to identify the speaker.
        enable_speaker_diarization = True

        # Optional. Specifies the estimated number of speakers in the conversation.
        diarization_speaker_count = 2

        # The language of the supplied audio
        language_code = "en-US"
        config = {
            "enable_speaker_diarization": enable_speaker_diarization,
            "diarization_speaker_count": diarization_speaker_count,
            "language_code": language_code,
        }
        with io.open(local_file_path, "rb") as f:
            content = f.read()
        audio = {"content": content}

        operation = client.long_running_recognize(config, audio)

        print(u"Waiting for operation to complete...")
        response = operation.result()

        for result in response.results:
            # First alternative has words tagged with speakers
            alternative = result.alternatives[0]
            print(u"Transcript: {}".format(alternative.transcript))
            # Print the speaker_tag of each word
            for word in alternative.words:
                print(u"Word: {}".format(word.word))
                print(u"Speaker tag: {}".format(word.speaker_tag))

    

Utiliser un bucket Google Cloud Storage

L'extrait de code suivant montre comment activer l'identification du locuteur dans une requête de transcription envoyée à Speech-to-Text à l'aide d'un fichier Google Cloud Storage.

Java

/**
     * Transcribe a remote audio file using speaker diarization.
     *
     * @param gcsUri the path to an audio file.
     */
    public static void transcribeDiarizationGcs(String gcsUri) throws Exception {
      try (SpeechClient speechClient = SpeechClient.create()) {
        SpeakerDiarizationConfig speakerDiarizationConfig =
            SpeakerDiarizationConfig.newBuilder()
                .setEnableSpeakerDiarization(true)
                .setMinSpeakerCount(2)
                .setMaxSpeakerCount(2)
                .build();

        // Configure request to enable Speaker diarization
        RecognitionConfig config =
            RecognitionConfig.newBuilder()
                .setEncoding(AudioEncoding.LINEAR16)
                .setLanguageCode("en-US")
                .setSampleRateHertz(8000)
                .setDiarizationConfig(speakerDiarizationConfig)
                .build();

        // Set the remote path for the audio file
        RecognitionAudio audio = RecognitionAudio.newBuilder().setUri(gcsUri).build();

        // Use non-blocking call for getting file transcription
        OperationFuture<LongRunningRecognizeResponse, LongRunningRecognizeMetadata> response =
            speechClient.longRunningRecognizeAsync(config, audio);

        while (!response.isDone()) {
          System.out.println("Waiting for response...");
          Thread.sleep(10000);
        }

        // Speaker Tags are only included in the last result object, which has only one alternative.
        LongRunningRecognizeResponse longRunningRecognizeResponse = response.get();
        SpeechRecognitionAlternative alternative =
            longRunningRecognizeResponse
                .getResults(longRunningRecognizeResponse.getResultsCount() - 1)
                .getAlternatives(0);

        // The alternative is made up of WordInfo objects that contain the speaker_tag.
        WordInfo wordInfo = alternative.getWords(0);
        int currentSpeakerTag = wordInfo.getSpeakerTag();

        // 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.
        StringBuilder speakerWords =
            new StringBuilder(
                String.format("Speaker %d: %s", wordInfo.getSpeakerTag(), wordInfo.getWord()));

        for (int i = 1; i < alternative.getWordsCount(); i++) {
          wordInfo = alternative.getWords(i);
          if (currentSpeakerTag == wordInfo.getSpeakerTag()) {
            speakerWords.append(" ");
            speakerWords.append(wordInfo.getWord());
          } else {
            speakerWords.append(
                String.format("\nSpeaker %d: %s", wordInfo.getSpeakerTag(), wordInfo.getWord()));
            currentSpeakerTag = wordInfo.getSpeakerTag();
          }
        }

        System.out.println(speakerWords.toString());
      }
    }

Node.js

// Imports the Google Cloud client library
    const speech = require('@google-cloud/speech').v1p1beta1;

    // Creates a client
    const client = new speech.SpeechClient();

    /**
     * TODO(developer): Uncomment the following line before running the sample.
     */
    // const uri = path to GCS audio file e.g. `gs:/bucket/audio.wav`;

    const config = {
      encoding: 'LINEAR16',
      sampleRateHertz: 8000,
      languageCode: 'en-US',
      enableSpeakerDiarization: true,
      diarizationSpeakerCount: 2,
      model: 'phone_call',
    };

    const audio = {
      uri: gcsUri,
    };

    const request = {
      config: config,
      audio: audio,
    };

    const [response] = await client.recognize(request);
    const transcription = response.results
      .map(result => result.alternatives[0].transcript)
      .join('\n');
    console.log(`Transcription: ${transcription}`);
    console.log('Speaker Diarization:');
    const result = response.results[response.results.length - 1];
    const wordsInfo = result.alternatives[0].words;
    // Note: 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:
    wordsInfo.forEach(a =>
      console.log(` word: ${a.word}, speakerTag: ${a.speakerTag}`)
    );