Bagikan melalui


Mulai cepat: Transkripsi rapat real time

Anda dapat mentranskripsikan rapat dengan kemampuan untuk menambahkan, menghapus, dan mengidentifikasi beberapa peserta dengan streaming audio ke layanan Ucapan. Anda terlebih dahulu membuat tanda tangan suara untuk setiap peserta menggunakan REST API, lalu menggunakan tanda tangan suara dengan Speech SDK untuk mentranskripsikan rapat. Lihat gambaran umum transkripsi rapat untuk informasi selengkapnya.

Pembatasan

  • Hanya tersedia di wilayah langganan berikut: centralus, eastasia, eastus, westeurope
  • Membutuhkan array multi-mikrofon melingkar 7-mikrofon. Array mikrofon harus memenuhi spesifikasi kami.

Catatan

Speech SDK untuk C++, Java, Objective-C, dan Swift mendukung transkripsi rapat, tetapi kami belum menyertakan panduan di sini.

Prasyarat

  • Langganan Azure - Buat langganan gratis.
  • Buat sumber daya Ucapan di portal Azure.
  • Kunci dan wilayah sumber daya Ucapan Anda. Setelah sumber daya Azure Cognitive Service untuk Ucapan Anda disebarkan, pilih Buka sumber daya untuk melihat dan mengelola kunci. Untuk informasi selengkapnya tentang sumber daya layanan Azure AI, lihat Mendapatkan kunci untuk sumber daya Anda.

Menyiapkan lingkungan

Sebelum Anda dapat melakukan tindakan apa pun, Anda harus menginstal Speech SDK for JavaScript. Jika Anda hanya ingin menginstal nama paket, jalankan npm install microsoft-cognitiveservices-speech-sdk. Untuk petunjuk penginstalan terpandu, lihat panduan penginstalan SDK.

Membuat tanda tangan suara

Jika Anda ingin mendaftarkan profil pengguna, langkah pertama adalah membuat tanda tangan suara untuk peserta rapat sehingga mereka dapat diidentifikasi sebagai pembicara unik. Ini tidak diperlukan jika Anda tidak ingin menggunakan profil pengguna yang telah terdaftar sebelumnya untuk mengidentifikasi peserta tertentu.

File audio input .wav untuk membuat tanda tangan suara harus 16-bit, laju sampel 16 kHz, dalam format saluran tunggal (mono). Panjang yang disarankan untuk setiap sampel audio adalah antara 30 detik dan dua menit. Sampel audio yang terlalu singkat menghasilkan akurasi yang berkurang saat mengenali speaker. File .wav harus menjadi sampel suara satu orang sehingga profil suara unik dibuat.

Contoh berikut menunjukkan cara membuat tanda tangan suara dengan menggunakan REST API di JavaScript. Anda harus memasukkan subscriptionKey, region Anda dan jalur ke file .wav sampel.

const fs = require('fs');
const axios = require('axios');
const formData = require('form-data');
 
const subscriptionKey = 'your-subscription-key';
const region = 'your-region';
 
async function createProfile() {
    let form = new formData();
    form.append('file', fs.createReadStream('path-to-voice-sample.wav'));
    let headers = form.getHeaders();
    headers['Ocp-Apim-Subscription-Key'] = subscriptionKey;
 
    let url = `https://signature.${region}.cts.speech.microsoft.com/api/v1/Signature/GenerateVoiceSignatureFromFormData`;
    let response = await axios.post(url, form, { headers: headers });
    
    // get signature from response, serialize to json string
    return JSON.stringify(response.data.Signature);
}
 
async function main() {
    // use this voiceSignature string with meeting transcription calls below
    let voiceSignatureString = await createProfile();
    console.log(voiceSignatureString);
}
main();

Menjalankan skrip ini akan menampilkan string tanda tangan suara dalam variabel voiceSignatureString. Jalankan fungsi ini dua kali sehingga Anda memiliki dua string yang akan digunakan sebagai input ke variabel voiceSignatureStringUser1dan voiceSignatureStringUser2 berikut.

