Sdílet prostřednictvím


Rychlý start: Přepis schůzky v reálném čase

Schůzky můžete přepisovat pomocí možnosti přidávat, odebírat a identifikovat více účastníků streamováním zvuku do služby Speech. Nejdřív vytvoříte hlasové podpisy pro každého účastníka pomocí rozhraní REST API a pak pomocí hlasových podpisů se sadou Speech SDK přepíšete schůzky. Další informace najdete v přehledu přepisu schůzky.

Omezení

  • K dispozici pouze v následujících oblastech předplatného: centralus, eastasia, eastuswesteurope
  • Vyžaduje kruhové 7 mikrofonní pole s více mikrofony. Pole mikrofonu by mělo splňovat naši specifikaci.

Poznámka:

Sada Speech SDK pro C++, Javu, Objective-C a Swift podporují přepis schůzek, ale zatím jsme do ní nezahrnuli průvodce.

Požadavky

Nastavení prostředí

Než budete moct cokoli udělat, musíte nainstalovat sadu Speech SDK pro JavaScript. Pokud chcete, aby se název balíčku nainstaloval, spusťte npm install microsoft-cognitiveservices-speech-sdkpříkaz . Pokyny k instalaci s asistencí najdete v průvodci instalací sady SDK.

Vytváření hlasových podpisů

Pokud chcete zaregistrovat profily uživatelů, prvním krokem je vytvoření hlasových podpisů pro účastníky schůzky, aby je bylo možné identifikovat jako jedinečné mluvčí. To se nevyžaduje, pokud nechcete k identifikaci konkrétních účastníků používat předem zaregistrované profily uživatelů.

Vstupní .wav zvukový soubor pro vytváření hlasových podpisů musí být 16bitová vzorkovací frekvence 16 kHz v jednokanálovém (mono) formátu. Doporučená délka každého zvukového vzorku je 30 sekund až dvě minuty. Zvukový vzorek, který je příliš krátký, snižuje přesnost při rozpoznávání mluvčího. Soubor .wav by měl být vzorek hlasu jedné osoby, aby se vytvořil jedinečný hlasový profil.

Následující příklad ukazuje, jak vytvořit hlasový podpis pomocí rozhraní REST API v JavaScriptu. Musíte vložit soubor subscriptionKey, regiona cestu k ukázkového .wav souboru.

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

Spuštění tohoto skriptu vrátí řetězec hlasového podpisu v proměnné voiceSignatureString. Spusťte funkci dvakrát, abyste měli dva řetězce, které můžete použít jako vstup do proměnných voiceSignatureStringUser1 a voiceSignatureStringUser2 níže.

Poznámka:

Hlasové podpisy je možné vytvořit pouze pomocí rozhraní REST API.

Přepis schůzek

Následující ukázkový kód ukazuje, jak přepisovat schůzky v reálném čase pro dva mluvčí. Předpokládá se, že jste už pro každého mluvčího vytvořili řetězce hlasových podpisů, jak je znázorněno výše. Nahraďte skutečné informace a subscriptionKeyregioncestu filepath ke zvukovému záznamu, který chcete přepsat.

Pokud nepoužíváte předem zaregistrované profily uživatelů, trvá to několik sekund, než dokončíte první rozpoznávání neznámých uživatelů jako mluvčí1, mluvčí2 atd.

Poznámka:

Ujistěte se, že se stejná subscriptionKey používá v rámci vaší aplikace k vytvoření podpisu nebo dojde k chybám.

Tento ukázkový kód provede následující:

  • Vytvoří stream nabízených oznámení, který se použije k přepisu, a zapíše do něj ukázkový .wav soubor.
  • Vytvoří Meeting pomocí createMeetingAsync().
  • Vytvoří MeetingTranscriber pomocí konstruktoru.
  • Přidá účastníky do schůzky. Řetězce voiceSignatureStringUser1 a voiceSignatureStringUser2 měly by pocházet jako výstup z výše uvedených kroků.
  • Zaregistruje se k událostem a začne přepis.
  • Pokud chcete odlišit reproduktory bez poskytnutí hlasových ukázek, povolte DifferentiateGuestSpeakers funkci jako v přehledu přepisu schůzky.

