Ratatoskr: głos do schowka, bez chmury

Lokalne narzędzie speech-to-text: naciskasz skrót, mówisz i wklejasz transkrypcję. Bez chmury, bez kont.

Każde narzędzie do dyktowania, które testowałem, chciało rejestracji, otwarcia przeglądarki albo wysłania mojego audio na czyjś serwer. Ja chciałem tylko nacisnąć klawisz, powiedzieć tekst i wkleić wynik. Zbudowałem więc narzędzie, które robi dokładnie to.

Pomysł

Ratatoskr siedzi w trayu systemowym i robi jedną rzecz: naciskasz skrót, mówisz, dostajesz tekst w schowku. Wszystko działa lokalnie przez faster-whisper, czyli ten sam model Whisper udostępniony przez OpenAI, ale zoptymalizowany przez CTranslate2. Audio nigdy nie opuszcza twojego komputera. Jedyny request sieciowy to jednorazowe pobranie modelu z Hugging Face przy pierwszym uruchomieniu.

To ostatnie było dla mnie ważne. Dyktuję notatki, szkice wiadomości i półuformowane myśli, a żadna z tych rzeczy nie powinna lądować na cudzym serwerze.

Jak to działa

Naciskasz Ctrl+Alt+R (albo skrót, który sobie ustawisz). W prawym dolnym rogu pojawia się mały overlay pokazujący, że trwa nagrywanie, z timerem oraz przyciskami pauzy i stopu.

Overlay nagrywania Ratatoskra: minimalistyczny ciemny pasek ze statusem nagrywania, upływającym czasem oraz przyciskami pauzy i stopu.

Kiedy zatrzymasz nagranie, audio trafia prosto do Whispera. Kilka sekund później transkrypcja ląduje w schowku. Wklejasz ją tam, gdzie chcesz: do maila, Slacka, edytora albo terminala. Jeśli chcesz dodatkowo zapisać plik .txt, jest do tego przełącznik.

To cały workflow. Nie ma nic do zarządzania i żadnego UI, przez które trzeba się przeklikiwać; aplikacja pozostaje niewidoczna, dopóki jej nie potrzebujesz.

Pod maską

Stack jest celowo mały:

Model ładuje się w tle podczas startu aplikacji, żeby pierwsza transkrypcja nie przycinała. Audio jest trzymane w pamięci jako tablica numpy float32 i przekazywane bezpośrednio do Whispera, bez plików tymczasowych w typowej ścieżce działania.

Na dysk trafia jeden plik: awaryjny WAV zapisywany tuż przed startem transkrypcji. Jeśli aplikacja wysypie się w trakcie, kolejne uruchomienie podnosi ten plik i kończy zadanie. Po sukcesie albo błędzie plik jest usuwany.

Ustawienia

Kliknięcie prawym przyciskiem ikony w trayu otwiera ustawienia. Możesz zmienić rozmiar modelu Whisper (od tiny dla szybkości do large-v3 dla dokładności), wybrać język źródłowy albo zostawić autodetekcję, przemapować skrót oraz włączyć/wyłączyć zapis do schowka i pliku.

Domyślny jest model small. To dobry kompromis: wystarczająco szybki do użycia na bieżąco i wystarczająco dokładny dla większości języków. Jeśli masz GPU, większe modele też stają się praktyczne.

Vibe-codowane, potem audytowane

Tak jak Mamrot, Ratatoskr zaczął się jako projekt vibe-codingowy: opisałem, czego chcę, i pozwoliłem Claude’owi zbudować pierwszą wersję. Przed publikacją poprosiłem Claude’a i GPT o wzajemny audyt kodu pod kątem bezpieczeństwa wątków, zgodności licencji, prywatności (czy audio nie zostaje na dysku po błędzie), struktury TOML i bugów renderowania fontów. Dwa modele wyłapujące nawzajem swoje dziury znalazły więcej problemów niż każde z nich osobno. Vibe-coding szybko prowadzi do działającego prototypu; cross-audit robi z niego coś, co naprawdę można wypuścić.

Czego się nauczyłem

RegisterHotKey zamiast bibliotek keyboard. Zacząłem od pythonowego pakietu keyboard do globalnych skrótów. Działał dobrze, aż w końcu przestał. Niektóre antywirusy flagują niskopoziomowe hooki klawiatury, a w części konfiguracji biblioteka wymagała uprawnień administratora. Przejście na natywne Win32 API RegisterHotKey naprawiło wszystko. To kilka linijek ctypes więcej, ale po prostu działa.

Trzymaj audio w pamięci. Wczesne wersje zapisywały WAV na dysk, przekazywały ścieżkę do Whispera, a potem usuwały plik. Wycięcie rundy przez dysk i przekazywanie tablicy numpy bezpośrednio sprawiło, że cały flow stał się zauważalnie szybszy, a do sprzątania został jeden plik mniej.

Rozmiary fontów w stylesheetach Qt: używaj pt, nie px. Jeśli ustawisz font-size: 13px w stylesheetcie Qt, część widgetów próbuje wewnętrznie odczytać rozmiar w punktach, dostaje -1 i Qt wypisuje ostrzeżenie. Przejście na jednostki pt naprawiło to bezszelestnie.

Wypróbuj

git clone https://github.com/konradozog/Ratatoskr.git
cd Ratatoskr
python -m venv .venv
.venv\Scripts\activate
pip install .
ratatoskr

Windows 10/11, Python 3.10+. Tylko tyle potrzeba.

GitHub →