Catatan

Tanda tangan suara hanya bisa dibuat menggunakan REST API.

Mentranskripsikan rapat

Contoh kode berikut menunjukkan cara mentranskripsikan rapat secara real time untuk dua pembicara. Ini mengasumsikan Anda sudah membuat string tanda tangan suara untuk setiap pembicara seperti yang ditunjukkan di atas. Ganti informasi nyata untuk subscriptionKey, region, dan jalur filepath untuk audio yang ingin ditranskrip.

Jika Anda tidak menggunakan profil pengguna yang telah terdaftar sebelumnya, dibutuhkan beberapa detik lagi untuk menyelesaikan pengenalan pertama pengguna yang tidak dikenal sebagai speaker1, speaker2, dll.

Catatan

Pastikan subscriptionKey yang sama digunakan di seluruh aplikasi Anda untuk pembuatan tanda tangan, atau Anda akan menemukan kesalahan.

Sampel kode akan melakukan hal berikut:

  • Membuat aliran push yang akan digunakan untuk transkripsi, dan menulis file .wav sampel ke dalamnya.
  • Membuat Meeting menggunakan createMeetingAsync().
  • Membuat MeetingTranscriber menggunakan konstruktor.
  • Menambahkan peserta ke rapat. String voiceSignatureStringUser1 dan voiceSignatureStringUser2 harus muncul sebagai hasil dari langkah-langkah di atas.
  • Mendaftar ke peristiwa dan memulai transkripsi.
  • Jika Anda ingin membedakan pembicara tanpa menyediakan sampel suara, aktifkan DifferentiateGuestSpeakers fitur seperti dalam Gambaran Umum Transkripsi Rapat.

Jika identifikasi atau diferensiasi pembicara diaktifkan, maka bahkan jika Anda telah menerima transcribed hasil, layanan masih mengevaluasinya dengan mengakumulasi informasi audio. Jika layanan menemukan bahwa hasil sebelumnya diberi hasil yang salah speakerId, maka hasil yang hampir identik Transcribed dikirim lagi, di mana hanya speakerId dan UtteranceId berbeda. UtteranceId Karena formatnya adalah {index}_{speakerId}_{Offset}, ketika Anda menerima transcribed hasil, Anda dapat menggunakan UtteranceId untuk menentukan apakah hasil saat ini transcribed akan memperbaiki yang sebelumnya. Logika klien atau UI Anda dapat memutuskan perilaku, seperti menimpa output sebelumnya, atau untuk mengabaikan hasil terbaru.

(function() {
    "use strict";
    var sdk = require("microsoft-cognitiveservices-speech-sdk");
    var fs = require("fs");
    
    var subscriptionKey = "your-subscription-key";
    var region = "your-region";
    var filepath = "audio-file-to-transcribe.wav"; // 8-channel audio
    
    var speechTranslationConfig = sdk.SpeechTranslationConfig.fromSubscription(subscriptionKey, region);
    var audioConfig = sdk.AudioConfig.fromWavFileInput(fs.readFileSync(filepath));
    speechTranslationConfig.setProperty("ConversationTranscriptionInRoomAndOnline", "true");

    // en-us by default. Adding this code to specify other languages, like zh-cn.
    speechTranslationConfig.speechRecognitionLanguage = "en-US";
    
    // create meeting and transcriber
    var meeting = sdk.Meeting.createMeetingAsync(speechTranslationConfig, "myMeeting");
    var transcriber = new sdk.MeetingTranscriber(audioConfig);
    
    // attach the transcriber to the meeting
    transcriber.joinMeetingAsync(meeting,
    function () {
        // add first participant using voiceSignature created in enrollment step
        var user1 = sdk.Participant.From("user1@example.com", "en-us", voiceSignatureStringUser1);
        meeting.addParticipantAsync(user1,
        function () {
            // add second participant using voiceSignature created in enrollment step
            var user2 = sdk.Participant.From("user2@example.com", "en-us", voiceSignatureStringUser2);
            meeting.addParticipantAsync(user2,
            function () {
                transcriber.sessionStarted = function(s, e) {
                console.log("(sessionStarted)");
                };
                transcriber.sessionStopped = function(s, e) {
                console.log("(sessionStopped)");
                };
                transcriber.canceled = function(s, e) {
                console.log("(canceled)");
                };
                transcriber.transcribed = function(s, e) {
                console.log("(transcribed) text: " + e.result.text);
                console.log("(transcribed) speakerId: " + e.result.speakerId);
                };
    
                // begin meeting transcription
                transcriber.startTranscribingAsync(
                function () { },
                function (err) {
                    console.trace("err - starting transcription: " + err);
                });
        },
        function (err) {
            console.trace("err - adding user1: " + err);
        });
    },
    function (err) {
        console.trace("err - adding user2: " + err);
    });
    },
    function (err) {
    console.trace("err - " + err);
    });
}()); 

