惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Schneier on Security
P
Proofpoint News Feed
Apple Machine Learning Research
Apple Machine Learning Research
WordPress大学
WordPress大学
博客园 - Franky
V
V2EX
爱范儿
爱范儿
J
Java Code Geeks
小众软件
小众软件
Last Week in AI
Last Week in AI
The Cloudflare Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Hugging Face - Blog
Hugging Face - Blog
T
The Blog of Author Tim Ferriss
酷 壳 – CoolShell
酷 壳 – CoolShell
The Register - Security
The Register - Security
GbyAI
GbyAI
Vercel News
Vercel News
Y
Y Combinator Blog
腾讯CDC
F
Fortinet All Blogs
I
InfoQ
N
Netflix TechBlog - Medium
B
Blog RSS Feed
D
Docker
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
量子位
博客园 - 司徒正美
阮一峰的网络日志
阮一峰的网络日志
The GitHub Blog
The GitHub Blog
Microsoft Security Blog
Microsoft Security Blog
V
Visual Studio Blog
博客园 - 三生石上(FineUI控件)
宝玉的分享
宝玉的分享
Blog — PlanetScale
Blog — PlanetScale
H
Help Net Security
云风的 BLOG
云风的 BLOG
A
About on SuperTechFans
Scott Helme
Scott Helme
T
Tor Project blog
U
Unit 42
Google Online Security Blog
Google Online Security Blog
PCI Perspectives
PCI Perspectives
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
NISL@THU
NISL@THU
D
Darknet – Hacking Tools, Hacker News & Cyber Security
aimingoo的专栏
aimingoo的专栏
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Stack Overflow Blog
Stack Overflow Blog
Security Archives - TechRepublic
Security Archives - TechRepublic

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Govorun PC: переносим офлайн-диктовку с Android на Windows за один вечер (с Claude)
size222 · 2026-05-04 · via Все публикации подряд на Хабре

Предыстория

На Android у меня живёт Govorun Lite - офлайн-диктовка на русском. Нажал кнопку, сказал, текст вставился. Никаких облаков, никакой отправки голоса на серверы. Работает через GigaAM v2 от Сбера.

Проблема одна: на ПК такого нет. Встроенная Windows-диктовка - онлайн. Whisper — либо медленный, либо требует видеокарту. Сторонние сервисы - снова облако.

Я решил портировать Govorun на Windows, и для ускорения взял Claude как пару-программиста. Что из этого вышло - в этой статье.

Стек

Компонент

Библиотека

Лицензия

Распознавание речи

GigaAM v2 (NeMo CTC)

MIT

ONNX-рантайм

sherpa-onnx

Apache 2.0

Захват звука

sounddevice

MIT

Глобальные хоткеи

keyboard

MIT

Буфер обмена

pyperclip

BSD

Пунктуация

punctuators (xlm-roberta)

Apache 2.0

Системный трей

pystray

LGPL

Иконки

Pillow

HPND

Всё офлайн. После первоначальной загрузки моделей (~380 МБ суммарно) интернет не нужен.

Как это устроено внутри

Программа делает четыре простых вещи последовательно:

1. Слушает нажатие клавиш
Фоновый хук отслеживает Alt+X во всей системе - в любом окне, в любом приложении.

2. Пишет микрофон
Первое нажатие Alt+X - открывается поток с микрофона (16 кГц, моно). Звук накапливается в памяти кусками. Второе нажатие - поток закрывается, все куски склеиваются в один массив чисел.

3. Распознаёт речь
Массив уходит в GigaAM v2 через sherpa-onnx. Модель работает офлайн прямо на процессоре, возвращает строку без знаков препинания - это особенность CTC-архитектуры.

4. Восстанавливает пунктуацию и вставляет
Строка проходит через вторую модель (xlm-roberta ONNX) - она расставляет запятые, точки и заглавные буквы. Готовый текст копируется в буфер обмена и вставляется через Ctrl+V в то окно, где стоял курсор.

Alt+X → 🎤 Запись → Alt+X → 🧠 GigaAM v2 → ✏️ xlm-roberta → 📋 Ctrl+V в активное окно

