Локальная расшифровка звонков на Mac M4 без OBS

Во время созвона ноут начинал тормозить, а после него я тратил порядка трёх часов на расшифровку и всё равно половину фраз перечитывал по памяти. За вечер мы собрали на Mac M4 контур, который час разговора превращает в субтитры с метками «кто говорил», и ни один байт аудио никуда не уезжает. Ниже схема, цифры с двух реальных звонков недели и грабли, на которые я наступил при первой настройке.
Словарь на одну минуту. STT (speech-to-text): превращение речи в текст. Диаризация: разметка «кто когда говорил» без имён, только SPEAKER_00 и SPEAKER_01. VTT: файл субтитров с таймкодами, как на YouTube. 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 и подставляю роли («SEO-специалист», «ученик на уроке по Cursor»).
Между шагами 2 и 3 у меня небольшой Python-скрипт в командной обёртке (CLI): гоняет mlx-whisper, потом pyannote и накладывает метки спикеров на готовые субтитры. На выходе .vtt с таймкодами и SPEAKER_00/01. Писать его с нуля не обязательно: скрипты и README — https://github.com/naimax/mac-call-transcribe. Шаг 4 (имена) я ускоряю другой, мелкой CLI-обёрткой поверх уже готового 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 шёл почти час; там важны были паузы и вопросы ученика, контекст плотнее, чем на спокойном диалоге двух человек.
После прогона получаю VTT с таймкодами. Имена спикеров pyannote не угадывает: только метки SPEAKER_00/01. Я открываю начало файла, смотрю, кто представился, и подставляю роли вручную.
Дальше я читаю текст как протокол встречи: что решили, кто взял задачу, какие цифры прозвучали. Таймкоды помогают вернуться к спорному месту в записи, если формулировка в VTT размыта. Ставка простая: не терять договорённости и не откладывать разбор на «завтра».
Грабли и честная цена
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 путает SPEAKER_00 и SPEAKER_01, длинный монолог одного человека повышает риск съехавших границ фраз. Это ограничение модели, не баг настройки. Зато вы не платите за минуты в облаке и не отдаёте запись третьей стороне.
Если у вас похожая боль с созвонами и вы сначала хотите проверить процесс на прототипе, а не подписывать смету на полгода разработки, напишите, что собираете: сначала соберём рабочий контур, без абстрактного ТЗ.
Где читать дальше
Ещё кейсы про инструменты и агентов: AI Vibe News в MAX и Telegram @aivibenews.
Источники
- 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 — заказная разработка