Prasyarat

  • Langganan Azure - Buat langganan gratis.
  • Buat sumber daya Ucapan di portal Azure.
  • Kunci dan wilayah sumber daya Ucapan Anda. Setelah sumber daya Azure Cognitive Service untuk Ucapan Anda disebarkan, pilih Buka sumber daya untuk melihat dan mengelola kunci. Untuk informasi selengkapnya tentang sumber daya layanan Azure AI, lihat Mendapatkan kunci untuk sumber daya Anda.

Menyiapkan lingkungan

Speech SDK tersedia sebagai paket NuGet dan menerapkan .NET Standar 2.0. Anda menginstal Speech SDK nanti dalam panduan ini, tetapi pertama-tama periksa instruksi penginstalan khusus platform untuk persyaratan lainnya.

Membuat tanda tangan suara

Jika Anda ingin mendaftarkan profil pengguna, langkah pertama adalah membuat tanda tangan suara untuk peserta rapat sehingga mereka dapat diidentifikasi sebagai pembicara unik. Ini tidak diperlukan jika Anda tidak ingin menggunakan profil pengguna yang telah terdaftar sebelumnya untuk mengidentifikasi peserta tertentu.

File audio input .wav untuk membuat tanda tangan suara harus 16-bit, laju sampel 16 kHz, dalam format saluran tunggal (mono). Panjang yang disarankan untuk setiap sampel audio adalah antara 30 detik dan dua menit. Sampel audio yang terlalu singkat menghasilkan akurasi yang berkurang saat mengenali speaker. File .wav harus menjadi sampel suara satu orang sehingga profil suara unik dibuat.

Contoh berikut menunjukkan cara membuat tanda tangan suara dengan menggunakan REST API di C#. Anda harus memasukkan subscriptionKey, region Anda dan jalur ke file .wav sampel.

using System;
using System.IO;
using System.Net.Http;
using System.Runtime.Serialization;
using System.Threading.Tasks;
using Newtonsoft.Json;

[DataContract]
internal class VoiceSignature
{
    [DataMember]
    public string Status { get; private set; }

    [DataMember]
    public VoiceSignatureData Signature { get; private set; }

    [DataMember]
    public string Transcription { get; private set; }
}

[DataContract]
internal class VoiceSignatureData
{
    internal VoiceSignatureData()
    { }

    internal VoiceSignatureData(int version, string tag, string data)
    {
        this.Version = version;
        this.Tag = tag;
        this.Data = data;
    }

    [DataMember]
    public int Version { get; private set; }

    [DataMember]
    public string Tag { get; private set; }

    [DataMember]
    public string Data { get; private set; }
}

