Powrót do bloga
aigooglecloudffmpegbuildinpublic

Wymieniłem silnik TTS. Wywołanie API było najprostszą częścią

Jak wbudować Google Chirp 3 HD w pipeline dubbingu wideo, gdy precyzja czasowa ma większe znaczenie niż jakość pojedynczego zdania.

13 września 2026

Wymieniłem silnik TTS. Wywołanie API było najprostszą częścią

Katto już miało dubbing AI. Twórca mógł wziąć krótki klip, wybrać język i otrzymać przetłumaczoną wersję. Pierwsza implementacja używała Kokoro i obsługiwała osiem języków.

Niedawno przerzuciłem główny silnik mowy na Google Cloud Text-to-Speech z Chirp 3 HD. Cel wyglądał prosto: lepsze głosy i więcej języków. Katto teraz oferuje 19 języków dubbingu i 12 wyselekcjonowanych głosów w edytorze.

Spodziewałem się, że migracja to głównie zamiana API.

Nie była.

Wygenerowanie naturalnego zdania jest łatwe. Sprawienie, by to zdanie zaczęło się i skończyło dokładnie w miejscu pozostawionym przez innego mówcę — to właściwy problem dubbingu.

Jeśli oryginalny mówca wypowiada coś w 2,4 sekundy, a tłumaczenie zajmuje 3,2 sekundy, dobry model TTS nie uratuje klipu. Głos wchodzi w następne zdanie, napisy się rozjeżdżają albo mowę trzeba przyspieszyć, aż brzmi pospiesznie.

Okazało się, że żądanie TTS to najmniejsza część systemu.

Pipeline, który powstał

zbuforowane timingowanie słów
        |
        v
segmenty fraz z ustalonymi slotami czasowymi
        |
        v
tłumaczenie uwzględniające długość
        |
        v
Google Chirp 3 HD, jedna fraza na raz
        |
        v
ograniczone dopasowanie audio przez FFmpeg
        |
        +----> przetłumaczone napisy z tych samych segmentów
        |
        v
finalne remuksowanie MP4

Każdy etap istnieje, bo prostsza wersja zawodziła w inny sposób.

Zachowanie oryginalnego timingu jako danych

Katto już ma znaczniki czasowe słów z pipeline'u transkrypcji. Nie wysyłam całego transkryptu do tłumaczenia i TTS jako jednego bloku. Grupuję słowa w frazy.

Fraza kończy się na interpunkcji zdaniowej, po pauzie dłuższej niż 0,6 sekundy lub gdy przekroczyłaby sześć sekund. Każdy segment zachowuje swój oryginalny start i koniec. Te liczby stają się kontraktem dla wszystkich późniejszych etapów.

Synteza pełnego transkryptu może brzmieć płynniej, ale usuwa kotwice potrzebne do umieszczenia mowy z powrotem na osi czasu wideo. Synteza na poziomie fraz zachowuje wystarczający kontekst dla naturalnego głosu, jednocześnie utrzymując użyteczne granice czasowe.

Tłumaczenie pod kątem czasu trwania mowy, nie tylko znaczenia

Poprawne tłumaczenie pisemne może być złym tłumaczeniem dubbingowym. Niektóre języki potrzebują więcej sylab, by wyrazić tę samą myśl. Dosłowna wersja może zachować każdy niuans i nadal być bezużyteczna, bo nie mieści się w swoim slocie.

Dla każdej grupy fraz proszę Claude Haiku o naturalne tłumaczenie mówione, które preferuje krótsze sformułowania i mniej sylab. Odpowiedź zachowuje każdy indeks segmentu źródłowego.

Prompt jest częścią systemu audio. Jego zadaniem nie jest tylko dokładność językowa. Redukuje też rozciąganie czasowe potrzebne później.

To pozostaje heurystyką. LLM nie może zagwarantować czasu trwania, bo wybrany głos też zmienia tempo. Warstwa audio nadal mierzy wygenerowany WAV. Pamięć procesu, indeksowana językiem docelowym i segmentami źródłowymi, pozwala ponownym renderom użyć tłumaczenia, dopóki worker działa.

Synteza jednej frazy na raz

Każda przetłumaczona fraza trafia do Google Cloud Text-to-Speech REST API jako audio LINEAR16 24 kHz. Nazwy głosów mają format locale-Chirp3-HD-speaker udokumentowany przez Google.

Google wspiera więcej lokalizacji Chirp 3 HD, niż Katto obecnie eksponuje. Celowo ograniczyłem produkt do 19 języków przepuszczonych przez pełną ścieżkę: UI, mapowanie lokalizacji, fonty, napisy i zachowanie fallback. API deklarujące język nie oznacza, że otaczający produkt wspiera go poprawnie.

