Transkrypcja mowy na tekst w czasie rzeczywistym poniżej 200 ms: przewodnik po architekturze
- Opublikowano
- Ostatnia aktualizacja
PosłuchajPosłuchaj tego artykułu
Zamiana mowy na tekst (STT) w czasie rzeczywistym transkrybuje dźwięk na bieżąco, zwracając tekst w ciągu kilkuset milisekund. Niskie opóźnienie STT to nie tylko kwestia modelu, ale też architektury. Trzeba zaplanować transport, dzielenie na fragmenty, kończenie segmentów i przechwytywanie dźwięku – każdy z tych etapów dokłada opóźnienie. Jeśli którykolwiek z nich jest nieefektywny, przekroczysz budżet 200 ms.
Ten przewodnik pokazuje praktyczny system, dzięki któremu zbudujesz pipeline’y zamiany mowy na tekst od warstwy transportu w górę. Skupimy się na Scribe v2 Realtime, który generuje częściowe transkrypcje w ok. 150 ms opóźnienia modelu, obsługuje ponad 90 języków, przyjmuje dźwięk PCM (8kHz-48kHz) i mu-law oraz udostępnia Voice Activity Detection i ręczne zatwierdzanie segmentów.
Prześledzimy, jak dźwięk trafia na serwer, jak hipotezy zamieniają się w zatwierdzony tekst, ile kosztują funkcje w strumieniu i jak poprawnie przechwytywać oraz przesyłać dźwięk.
W skrócie
- Tworzenie systemów zamiany mowy na tekst w czasie rzeczywistym wymaga dopracowania architektury, by opóźnienia były niskie w całym pipeline’ie.
- WebSocket to najlepszy wybór dla większości pipeline’ów, choć WebRTC daje dodatkowe korzyści, ale jest bardziej złożony.
- Voice Activity Detection dzieli nagranie bez użycia rąk, a ręczne zatwierdzanie pozwala aplikacji przejąć kontrolę, gdy wiadomo, że wypowiedź się skończyła.
- Częściowe transkrypcje są tymczasowe, a końcowe – zatwierdzone, więc warto je wyświetlać inaczej.
- Małe fragmenty PCM (ok. 100 ms) minimalizują opóźnienie do pierwszej częściowej transkrypcji.
WebSocket czy WebRTC do zamiany mowy na tekst w czasie rzeczywistym
Zanim zacznie się transkrypcja, dźwięk musi dotrzeć od źródła do rozpoznawania. Kanał, który wybierzesz, ustala minimalne opóźnienie dla całego procesu. Są dwa sensowne sposoby przesłania dźwięku do warstwy transkrypcji.
WebSocket to trwały, uporządkowany, niezawodny, dwukierunkowy kanał oparty na TCP. Otwierasz połączenie, wysyłasz binarne ramki audio i odbierasz zdarzenia z transkrypcją. Jest prosty po stronie klienta i serwera, przechodzi przez firmowe proxy i firewalle, które przepuszczają HTTPS, i działa w każdej przeglądarce oraz środowisku serwerowym.
Ograniczeniem WebSocket jest to, że działa na TCP. Jeśli pakiet zginie, TCP retransmituje go i wstrzymuje kolejne dane, aż luka zostanie uzupełniona. Przy dobrej sieci to niezauważalne, ale przy utracie pakietów pojawia się blokada kolejki – dźwięk chwilowo się zatrzymuje, a potem dociera naraz.
WebRTC jest stworzony do mediów w czasie rzeczywistym. Przesyła dźwięk przez UDP (SRTP), więc utrata pakietu nie zatrzymuje strumienia – pipeline działa dalej. Ma bufor jittera, który wyrównuje różnice w czasie dostarczania pakietów, negocjuje połączenia przez NAT (ICE/STUN/TURN), a także obsługuje własne przechwytywanie i kodowanie dźwięku.
Zwykle potrzebujesz serwerów TURN dla klientów, którzy nie mogą połączyć się bezpośrednio, a po stronie serwera trzeba zakończyć strumień mediów, a nie tylko czytać bajty.
Oto szybkie porównanie:
W większości przypadków WebSocket to najlepszy wybór. Używaj go, gdy klienci mają dobrą łączność i kontrolujesz przechwytywanie dźwięku: pipeline’y serwer-serwer, aplikacje desktopowe, przeglądarkowe na szerokopasmowym internecie i większość backendów call center, gdzie dźwięk już trafia na twój serwer inną drogą.
Wybierz WebRTC, gdy przechwytujesz dźwięk bezpośrednio z urządzeń użytkowników na niestabilnych sieciach mobilnych, gdy już korzystasz ze stosu WebRTC do dwukierunkowego audio (np. agent głosowy, który też mówi), albo gdy zależy ci bardziej na odporności na straty niż na prostocie wdrożenia.
Dalsza część przewodnika korzysta z transportu WebSocket do połączenia z rozpoznawaniem, bo to najprostszy start dla większości zespołów i pozwala łatwo śledzić każdy etap. Nic nie jest tu specyficzne dla WebSocket – możesz później dodać WebRTC z przodu, zdekodować dźwięk do PCM na serwerze i przesłać te same fragmenty dalej.
Częściowe i końcowe transkrypcje: czym się różnią
Rozpoznawanie w czasie rzeczywistym nie czeka na całe zdanie. Zamiast tego wysyła strumień przypuszczeń, które precyzują się wraz z kolejnym dźwiękiem, a potem są zatwierdzane. Zrozumienie różnicy między tymi stanami sprawia, że transkrypcja wydaje się „żywa”, a nie „zepsuta”.
Częściowa (tymczasowa) hipoteza to najlepsze przypuszczenie modelu na podstawie dotychczasowego dźwięku. Częściowe transkrypcje są z założenia niestabilne. Gdy pojawia się więcej dźwięku, model poprawia wcześniejsze słowa: „Chcę” może zmienić się w „Chcę dwa bilety”, gdy dalszy kontekst rozstrzyga niejasność. Pojawiają się szybko (to właśnie opisuje opóźnienie ~150 ms) i mają być nadpisywane.
Końcowa hipoteza to zatwierdzony segment, który już się nie zmieni. Po zatwierdzeniu segmentu rozpoznawanie przechodzi dalej, a kolejne hipotezy dotyczą następnego fragmentu dźwięku. Końcowe transkrypcje to te, które zapisujesz, wysyłasz do LLM lub przechowujesz jako zapis rozmowy.
Różnica między częściowymi a końcowymi transkrypcjami wpływa na trzy rzeczy, które łatwo pomylić:
- Doświadczenie użytkownika: Pokazywanie częściowych transkrypcji sprawia, że tekst pojawia się na żywo – użytkownik widzi słowa w trakcie mówienia, co potwierdza, że mikrofon działa i system słucha.
- Kończenie segmentów: Częściowe transkrypcje dają ciągły sygnał aktywności mowy. Razem z VAD pozwalają określić, kiedy mówca faktycznie skończył.
- Czas w pipeline’ie: W pipeline’ie agenta głosowego kroki to: najpierw audio, potem speech to text, później LLM, a następnie
Wyświetlaj częściowe i końcowe transkrypcje inaczej. Prosty sposób to trzymać jedną „bieżącą linię” z najnowszą częściową transkrypcją i dodawać ją do zapisu, gdy pojawi się końcowa:
Wizualnie pokazuj zatwierdzone teksty jako zwykłe, a bieżące – jaśniej lub kursywą, by użytkownik wiedział, że mogą się jeszcze zmienić.
Kończenie segmentów i Voice Activity Detection (VAD)
Wiedzieć, co zostało powiedziane, to tylko połowa sukcesu. Rozpoznawanie musi też wiedzieć, kiedy myśl się skończyła. To decyduje, kiedy zatwierdzić segment i – w przypadku agenta – kiedy system zaczyna odpowiadać.
Kończenie segmentu to decyzja, że wypowiedź się skończyła. Zatwierdzenie zbyt wcześnie ucina użytkownika w połowie zdania. Zbyt późno – sprawia, że agent milczy, choć użytkownik już skończył.
Scribe v2 Realtime daje ci dwa uzupełniające się mechanizmy:
- Voice Activity Detection dzieli dźwięk na podstawie ciszy: Rozpoznawanie wykrywa, kiedy mowa przechodzi w dłuższą ciszę i automatycznie kończy segment. VAD to domyślne rozwiązanie dla interfejsów konwersacyjnych, bo dostosowuje się do naturalnego rytmu mowy bez ręcznego śledzenia czasu.
- Ręczne zatwierdzanie:Ręczne zatwierdzanie pozwala twojej aplikacji zdecydować, kiedy zakończyć bieżący segment, niezależnie od ciszy. Wysyłasz sygnał commit, rozpoznawanie zamyka segment i zwraca końcową transkrypcję. To dobre rozwiązanie, gdy aplikacja już wie, że wypowiedź się skończyła: puszczenie przycisku push-to-talk, kliknięcie „wyślij” albo zewnętrzna logika zmiany tury.
Oba mechanizmy dobrze się uzupełniają. Typowy agent głosowy używa VAD do obsługi bez użycia rąk i udostępnia ręczne zatwierdzanie jako nadpisanie – użytkownik, który robi pauzę, nie zostanie ucięty, a ten, który kliknie przycisk, dostaje natychmiastową granicę.
Próg ciszy to prawdziwy kompromis – nie ma jednej dobrej wartości:
- Krótki timeout (np. zatwierdzenie po ~200-400 ms ciszy) sprawia, że system wydaje się szybki. Ale ucina użytkowników, którzy robią naturalne pauzy, dzieląc jedną myśl na kilka segmentów i – w przypadku agenta – wywołując przedwczesną odpowiedź.
- Długi timeout (np. ~800-1200 ms) pozwala na naturalne pauzy i trzyma wypowiedzi w całości, ale powoduje zauważalne opóźnienie reakcji systemu.
Nie ma tu uniwersalnej wartości – dostosuj próg do sytuacji:
- Dyktowanie i notatki mogą mieć dłuższe pauzy, bo użytkownicy myślą w trakcie mówienia. Wybierz dłuższe timeouty i polegaj na VAD.
- Agenci do komend i transakcji lepiej działają z krótszymi timeoutami i ręcznym zatwierdzaniem, bo wypowiedzi są krótkie i konkretne.
- Wielojęzyczni lub nie-native speakerzy robią więcej pauz, więc daj im więcej czasu przed zatwierdzeniem.
Te wskazówki pomogą ci zbudować skuteczny system kończenia segmentów i zbliżyć się do zamiany mowy na tekst w czasie rzeczywistym.
Funkcje w strumieniu: rozpoznawanie języka i diarizacja mówców
Rozpoznawanie strumieniowe może robić więcej niż tylko zamieniać dźwięk na słowa. Każdy dodatkowy sygnał wpływa jednak na opóźnienie i stabilność. Zasada jest prosta: włączaj tylko to, czego naprawdę potrzebuje doświadczenie na żywo, resztę zostaw na przetwarzanie wsadowe.
Automatyczne rozpoznawanie języka pozwala Scribe v2 Realtime wykryć język spośród ponad 90 obsługiwanych, bez konieczności podawania go z góry. Model potrzebuje jednak krótkiego fragmentu dźwięku, by pewnie rozpoznać język, więc pierwsze częściowe transkrypcje mogą być mniej stabilne, zanim język się ustali. Jeśli już znasz język, podanie go z góry daje stabilniejsze wyniki na starcie.
Diarizacja mówców przypisuje wypowiedzi do konkretnych osób, czyli rozpoznaje, kto co powiedział. W transkrypcji wsadowej to łatwiejsze, bo model widzi cały plik. W strumieniowej – trudniejsze: rozpoznawanie musi przypisać etykietę mówcy tylko na podstawie dotychczasowego dźwięku, a etykieta dla początku może wymagać korekty, gdy pojawi się więcej głosu tej osoby. Traktuj etykiety mówców w strumieniu tak jak częściowe transkrypcje: są tymczasowe, dopóki segment nie zostanie zatwierdzony.
Czas na poziomie słowa i kontekst encji działają podobnie. Im więcej metadanych na token prosisz, tym więcej musi obsłużyć model i sieć. W większości interfejsów na żywo wystarczy tekst i granice segmentów, a szczegółowe metadane możesz dodać później w przetwarzaniu wsadowym z Scribe v2.
Formaty audio do strumieniowania: PCM i mu-law
Transport i logika rozpoznawania zwykle skupiają uwagę, ale wiele błędów w praktyce wynika z warstwy niżej – z tego, jak kodujesz i dzielisz dźwięk. Dobry format i rozmiar fragmentów to najprostszy sposób na obniżenie opóźnienia zamiany mowy na tekst.
PCM (liniowy, 16-bitowy, little-endian) to najlepszy format, gdy kontrolujesz przechwytywanie. Wyższe próbkowanie daje więcej szczegółów: 16 kHz to standard dla rozpoznawania mowy i zwykle wystarcza; 8 kHz to jakość telefoniczna i traci wysokie częstotliwości. Użyj takiego próbkowania, jakie ma twoje źródło. Nie ma sensu podbijać 8 kHz do 48 kHz – tych informacji nie da się odzyskać.
Mu-law 8 kHz to format telefoniczny. Jeśli odbierasz rozmowy od dostawcy typu Twilio, dźwięk przychodzi jako 8 kHz mu-law i najlepiej przesłać go dalej w tym formacie, bez podwójnej konwersji. Dopasowanie formatu źródła unika artefaktów resamplingu i zbędnych konwersji.
Rozmiar fragmentów najbardziej wpływa na odczuwalne opóźnienie. Wysyłasz dźwięk w kawałkach, a rozpoznawanie generuje częściowe transkrypcje w miarę ich przychodzenia. Mniejsze fragmenty to częstsze aktualizacje i niższe opóźnienie do pierwszej transkrypcji; większe – mniej wiadomości i trochę więcej kontekstu na raz. Praktyczny zakres to 20-250 ms dźwięku na fragment. Dla przykładu: przy 16 kHz mono 16-bit PCM sekunda dźwięku to 32 000 bajtów, więc 100 ms to ok. 3 200 bajtów.
Przechwytywanie mikrofonu w przeglądarce
W przeglądarce najlepszym narzędziem jest Web Audio API z AudioWorklet. Worklet działa na wątku audio, odbiera dźwięk w małych ramkach i nie blokuje głównego wątku jak stary ScriptProcessorNode. Jego zadanie to konwersja natywnych próbek float na 16-bit PCM i przekazanie ich do głównego wątku, który wysyła je przez WebSocket.
Podstawą procesora worklet jest konwersja float na PCM:
Pipeline w kodzie
Pipeline ma trzy elementy: klienta w przeglądarce, który przechwytuje mikrofon i strumieniuje PCM na twój serwer; serwer Node, który przekazuje dźwięk do Scribe v2 Realtime i zwraca transkrypcje; oraz klienta backendowego, który strumieniuje PCM z pliku lub mostka telefonicznego.
Serwer przekazuje dźwięk zamiast udostępniać rozpoznawanie bezpośrednio przeglądarce z jednego powodu: twój klucz API ElevenLabs to tajemnica i nigdy nie powinien trafić do kodu po stronie klienta. Klucz trzymasz na serwerze. Jeśli musisz połączyć przeglądarkę bezpośrednio z rozpoznawaniem, wygeneruj krótkotrwały jednorazowy token po stronie serwera i przekaż go klientowi zamiast klucza API.
Klient przeglądarkowy
Klient otwiera WebSocket do twojego serwera, przechwytuje mikrofon przez powyższy worklet i przesyła każdą ramkę PCM od razu. Zdarzenia przychodzące (już znormalizowane przez serwer do { type, text }) sterują stanem częściowym/końcowym jak wyżej:
Przekaźnik serwerowy
Serwer otwiera jedno połączenie z rozpoznawaniem na klienta, trzyma klucz API na serwerze, przesyła binarne PCM bez zmian i normalizuje zdarzenia rozpoznawania do formatu { type, text }, który odbiera klient:
Wszystko, co zależy od endpointu, jest zamknięte w dwóch funkcjach adaptera poniżej. Podmień nazwy pól na dokładne z dokumentacji Speech to Text – reszta pipeline’u się nie zmienia:
Klient backendowy do skryptów
Dla pipeline’ów backendowych i benchmarku poniżej to samo połączenie z rozpoznawaniem działa bez przeglądarki: czytaj PCM z dowolnego źródła, wysyłaj w tempie czasu rzeczywistego i odbieraj zdarzenia. Klucz API i URL pobierasz ze środowiska, jak na serwerze.
Benchmarkowanie opóźnienia i wskaźnika błędów zamiany mowy na tekst
Opóźnienie i wskaźnik błędów zależą od mówcy, języka, warunków akustycznych, długości nagrania, trasy sieciowej do najbliższego regionu dostawcy i aktualnego obciążenia usługi.
Wynik z laptopa w jednym mieście nie przekłada się na produkcję w innym. Uruchamiaj testy na infrastrukturze podobnej do produkcyjnej, na dźwięku zbliżonym do rzeczywistego i raportuj zakresy oraz rozkłady, nie pojedyncze liczby.
Liczą się tylko te opóźnienia i dokładność, które zmierzysz na własnym dźwięku i infrastrukturze zbliżonej do produkcyjnej. Oto przewodnik po benchmarkowaniu zamiany mowy na tekst.
Co mierzyć przy benchmarku opóźnienia zamiany mowy na tekst
Oto główne metryki, które warto mierzyć przy benchmarku zamiany mowy na tekst w czasie rzeczywistym:
- Czas do pierwszej częściowej transkrypcji: Od wysłania pierwszego fragmentu dźwięku do otrzymania pierwszej niepustej transkrypcji częściowej.
- Opóźnienie od częściowej do końcowej: Od ostatniego fragmentu dźwięku do końcowej hipotezy.
- Wskaźnik błędów słów (WER): WER na końcowej transkrypcji względem ludzkiego wzorca, liczony identycznie dla wszystkich systemów.
- Stabilność transkrypcji: Ile razy częściowe transkrypcje są poprawiane przed zatwierdzeniem. To pokazuje, jak bardzo UI na żywo będzie się zmieniać.
Kontrola
Aby uniknąć niepewnych danych, wprowadź kilka kontroli w swoim eksperymencie, by wyniki były spójne.
Oto główne zasady kontroli przy benchmarku zamiany mowy na tekst:
- Identyczny dźwięk: Użyj tych samych plików, tego samego próbkowania i kodowania dla każdego systemu.
- Identyczne tempo:Strumieniuj każdy system z tym samym tempem fragmentów (np. 100 ms).
- Powtarzaj i raportuj rozkłady: Uruchom każdy plik wiele razy w ciągu dnia; raportuj medianę i ogon (p50/p95).
- Identyczne wzorce i scoring: Normalizuj tekst tak samo (wielkość liter, interpunkcja, liczby) przed liczeniem WER.
- Podaj region i sieć: Powiedz, gdzie uruchamiałeś test i jak wyglądała trasa do każdego dostawcy.
Trzymając się tych zasad, uzyskasz dokładniejsze metryki.
Szkielet testera
Rdzeń pomiarowy bierze adapter dostawcy i zapisuje czas do pierwszej transkrypcji częściowej, opóźnienie zatwierdzenia i liczbę poprawek transkrypcji:
WER to standardowa odległość Levenshteina na poziomie tokenów dla znormalizowanego tekstu. Przed liczeniem zamień na małe litery i usuń interpunkcję zarówno w wzorcu, jak i hipotezie – inaczej zmierzysz swój normalizator, a nie model. Owiń to w pętlę, która uruchamia każdy plik ok. 10 razy na dostawcę i raportuje medianę czasu do pierwszej transkrypcji i medianę WER (p50/p95), bo pojedynczy wynik zdominuje zmienność sieci.
Aby to uruchomić, potrzebujesz dwóch rzeczy. Po pierwsze, napisz jeden adapter StreamFn na system. Klient skryptowy powyżej już taki jest, a adaptery dla innych działają na tym samym kontrakcie (audioPath, onEvent, result) i ustawiają result.lastChunkSentAt, gdy wyślesz ostatni fragment dźwięku. Po drugie, załaduj swoje pliki audio i wzorce i uruchom pomiary na nich. Rób to na maszynie podobnej do produkcyjnej, na dźwięku podobnym do twoich użytkowników – wtedy porównanie będzie powtarzalne.
Podsumowanie: jak osiągnąć zamianę mowy na tekst w czasie rzeczywistym
W tym artykule opisaliśmy wiele zmian architektonicznych, które pozwolą ci stopniowo ulepszać system i zbliżyć się do zamiany mowy na tekst w czasie rzeczywistym.
System STT w produkcji sprowadza się do kilku decyzji:
- Transport: Wybierz WebSocket dla prostoty i kontrolowanych sieci, a WebRTC, gdy potrzebujesz odporności na straty i przechwytujesz dźwięk z urządzeń użytkowników.
- Częściowe i końcowe transkrypcje: Traktuj częściowe jako tymczasowe, a końcowe jako zatwierdzone i wyświetlaj je inaczej, by użytkownicy ufali tekstowi na żywo.
- Kończenie segmentów: Używaj VAD do dzielenia bez użycia rąk, ręcznego zatwierdzania jako nadpisania i dostosuj próg ciszy do sytuacji, a nie do stałej.
- Funkcje w strumieniu: Włączaj tylko te funkcje w strumieniu, które są potrzebne na żywo, resztę zostaw na przetwarzanie wsadowe z Scribe v2.
- Format audio: Przechwytuj w małych ramkach PCM, wysyłaj fragmenty ok. 100 ms i dopasuj format do źródła w przypadku telefonii.
- Benchmarkowanie: Dopasuj dokładność i opóźnienie na podstawie własnego dźwięku i docelowej metryki.
- Bezpieczeństwo API: Trzymaj swój klucz API na serwerze, albo generuj jednorazowe tokeny dla bezpośrednich połączeń klienta.
Jeśli chcesz zobaczyć, jak optymalizować opóźnienia w agencie głosowym, przygotowaliśmy też osobny przewodnik.
Buduj systemy zamiany mowy na tekst w czasie rzeczywistym z Scribe v2 Realtime
Scribe v2 Realtime generuje częściowe transkrypcje w ok. 150 ms opóźnienia modelu. To, czy użytkownicy zobaczą taki wynik, zależy od architektury wokół – na to masz wpływ. Korzystając ze strategii opisanych w tym artykule, zbudujesz lepszy pipeline z niższym opóźnieniem i lepszym doświadczeniem dla użytkowników.
Jeśli chcesz dowiedzieć się więcej, sprawdź możliwości Speech to Text, przeczytaj naszą dokumentację modeli z pełną listą funkcji i języków oraz odwiedź strony produktów na żywo: Speech to Text API w czasie rzeczywistym i Speech to Text w czasie rzeczywistym.
Gdy będziesz gotowy, załóż darmowe konto ElevenLabs i przetestuj swoją pierwszą transkrypcję już dziś.


.webp&w=3840&q=80)
.webp&w=3840&q=80)
