Sprachtranskription

Mit der Sprachtranskription können Sie Ihre Streaming-Audiodaten in Echtzeit in transkribierten Text umwandeln. Agent Assist gibt Vorschläge auf der Grundlage von Text. Daher müssen Audiodaten konvertiert werden, bevor sie verwendet werden können. Sie können transkribierte Streaming-Audiodaten auch mit Customer Experience Insights verwenden, um Echtzeitdaten zu Agenten Unterhaltungen zu erfassen (z. B. Themen Modellierung).

Es gibt zwei Möglichkeiten, Streaming-Audiodaten für die Verwendung mit Agent Assist zu transkribieren: mit der SIPREC-Funktion oder durch gRPC-Aufrufe mit Audiodaten als Nutzlast. Auf dieser Seite wird beschrieben, wie Sie Streaming-Audiodaten mit gRPC-Aufrufen transkribieren.

Die Sprachtranskription funktioniert mit der Streaming-Spracherkennung von Speech-to-Text Streaming-Spracherkennung. Speech-to-Text bietet mehrere Erkennungs modelle, sowohl Standard- als auch optimierte Modelle. Agent Assist schränkt nicht ein, welche Modelle Sie für die Sprach transkription verwenden können. Die Sprachtranskription wird jedoch auf GA-Ebene nur unterstützt, wenn sie mit dem Telefonie- oder Chirp 3 Modell verwendet wird. Für eine optimale Transkriptionsqualität wird das Chirp 3-Modell empfohlen, sofern es in Ihrer Region verfügbar ist.

Vorbereitung

Unterhaltungsprofil erstellen

Um ein Unterhaltungsprofil zu erstellen, verwenden Sie die Agent Assist Console oder rufen Sie die Methode create für die ConversationProfile Ressource direkt auf.

Für die Sprachtranskription empfehlen wir, ConversationProfile.stt_config als Standard-InputAudioConfig zu konfigurieren, wenn Sie Audiodaten in einer Unterhaltung senden.

Transkriptionen während der Unterhaltung abrufen

Wenn Sie Transkriptionen während der Unterhaltung abrufen möchten, müssen Sie Teilnehmer für die Unterhaltung erstellen und für jeden Teilnehmer Audiodaten senden.

Teilnehmer erstellen

Es gibt drei Arten von Teilnehmern. Weitere Informationen zu ihren Rollen finden Sie in der reference documentation. Rufen Sie die Methode create für den participant auf und geben Sie die role an. Nur ein END_USER- oder ein HUMAN_AGENT-Teilnehmer kann StreamingAnalyzeContent aufrufen, was für eine Transkription erforderlich ist.

Audiodaten senden und Transkript abrufen

Mit StreamingAnalyzeContent können Sie die Audiodaten eines Teilnehmers an Google senden und eine Transkription erhalten. Verwenden Sie dazu die folgenden Parameter:

  • Die erste Anfrage im Stream muss InputAudioConfig sein. Die hier konfigurierten Felder überschreiben die entsprechenden Einstellungen unter ConversationProfile.stt_config. Senden Sie erst mit der zweiten Anfrage eine Audioeingabe.

    • audioEncoding muss auf AUDIO_ENCODING_LINEAR_16 oder AUDIO_ENCODING_MULAW festgelegt werden.
    • model: Dies ist das Speech-to-Text Modell, das Sie zum Transkribieren Ihrer Audiodaten verwenden möchten. Legen Sie für dieses Feld chirp_3 fest. Die Variante hat keine Auswirkungen auf die Transkriptionsqualität. Sie können also Speech model variant nicht angeben oder Use best available auswählen.
    • singleUtterance sollte für eine optimale Transkriptionsqualität auf false gesetzt werden. Wenn singleUtterance auf false gesetzt ist, sollten Sie nicht mit END_OF_SINGLE_UTTERANCE rechnen. Sie können sich jedoch auf isFinal==true in StreamingAnalyzeContentResponse.recognition_result verlassen, um den Stream halb zu schließen.
    • Optionale zusätzliche Parameter: Die folgenden Parameter sind optional. Wenden Sie sich an Ihren Google-Ansprechpartner, um Zugriff auf diese Parameter zu erhalten.
      • languageCode: language_code des Audios. Der Standardwert ist en-US.
      • alternativeLanguageCodes: Diese Funktion ist nur auf GA-Ebene für das Chirp 3-Modell verfügbar. Zusätzliche Sprachen, die im Audio erkannt werden können. Agent Assist verwendet das Feld language_code, um die Sprache am Anfang des Audios automatisch zu erkennen und verwendet diese Sprache in allen folgenden Unterhaltungsrunden. Mit dem Feld alternativeLanguageCodes können Sie weitere Optionen für Agent Assist angeben.
      • phraseSets: Der Name der Speech-to-Text-Modell anpassungs phraseSet ressource.
        • Wenn Sie die Anpassung für das Chirp 3-Modell konfigurieren möchten, fügen Sie Inline-Phrasen hinzu, die durch Zeilenumbrüche getrennt sind und keine Kommas enthalten.
        • Wenn Sie die Modellanpassung mit anderen Modellen wie telephony für die Sprachtranskription verwenden möchten, müssen Sie zuerst das phraseSet mit der Speech-to-Text API erstellen und hier den Ressourcennamen angeben.
  • Nachdem Sie die zweite Anfrage mit der Audio-Nutzlast gesendet haben, sollten Sie einige StreamingAnalyzeContentResponses aus dem Stream erhalten.

    • Sie können den Stream halb schließen (oder in einigen Sprachen wie Python das Senden beenden), wenn is_final in StreamingAnalyzeContentResponse.recognition_result auf true gesetzt ist.
    • Nachdem Sie den Stream halb geschlossen haben, sendet der Server die Antwort mit der endgültigen Transkription sowie potenziellen Dialogflow- oder Agent Assist-Vorschlägen zurück.
  • Die endgültige Transkription finden Sie an den folgenden Stellen:

    • StreamingAnalyzeContentResponse.message.content.
    • Wenn Sie Pub/Sub Benachrichtigungen aktivieren, können Sie die Transkription auch in Pub/Sub sehen.
  • Starten Sie einen neuen Stream, nachdem der vorherige Stream geschlossen wurde.

    • Audio erneut senden: Audiodaten, die nach dem letzten speech_end_offset der Antwort mit is_final=true generiert wurden, müssen an die neue Startzeit des Streams gesendet werden, damit StreamingAnalyzeContent eine optimale Transkriptionsqualität erzielen kann.
  • Das folgende Diagramm veranschaulicht die Funktionsweise des Streams.