Wpasowanie mowy w slot bez jej zniszczenia

Po syntezie porównuję wygenerowany czas trwania z oryginalnym slotem.

target_duration = segment["end"] - segment["start"]
ratio = generated_duration / target_duration

Jeśli mowa jest nieco za długa, filtr atempo FFmpeg przyspiesza ją, zachowując wysokość dźwięku. Ograniczam przyspieszenie do 1,3x.

Ten limit ma znaczenie. Wcześniejszy limit 1,6x sprawiał, że więcej fraz się mieściło, ale niektóre głosy brzmiały nienaturalnie pospiesznie. Idealne dopasowanie nie jest użyteczne, jeśli rezultat jest nieprzyjemny w słuchaniu.

Każda dostosowana fraza jest umieszczana na swoim oryginalnym przesunięciu w głównej ścieżce. Krótkie frazy pozostawiają naturalną pauzę. Dłuższe frazy dostają ograniczoną korektę. To nie rozwiązuje każdego patologicznego tłumaczenia. Wymusza bardziej użyteczną regułę: zachować zrozumiałość przed gonią za matematycznie idealnym timingiem.

Wspólny zegar dla mowy i napisów

Odpowiedź syntezy daje mi audio, nie wiarygodne znaczniki czasowe słów dla nowo wypowiedzianego tekstu. Wymyślenie timingu na poziomie słów sprawiłoby, że napisy wyglądałyby precyzyjnie, będąc błędnymi.

Dubbingowane klipy używają więc napisów na poziomie fraz wygenerowanych z tych samych przetłumaczonych segmentów użytych dla mowy. Ich czasy startu i końca już pasują do umieszczenia audio.

Renderer wybiera też fonty pokrywające docelowy skrypt. Fonty łacińskie nie wystarczą dla japońskiego, chińskiego, hindi czy arabskiego. Tytuły intro i hooki AI podążają tą samą ścieżką lokalizacji, więc ekran nie mówi jednym językiem i nie wyświetla innego.

Zwykłe problemy produkcyjne też miały znaczenie

Nie każdy wyselekcjonowany speaker działał w każdej lokalizacji, którą testowałem. Jeśli wybrany głos jest niedostępny, Katto ponawia próbę raz ze znanym domyślnym dla wybranej płci. Podgląd na żywo w edytorze wywołuje ten sam silnik Google. Próbka z innego modelu pozwoliłaby użytkownikowi wybrać głos, którego nigdy nie otrzyma.

Produkcyjny klucz API jest ograniczony do adresu IPv4 VPS, ale VPS preferował IPv6 przy łączeniu się z Google. Poprawne żądania były odrzucane, dopóki wywołanie TTS nie zostało wymuszone przez IPv4. API, klucz i kod były poprawne. Ścieżka sieciowa nie była.

Dubbing tworzy osobny wariant wideo. Jeśli tłumaczenie, synteza, renderowanie napisów lub remuksowanie zawiedzie, oryginalny klip pozostaje nienaruszony. Dla pierwotnych ośmiu języków Kokoro pozostaje dostępne, gdy ścieżka Google jest wyłączona lub nieskonfigurowana.

Co się zmieniło, a co nie

Widocznym rezultatem była ekspansja z 8 do 19 języków dubbingu, plus wybieralne głosy i podglądy na żywo.

Głębszą poprawą była architektura. Tłumaczenie, mowa, napisy, nakładki i renderowanie wideo teraz dzielą jedną jednostkę czasową: segment frazy.

System nie klonuje oryginalnego mówcy, nie wykonuje synchronizacji warg ani nie wymyśla wygenerowanych znaczników czasowych słów. Bardzo długie tłumaczenia nadal mogą przekroczyć swój idealny slot. Te limity są lepsze niż deklarowanie precyzji, której pipeline nie może dostarczyć.

Myślałem, że wymieniam silnik mowy. Skończyłem na zacieśnieniu kontraktu między niemal każdym etapem pipeline'u mediów.

Wywołanie API było prostą częścią. Sprawienie, by rezultat należał do oryginalnej osi czasu, było pracą.

Katto zamienia długie wideo w krótkie pionowe klipy i może teraz dubbingować te klipy na 19 języków. Jeśli budujesz wielojęzyczne wideo, byłbym zainteresowany usłyszeć, jak radzisz sobie z timingiem bez sprawiania, że głos brzmi pospiesznie.

Odniesienia

Gotowy, aby zamienić swoje filmy w wiralowe klipy?

Katto automatycznie wycina klipy, dodaje napisy i przekadrowuje Twoje długie filmy w treści krótkie.

Wypróbuj Katto za darmo
Wymieniłem silnik TTS. Wywołanie API było najprostszą częścią | Katto