Transkripsi suara

Transkripsi suara memungkinkan Anda mengonversi data audio streaming menjadi teks yang ditranskripsikan secara real time. Agent Assist memberikan saran berdasarkan teks, sehingga data audio harus dikonversi sebelum dapat digunakan. Anda juga dapat menggunakan audio streaming yang ditranskripsikan dengan Customer Experience Insights untuk mengumpulkan data real-time tentang percakapan agen (misalnya, Pemodelan Topik).

Ada dua cara untuk mentranskripsikan audio streaming untuk digunakan dengan Agent Assist: Menggunakan fitur SIPREC, atau dengan melakukan panggilan gRPC dengan data audio sebagai payload. Halaman ini menjelaskan proses mentranskripsikan data audio streaming menggunakan panggilan gRPC.

Transkripsi suara berfungsi menggunakan pengenalan ucapan streaming Speech-to-Text streaming speech recognition. Speech-to-Text menawarkan beberapa model pengenalan, standar dan ditingkatkan. Agent Assist tidak membatasi model yang dapat Anda gunakan dengan transkripsi suara, tetapi transkripsi suara didukung di tingkat GA hanya jika digunakan dengan model telepon atau Chirp 3. Untuk kualitas transkripsi yang optimal, model Chirp 3 direkomendasikan, bergantung pada ketersediaan regional.

Prasyarat

Membuat profil percakapan

Untuk membuat profil percakapan, gunakan konsol Agent Assist atau panggil metode create pada ConversationProfile resource secara langsung.

Untuk transkripsi suara, sebaiknya konfigurasi ConversationProfile.stt_config sebagai InputAudioConfig default saat mengirim data audio dalam percakapan.

Mendapatkan transkripsi saat runtime percakapan

Untuk mendapatkan transkripsi saat runtime percakapan, Anda harus membuat peserta untuk percakapan, dan mengirim data audio untuk setiap peserta.

Membuat peserta

Ada tiga jenis peserta. Lihat dokumentasi referensi untuk mengetahui detail selengkapnya tentang perannya. Panggil metode create pada participant dan tentukan role. Hanya peserta END_USER atau HUMAN_AGENT yang dapat memanggil StreamingAnalyzeContent, yang diperlukan untuk mendapatkan transkripsi.

Mengirim data audio dan mendapatkan transkrip

Anda dapat menggunakan StreamingAnalyzeContent untuk mengirim audio peserta ke Google dan mendapatkan transkripsi, dengan parameter berikut:

  • Permintaan pertama dalam streaming harus berupa InputAudioConfig. (Kolom yang dikonfigurasi di sini akan mengganti setelan yang sesuai di ConversationProfile.stt_config.) Jangan kirim input audio apa pun hingga permintaan kedua.

    • audioEncoding harus ditetapkan ke AUDIO_ENCODING_LINEAR_16 atau AUDIO_ENCODING_MULAW.
    • model: Ini adalah model Speech-to-Text yang ingin Anda gunakan untuk mentranskripsikan audio. Tetapkan kolom ini ke chirp_3. Varian tidak memengaruhi kualitas transkripsi sehingga, Anda dapat membiarkan Varian model ucapan tidak ditentukan atau memilih Gunakan yang terbaik.
    • singleUtterance harus ditetapkan ke false untuk kualitas transkripsi terbaik. Anda tidak boleh mengharapkan END_OF_SINGLE_UTTERANCE jika singleUtterance adalah false, tetapi Anda dapat bergantung pada isFinal==true di dalam StreamingAnalyzeContentResponse.recognition_result untuk menutup streaming sebagian.
    • Parameter tambahan opsional: Parameter berikut bersifat opsional. Untuk mendapatkan akses ke parameter ini, hubungi perwakilan Google Anda.
      • languageCode: language_code audio. Nilai defaultnya adalah en-US.
      • alternativeLanguageCodes: Fitur ini hanya tersedia di tingkat GA untuk model Chirp 3. Bahasa tambahan yang mungkin terdeteksi dalam audio. Agent Assist menggunakan kolom language_code untuk otomatis mendeteksi bahasa di awal audio dan menetapkannya sebagai default di semua giliran percakapan berikutnya. Kolom alternativeLanguageCodes memungkinkan Anda menentukan lebih banyak opsi untuk dipilih Agent Assist.
      • phraseSets: Nama resource adaptasi phraseSet model Speech-to-Text.
        • Untuk mengonfigurasi adaptasi untuk model Chirp 3, tambahkan frasa inline yang dipisahkan oleh baris baru, tanpa koma.
        • Untuk menggunakan adaptasi model dengan model lain seperti telephony untuk transkripsi suara, Anda harus membuat phraseSet terlebih dahulu menggunakan Speech-to-Text API dan menentukan nama resource di sini.
  • Setelah mengirim permintaan kedua dengan payload audio, Anda akan mulai menerima beberapa StreamingAnalyzeContentResponses dari streaming.

    • Anda dapat menutup streaming sebagian (atau berhenti mengirim dalam beberapa bahasa seperti Python) saat melihat is_final ditetapkan ke true di StreamingAnalyzeContentResponse.recognition_result.
    • Setelah Anda menutup streaming sebagian, server akan mengirim kembali respons yang berisi transkrip akhir, beserta saran Dialogflow atau saran Agent Assist yang potensial.
  • Anda dapat menemukan transkripsi akhir di lokasi berikut:

  • Mulai streaming baru setelah streaming sebelumnya ditutup.

    • Pengiriman ulang audio: Data audio yang dihasilkan setelah speech_end_offset terakhir dari respons dengan is_final=true ke waktu mulai streaming baru harus dikirim ulang ke StreamingAnalyzeContent untuk kualitas transkripsi terbaik.
  • Berikut diagram yang menggambarkan cara kerja streaming.

Contoh kode permintaan pengenalan streaming

Contoh kode berikut menggambarkan cara mengirim permintaan transkripsi streaming.

Python

Untuk melakukan autentikasi ke Agent Assist, siapkan Kredensial Default Aplikasi. Untuk mengetahui informasi selengkapnya, lihat Menyiapkan autentikasi untuk lingkungan pengembangan lokal.

# 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()

Ikuti langkah-langkah berikut untuk melihat file Python untuk conversation_management dan participant_management.

  1. Buka repositori GitHub untuk dokumen Python.

    Buka GitHub

  2. Klik Go to file dan masukkan nama file: conversation_management atau participant_management.

  3. Klik Enter.

Praktik terbaik

Waktu pengiriman pesan adalah saat ucapan dimulai. Gunakan waktu pengiriman pesan untuk menentukan urutan pesan suara ditampilkan atau dianalisis oleh pusat kontak Anda.