private static async Task<string> GetVoiceSignatureString()
{
    var subscriptionKey = "your-subscription-key";
    var region = "your-region";

    byte[] fileBytes = File.ReadAllBytes("path-to-voice-sample.wav");
    var content = new ByteArrayContent(fileBytes);
    var client = new HttpClient();
    client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", subscriptionKey);
    var response = await client.PostAsync($"https://signature.{region}.cts.speech.microsoft.com/api/v1/Signature/GenerateVoiceSignatureFromByteArray", content);
    
    var jsonData = await response.Content.ReadAsStringAsync();
    var result = JsonConvert.DeserializeObject<VoiceSignature>(jsonData);
    return JsonConvert.SerializeObject(result.Signature);
}

Menjalankan fungsi GetVoiceSignatureString() mengembalikan untai (karakter) tanda suara dalam format yang benar. Jalankan fungsi ini dua kali sehingga Anda memiliki dua string yang akan digunakan sebagai input ke variabel voiceSignatureStringUser1dan voiceSignatureStringUser2 berikut.

Catatan

Tanda tangan suara hanya bisa dibuat menggunakan REST API.

Mentranskripsikan rapat

Contoh kode berikut menunjukkan cara mentranskripsikan rapat secara real time untuk dua pembicara. Ini mengasumsikan Anda sudah membuat string tanda tangan suara untuk setiap pembicara seperti yang ditunjukkan di atas. Ganti informasi nyata untuk subscriptionKey, region, dan jalur filepath untuk audio yang ingin ditranskrip.

Jika Anda tidak menggunakan profil pengguna yang telah terdaftar sebelumnya, dibutuhkan beberapa detik lagi untuk menyelesaikan pengenalan pertama pengguna yang tidak dikenal sebagai speaker1, speaker2, dll.

Catatan

Pastikan subscriptionKey yang sama digunakan di seluruh aplikasi Anda untuk pembuatan tanda tangan, atau Anda akan menemukan kesalahan.

Sampel kode akan melakukan hal berikut:

  • Membuat AudioConfig dari file sampel .wav untuk ditranskripsikan.
  • Membuat Meeting menggunakan CreateMeetingAsync().
  • Membuat MeetingTranscriber menggunakan konstruktor, dan berlangganan acara yang diperlukan.
  • Menambahkan peserta ke rapat. Untai (karakter)voiceSignatureStringUser1 dan voiceSignatureStringUser2 harus muncul sebagai hasil dari langkah-langkah di atas dari fungsi GetVoiceSignatureString().
  • Bergabung dalam rapat dan memulai transkripsi.
  • Jika Anda ingin membedakan pembicara tanpa menyediakan sampel suara, aktifkan DifferentiateGuestSpeakers fitur seperti dalam Gambaran Umum Transkripsi Rapat.

Catatan

AudioStreamReaderAdalah kelas pembantu yang bisa Anda dapatkan di GitHub.

Jika identifikasi atau diferensiasi pembicara diaktifkan, maka bahkan jika Anda telah menerima Transcribed hasil, layanan masih mengevaluasinya dengan mengakumulasi informasi audio. Jika layanan menemukan bahwa hasil sebelumnya diberi hasil yang salah UserId, maka hasil yang hampir identik Transcribed dikirim lagi, di mana hanya UserId dan UtteranceId berbeda. UtteranceId Karena formatnya adalah {index}_{UserId}_{Offset}, ketika Anda menerima Transcribed hasil, Anda dapat menggunakan UtteranceId untuk menentukan apakah hasil saat ini Transcribed akan memperbaiki yang sebelumnya. Logika klien atau UI Anda dapat memutuskan perilaku, seperti menimpa output sebelumnya, atau untuk mengabaikan hasil terbaru.

Panggil fungsi TranscribeMeetingsAsync() untuk memulai transkripsi rapat.

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.CognitiveServices.Speech;
using Microsoft.CognitiveServices.Speech.Audio;
using Microsoft.CognitiveServices.Speech.Transcription;

class TranscribeMeeting
{
    // all your other code