Pokud je povolena identifikace nebo rozlišení mluvčího, pak i když jste již obdrželi transcribed výsledky, služba je stále vyhodnocuje shromážděnými zvukovými informacemi. Pokud služba zjistí, že jakýkoli předchozí výsledek byl přiřazen nesprávný speakerId, pak se znovu odešle téměř identický Transcribed výsledek, kde se liší pouze speakerId a UtteranceId jsou odlišné. Vzhledem k tomu, že formát UtteranceId je {index}_{speakerId}_{Offset}, když obdržíte transcribed výsledek, můžete použít UtteranceId k určení, jestli aktuální transcribed výsledek bude opravovat předchozí výsledek. Logika klienta nebo uživatelského rozhraní může rozhodnout o chování, jako je přepsání předchozího výstupu nebo ignorování nejnovějšího výsledku.

(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);
    });
}()); 

Požadavky

Nastavení prostředí

Sada Speech SDK je k dispozici jako balíček NuGet a implementuje .NET Standard 2.0. Sadu Speech SDK nainstalujete později v této příručce, ale nejprve si projděte pokyny pro instalaci specifickou pro platformu, kde najdete další požadavky.

Vytváření hlasových podpisů

Pokud chcete zaregistrovat profily uživatelů, prvním krokem je vytvoření hlasových podpisů pro účastníky schůzky, aby je bylo možné identifikovat jako jedinečné mluvčí. To se nevyžaduje, pokud nechcete k identifikaci konkrétních účastníků používat předem zaregistrované profily uživatelů.

Vstupní .wav zvukový soubor pro vytváření hlasových podpisů musí být 16bitová vzorkovací frekvence 16 kHz v jednokanálovém (mono) formátu. Doporučená délka každého zvukového vzorku je 30 sekund až dvě minuty. Zvukový vzorek, který je příliš krátký, snižuje přesnost při rozpoznávání mluvčího. Soubor .wav by měl být vzorek hlasu jedné osoby, aby se vytvořil jedinečný hlasový profil.

Následující příklad ukazuje, jak vytvořit hlasový podpis pomocí rozhraní REST API v jazyce C#. Musíte vložit soubor subscriptionKey, regiona cestu k ukázkového .wav souboru.

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);
}

Spuštění funkce GetVoiceSignatureString() vrátí řetězec hlasového podpisu ve správném formátu. Spusťte funkci dvakrát, abyste měli dva řetězce, které můžete použít jako vstup do proměnných voiceSignatureStringUser1 a voiceSignatureStringUser2 níže.

Poznámka:

Hlasové podpisy je možné vytvořit pouze pomocí rozhraní REST API.

Přepis schůzek

Následující ukázkový kód ukazuje, jak přepisovat schůzky v reálném čase pro dva mluvčí. Předpokládá se, že jste už pro každého mluvčího vytvořili řetězce hlasových podpisů, jak je znázorněno výše. Nahraďte skutečné informace a subscriptionKeyregioncestu filepath ke zvukovému záznamu, který chcete přepsat.

Pokud nepoužíváte předem zaregistrované profily uživatelů, trvá to několik sekund, než dokončíte první rozpoznávání neznámých uživatelů jako mluvčí1, mluvčí2 atd.

Poznámka:

Ujistěte se, že se stejná subscriptionKey používá v rámci vaší aplikace k vytvoření podpisu nebo dojde k chybám.

Tento ukázkový kód provede následující:

  • Vytvoří z ukázkového .wav souboru, AudioConfig který se má přepsat.
  • Vytvoří Meeting pomocí CreateMeetingAsync().
  • MeetingTranscriber Vytvoří pomocí konstruktoru a přihlásí se k odběru potřebných událostí.
  • Přidá účastníky do schůzky. Řetězce voiceSignatureStringUser1 a voiceSignatureStringUser2 měly by pocházet jako výstup z výše uvedených kroků z funkce GetVoiceSignatureString().
  • Připojí se ke schůzce a zahájí přepis.
  • Pokud chcete odlišit reproduktory bez poskytnutí hlasových ukázek, povolte DifferentiateGuestSpeakers tuto funkci jako v přehledu přepisu schůzky.

Poznámka:

AudioStreamReader je pomocná třída, kterou můžete získat na GitHubu.

Pokud je povolena identifikace nebo rozlišení mluvčího, pak i když jste již obdrželi Transcribed výsledky, služba je stále vyhodnocuje shromážděnými zvukovými informacemi. Pokud služba zjistí, že jakýkoli předchozí výsledek byl přiřazen nesprávný UserId, pak se znovu odešle téměř identický Transcribed výsledek, kde se liší pouze UserId a UtteranceId jsou odlišné. Vzhledem k tomu, že formát UtteranceId je {index}_{UserId}_{Offset}, když obdržíte Transcribed výsledek, můžete použít UtteranceId k určení, jestli aktuální Transcribed výsledek bude opravovat předchozí výsledek. Logika klienta nebo uživatelského rozhraní může rozhodnout o chování, jako je přepsání předchozího výstupu nebo ignorování nejnovějšího výsledku.