Codebeispiel für eine Anfrage zur Streamingerkennung

Das folgende Codebeispiel veranschaulicht, wie Sie eine Anfrage zur Streaming-Transkription senden.

Python

Richten Sie zur Authentifizierung bei Agent Assist die Standardanmeldedaten für Anwendungen (ADC) ein. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Google Cloud Dialogflow API sample code using the StreamingAnalyzeContent
API.

Also please contact Google to get credentials of this project and set up the
credential file json locations by running:
export GOOGLE_APPLICATION_CREDENTIALS=<cred_json_file_location>

Example usage:
    export GOOGLE_CLOUD_PROJECT='cloud-contact-center-ext-demo'
    export CONVERSATION_PROFILE='FnuBYO8eTBWM8ep1i-eOng'
    export GOOGLE_APPLICATION_CREDENTIALS='/Users/ruogu/Desktop/keys/cloud-contact-center-ext-demo-78798f9f9254.json'
    python streaming_transcription.py

Then started to talk in English, you should see transcription shows up as you speak.

Say "Quit" or "Exit" to stop.
"""

import os
import re
import sys

from google.api_core.exceptions import DeadlineExceeded, OutOfRange

import pyaudio

from six.moves import queue

import conversation_management
import participant_management

PROJECT_ID = os.getenv("GOOGLE_CLOUD_PROJECT")
CONVERSATION_PROFILE_ID = os.getenv("CONVERSATION_PROFILE")

# Audio recording parameters
SAMPLE_RATE = 16000
CHUNK_SIZE = int(SAMPLE_RATE / 10)  # 100ms
RESTART_TIMEOUT = 160  # seconds
MAX_LOOKBACK = 3  # seconds
HALF_CLOSE_DURATION_MS = 90 * 1000  # milliseconds

YELLOW = "\033[0;33m"


class ResumableMicrophoneStream:
    """Opens a recording stream as a generator yielding the audio chunks."""

    def __init__(self, rate, chunk_size):
        self._rate = rate
        self.chunk_size = chunk_size
        self._num_channels = 1
        self._buff = queue.Queue()
        self.is_final = False
        self.closed = True
        # Count the number of times the stream analyze content restarts.
        self.restart_counter = 0
        self.last_start_time = 0
        # Time end of the last is_final in millisec since last_start_time.
        self.is_final_offset = 0
        # Save the audio chunks generated from the start of the audio stream for
        # replay after restart.
        self.audio_input_chunks = []
        self.new_stream = True
        self._audio_interface = pyaudio.PyAudio()
        self._audio_stream = self._audio_interface.open(
            format=pyaudio.paInt16,
            channels=self._num_channels,
            rate=self._rate,
            input=True,
            frames_per_buffer=self.chunk_size,
            # Run the audio stream asynchronously to fill the buffer object.
            # This is necessary so that the input device's buffer doesn't
            # overflow while the calling thread makes network requests, etc.
            stream_callback=self._fill_buffer,
        )

    def __enter__(self):
        self.closed = False
        return self

    def __exit__(self, type, value, traceback):
        self._audio_stream.stop_stream()
        self._audio_stream.close()
        self.closed = True
        # Signal the generator to terminate so that the client's
        # streaming_recognize method will not block the process termination.
        self._buff.put(None)
        self._audio_interface.terminate()

    def _fill_buffer(self, in_data, *args, **kwargs):
        """Continuously collect data from the audio stream, into the buffer in
        chunksize."""

        self._buff.put(in_data)
        return None, pyaudio.paContinue

    def generator(self):
        """Stream Audio from microphone to API and to local buffer"""
        try:
            # Handle restart.
            print("restart generator")
            # Flip the bit of is_final so it can continue stream.
            self.is_final = False
            total_processed_time = self.last_start_time + self.is_final_offset
            processed_bytes_length = (
                int(total_processed_time * SAMPLE_RATE * 16 / 8) / 1000
            )
            self.last_start_time = total_processed_time
            # Send out bytes stored in self.audio_input_chunks that is after the
            # processed_bytes_length.
            if processed_bytes_length != 0:
                audio_bytes = b"".join(self.audio_input_chunks)
                # Lookback for unprocessed audio data.
                need_to_process_length = min(
                    int(len(audio_bytes) - processed_bytes_length),
                    int(MAX_LOOKBACK * SAMPLE_RATE * 16 / 8),
                )
                # Note that you need to explicitly use `int` type for substring.
                need_to_process_bytes = audio_bytes[(-1) * need_to_process_length :]
                yield need_to_process_bytes

            while not self.closed and not self.is_final:
                data = []
                # Use a blocking get() to ensure there's at least one chunk of
                # data, and stop iteration if the chunk is None, indicating the
                # end of the audio stream.
                chunk = self._buff.get()

                if chunk is None:
                    return
                data.append(chunk)
                # Now try to the rest of chunks if there are any left in the _buff.
                while True:
                    try:
                        chunk = self._buff.get(block=False)

                        if chunk is None:
                            return
                        data.append(chunk)

                    except queue.Empty:
                        break
                self.audio_input_chunks.extend(data)
                if data:
                    yield b"".join(data)
        finally:
            print("Stop generator")


def main():
    """start bidirectional streaming from microphone input to Dialogflow API"""
    # Create conversation.
    conversation = conversation_management.create_conversation(
        project_id=PROJECT_ID, conversation_profile_id=CONVERSATION_PROFILE_ID
    )

    conversation_id = conversation.name.split("conversations/")[1].rstrip()

    # Create end user participant.
    end_user = participant_management.create_participant(
        project_id=PROJECT_ID, conversation_id=conversation_id, role="END_USER"
    )
    participant_id = end_user.name.split("participants/")[1].rstrip()

    mic_manager = ResumableMicrophoneStream(SAMPLE_RATE, CHUNK_SIZE)
    print(mic_manager.chunk_size)
    sys.stdout.write(YELLOW)
    sys.stdout.write('\nListening, say "Quit" or "Exit" to stop.\n\n')
    sys.stdout.write("End (ms)       Transcript Results/Status\n")
    sys.stdout.write("=====================================================\n")

    with mic_manager as stream:
        while not stream.closed:
            terminate = False
            while not terminate:
                try:
                    print(f"New Streaming Analyze Request: {stream.restart_counter}")
                    stream.restart_counter += 1
                    # Send request to streaming and get response.
                    responses = participant_management.analyze_content_audio_stream(
                        conversation_id=conversation_id,
                        participant_id=participant_id,
                        sample_rate_herz=SAMPLE_RATE,
                        stream=stream,
                        timeout=RESTART_TIMEOUT,
                        language_code="en-US",
                        single_utterance=False,
                        # Uncomment to process multiple utterances detected in the audio stream
                        # individually instead of stitching together to form a single utterance.
                        # output_multiple_utterances=True,
                    )

                    # Now, print the final transcription responses to user.
                    for response in responses:
                        if response.message:
                            print(response)
                        if response.recognition_result.is_final:
                            print(response)
                            # offset return from recognition_result is relative
                            # to the beginning of audio stream.
                            offset = response.recognition_result.speech_end_offset
                            stream.is_final_offset = int(
                                offset.seconds * 1000 + offset.microseconds / 1000
                            )
                            transcript = response.recognition_result.transcript
                            # Half-close upon final results for better streaming experiences
                            # (in Python just stop yielding requests)
                            if stream.is_final_offset > HALF_CLOSE_DURATION_MS:
                                stream.is_final = True
                            # Exit recognition if any of the transcribed phrase could be
                            # one of our keywords.
                            if re.search(r"\b(exit|quit)\b", transcript, re.I):
                                sys.stdout.write(YELLOW)
                                sys.stdout.write("Exiting...\n")
                                terminate = True
                                stream.closed = True
                                break
                except OutOfRange:
                    print("Maximum audio duration exceeded in the stream, restarting.")
                except DeadlineExceeded:
                    print("Deadline Exceeded, restarting.")

            if terminate:
                conversation_management.complete_conversation(
                    project_id=PROJECT_ID, conversation_id=conversation_id
                )
                break


if __name__ == "__main__":
    main()

So rufen Sie die Python-Dateien für conversation_management und participant_management auf:

  1. Rufen Sie das GitHub-Repository für Python-Dokumente auf.

    Zu GitHub

  2. Klicken Sie auf Go to file (Zur Datei) und geben Sie den Dateinamen ein: conversation_management oder participant_management.

  3. Drücken Sie die Eingabetaste.