Сколько раз я сказал «короче»: русский голосовой ввод для Mac, который работает без интернета

После Качалки, «Чисто» и Кружка — программа для Mac. Я много пишу голосом и хотел одну клавишу: нажал, сказал, и текст появился там, где курсор, в любой программе.
Самый известный вариант — Wispr Flow: $15 в месяц или $12 при оплате за год, бесплатно 2 000 слов в неделю. В их FAQ сказано прямо: «Transcription always happens in the cloud». Есть и бесплатные без облака. Handy — открытый код, много языков. По-русски — Говорун: тоже бесплатный и открытый, на той же модели, что у меня, и умеет больше — Android, Windows, синхронизация.
Мне хотелось проще: только Mac, одна клавиша, без аккаунтов и без облачных функций даже по желанию. Писать с нуля не стал — взял Handy и сделал из него программу для одного языка. Так появился Tolkovo («Толково»). Бесплатно, без регистрации, код открыт. Интернет нужен один раз — скачать модель.

Что умеет и что здесь моё
Запись, распознавание и вставка текста — это Handy, автор CJ Pais. Приложение на Tauri: ядро на Rust, интерфейс на React в системном WebView, не Electron. Handy — это около 29 тысяч строк на Rust. Моих поверх — примерно 2 200 строк на Rust и 3 100 на TypeScript и CSS:
⌥ Space. Коротко нажал — запись пошла, нажал ещё раз — остановилась. Зажал — пишет, пока держишь. Сочетание меняется в настройках.
Одна модель, без выбора. GigaAM v3 от SberDevices — открытая русская модель, сама ставит знаки препинания. В каталоге Handy она тоже есть, среди 69 моделей. Я выбрал её за пользователя: качается сама при первом запуске, списков и мегабайт человек не видит.
Пилюля вместо стандартного окна записи Handy. Висит поверх всех окон, перетаскивается, клик — старт или стоп.
Строка меню вместо Dock, запуск вместе с Маком.
Словарь англицизмов: 191 замена из коробки плюс свои.
Статистика: слова, диктовки, слова-паразиты, частые слова, «Итоги месяца» картинкой 1080×1920. «Сэкономленное время» — оценка по формуле: слова ÷ 40 в минуту (печать) минус слова ÷ 130 в минуту (речь). Скорость речи программа не измеряет.
Интерфейс полностью на русском.


