Диктовка без «ну» и «вот»: Whisper на своём компьютере и маленький посредник к LLM. Claude.. Claude. Handy.. Claude. Handy. llm.. Claude. Handy. llm. Natural Language Processing.. Claude. Handy. llm. Natural Language Processing. Open source.. Claude. Handy. llm. Natural Language Processing. Open source. python.. Claude. Handy. llm. Natural Language Processing. Open source. python. whisper.. Claude. Handy. llm. Natural Language Processing. Open source. python. whisper. Блог компании Высшая школа бизнеса НИУ ВШЭ.. Claude. Handy. llm. Natural Language Processing. Open source. python. whisper. Блог компании Высшая школа бизнеса НИУ ВШЭ. голосовой ввод.. Claude. Handy. llm. Natural Language Processing. Open source. python. whisper. Блог компании Высшая школа бизнеса НИУ ВШЭ. голосовой ввод. Голосовые интерфейсы.. Claude. Handy. llm. Natural Language Processing. Open source. python. whisper. Блог компании Высшая школа бизнеса НИУ ВШЭ. голосовой ввод. Голосовые интерфейсы. диктовка.. Claude. Handy. llm. Natural Language Processing. Open source. python. whisper. Блог компании Высшая школа бизнеса НИУ ВШЭ. голосовой ввод. Голосовые интерфейсы. диктовка. искусственный интеллект.

Я пишу книги, и кроме самих книг за день набирается много другого текста: сообщения, письма, задания нейросетям. Говорить быстрее, чем печатать, поэтому большую часть этого я диктую. Только живая речь, записанная слово в слово, читается плохо. Вот фраза, которую 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}, а остальное делает посредник:

  1. Промпт и словарь лежат в двух текстовых файлах и перечитываются при каждой диктовке. Поправил строчку, продиктовал снова — без перезапуска и без походов в настройки. За первые дни я правил промпт десятки раз, так что это главное удобство.

  2. Одно тёплое соединение. Handy создаёт новый HTTP-клиент на каждый запрос, то есть каждый раз заново проходит TCP и TLS. Посредник держит одно соединение и освежает его, если долго не было диктовок.

  3. Ключ API хранится не в настройках Handy, а в отдельном файле или переменной окружения.

  4. Тайм-аут 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 — с локальной моделью с компьютера вообще ничего не уходит. Но как небольшие локальные модели держат такие правила, я не проверял. Если пробовали, расскажите в комментариях, какая справляется.

Больше всего мне это помогает в общении в телеге и других мессенджерах. Просто бесценная экономия времени, поэтому решил поделиться ей публично. Вдруг ещё кому пригодится.

Автор: viacheslavnu

Источник