    public static async Task TranscribeMeetingsAsync(string voiceSignatureStringUser1, string voiceSignatureStringUser2)
    {
        var subscriptionKey = "your-subscription-key";
        var region = "your-region";
        var filepath = "audio-file-to-transcribe.wav";

        var config = SpeechConfig.FromSubscription(subscriptionKey, region);
        config.SetProperty("ConversationTranscriptionInRoomAndOnline", "true");

        // en-us by default. Adding this code to specify other languages, like zh-cn.
        // config.SpeechRecognitionLanguage = "zh-cn";
        var stopRecognition = new TaskCompletionSource<int>();

        using (var audioInput = AudioConfig.FromWavFileInput(filepath))
        {
            var meetingID = Guid.NewGuid().ToString();
            using (var meeting = await Meeting.CreateMeetingAsync(config, meetingID))
            {
                // create a meeting transcriber using audio stream input
                using (var meetingTranscriber = new MeetingTranscriber(audioInput))
                {
                    meetingTranscriber.Transcribing += (s, e) =>
                    {
                        Console.WriteLine($"TRANSCRIBING: Text={e.Result.Text} SpeakerId={e.Result.UserId}");
                    };

                    meetingTranscriber.Transcribed += (s, e) =>
                    {
                        if (e.Result.Reason == ResultReason.RecognizedSpeech)
                        {
                            Console.WriteLine($"TRANSCRIBED: Text={e.Result.Text} SpeakerId={e.Result.UserId}");
                        }
                        else if (e.Result.Reason == ResultReason.NoMatch)
                        {
                            Console.WriteLine($"NOMATCH: Speech could not be recognized.");
                        }
                    };

                    meetingTranscriber.Canceled += (s, e) =>
                    {
                        Console.WriteLine($"CANCELED: Reason={e.Reason}");

                        if (e.Reason == CancellationReason.Error)
                        {
                            Console.WriteLine($"CANCELED: ErrorCode={e.ErrorCode}");
                            Console.WriteLine($"CANCELED: ErrorDetails={e.ErrorDetails}");
                            Console.WriteLine($"CANCELED: Did you set the speech resource key and region values?");
                            stopRecognition.TrySetResult(0);
                        }
                    };

                    meetingTranscriber.SessionStarted += (s, e) =>
                    {
                        Console.WriteLine($"\nSession started event. SessionId={e.SessionId}");
                    };

                    meetingTranscriber.SessionStopped += (s, e) =>
                    {
                        Console.WriteLine($"\nSession stopped event. SessionId={e.SessionId}");
                        Console.WriteLine("\nStop recognition.");
                        stopRecognition.TrySetResult(0);
                    };

                    // Add participants to the meeting.
                    var speaker1 = Participant.From("User1", "en-US", voiceSignatureStringUser1);
                    var speaker2 = Participant.From("User2", "en-US", voiceSignatureStringUser2);
                    await meeting.AddParticipantAsync(speaker1);
                    await meeting.AddParticipantAsync(speaker2);

                    // Join to the meeting and start transcribing
                    await meetingTranscriber.JoinMeetingAsync(meeting);
                    await meetingTranscriber.StartTranscribingAsync().ConfigureAwait(false);

                    // waits for completion, then stop transcription
                    Task.WaitAny(new[] { stopRecognition.Task });
                    await meetingTranscriber.StopTranscribingAsync().ConfigureAwait(false);
                }
            }
        }
    }
}

Prasyarat

  • Langganan Azure - Buat langganan gratis.
  • Buat sumber daya Ucapan di portal Azure.
  • Kunci dan wilayah sumber daya Ucapan Anda. Setelah sumber daya Azure Cognitive Service untuk Ucapan Anda disebarkan, pilih Buka sumber daya untuk melihat dan mengelola kunci. Untuk informasi selengkapnya tentang sumber daya layanan Azure AI, lihat Mendapatkan kunci untuk sumber daya Anda.

Menyiapkan lingkungan

Sebelum Anda dapat melakukan apa pun, instal Speech SDK untuk Python. Anda dapat menginstal Speech SDK dari PyPI dengan menjalankan pip install azure-cognitiveservices-speech.