Цифры
MacBook Pro M2, 8 ГБ памяти, версия 0.2.0, данные из лога программы за неделю обычной работы:
DMG — 20,7 МБ, программа после установки — 42 МБ.
Модель GigaAM v3 E2E-RNN-T — 223 млн параметров, файл на 274 МБ.
Модель грузится за 0,4–0,5 с. Через 5 минут без диктовки программа её выгружает.
Память: 360 МБ с загруженной моделью, 90 МБ без неё. Плюс процессы системного WebView для окон.
Микрофон открывается за 60–100 мс.
Распознавание: фраза на 5 секунд — 0,15 с, полторы минуты речи — 1,1 с, почти три минуты — 2,7 с. Первая диктовка после простоя дольше, потому что грузится модель: 5,6 секунды речи — 2,1 с.
Вставка готового текста — около 0,23 с.
Грабли №1: модель пишет английские слова по-русски
GigaAM обучена на русской речи и пишет то, что слышит: «гитхаб», «телега», «пул реквест». Перед вставкой текст проходит через словарь: «гитхаб» → GitHub.
Простая замена ломается на падежах: «в гитхабе», «в телегу». Словарь научился проглатывать русское окончание после последнего слова: «в гитхабе» → «в GitHub». Внутри более длинных слов он ничего не трогает.
Из стартового набора я убрал слова, которые одновременно и обычные русские, и названия продуктов: «курсор», «бан», «лама». Иначе программа портила бы нормальную речь.
Грабли №2: первое нажатие после запуска не работало
Сразу после запуска первое короткое нажатие ⌥ Space включало запись и тут же её выключало, без единого сэмпла. Дальше всё работало.
Нажатия обрабатываются по очереди в одном потоке. Первый старт тяжёлый: загрузить модель и открыть микрофон — около 0,4 с. Пока он шёл, событие «клавишу отпустили» ждало в очереди. Время нажатия засекалось, когда событие доставали из очереди, а не когда оно случилось. Нажатие на 250 мс превращалось в 430 мс. Это больше порога в 300 мс, значит «зажал», и отпускание останавливало запись.
Исправление — засекать время там, где событие произошло:
// было: время бралось в потоке-обработчике
Command::Input(input) => state.on_input(input, Instant::now())
// стало: время приходит вместе с событием
Command::Input { input, at } => state.on_input(input, at)
Повторный старт занимает около 75 мс, поэтому ошибка проявлялась только на первом нажатии.
Грабли №3: пилюля выкидывала на другой рабочий стол
Стоило перетащить пилюлю, сидя в браузере, — и macOS перебрасывала меня на другой рабочий стол. Клик делал Tolkovo активной программой, а macOS переключалась туда, где лежит её окно настроек. Диктовать после этого было некуда.
Для таких окон в macOS есть «неактивирующая» панель. Но Tauri сначала создаёт обычное окно, плагин превращает его в панель потом, а AppKit учитывает этот флаг только при создании окна. Помог закрытый метод самого окна:
let selector = sel!(_setPreventsActivation:);
let responds: Bool = msg_send![&*ns_window, respondsToSelector: selector];
if responds.as_bool() {
let _: () = msg_send![&*ns_window, _setPreventsActivation: Bool::YES];
}
Метод вызывается, только если окно его понимает, — на случай, если Apple его уберёт. Перетаскивание я написал вручную: системное тоже активировало программу.
Грабли №4: пять вариантов пилюли
На macOS 26 пилюля стоит на настоящем стекле Apple — системный NSGlassEffectView. Класс ищется во время работы: на macOS 14–25 его нет, и стекло рисуется через CSS.
Внутри стекла были жидкость с волнами и пузырьками, «лава-лампа», включение как у старого телевизора. Всё это отвлекало. Осталось самое простое: во время записи капсула за 0,45 с наливается бордовым, а внутри тонкие белые полоски расходятся в такт голосу. Отпустил клавишу — бордовый уходит вниз, пока распознаётся текст. Появляется и пропадает пилюля за 0,18 с.
Что хранится
Звук и текст живут в памяти, пока идёт распознавание, на диск не пишутся. Handy по умолчанию сохраняет историю — WAV и текст каждой диктовки. Я заметил это поздно: до версии 0.2.1 в Tolkovo хранились пять последних записей. В 0.2.1 история выключена, а старые записи программа удаляет сама при запуске.
Статистика — счётчики и до 300 самых частых слов за день, без самих диктовок. Её можно выключить и сбросить.
В сеть программа ходит один раз — за моделью. После загрузки файл сверяется по SHA-256: библиотека, которая качает с Hugging Face, сама этого не делает.
В логах текста нет. Handy убирал его только из релизных сборок, теперь его нет ни в одной.
Облачная обработка текста из Handy выключена. Флаг
--toggle-post-processраньше всё равно мог отправить текст провайдеру — закрыл.Вставка. Текст кладётся в буфер, и программа «нажимает» ⌘V. Для этого macOS просит разрешение «Универсальный доступ». Содержимое других программ Tolkovo не читает — для статистики берёт только название активной программы.
Каждый релиз собирается на серверах GitHub из репозитория, происхождение сборки можно проверить:
gh attestation verify ~/Downloads/Tolkovo-*.dmg --repo kozliq/Tolkovo

Чем отличается
Данные на 26.10.2026, с сайтов и GitHub самих программ.
Tolkovo | Говорун | Handy | Wispr Flow | |
|---|---|---|---|---|
Цена | бесплатно | бесплатно; улучшение текста через их сервис — платное, сейчас промо | бесплатно |
|
Где распознаётся | на Маке | на устройстве | на компьютере | в облаке |
Код | открыт, MIT | открыт, MIT | открыт, MIT | закрыт |
Платформы | Mac (Apple Silicon) | Android, Windows, Mac | Mac, Windows, Linux | Mac, Windows, iPhone, Android |
Аккаунт | нет | по желанию, для синхронизации | нет | есть вход и синхронизация |
Скачать | 21 МБ + 274 МБ модель | 283 МБ, модель внутри | — | — |
Нужен английский или Linux — берите Handy. Нужен телефон или Windows — Говорун. Tolkovo — если у вас Mac и хочется одну клавишу без настроек и аккаунтов.
Чего Tolkovo не умеет
Только Mac на Apple Silicon и macOS 14 или новее. Настоящее стекло — с macOS 26.
Программа не подписана платным сертификатом Apple. После установки нужно один раз выполнить
xattr -drcom.apple.quarantine /Applications/Tolkovo.app.Английские слова, которых нет в словаре, иногда пишутся по-русски.
Текст появляется после того, как отпустил клавишу. Во время речи слов не видно.
⌥ Space по умолчанию занят и у ChatGPT для Mac. Если пользуетесь им — поменяйте сочетание в одной из программ.
Скачать: github.com/kozliq/Tolkovo/releases, исходники — github.com/kozliq/Tolkovo.
Если Tolkovo пишет какое-то слово криво — напишите в комментариях, добавлю в словарь.
Будет ещё.
Раньше в серии: Качалка — видео без водяных знаков, «Чисто» — без рекламы, Кружок — кружок из любого видео.
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.