Шаги 3 и 4 выполняются в отдельном потоке - пока идёт распознавание, хоткей не блокируется и программа не зависает.

Что докрутили по дороге

Изначально в плане были только распознавание и вставка. Но по ходу добавили ещё несколько вещей.

Системный трей
Приложение работает в фоне - терминал держать открытым не нужно. Иконка в трее показывает состояние: серая в покое, красная при записи. Реализовано через pystray + Pillow - иконка рисуется программно, без внешних файлов.

Ключевые куски кода

def _make_icon(recording: bool) -> Image.Image:
    img  = Image.new("RGBA", (64, 64), (0, 0, 0, 0))
    draw = ImageDraw.Draw(img)
    bg = (210, 40, 40, 255) if recording else (60, 60, 60, 255)
    draw.ellipse([2, 2, 62, 62], fill=bg)
    draw.rounded_rectangle([24, 10, 40, 36], radius=8, fill="white")
    # ... микрофон
    if recording:
        draw.ellipse([46, 4, 60, 18], fill=(255, 80, 80, 255))  # красная точка
    return img

Индикатор записи
Когда идёт запись - в трее красный бейдж с точкой, а тултип меняется на 🎤 Запись идёт.... Сразу видно что приложение активно.

GUI настроек
Правый клик на иконке → Настройки - открывается окно на tkinter. Там можно:

  • Сменить горячую клавишу (применяется без перезапуска)

  • Выбрать микрофон из выпадающего списка

  • Включить/выключить пунктуацию

class SettingsWindow:
    def _apply(self) -> None:
        # Горячая клавиша — снимаем старый хук, вешаем новый
        keyboard.remove_hotkey(HOTKEY)
        keyboard.add_hotkey(new_hotkey, self.ctrl.toggle, suppress=True)
        # Микрофон — просто меняем глобал, следующая запись возьмёт новый
        INPUT_DEVICE = new_device_id

Запись звука

class Recorder:
    def _callback(self, indata, frames, time_info, status):
        if status:
            print(f"[!] sounddevice: {status}")
        with self._lock:
            if self.recording:
                self.frames.append(indata.copy())

    def start(self) -> None:
        self.stream = sd.InputStream(
            samplerate=16_000, channels=1, dtype="float32",
            device=INPUT_DEVICE, callback=self._callback,
        )
        self.stream.start()

GigaAM ожидает моно, 16 кГц, float32 - именно это мы и пишем.

Распознавание

def load_recognizer() -> sherpa_onnx.OfflineRecognizer:
    return sherpa_onnx.OfflineRecognizer.from_nemo_ctc(
        model="models/model.onnx",
        tokens="models/tokens.txt",
        num_threads=4,
        sample_rate=16_000,
        feature_dim=80,
        decoding_method="greedy_search",
    )

Вставка в активное окно

def paste_text(text: str) -> None:
    pyperclip.copy(text)
    time.sleep(0.05)
    keyboard.send("ctrl+v")

Грабли, которые мы собрали

1. Неправильный микрофон

sounddevice без параметра device берёт системный дефолт - но на Windows это может оказаться виртуальным устройством или стереомикшером. Добавили вывод списка устройств при старте и флаг --device N.

def print_devices():
    devices = sd.query_devices()
    default_in = sd.default.device[0]
    for i, d in enumerate(devices):
        if d["max_input_channels"] > 0:
            marker = " ◄ дефолт" if i == default_in else ""
            print(f"[{i}] {d['name']}{marker}")

И флаг --device N для выбора нужного микрофона.

2. Нет пунктуации

GigaAM CTC - это «сырая» модель: она выдаёт слова строчными буквами без запятых и точек. Это ограничение архитектуры CTC, а не конкретной модели.

Решение - постобработка через отдельную модель. Сначала попробовали deepmultilingualpunctuation (PyTorch), но она потянула 1.5 ГБ зависимостей. Перешли на punctuators - ONNX-based xlm-roberta, ~50 МБ, поддерживает русский:

