Диктовка без «ну» и «вот»: Whisper на своём компьютере и маленький посредник к LLM

Я пишу книги, и кроме самих книг за день набирается много другого текста: сообщения, письма, задания нейросетям. Говорить быстрее, чем печатать, поэтому большую часть этого я диктую. Только живая речь, записанная слово в слово, читается плохо. Вот фраза, которую Whisper распознал без единой ошибки:
Ну вот, короче, я, это самое, хотел сказать, что, ну, завтра... завтра созвон переносится, ну, на три часа, не, на четыре.
А отправить я хотел вот это:
Я хотел сказать, что завтра созвон переносится на четыре.
Второй вариант — настоящий ответ программы, о которой эта статья. От момента, когда я отпустил клавишу, до вставки текста прошло меньше двух секунд. Расскажу, как это устроено и на какие грабли я наступил, а в конце дам ссылку на код: он открытый и бесплатный.
Распознавание: Handy и Whisper
Для самой диктовки я взял Handy, открытую программу (MIT) на Tauri. Держишь горячую клавишу, говоришь, отпускаешь, и текст появляется там, где стоит курсор, в любом окне. Речь распознаёт Whisper прямо на компьютере, звук никуда не уходит.
Модель — Whisper Large v3 Turbo. На RTX 4080 Super восемь секунд речи распознаются за 0,17 с, сорок две — за 0,45 с. Без видеокарты будет заметно медленнее.
Для русского есть сборка klava-nevinovata: в ней готовая подсказка Whisper для русского языка и защита от зацикливания на тишине — это когда модель вместо паузы пишет «и я хочу и я хочу и я хочу…».
Один совет сразу: в настройках поставьте «Выгрузить модель» → «Никогда». Иначе после простоя первая диктовка ждёт, пока модель снова загрузится в память.
Почему не хватит регулярки
Первая мысль — вычистить «ну» и «вот» заменой по списку. Не выйдет:
«Вот этот курс» → «этот курс», а «Вот, отлично» → «Отлично». Слово одно, но во втором случае надо ещё убрать запятую и поднять заглавную. А иногда «вот» нужно и выкидывать его нельзя.
«На три часа, не, на четыре» → «на четыре». Самоисправление правилом не опишешь.
С повторами, оборванными словами, «знаешь» и «слушай» посреди фразы та же история.
Тут нужна модель, которая понимает смысл. У Handy для этого есть постобработка: распознанный текст уходит в любой API, совместимый с OpenAI, а в окно вставляется ответ модели. Я использую Claude Sonnet 5.5, чистка занимает от полутора до трёх секунд.
Зачем посредник
Можно прописать в Handy адрес API, ключ и промпт, и всё заработает. Я так и начинал, но быстро сделал прослойку и назвал её Чистовик. Это один файл на Python, только стандартная библиотека. Он слушает localhost:8765, и Handy видит в нём обычный API. В настройках Handy вместо промпта остаётся одна строка ${output}, а остальное делает посредник:
Промпт и словарь лежат в двух текстовых файлах и перечитываются при каждой диктовке. Поправил строчку, продиктовал снова — без перезапуска и без походов в настройки. За первые дни я правил промпт десятки раз, так что это главное удобство.
Одно тёплое соединение. Handy создаёт новый HTTP-клиент на каждый запрос, то есть каждый раз заново проходит TCP и TLS. Посредник держит одно соединение и освежает его, если долго не было диктовок.
Ключ API хранится не в настройках Handy, а в отдельном файле или переменной окружения.
Тайм-аут 10 секунд. Если API молчит, Handy вставит сырой текст, а не зависнет.
Главная подмена выглядит так:
def rewrite(payload):
msgs = payload.get("messages") or []
if not msgs or not isinstance(msgs[-1].get("content"), str):
return False
tmpl = here(CFG["prompt_file"]).read_text(encoding="utf-8-sig")
text = msgs[-1]["content"].strip()
msgs[-1]["content"] = tmpl.replace("${dictionary}", dictionary() or "(empty)").replace("${output}", text)
return TrueСловарь, который понимает контекст
Whisper путает редкие слова, имена и сленг. У меня это, например, «ИИшный»: Whisper слышит его как «яичный». В Handy есть встроенный словарь, но, судя по описанию в самой программе, нечёткая коррекция там работает только для слов из латиницы и цифр, так что русским словам он не помогает.
К тому же простая замена здесь вредна: «яичный» бывает и настоящим... наверное...у кого-то и такое слово в переписке встречается. Модели же условие можно объяснить словами. Строка словаря выглядит так: слева как писать, справа как слышит распознавание, в скобках — когда заменять.
ИИшный, ИИшные, ИИшно ← иишный, яичный (replace «яичный» only when the text is not about eggs or food)
Claude (always written Claude, in any grammatical case) ← Клод, Клоду, Клода, Clod, ClotПояснения в репозитории на английском, но модель одинаково понимает их и по-русски. Проверка:
Посоветуй, ну, рецепт яичного салата, вот, чтобы быстро.
→ Посоветуй рецепт яичного салата, чтобы быстро.
Слушай, текст какой-то яичный получился, ну, прям чувствуется, что нейросеть писала.
→ Слушай, текст какой-то ИИшный получился, прям чувствуется, что нейросеть писала.
Салат остался салатом.
Грабли промпта
Модель отвечает на диктовку
Продиктовал «напиши письмо начальнику, что я завтра не приду» — и получил письмо. Модель приняла диктовку за просьбу к себе. Помогли две вещи: расшифровка стоит внутри тега <dictation>, а в правилах прямо сказано, что вопросы и просьбы из текста не выполняются, это просто текст для чистки.
Напиши, пожалуйста, ну, письмо начальнику, что я, это самое, завтра не приду, заболел.
→ Напиши, пожалуйста, письмо начальнику, что я завтра не приду, заболел.
Модель «облагораживает» речь
Модели любят заменять разговорные слова «правильными»: «прикольно» превращается в «интересно», «пофигу» — в «неважно», «чё» — в «что». Сообщения начинают звучать чужим голосом. Правило: разговорное остаётся разговорным, слова человека не заменять. Примеры прямо в правиле работают лучше общих слов.
Ну это прикольно, мне вообще пофигу, чё там они скажут.
→ Это прикольно, мне вообще пофигу, чё там они скажут.
Модель комментирует
Когда я диктовал о самих ошибках распознавания («мне вместо Клода написало какой-то Клот, Силод»), модель дописывала пояснение: здесь, мол, человек говорит о распознавании. А ответ ведь вставляется прямо в окно, где я пишу. Помогло последнее правило в промпте: ответ вставляется туда, где человек печатает, поэтому в нём должен быть только готовый текст. И отдельное правило: если человек приводит, как ошиблось распознавание, эти примеры оставить как есть.
«Вот» бывает нужным
Если «вот» стоит в списке паразитов, модель вычищает его целиком, а иногда оно держит смысл. Помогли примеры в самом правиле:
Вот, отлично, вот этот курс, короче, и возьмём.
→ Отлично, этот курс и возьмём.
Личные правила
Моё короткое «чё» Whisper слышит как «чёрт», хотя этого слова я не говорю. Такое правило живёт только в моём промпте, в публичной версии его нет: у каждого свои особенности, и их удобно дописать самому.
Грабли интеграции
Ошибку постобработки не видно. При любой ошибке Handy молча вставляет сырой текст. Несколько дней мои диктовки уходили без чистки, а я думал, что модель просто плохо справляется. Поэтому посредник пишет лог на каждую диктовку: время, статус и длительность, без самого текста. Проверять тоже лучше через саму программу, а не отдельным запросом из консоли.
localhost может сначала уйти на ::1. Windows часто отдаёт для localhost адрес IPv6, поэтому посредник слушает и 127.0.0.1, и ::1.
Цифры
8 с речи | 42 с речи | |
|---|---|---|
Распознавание (Whisper Large v3 Turbo, RTX 4080 Super) | 0,17 с | 0,45 с |
Чистка (Claude Sonnet 5.5) | ~1,7 с | ~3 с |
Всего, от клавиши до вставки | ~2 с | ~3,5 с |
Запрос — около 1100 токенов, почти всё это правила и словарь. Ответ — по длине текста.
Что в итоге
Код открытый (MIT): github.com/Tataut/chistovik. На Windows ставится одним скриптом PowerShell, дальше нужно заполнить пару полей в настройках Handy, пошагово всё описано в README. Сам посредник кроссплатформенный, Handy тоже есть для macOS и Linux.
Проверял я только с Claude Sonnet 5.5. Подойдёт любой API, совместимый с OpenAI: OpenAI, OpenRouter, локальные модели через Ollama или LM Studio — с локальной моделью с компьютера вообще ничего не уходит. Но как небольшие локальные модели держат такие правила, я не проверял. Если пробовали, расскажите в комментариях, какая справляется.
Больше всего мне это помогает в общении в телеге и других мессенджерах. Просто бесценная экономия времени, поэтому решил поделиться ей публично. Вдруг ещё кому пригодится.
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.