Mac dictation: Hammerspoon + Groq Whisper решение
- decisions/2026-05-05-mac-dictation-groq-hammerspoon.md: полный план, грабли с раскладкой, fallback на whisper-cpp, восстановление на новом Mac - notes/ru-geoblocked-services.md: реестр CDN с RU-блоком (cdn.spokenly, dl.wisprflow и пр.) + принципы обхода - snippets/mac-dictation/: рабочая версия скриптов и init.lua Триггер — одиночный Fn, Groq cloud first → tiny local fallback, вставка через hs.eventtap.event keycode 9 (минует ru-keymap warnings). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
72
decisions/2026-05-05-mac-dictation-groq-hammerspoon.md
Normal file
72
decisions/2026-05-05-mac-dictation-groq-hammerspoon.md
Normal file
@@ -0,0 +1,72 @@
|
||||
# 2026-05-05 — Mac dictation: Hammerspoon + Groq Whisper
|
||||
|
||||
## Контекст
|
||||
Олег на Intel MacBook Pro (i9-9880H, 2019), нужна голосовая диктовка для русского. Все современные приложения (superwhisper PRO, VoiceInk, Spokenly Parakeet) либо требуют Apple Silicon, либо платную PRO-лицензию ($150-250). Бесплатный free-tier у superwhisper исчерпан и валидируется на их сервере (см. [feedback_superwhisper_no_license](../../.claude/projects/-Users-ai-knowledge-base/memory/feedback_superwhisper_no_license.md)).
|
||||
|
||||
## Решение
|
||||
Свой скрипт + Hammerspoon + Groq Whisper API:
|
||||
- **Hammerspoon** ловит глобальный hotkey `⌘⇧D`
|
||||
- **Bash скрипт** toggle-режим: первый запуск → ffmpeg запись с микрофона; второй → стоп → POST в Groq → текст в `/tmp/groq-dictate.last`
|
||||
- **Lua callback** в Hammerspoon читает файл, кладёт в pasteboard, нажимает Cmd+V через `hs.eventtap.keyStroke`
|
||||
- **Groq Whisper-large-v3-turbo** — бесплатно ~14400 запросов/день, 0.5с на 4-сек запись, RU IP не блочится
|
||||
|
||||
## Файлы
|
||||
- `~/bin/groq-dictate.sh` — скрипт записи + Groq POST + **fallback на whisper-cpp** + write to `/tmp/groq-dictate.last`
|
||||
- `~/bin/dictation-doctor.sh` — health-check всех компонентов (Hammerspoon / TCC / зависимости / Groq / mic / Fn-key); запускать когда «не работает»
|
||||
- `~/.hammerspoon/init.lua` — Fn (одиночное нажатие) trigger через eventtap, paste через `hs.eventtap.keyStroke`
|
||||
- `~/.cache/whisper-cpp/ggml-tiny-q5_1.bin` — 31MB локальная модель для offline fallback
|
||||
- Groq API key — в `reference_groq_api.md` private memory
|
||||
|
||||
## Финальный hotkey
|
||||
**Fn (Globe) одиночное нажатие** — toggle (старт/стоп). Срабатывает быстрее ⌘⇧D, освобождает руки. Apple Dictation на двойное Fn остаётся (если не отключить «Нажатие клавиши Fn» в System Settings → Keyboard).
|
||||
|
||||
## Критические грабли (и фиксы)
|
||||
1. **Hammerspoon Accessibility кеширует статус** — после Enable в System Settings нужен **`killall Hammerspoon && open -a Hammerspoon`**, иначе Hammerspoon продолжает показывать WARNING и hotkey не работает.
|
||||
|
||||
2. **`hs.hotkey.bind({"cmd","shift"}, "d", ...)`** на русской раскладке выдаёт warning `key 'd' not found in active keymap; using ANSI-standard US keyboard layout as fallback, returning '2'`. Решение: **биндить по числовому keycode** — `hs.hotkey.bind({"cmd","shift"}, 2, ...)` (2 = физическая клавиша D). Так работает на любой раскладке.
|
||||
|
||||
3. **`osascript -e 'tell application "System Events" to keystroke "v" using command down'`** на русской раскладке вместо Cmd+V вставляет UTF-8 байты текста как символы → получается мусор типа `—В—ь—А—∞—ь—В?` для строки «Ты меня слышишь?». Решение: **никогда не использовать `keystroke` для paste**. Использовать `hs.eventtap.keyStroke({"cmd"}, "v")` напрямую из Lua (отправляет настоящий low-level KeyDown event).
|
||||
|
||||
4. **Toggle через PID-файл** — `/tmp/groq-dictate.pid`. Если процесс упал/убит — удалить руками. Скрипт устойчив: `kill -INT` корректно закрывает .wav, ждёт до 0.5с дописать заголовок.
|
||||
|
||||
5. **ffmpeg avfoundation `:0`** = default mic. Если нужен другой — `ffmpeg -f avfoundation -list_devices true -i ""`.
|
||||
|
||||
## Стоимость
|
||||
- Hammerspoon бесплатный
|
||||
- Groq бесплатный (14400 req/day, ~120 минут диктовки в день — намного больше нужного)
|
||||
- Итого: 0₽
|
||||
|
||||
## Альтернативы которые НЕ подошли
|
||||
- **superwhisper** — free tier 530 сек, потом сервер бракует
|
||||
- **VoiceInk** — официально Apple Silicon only, на Intel CPU крутит большую модель часами
|
||||
- **Spokenly** — `cdn.spokenly.app` блокирует RU IP (3.8 KB/s), Parakeet требует Neural Engine
|
||||
- **Wispr Flow** — `dl.wisprflow.com` блокирует RU IP, плюс $144/год Pro для регулярного использования
|
||||
- **MacWhisper** — $59 lifetime + не пробовали (всё уже работало бесплатно)
|
||||
- **OpenWhispr** — 273MB dmg в GitHub, не докачался
|
||||
|
||||
## Связано
|
||||
- [RU-заблокированные сервисы](../notes/ru-geoblocked-services.md)
|
||||
- [Groq API](../../.claude/projects/-Users-ai-knowledge-base/memory/reference_groq_api.md)
|
||||
- [Superwhisper — нет PRO](../../.claude/projects/-Users-ai-knowledge-base/memory/feedback_superwhisper_no_license.md)
|
||||
|
||||
## Воспроизведение на новом Mac
|
||||
```bash
|
||||
brew install --cask hammerspoon
|
||||
brew install whisper-cpp jq ffmpeg
|
||||
mkdir -p ~/bin ~/.hammerspoon ~/.cache/whisper-cpp
|
||||
|
||||
# скопировать ~/bin/groq-dictate.sh + ~/bin/dictation-doctor.sh → chmod +x
|
||||
# скопировать ~/.hammerspoon/init.lua
|
||||
|
||||
# скачать локальную fallback-модель (31 MB, GitHub не блочит RU)
|
||||
curl -sSL -o ~/.cache/whisper-cpp/ggml-tiny-q5_1.bin \
|
||||
"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny-q5_1.bin?download=true"
|
||||
|
||||
open -a Hammerspoon
|
||||
# Hammerspoon Preferences → Enable Accessibility → System Settings → включить
|
||||
killall Hammerspoon && open -a Hammerspoon # ОБЯЗАТЕЛЬНО после grant — кеш
|
||||
|
||||
# System Settings → Клавиатура → Нажатие клавиши Fn → "Действие не требуется"
|
||||
~/bin/dictation-doctor.sh # должно быть всё зелёное
|
||||
```
|
||||
Готово. **Fn → говори → Fn** — текст вставится в активное окно.
|
||||
Reference in New Issue
Block a user