Files
home-voice-assistant/README.md
Daniil Klimov 780f6f0084 Switch wake word from Porcupine to openwakeword + training pipeline
- Add training/ pipeline (step_1..step_5) and own-samples flow
- record_wav.py with single-shot and long-record modes, RMS-based silence filter
- remove_silent.py to drop silent samples and renumber
- modes.py: openwakeword inference with reset() and quiet predictions; commented Lusya block for later
- stt.py: drop local faster-whisper fallback, Groq-only
- config.py: remove unused STT_PROVIDER/WHISPER_*
- llm.py: replace __import__("os") hack with proper import
- tts.py: remove debug traceback in play_error_sound
- requirements.txt: add openwakeword/sounddevice/scipy, drop faster-whisper
- deploy/setup.sh: validate ELEVENLABS_API_KEY and WAKE_WORD_COSMO presence
- README.md, CLAUDE.md, project_roadmap memory updated to reflect new architecture
2026-04-13 15:40:44 +03:00

7.9 KiB
Raw Blame History

Cosmo Voice Satellite

Домашний голосовой ассистент. Слушает wake word, распознаёт речь, ходит в OpenClaw gateway, проигрывает ответ через ElevenLabs.

Два агента: Cosmo (владельца) и Люся (жены) — каждый со своим wake word и своим gateway.

Архитектура

mic ─► wake word (openwakeword) ─► STT (Groq) ─► OpenClaw gateway ─► TTS (ElevenLabs) ─► mpv ─► speakers
  • Wake word: openwakeword (обучается на своих записях, см. ниже). Раньше планировался Porcupine — отказались.
  • STT: Groq API, whisper-large-v3-turbo, ru.
  • LLM: OpenClaw gateway на N100 (192.168.31.103:18789 для cosmo, :18790 для lusya), openai/gpt-5.4-mini.
  • TTS: ElevenLabs eleven_flash_v2_5 стримом через mpv stdin.

Структура