from punctuators.models import PunctCapSegModelONNX
model = PunctCapSegModelONNX.from_pretrained(
    "1-800-BAD-CODE/xlm-roberta_punctuation_fullstop_truecase"
)
result = model.infer(["привет как дела это тест"])
# → ["Привет, как дела? Это тест."]

3. WinError 6714 — транзакция NTFS

При первом запуске с deepmultilingualpunctuation PyTorch попытался писать временные файлы прямо в C:\Govorun. Windows заблокировала директорию через TxF (Transactional NTFS) и не отпустила — все последующие Path.exists() в той же папке падали с OSError: [WinError 6714].

Лечится перезагрузкой ПК. Но чтобы не повторялось — нужно заранее перенаправить кэши:

_CACHE = Path.home() / ".cache" / "govorun"
os.environ.setdefault("HF_HOME",           str(_CACHE / "huggingface"))
os.environ.setdefault("TRANSFORMERS_CACHE", str(_CACHE / "huggingface" / "hub"))
os.environ.setdefault("TORCH_HOME",        str(_CACHE / "torch"))

Важно: эти строки должны стоять до любых import torch / import transformers.

4. pyautogui не вставлял текст

Первоначально вставка делалась через pyautogui.hotkey("ctrl", "v"). Из фонового потока это иногда не срабатывало - фокус окна успевал уйти пока шло распознавание.

Заменили на keyboard.send("ctrl+v") из той же библиотеки, что уже используется для хоткеев. Работает надёжнее, потому что эмулирует нажатие на уровне драйвера, а не через UI Automation.


Что получилось

📋 Доступные устройства ввода: [0] Микрофон (Realtek HD Audio) ◄ дефолт

🎙 Используется устройство [0]: Микрофон (Realtek HD Audio)

⏳ Загружаю модель пунктуации (ONNX)… ✅ Пунктуация готова.

⏳ Загружаю GigaAM… ✅ Модель готова.

🎯 [ALT+X] — старт/стоп записи. Настройки и выход — иконка в системном трее.

🎤 Запись… (ALT+X — остановить) ⏹ Записано 4.2с, уровень: 0.0318, распознаю… 📝 Привет, это тестовая запись. Всё работает отлично. ✅ Скопировано и вставлено

Текст появляется в том поле, где стоял курсор - в браузере, Telegram, Word, IDE, где угодно

Установка

Вариант 1 — готовый exe (не нужен Python)

  1. Скачайте GovorunPC.exe (38 МБ)

  2. Положите рядом папку models/ с файлами модели

  3. Запустите GovorunPC.exe

При первом запуске punctuators скачает xlm-roberta (~50 МБ) в ~/.cache/govorun/. Интернет больше не понадобится.

Модели скачиваются отдельно (~330 МБ, один раз):

pip install requests tqdm
python download_models.py

Вариант 2 — из исходников

# Скачать исходники
# Распаковать архив со страницы релиза

pip install -r requirements.txt
python download_models.py   # ~330 МБ, один раз
python govorun_pc.py        # или двойной клик на govorun.vbs

При первом запуске punctuators скачает xlm-roberta (~50 МБ) в ~/.cache/govorun/. После этого интернет больше не нужен.

Итог

На всё ушло меньше вечера. Начали с простого скрипта - распознавание + вставка. По дороге добавили трей, индикатор записи, GUI настроек и собрали готовый .exe.

Основная часть времени - не написание кода, а отладка специфических Windows-проблем: WinError 6714, выбор микрофона, ненадёжная вставка через pyautogui. Claude предлагал решения, я проверял на живой машине, правили вместе.

Стек получился полностью офлайн, без PyTorch в рантайме (только ONNX), и работает на обычном процессоре без GPU.

Буду рад вопросам в комментариях.


Благодарности

Отдельное спасибо amidexe - автору оригинального Govorun Lite для Android. Именно его работа стала отправной точкой: готовая идея, проверенный стек (GigaAM + sherpa-onnx), понятная концепция «нажал - сказал - вставилось».

Без его приложения я бы не знал, с чего начать, и вряд ли вообще взялся за эту задачу.