Zavoláním funkce TranscribeMeetingsAsync() zahájíte přepis schůzky.

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);
                }
            }
        }
    }
}

Požadavky

Nastavení prostředí

Než budete moct cokoli udělat, nainstalujte sadu Speech SDK pro Python. Sadu Speech SDK můžete nainstalovat z PyPI spuštěním pip install azure-cognitiveservices-speechpříkazu .

Vytváření hlasových podpisů

Pokud chcete zaregistrovat profily uživatelů, prvním krokem je vytvoření hlasových podpisů pro účastníky schůzky, aby je bylo možné identifikovat jako jedinečné mluvčí. To se nevyžaduje, pokud nechcete k identifikaci konkrétních účastníků používat předem zaregistrované profily uživatelů.

Vstupní .wav zvukový soubor pro vytváření hlasových podpisů musí být 16bitová vzorkovací frekvence 16 kHz v jednokanálovém (mono) formátu. Doporučená délka každého zvukového vzorku je 30 sekund až dvě minuty. Zvukový vzorek, který je příliš krátký, snižuje přesnost při rozpoznávání mluvčího. Soubor .wav by měl být vzorek hlasu jedné osoby, aby se vytvořil jedinečný hlasový profil.

Následující příklad ukazuje, jak vytvořit hlasový podpis pomocí rozhraní REST API v Pythonu. Musíte vložit soubor subscriptionKey, regiona cestu k ukázkového .wav souboru.

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)

Tyto dvě voice_signature_string můžete použít jako vstup do proměnných voice_signature_user1 a voice_signature_user2 později v ukázkovém kódu.

Poznámka:

Hlasové podpisy je možné vytvořit pouze pomocí rozhraní REST API.

Přepis schůzek

Následující ukázkový kód ukazuje, jak přepisovat schůzky v reálném čase pro dva mluvčí. Předpokládá se, že jste už pro každého mluvčího vytvořili řetězce hlasových podpisů, jak je znázorněno dříve. Nahraďte skutečné informace a subscriptionKeyregioncestu filepath ke zvukovému záznamu, který chcete přepsat.

Pokud nepoužíváte předem zaregistrované profily uživatelů, trvá to několik sekund, než dokončíte první rozpoznávání neznámých uživatelů jako mluvčí1, mluvčí2 atd.

Poznámka:

Ujistěte se, že se stejná subscriptionKey používá v rámci vaší aplikace k vytvoření podpisu nebo dojde k chybám.

Tady je postup, který ukázka dělá:

  • Vytvoří konfiguraci řeči s informacemi o předplatném.
  • Vytvořte konfiguraci zvuku pomocí streamu nabízených oznámení.
  • MeetingTranscriber Vytvoří událost a přihlásí se k odběru událostí aktivovaných přepisem schůzky.
  • Identifikátor schůzky pro vytvoření schůzky
  • Přidá účastníky do schůzky. Řetězce voiceSignatureStringUser1 a voiceSignatureStringUser2 měly by pocházet jako výstup z předchozích kroků.
  • Přečtěte si všechny soubory vln najednou a streamujte je do sady SDK a začnete přepisovat.
  • Pokud chcete odlišit reproduktory bez poskytnutí hlasových ukázek, povolíte DifferentiateGuestSpeakers tuto funkci jako v přehledu přepisu schůzky.

Pokud je povolena identifikace nebo rozlišení mluvčího, pak i když jste již obdrželi transcribed výsledky, služba je stále vyhodnocuje shromážděnými zvukovými informacemi. Pokud služba zjistí, že jakýkoli předchozí výsledek byl přiřazen nesprávný speakerId, pak se znovu odešle téměř identický Transcribed výsledek, kde se liší pouze speakerId a UtteranceId jsou odlišné. Vzhledem k tomu, že formát UtteranceId je {index}_{speakerId}_{Offset}, když obdržíte transcribed výsledek, můžete použít UtteranceId k určení, jestli aktuální transcribed výsledek bude opravovat předchozí výsledek. Logika klienta nebo uživatelského rozhraní může rozhodnout o chování, jako je přepsání předchozího výstupu nebo ignorování nejnovějšího výsledku.

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

Další kroky