Membuat tanda tangan suara

Jika Anda ingin mendaftarkan profil pengguna, langkah pertama adalah membuat tanda tangan suara untuk peserta rapat sehingga mereka dapat diidentifikasi sebagai pembicara unik. Ini tidak diperlukan jika Anda tidak ingin menggunakan profil pengguna yang telah terdaftar sebelumnya untuk mengidentifikasi peserta tertentu.

File audio input .wav untuk membuat tanda tangan suara harus 16-bit, laju sampel 16 kHz, dalam format saluran tunggal (mono). Panjang yang disarankan untuk setiap sampel audio adalah antara 30 detik dan dua menit. Sampel audio yang terlalu singkat menghasilkan akurasi yang berkurang saat mengenali speaker. File .wav harus menjadi sampel suara satu orang sehingga profil suara unik dibuat.

Contoh berikut menunjukkan cara membuat tanda tangan suara dengan menggunakan REST API di Python. Anda harus memasukkan subscriptionKey, region Anda dan jalur ke file .wav sampel.

import requests
from scipy.io.wavfile import read
import json

speech_key, service_region = "your-subscription-key", "your-region"
endpoint = f"https://signature.{service_region}.cts.speech.microsoft.com/api/v1/Signature/GenerateVoiceSignatureFromByteArray"

#Enrollment audio for each speaker. In this example, two speaker enrollment audio files are added.
enrollment_audio_speaker1 = "enrollment-audio-speaker1.wav"
enrollment_audio_speaker2 = "enrollment-audio-speaker2.wav"

def voice_data_converter(enrollment_audio):
  with open(enrollment_audio, "rb") as wav_file:
    input_wav = wav_file.read()
  return input_wav
  
def voice_signature_creator(endpoint, speech_key, enrollment_audio):
  data = voice_data_converter(enrollment_audio)
  headers = {"Ocp-Apim-Subscription-Key":speech_key}
  r = requests.post(url = endpoint,headers = headers, data = data)
  voice_signature_string = json.dumps(r.json()['Signature'])
  return voice_signature_string

voice_signature_user1 = voice_signature_creator(endpoint, speech_key, enrollment_audio_speaker1)
voice_signature_user2 = voice_signature_creator(endpoint, speech_key, enrollment_audio_speaker2)

Anda dapat menggunakan kedua voice_signature_string ini sebagai input ke variabel voice_signature_user1 dan voice_signature_user2 nanti dalam kode sampel.

Catatan

Tanda tangan suara hanya bisa dibuat menggunakan REST API.

Mentranskripsikan rapat

Contoh kode berikut menunjukkan cara mentranskripsikan rapat secara real time untuk dua pembicara. Ini mengasumsikan Anda telah membuat string tanda tangan suara untuk setiap speaker seperti yang ditunjukkan sebelumnya. Ganti informasi nyata untuk subscriptionKey, region, dan jalur filepath untuk audio yang ingin ditranskrip.

Jika Anda tidak menggunakan profil pengguna yang telah terdaftar sebelumnya, dibutuhkan beberapa detik lagi untuk menyelesaikan pengenalan pertama pengguna yang tidak dikenal sebagai speaker1, speaker2, dll.

Catatan

Pastikan subscriptionKey yang sama digunakan di seluruh aplikasi Anda untuk pembuatan tanda tangan, atau Anda akan menemukan kesalahan.

Berikut adalah apa yang dilakukan sampel:

  • Membuat konfigurasi ucapan dengan informasi langganan.
  • Buat konfigurasi audio menggunakan aliran push.
  • MeetingTranscriber Membuat dan Berlangganan peristiwa yang ditembakkan oleh transcriber rapat.
  • Pengidentifikasi rapat untuk membuat rapat.
  • Menambahkan peserta ke rapat. String voiceSignatureStringUser1 dan voiceSignatureStringUser2 harus berasal sebagai output dari langkah-langkah sebelumnya.
  • Baca seluruh file gelombang sekaligus dan streaming ke SDK dan mulai transkripsi.
  • Jika Anda ingin membedakan pembicara tanpa menyediakan sampel suara, Anda mengaktifkan DifferentiateGuestSpeakers fitur seperti dalam Gambaran Umum Transkripsi Rapat.

