
Проблема
По мере погружения в ИИ и вайб‑кодинг, я столкнулся с одним неудобным моментом — отсутствием возможности диктовать на русском языке в некоторых программах. И если OpenAI в своем приложении позаботились об этом, то в Anthropic такой возможности на тот момент просто не оказалось. А мне уже так понравилось, откинувшись на спинку кресла с чашкой чая, надиктовывать промпты без клавиатуры.
Но я быстро нашел выход, хоть и костыльный — просто диктовать свой текст в окошке GPT, потом копировать его и вставлять в Claude. Вроде несложно, но и удобным этот метод я бы не назвал. И я задумался, как этот процесс оптимизировать.
И какая же идея могла прийти в голову в 3 часа ночи человеку, который полжизни занимается программированием? Ну конечно же — разработать свое приложение.
Посоветовавшись с Claude и GPT, я набросал небольшой план и приступил к разработке.
Поскольку я работаю на macOS, то для начала не стал заморачиваться с мультиплатформенностью и решил делать все на Swift.
Первая версия приложения
Изначально идея была просто распознавать голос и выводить его в плавающем окне поверх всех окон, а потом, кликнув по нему мышкой, копировать текст в буфер обмена.
Расшифровка происходила через сервер OpenAI. Этот функционал я реализовал достаточно быстро. Но, как оказалось, это тоже не совсем удобно. Постоянно искать окно на экране, кликать по нему…
Тогда я решил пойти дальше и добавить хоткеи, по которым будет запускаться запись голоса, а после остановки расшифрованный текст будет вставляться в то место, где сейчас находится курсор.
По умолчанию я сделал активацию микрофона на правый Option. Правда, не был уверен, что это лучший вариант, поэтому на всякий случай добавил в настройки возможность смены горячей клавиши.

И знаете, это оказалось действительно удобно. Получился аналог диктовки в GPT, только теперь это можно было использовать вообще в любом месте, где можно вводить текст, и в любой программе.
Автоматический перевод
Но диктовка на русском — это хорошо. А что делать, если нужно ввести промпт на английском?
Тогда я решил добавить автоматический перевод диктовки, который можно включить прямо из окна приложения. Перевод также осуществляется через OpenAI.
Казалось, теперь все работает отлично, если бы не два «но»…
Во‑первых, периодически текст распознавался вообще без знаков препинания. Во‑вторых, некоторые термины из программирования распознавались неправильно, и в итоге получалась какая‑то ерунда.
Первую проблему удалось решить путем добавления вводного промпта с примером того, как именно нужно расшифровывать текст.
А вот со второй пришлось немного помучаться.
Словари терминов
Сначала Claude предложил создать глоссарии терминов и добавлять их в начало промпта. В принципе, это работало, но, во‑первых, там было ограничение на 800 символов, и не все термины помещались, а во‑вторых, иногда из‑за этого расшифровка происходила не на том языке, на котором я говорил.
И тут я вспомнил, что всё‑таки «я же программист», и до эпохи ИИ подобные задачи как‑то решались обычным поиском и заменой в тексте.
Тогда было принято решение создать словари алиасов в таком формате:
Т. е. ищем по тексту aliases, и если находим, то заменяем их на значение из canonical.
Составить такие варианты мне помог Claude, и в прицнипе справился с этим неплохо. Только некоторые моменты пришлось руками поправить.
Ну и я не удержался, чтобы не попросить Claude накидать еще словарей под разные профили — на случай, если я решу поделиться приложением с коллегами.

И о чудо — «пул реквест» начал превращаться в «pull request». Тут уже стало вырисовываться вполне годное приложение.
Неожиданные проблемы
В силу своей многолетней профдеформации я начал продумывать возможные сценарии использования и настройки, которые имело бы смысл добавить, если делать приложение не только для себя, но и для других пользователей.
Я добавил:
-
звуковые уведомления при активации микрофона;
-
настройку громкости;
-
более аккуратный интерфейс;
-
мультиязычность;
-
всякие удобные кнопки, настройки и так далее
И тут внезапно заметил, что при молчании в микрофон иногда получаю расшифровки вроде «редактор субтитров».
Погуглив, я узнал, что это довольно распространенная проблема. Видимо, модель обучалась в том числе на субтитрах с YouTube. Причем подобных фраз оказалось довольно много.
Поэтому пришлось создать еще один словарь — уже со словами‑исключениями, которые автоматически вычищаются из результата распознавания. Это полностью решило проблему.
Локальные модели
Следующим шагом захотелось прикрутить локальные модели на случай, если не будет доступа к интернету, а расшифровка все‑таки понадобится.
Тогда я организовал интеграцию с локальными моделями openai_whisper.
Конечно, работают они не так хорошо, как распознавание на серверах OpenAI, но как запасной вариант — вполне достойно. А главное, в таком режиме мне вообще не нужно платить за токены. Хотя даже при использовании OpenAI API у меня выходит максимум в день около 11 центов в день, и это при активном использовании.
Журнал записей
Во время тестирования я столкнулся еще с одной проблемой. Если из‑за какого‑то сбоя расшифровка не проходила успешно, то все, что я надиктовал, просто исчезало бесследно.
И это было очень неприятно.
Решением стало хранение журнала голосовых записей. По умолчанию я сохраняю три последние записи.
То есть даже если расшифровка не удалась или локальная модель отработала плохо, я всегда могу повторить обработку с помощью другой модели. На практике это оказалось гораздо удобнее.
Дополнительная обработка текста
Более того, я добавил дополнительный слой ИИ‑обработки на случай, если захочется еще сильнее улучшить качество распознавания.
Уже готовый расшифрованный текст дополнительно прогоняется через OpenAI, где нормализуются возможные ошибки распознавания.
Эту функцию я сделал опциональной, так как в большинстве случаев она вообще не требуется.
Требования к железу и производительность
Мой основной компьютер — MacBook Pro на M4 Pro с 24 ГБ ОЗУ. На нем все буквально летает. Локальные модели работают стабильно, хотя по ощущениям они все же на 20–30% медленнее, чем распознавание через облако OpenAI.
Также я протестировал приложение на старом MacBook 2018 года с Intel‑процессором и 8 ГБ ОЗУ. Существенной разницы при обычной работе приложения я не заметил. Однако при попытке использовать локальные модели приложение начинало падать.
В итоге я решил оставить поддержку локальных моделей только для Mac с M‑процессорами.
Итог
В итоге у меня получилось вполне достойное приложение, которым я теперь постоянно пользуюсь.
Более того, мне на столько понравился результат, что я думаю попробовать превратить приложение в полноценный продукт. Но об этом я, пожалуй, расскажу уже в следующей публикации, а то эта и так получилась больше, чем я планировал.
Всем спасибо за внимание! Буду рад фидбеку, идеям и просто мнению со стороны.
Автор: DimasOdessa


