Локальная расшифровка звонков на Mac M4 без OBS
Во время созвона ноут начинал тормозить, а после него я тратил порядка трёх часов на расшифровку и всё равно половину фраз перечитывал по памяти. За вечер мы собрали на Mac M4 контур, который час разговора превращает в субтитры с метками «кто говорил», и ни один байт аудио никуда не уезжает. Ниже схема, цифры с реальных звонков и грабли, на которые я наступил при первой настройке.

Во время созвона ноут начинал тормозить, а после него я тратил порядка трёх часов на расшифровку и всё равно половину фраз перечитывал по памяти. За вечер мы собрали на Mac M4 контур, который час разговора превращает в субтитры с метками «кто говорил», и ни один байт аудио никуда не уезжает. Ниже схема, цифры с реальных звонков и грабли, на которые я наступил при первой настройке.
Обновление 2026-07-22: единый пайплайн transcribe-meeting.py (канон meeting.json, QC галлюцинаций, склейка фрагментов Hijack, --diarize auto для групп). Ниже актуальная схема; старый путь «mlx-whisper + diarize-vtt вручную» остаётся для точечных правок.
Словарь на одну минуту. STT (speech-to-text): превращение речи в текст. Диаризация: разметка «кто когда говорил» без имён, только SPEAKER_00 и далее. VTT: файл субтитров с таймкодами, как на YouTube. meeting.json: машиночитаемый протокол встречи (сегменты, QC, спикеры), из него собираются VTT и TXT. MLX: фреймворк Apple для нейросетей на чипах M-серии (репозиторий ml-explore). GPU здесь встроенный ускоритель в вашем Mac, не отдельная видеокарта.
Почему OBS и платные сервисы отпали
Раньше я писал звонки через OBS. Бесплатно, знакомо, но во время разговора процессор уходил в красную зону, а после записи ждал расшифровку часами. Качество текста было «так себе»: имена, термины, обрывки фраз. Половину приходилось восстанавливать по памяти, особенно если созвон был вечером и разбор откладывался на следующий день.
Облачные транскрибаторы вроде Otter или Fireflies снимают боль ожидания, но аудио уходит на чужой сервер, а подписка копится по месяцам. Для рабочих созвонов с договорённостями и цифрами это отдельный риск: запись лежит не у вас. Мне нужен был один файл со всеми голосами, локальная обработка и разметка спикеров без отправки записи в интернет.
Заранее я знал три вещи: OBS даёт нагрузку прямо на созвоне; облако стоит денег и забирает аудио; для диаризации нужен один смешанный трек, а не два раздельных файла «микрофон» и «система».
Поэтому порядок действий выстроился так: сначала стабильная запись без тормозов, потом быстрый STT на GPU, потом pyannote после Accept на Hugging Face, потом ручные имена по первым репликам.
На созвоне хватит лёгкой записи; после звонка не ждите часами расшифровку на процессоре и не платите подписку каждый месяц. На M4 весь цикл укладывается в минуты, если запись стабильная, а модели лежат на диске. Именно это я проверил на двух звонках подряд в ту же неделю.
Схема за вечер и что поставить один раз
Цепочка из четырёх шагов:
- Запись. Audio Hijack ловит звук из Chrome (Телемост, Meet, Zoom в браузере) и микрофон в один mp3.
- Текст. mlx-whisper на MLX гоняет распознавание речи на GPU Mac: модель large-v3-turbo, порт Whisper от OpenAI.
- Голоса. pyannote раскладывает моно 16 kHz на SPEAKER_00, SPEAKER_01 и дальше, сколько голосов насчитает модель. На вход pipeline ждёт один канал, не стерео с разнесёнными спикерами.
- Имена. Вручную: смотрю первые реплики в VTT и подставляю роли. На групповом созвоне один технический кластер иногда смешивает двух людей, тогда правлю по времени в
meeting.json, а не одним махом на весь SPEAKER_06.
Рекомендуемый путь сейчас: один вызов transcribe-meeting.py (STT, QC, диаризация и сборка meeting.json в одном прогоне). VTT и TXT экспортируются из JSON, имена можно пересобрать без повторного Whisper.
~/tools/mlx-whisper-env/bin/python transcribe-meeting.py run meeting.mp3 \
--out-dir ./transcripts --name 2026-07-20__meeting --diarize auto
Скрипты и README: https://github.com/naimax/mac-call-transcribe. Старый двухшаговый путь (transcribe-mlx + diarize-vtt.py) оставил для правок уже готового VTT. Готовый voxscriber у меня не завёлся; об этом ниже в разделе про грабли.
Что поставить один раз на Mac M1–M4:
- Audio Hijack: разовая покупка, не подписка (точную цену смотрите на сайте Rogue Amoeba).
- Python ARM64-native: «родной» формат для процессоров Apple M-серии. Не ставьте x86_64 (старый интеловский; Python под него на M-чипе идёт через прослойку и ломает MLX) через Homebrew, менеджер установки программ для Mac, из
/usr/local. pip install mlx-whisperи зависимости pyannote по документации моделей.- Для pipeline speaker-diarization-3.1 на Hugging Face нужны два Accept:
segmentation-3.0иspeaker-diarization-3.1, плюс Read-токен черезhf auth login. Без принятого условия или токена диаризация вернёт ошибку «доступ запрещён». - Веса Whisper (~1,5 ГБ) я скачал
curl-ом в локальную папку: штатная загрузка через HF hub внутри mlx зависала.
Суммарно на диске заложите порядка 5–8 ГБ под модели речи и спикеров.
Пример вызова распознавания из карточки mlx-community (путь к файлу подставьте свой):
import mlx_whisper
result = mlx_whisper.transcribe(
"meeting.mp3",
path_or_hf_repo="mlx-community/whisper-large-v3-turbo",
)
Запись в Audio Hijack и расшифровка на M4
Настройка сессии (один раз, потом копируете):
- Google Chrome → Recorder
- Микрофон → Recorder
- Google Chrome → Output Device (чтобы слышать собеседника в наушниках при записи)
- Один Recorder → один mp3 на звонок
- Automatic Connectors = Off (обязательно)
- Микрофон не вешать на Output, иначе услышите себя в ушах
- Без цепочки Chrome → Output при Run не слышно собеседника
На время звонка жму Run, по окончании Stop. Файл один, все голоса внутри. Сразу после Stop переношу mp3 в рабочую папку (у меня отдельный каталог для созвонов) и запускаю расшифровку: сначала mlx-whisper на GPU, потом диаризацию. Пока модели лежат на диске, повторный прогон того же файла сводится к одному вызову CLI-обёртки.
Rogue Amoeba формулирует это просто: «если слышно на Mac, Audio Hijack может записать» (страница продукта). Для браузерных созвонов это ровно наш кейс.
Скорость на M4 (по моим замерам, ваши минуты могут чуть плавать):
| Звонок | Длина аудио | Время транскрипции |
|---|---|---|
| SEO-созвон | ~14 мин | 1–2 мин |
| Урок по Cursor | ~56 мин | ~5 мин |
Оба прогона были в ту же неделю, что и сборка контура. Короткий SEO-созвон я разбирал сразу: договорённости по мониторингу и задачи на неделю. Длинный урок по Cursor шёл почти час; там важны были паузы и вопросы ученика, контекст плотнее, чем на спокойном диалоге двух человек.
После прогона получаю meeting.json и VTT с таймкодами. Имена спикеров pyannote не угадывает: только метки SPEAKER_XX. Я открываю начало файла, смотрю, кто представился, и подставляю роли вручную. Для диалога двоих удобен --speakers 2; для кейс-разбора на семь голосов я использую --diarize auto и не форсирую «двух спикеров», иначе все сливаются в два кластера и имена путаются.
QC встроен: на тишине Whisper иногда пишет «Субтитры…» или повторяет одно слово десятки раз. Фильтр убирает типовой мусор; полный список удалённого в meeting.json → removed и в *.qc.json. Спорные стыки помечаются SPEAKER_UNKNOWN, а не молча приписываются случайному голосу.
Если Hijack разбил запись на несколько App Recording ….mp3, transcribe-meeting.py принимает файлы списком: таймкоды склеиваются, диаризация идёт по объединённому WAV. Опционально --extract-commitments вытаскивает черновик цифр и «договорились» (эвристика, не замена ручному разбору).
Грабли и честная цена
Intel Python. Homebrew в /usr/local поставил x86-интерпретатор. MLX и стек mlx-whisper на нём не вариант. Переустановка на ARM64-native Python решила половину «почему ничего не работает». Проверка простая: python3 -c "import platform; print(platform.machine())" должен показать arm64, не x86_64 (интеловский).
Зависший HF hub. Загрузка mlx-community/whisper-large-v3-turbo из скрипта зависала. Прямой curl весов в локальную папку и указание пути в обёртке сработали с первого раза. Если у вас та же картина, не ждите час у прогресс-бара: скачайте веса руками по ссылкам из карточки модели.
Accept на Hugging Face. Для pipeline speaker-diarization-3.1 по README нужны два Accept: segmentation-3.0 и speaker-diarization-3.1, плюс Read-токен. Пропустите segmentation или не залогинитесь: на диаризации увидите «доступ запрещён». На моём стенде я принял условия ещё и на speaker-diarization-community-1, потому что пробовал отдельный community pipeline для offline; для базового 3.1 третья страница не требуется.
voxscriber. Хотел собрать «из коробки», но связка torchcodec и Intel ffmpeg у меня развалилась. В итоге своя CLI-обёртка поверх VTT; если вам хватает связки whisper + pyannote без красивого UI, можно не повторять этот путь.
Честный чек по деньгам: софт распознавания и диаризации бесплатен (open-source + локальные веса). Платный только Audio Hijack, разовая лицензия. OBS остаётся бесплатной альтернативой записи, если готовы мириться с тормозами на созвоне. Точность имён без ручной правки не обещаю: на стыках коротких реплик pyannote путает голоса; на групповых встречах один кластер может смешать двух людей, проверяйте первые минуты и абсурдные строки вроде «Саша: Саш, привет». Это ограничение модели, не баг настройки. Зато вы не платите за минуты в облаке и не отдаёте запись третьей стороне.
Дальше я читаю текст как протокол встречи: что решили, кто взял задачу, какие цифры прозвучали. Таймкоды помогают вернуться к спорному месту в записи, если формулировка в VTT размыта.
Если у вас похожая боль с созвонами и вы сначала хотите проверить процесс на прототипе, а не подписывать смету на полгода разработки, напишите, что собираете: сначала соберём рабочий контур, без абстрактного ТЗ.
Где читать дальше
Ещё кейсы про инструменты и агентов: AI Vibe News в MAX и Telegram @aivibenews.
История обновлений: 2026-07-22 (transcribe-meeting.py, meeting.json, QC, multipart, --diarize auto, extract_commitments); 2026-07-21 (первая публикация, двухшаговый CLI).
Источники
- mlx-community/whisper-large-v3-turbo — MLX-порт Whisper
- OpenAI Whisper — базовая open-source модель STT
- MLX — фреймворк для Apple Silicon
- pyannote speaker-diarization-3.1 — диаризация, gated
- pyannote segmentation-3.0 — зависимость, отдельный Accept
- pyannote speaker-diarization-community-1 — community pipeline, offline
- Audio Hijack — запись звука приложений на Mac
- mac-call-transcribe — https://github.com/naimax/mac-call-transcribe (скрипты из этой статьи)
- AI Vibe Craft development — заказная разработка