Jika identifikasi atau diferensiasi pembicara diaktifkan, maka bahkan jika Anda telah menerima transcribed hasil, layanan masih mengevaluasinya dengan mengakumulasi informasi audio. Jika layanan menemukan bahwa hasil sebelumnya diberi hasil yang salah speakerId, maka hasil yang hampir identik Transcribed dikirim lagi, di mana hanya speakerId dan UtteranceId berbeda. UtteranceId Karena formatnya adalah {index}_{speakerId}_{Offset}, ketika Anda menerima transcribed hasil, Anda dapat menggunakan UtteranceId untuk menentukan apakah hasil saat ini transcribed akan memperbaiki yang sebelumnya. Logika klien atau UI Anda dapat memutuskan perilaku, seperti menimpa output sebelumnya, atau untuk mengabaikan hasil terbaru.

import azure.cognitiveservices.speech as speechsdk
import time
import uuid
from scipy.io import wavfile

speech_key, service_region="your-subscription-key","your-region"
meetingfilename= "audio-file-to-transcribe.wav" # 8 channel, 16 bits, 16kHz audio

def meeting_transcription():
    
    speech_config = speechsdk.SpeechConfig(subscription=speech_key, region=service_region)
    speech_config.set_property_by_name("ConversationTranscriptionInRoomAndOnline", "true")
    # If you want to differentiate speakers without providing voice samples, uncomment the following line.
    # speech_config.set_property_by_name("DifferentiateGuestSpeakers", "true")

    channels = 8
    bits_per_sample = 16
    samples_per_second = 16000
    
    wave_format = speechsdk.audio.AudioStreamFormat(samples_per_second, bits_per_sample, channels)
    stream = speechsdk.audio.PushAudioInputStream(stream_format=wave_format)
    audio_config = speechsdk.audio.AudioConfig(stream=stream)

    transcriber = speechsdk.transcription.MeetingTranscriber(audio_config)

    meeting_id = str(uuid.uuid4())
    meeting = speechsdk.transcription.Meeting(speech_config, meeting_id)
    done = False

    def stop_cb(evt: speechsdk.SessionEventArgs):
        """callback that signals to stop continuous transcription upon receiving an event `evt`"""
        print('CLOSING {}'.format(evt))
        nonlocal done
        done = True
        
    transcriber.transcribed.connect(lambda evt: print('TRANSCRIBED: {}'.format(evt)))
    transcriber.session_started.connect(lambda evt: print('SESSION STARTED: {}'.format(evt)))
    transcriber.session_stopped.connect(lambda evt: print('SESSION STOPPED {}'.format(evt)))
    transcriber.canceled.connect(lambda evt: print('CANCELED {}'.format(evt)))
    # stop continuous transcription on either session stopped or canceled events
    transcriber.session_stopped.connect(stop_cb)
    transcriber.canceled.connect(stop_cb)

    # Note user voice signatures are not required for speaker differentiation.
    # Use voice signatures when adding participants when more enhanced speaker identification is required.
    user1 = speechsdk.transcription.Participant("user1@example.com", "en-us", voice_signature_user1)
    user2 = speechsdk.transcription.Participant("user2@example.com", "en-us", voice_signature_user2)

    meeting.add_participant_async(user1).get()
    meeting.add_participant_async(user2).get()
    transcriber.join_meeting_async(meeting).get()
    transcriber.start_transcribing_async()
    
    sample_rate, wav_data = wavfile.read(meetingfilename)
    stream.write(wav_data.tobytes())
    stream.close()
    while not done:
        time.sleep(.5)

    transcriber.stop_transcribing_async()

Langkah berikutnya