home-voice-assistant/
├── satellite.py             # entry-обёртка
├── satellite/               # рантайм
│   ├── __main__.py          # python -m satellite [--wake]
│   ├── config.py, text.py
│   ├── stt.py, audio.py, tts.py, llm.py
│   └── modes.py             # run_with_enter / run_with_porcupine (wake word)
├── record_wav.py            # запись датасета для wake word
├── remove_silent.py         # чистка тихих + перенумерация
├── training/                # пайплайн обучения wake word
│   ├── step_1.py … step_5.py
│   ├── training_config.json
│   ├── own_samples/<word>/{positive,negative}/*.wav
│   ├── openwakeword/        # форк
│   └── my_custom_model/<word>/  # фичи + .onnx
├── data/models/             # готовые .onnx wake word моделей
└── deploy/                  # setup.sh + systemd unit для Pi

Запуск

python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env  # заполнить ключи

python satellite.py           # режим Enter (без wake word, для отладки)
python satellite.py --wake    # режим wake word (нужна обученная модель в data/models/)

Системные зависимости:

  • Python 3.12+
  • portaudiobrew install portaudio
  • mpvbrew install mpv

Обучение своего wake word

OpenWakeWord обучает DNN-модель на твоих записях слова. Пайплайн в training/:

Шаг Что делает
step_1.py Установка зависимостей (piper, openwakeword)
step_2.py Создаёт training_config.json (параметры обучения)
step_3.py Скачивает датасеты (audioset, fma, RIRs, ACAV features) — ~17 GB
step_4.py Аугментация → тренировка → экспорт .onnx в data/models/
step_5.py Проверка моделей и подсказки для .env

Запись датасета

# по одной записи (Enter → 2 секунды → сохраняем)
python record_wav.py cosmo positive
python record_wav.py cosmo negative

# непрерывно N секунд → нарезаем по 2с, тишину выкидываем
python record_wav.py cosmo negative long 300
INPUT_DEVICE=1 python record_wav.py cosmo negative long 600

record_wav.py отбраковывает тихие записи по MIN_RMS=300 (изменить можно константой в начале файла).

Чистка

python remove_silent.py

Удаляет файлы с RMS ниже порога и переименовывает оставшиеся в 001.wav … NNN.wav.

Тренировка

  1. В training/training_config.json укажи wake_word_list, use_own_samples: true, параметры:
    {
      "wake_word_list": ["cosmo"],
      "use_own_samples": true,
      "false_activation_penalty": 100,
      "target_false_positives_per_hour": 3.0,
      "target_recall": 0.5,
      "number_of_training_steps": 3000,
      "layer_size": 64
    }
    
  2. В training/openwakeword/examples/custom_model.yml подними augmentation_rounds: 10 (или больше).
  3. Снеси кэш если был старый запуск:
    rm -rf training/my_custom_model/<word> data/models/<word>.onnx
    
  4. Запусти:
    python training/step_4.py
    
  5. Пропиши в .env: WAKE_WORD_COSMO=data/models/cosmo.onnx.

Сколько данных нужно

Positive Negative Recall
100200 200+ 0.10.3 (плохо)
300500 500+ 0.40.6 (минимум)
8001500 1000+ 0.70.85
2000+ 2000+ 0.9+

Главное — разнообразие: разные дистанции до микрофона, интонации, время дня, фоны. Аугментация (augmentation_rounds) умножит твой датасет в N раз во время обучения.

Негативы должны включать фонетически близкие слова ("космос", "косо", "просто"), обычную речь, имена других ассистентов ("алиса", "сири"), бытовые звуки.

Архитектурные решения

  • Одна сессия диалога на день на агента (Conversation в llm.py). История хранится клиентом, отправляется целиком. Сброс — фразой "сбрось историю" или сменой даты.
  • Keep-alive HTTP (requests.Session) — переиспользует TCP/TLS.
  • Streaming TTS — ElevenLabs пайпится в mpv через stdin, играет пока генерируется.
  • STT без диска — PCM → WAV в BytesIO → Groq.
  • Barge-instop_speaking() убивает mpv при новой активации.
  • Ошибки не роняют сервис — каждый слой ловит Exception, пишет в errors.log.

.env (ключевые переменные)

Переменная Что
GATEWAY_URL, LUSYA_GATEWAY_URL OpenClaw gateways
GATEWAY_TOKEN, LUSYA_GATEWAY_TOKEN Авторизация
AGENT, LUSYA_AGENT openclaw/main, openclaw/wife
VOICE_MODEL LLM для голоса (передаётся в x-openclaw-model)
GROQ_API_KEY STT
ELEVENLABS_API_KEY, COSMO_TTS_VOICE, LUSYA_TTS_VOICE TTS
WAKE_WORD_COSMO, WAKE_WORD_LUSYA Пути к .onnx моделям
SILENCE_THRESHOLD, SILENCE_DURATION VAD
MAX_HISTORY Лимит сообщений в сессии
AUDIO_SINK На Pi: bluez_sink.XX_XX_XX.a2dp_sink

Деплой на Raspberry Pi

sudo bash deploy/setup.sh
sudo systemctl start cosmo-satellite
sudo journalctl -u cosmo-satellite -f

Roadmap

  • Модулизация satellite
  • ElevenLabs streaming + barge-in
  • Сессии диалога с автосбросом
  • Пайплайн тренировки wake word на своих записях
  • Обучить рабочую модель cosmo (нужно ~500+ позитивов)
  • Подключить Люсю в run_with_porcupine (сейчас грузится только cosmo)
  • Проверить systemd autostart на Pi в проде
  • Home Assistant tool в OpenClaw
  • Real-time barge-in (прерывание голосом во время TTS)
  • Контекст окружения в system prompt
  • Speaker identification
  • Проактивные уведомления через WebSocket