refactor: VAD upgrade, retry, dead code cleanup, AGENT removal
- audio: switch VAD to webrtcvad with RMS gate + fallback to RMS - audio: honor FOLLOWUP_TIMEOUT — short silence wait after bot response - llm: retry with exponential backoff on network errors and 5xx - llm: VOICE_MAX_TOKENS env (default 300) instead of hardcoded 150 - tts: optional VAD-based barge-in (BARGE_IN_ENABLED, off by default) - tts: remove dead start_barge_in_listener / was_barge_in helpers - config: drop AGENT/LUSYA_AGENT — routing happens via session_key - modes: remove unused imports, pass FOLLOWUP_TIMEOUT to follow-up record() - docs: full rewrite of README and CLAUDE.md to match current architecture
This commit is contained in:
249
CLAUDE.md
249
CLAUDE.md
@@ -1,85 +1,83 @@
|
||||
# Cosmo Voice Satellite
|
||||
|
||||
Голосовой ассистент дома — аналог Алисы через OpenClaw. Два агента: **Cosmo** (владельца) и **Люся** (жены). Каждый активируется своим wake word и идёт на свой OpenClaw gateway.
|
||||
Голосовой ассистент дома — аналог Алисы, но поверх LLM (через OpenClaw Gateway). Два агента: **Cosmo** (владельца) и **Люся** (жены). Каждый активируется своим wake word и идёт на свой OpenClaw gateway.
|
||||
|
||||
## Архитектура
|
||||
|
||||
```
|
||||
┌─────────────┐ wake word ┌──────────────┐ STT (Groq)
|
||||
│ Microphone │ ───────────► │ Satellite │ ──────────────►
|
||||
└─────────────┘ └──────────────┘ │
|
||||
│ ▼
|
||||
│ ┌──────────────┐
|
||||
│ │ OpenClaw │
|
||||
│ │ Gateway │
|
||||
│ │ (N100 PC) │
|
||||
│ stream response └──────────────┘
|
||||
┌─────────────┐ wake word ┌──────────────┐ STT (Groq)
|
||||
│ Microphone │ ────────────► │ Satellite │ ──────────────► OpenClaw Gateway
|
||||
└─────────────┘ │ (Pi 5 / │ (N100, Proxmox)
|
||||
│ Mac) │ ◄── LLM stream ──
|
||||
└──────────────┘ │
|
||||
│ │
|
||||
▼ TTS текст │
|
||||
ElevenLabs stream (mp3) │
|
||||
│ │
|
||||
▼ │
|
||||
┌──────────────┐ │
|
||||
│ ElevenLabs │ ◄─────────────────┘
|
||||
│ TTS │
|
||||
└──────────────┘
|
||||
│
|
||||
▼ mp3 stream
|
||||
┌──────────────┐
|
||||
│ mpv │ → speakers (BT)
|
||||
└──────────────┘
|
||||
mpv (stdin) → speakers (BT/aux) ◄──┘
|
||||
```
|
||||
|
||||
Сессия диалога теперь **на стороне OpenClaw** — satellite отправляет лишь `x-openclaw-session-key`, а история и память живут в gateway. Клиент stateless.
|
||||
|
||||
## Инфраструктура
|
||||
|
||||
- **Сервер**: N100 Mini-PC, `192.168.31.103`, Proxmox
|
||||
- **Cosmo Gateway**: порт `18789`, агент `openclaw/main`
|
||||
- **Люся Gateway**: порт `18790`, агент `openclaw/wife`
|
||||
- **Модель**: `openai/gpt-5.4-mini` (через `x-openclaw-model` header)
|
||||
- **Cosmo Gateway**: порт `18789`, агент `openclaw/main`, session_key `agent:voice:voice:home`
|
||||
- **Люся Gateway**: порт `18790`, агент `openclaw/wife`, session_key `agent:wife:voice:home`
|
||||
- **Модель**: `openai/gpt-5.4-mini` (через `x-ocplatform-model` header; переопределяется через `VOICE_MODEL`)
|
||||
- **STT**: Groq API, `whisper-large-v3-turbo`, язык ru
|
||||
- **TTS**: ElevenLabs, `eleven_flash_v2_5` (~75ms латентность)
|
||||
- **Wake word**: Porcupine (на Pi), Enter (при разработке)
|
||||
- **TTS**: ElevenLabs (`eleven_flash_v2_5` / `eleven_turbo_v2_5` / `eleven_multilingual_v2` — выбирается через `ELEVENLABS_MODEL`)
|
||||
- **Wake word**: openwakeword (`.onnx`, обучается на своих голосах через `training/step_*.py`). Раньше закладывали Porcupine — отказались.
|
||||
|
||||
## Структура проекта
|
||||
|
||||
```
|
||||
home-voice-assistant/
|
||||
├── .env # секреты (не в git)
|
||||
├── .env.example # шаблон
|
||||
├── .env # секреты (не в git)
|
||||
├── .env.example # шаблон
|
||||
├── requirements.txt
|
||||
├── satellite.py # обёртка для запуска
|
||||
├── satellite.py # обёртка для запуска
|
||||
├── satellite/
|
||||
│ ├── __init__.py
|
||||
│ ├── __main__.py # entry: python -m satellite [--wake]
|
||||
│ ├── config.py # env, AGENTS dict, keep-alive sessions
|
||||
│ ├── text.py # clean_for_speech, find_sentence_end
|
||||
│ ├── stt.py # transcribe (Groq, BytesIO, без temp файла)
|
||||
│ ├── audio.py # record, record_with_timeout (VAD)
|
||||
│ ├── tts.py # ElevenLabs streaming через mpv, barge-in
|
||||
│ ├── llm.py # ask_agent_stream, Conversation (history)
|
||||
│ └── modes.py # run_with_enter, run_with_porcupine
|
||||
│ ├── __main__.py # entry: python -m satellite [--wake]
|
||||
│ ├── config.py # env, AGENTS dict, keep-alive sessions
|
||||
│ ├── text.py # clean_for_speech (+ pymorphy3/num2words для времени)
|
||||
│ ├── stt.py # transcribe (Groq, BytesIO, без temp файла)
|
||||
│ ├── audio.py # record (RMS VAD)
|
||||
│ ├── tts.py # ElevenLabs streaming через mpv stdin
|
||||
│ ├── llm.py # ask_agent_stream, strip_fillers, RESET_PATTERNS
|
||||
│ └── modes.py # run_with_enter / run_with_porcupine + /new через slash
|
||||
├── record_wav.py # запись обучающих wav-ов для wake word
|
||||
├── remove_silent.py # чистка тихих записей
|
||||
├── training/ # пайплайн обучения wake word (не в git)
|
||||
└── deploy/
|
||||
├── setup.sh # установка на Raspberry Pi
|
||||
└── cosmo-satellite.service # systemd unit
|
||||
└── cosmo-satellite.service # systemd unit
|
||||
```
|
||||
|
||||
## Что важно знать
|
||||
## Ключевые инварианты
|
||||
|
||||
### Сессии диалога
|
||||
- **Одна сессия на день** для каждого агента. Это осознанное решение: каждая новая сессия в OpenClaw тяжёлая (чтение памяти, большой контекст).
|
||||
- История хранится в `Conversation.messages[]` на клиенте и отправляется целиком с каждым запросом (stateless к серверу).
|
||||
- Сброс сессии: фраза "начни новую сессию" / "сбрось историю" / "очисти контекст" — паттерны в `RESET_PATTERNS` в `llm.py`.
|
||||
- Автосброс при смене даты (`Conversation.is_expired()`).
|
||||
- `MAX_HISTORY=20` — лимит сообщений, чтобы не раздувать контекст.
|
||||
- История и контекст **на стороне OpenClaw**. Клиент шлёт только текущий user-message + `x-openclaw-session-key`.
|
||||
- Сброс: фраза «начни новую сессию» / «сбрось историю» / «очисти контекст» (паттерны в `llm.py::RESET_PATTERNS`) → `modes._handle_reset` делает прямой POST с `/new`.
|
||||
- Автосброс по таймауту **пока не реализован** (кандидат Этапа 1).
|
||||
|
||||
### Оптимизации скорости (все уже внедрены)
|
||||
1. **Keep-alive HTTP сессии** (`requests.Session()`) — в `config.py._make_session()`, переиспользуется TCP/TLS.
|
||||
### Оптимизации скорости
|
||||
1. **Keep-alive HTTP сессии** (`requests.Session()`) — в `config.py::_make_session()`, переиспользует TCP/TLS.
|
||||
2. **Streaming TTS** — ElevenLabs аудио пайпится в `mpv` через stdin, играет пока генерируется.
|
||||
3. **STT без диска** — PCM → WAV в `BytesIO` → Groq, без temp файлов.
|
||||
4. **Barge-in** — `stop_speaking()` вызывается при каждой активации, убивает текущий mpv процесс.
|
||||
3. **STT без диска** — PCM → WAV в `BytesIO` → Groq.
|
||||
4. **Низкокачественный mp3 для речи** (`mp3_22050_32`) — меньше латентность без заметной потери качества для голоса.
|
||||
5. **`optimize_streaming_latency=3`** в ElevenLabs convert — выдаёт первый чанк быстрее.
|
||||
|
||||
### Роутинг по wake word
|
||||
В `modes.py::run_with_porcupine` Porcupine грузит оба wake word:
|
||||
- index 0 = Cosmo → `AGENTS["cosmo"]` (:18789)
|
||||
- index 1 = Люся → `AGENTS["lusya"]` (:18790)
|
||||
`modes.py::run_with_porcupine` сейчас грузит только модель Cosmo. Код Люси закомментирован до того, как модель обучена. Когда готова:
|
||||
- index 0 → `AGENTS["cosmo"]` (:18789)
|
||||
- index 1 → `AGENTS["lusya"]` (:18790)
|
||||
|
||||
Каждый агент имеет свой `tts_voice` в ElevenLabs.
|
||||
### Нормализация речи перед TTS
|
||||
Два слоя защиты:
|
||||
1. `text.py::clean_for_speech` — regex-правила: эмодзи, `**жирный**`, числа с плюсом/минусом, проценты, слэши, градусы, аббревиатуры (`т.е.`, `т.к.`), UNIT_SLASH (км/ч → «километров в час»), время `HH:MM` → прописью в правильном падеже через pymorphy3 + num2words.
|
||||
2. `llm.py::strip_fillers` — режет фразы-заглушки («сейчас посмотрю», «дай секунду») которые агент генерит перед вызовом tool.
|
||||
|
||||
### Ошибки не должны ронять сервис
|
||||
Каждый слой (stt, tts, llm, audio, modes) ловит `Exception` и пишет в `errors.log` через `config.log`. Верхний уровень в modes.py ловит всё непредвиденное и продолжает цикл.
|
||||
@@ -88,103 +86,126 @@ home-voice-assistant/
|
||||
|
||||
### macOS / Windows (разработка)
|
||||
```bash
|
||||
python -m venv .venv
|
||||
# macOS/Linux: source .venv/bin/activate
|
||||
# Windows: .venv\Scripts\activate
|
||||
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 # режим Porcupine (нужны .ppn + PORCUPINE_KEY)
|
||||
python satellite.py --wake # режим openwakeword (нужна обученная .onnx)
|
||||
```
|
||||
|
||||
### Raspberry Pi (продакшн)
|
||||
```bash
|
||||
sudo bash deploy/setup.sh
|
||||
# далее:
|
||||
sudo systemctl start cosmo-satellite
|
||||
sudo journalctl -u cosmo-satellite -f
|
||||
```
|
||||
|
||||
## Зависимости системы
|
||||
|
||||
- **Python 3.12+**
|
||||
- **portaudio** — для `pyaudio` (`brew install portaudio` / `apt install portaudio19-dev`)
|
||||
- **mpv** — для воспроизведения TTS (`brew install mpv` / `apt install mpv`)
|
||||
- **ffmpeg** — опционально, для совместимости форматов
|
||||
- Python 3.12+
|
||||
- `portaudio` — для `pyaudio` (`brew install portaudio` / `apt install portaudio19-dev`)
|
||||
- `mpv` — для воспроизведения TTS (`brew install mpv` / `apt install mpv`)
|
||||
|
||||
### Windows
|
||||
- Python 3.12+ с pip
|
||||
- `pip install pyaudio` — обычно работает через колеса pipwin или pre-built wheels. Если нет — `pip install pipwin && pipwin install pyaudio`
|
||||
- mpv: скачать с [mpv.io](https://mpv.io/installation/), положить `mpv.exe` в PATH
|
||||
- Porcupine работает и на Windows — wake word модель нужна под платформу windows (качать отдельную `.ppn`)
|
||||
|
||||
## Переменные окружения
|
||||
|
||||
Все в `.env`. Ключевые:
|
||||
## Переменные окружения (ключевые)
|
||||
|
||||
| Переменная | Что |
|
||||
|-----------|-----|
|
||||
| `GATEWAY_URL`, `LUSYA_GATEWAY_URL` | URL OpenClaw gateway на N100 |
|
||||
| `GATEWAY_TOKEN`, `LUSYA_GATEWAY_TOKEN` | Токены авторизации |
|
||||
| `AGENT`, `LUSYA_AGENT` | Имя агента в OpenClaw (`openclaw/main`, `openclaw/wife`) |
|
||||
| `VOICE_MODEL`, `LUSYA_VOICE_MODEL` | Модель LLM для голоса |
|
||||
|---|---|
|
||||
| `GATEWAY_URL`, `LUSYA_GATEWAY_URL` | URL OpenClaw gateway |
|
||||
| `GATEWAY_TOKEN`, `LUSYA_GATEWAY_TOKEN` | Bearer токены |
|
||||
| `AGENT`, `LUSYA_AGENT` | Имя агента (`openclaw/main`, `openclaw/wife`) |
|
||||
| `VOICE_MODEL`, `LUSYA_VOICE_MODEL` | LLM (передаётся в `x-ocplatform-model`) |
|
||||
| `COSMO_SESSION_KEY`, `LUSYA_SESSION_KEY` | Идентификатор серверной сессии OpenClaw |
|
||||
| `GROQ_API_KEY` | Groq для STT |
|
||||
| `ELEVENLABS_API_KEY` | ElevenLabs TTS |
|
||||
| `ELEVENLABS_API_KEY`, `ELEVENLABS_MODEL` | TTS |
|
||||
| `COSMO_TTS_VOICE`, `LUSYA_TTS_VOICE` | Voice ID в ElevenLabs |
|
||||
| `ELEVENLABS_MODEL` | `eleven_flash_v2_5` (быстрый) |
|
||||
| `AUDIO_SINK` | На Pi: `bluez_sink.XX_XX_XX.a2dp_sink`. На Mac/Win: пусто. |
|
||||
| `PORCUPINE_KEY`, `WAKE_WORD_COSMO`, `WAKE_WORD_LUSYA` | Только для `--wake` режима |
|
||||
| `SILENCE_THRESHOLD=500` | VAD: чувствительность (ниже = ловит тихую речь) |
|
||||
| `SILENCE_DURATION=1.5` | Сек тишины = конец фразы |
|
||||
| `FOLLOWUP_TIMEOUT=8` | Сек ожидания продолжения диалога |
|
||||
| `MAX_HISTORY=20` | Макс. сообщений в сессии |
|
||||
| `WAKE_WORD_COSMO`, `WAKE_WORD_LUSYA` | Пути к `.onnx` моделям wake word |
|
||||
| `WAKE_THRESHOLD` | Порог активации (0..1, дефолт 0.5) |
|
||||
| `AUDIO_SINK` | На Pi: `bluez_sink.XX_XX_XX.a2dp_sink`. На Mac/Win: пусто |
|
||||
| `SILENCE_THRESHOLD`, `SILENCE_DURATION`, `MAX_DURATION`, `FOLLOWUP_TIMEOUT` | VAD |
|
||||
| `TTS_MODE` | `full` (целостная интонация) или `stream` (быстрый старт, рваный) |
|
||||
| `ECHO_WARMUP` | Сек пропуска в начале записи (гасит эхо от TTS) |
|
||||
|
||||
## Частые задачи
|
||||
|
||||
**Сменить голос у агента**: меняй `COSMO_TTS_VOICE` / `LUSYA_TTS_VOICE` в `.env`. Voice ID берётся на [elevenlabs.io/app/voice-library](https://elevenlabs.io/app/voice-library).
|
||||
**Сменить голос у агента**: меняй `COSMO_TTS_VOICE` / `LUSYA_TTS_VOICE` в `.env`. Voice ID — на [elevenlabs.io/app/voice-library](https://elevenlabs.io/app/voice-library). Для русского лучше native-русские голоса, а не мультиязычные (не будет англоязычного акцента).
|
||||
|
||||
**Отладить VAD (ассистент не слышит / слушает слишком долго)**: `SILENCE_THRESHOLD` (громкость) и `SILENCE_DURATION` (сек).
|
||||
**Отладить VAD**: `SILENCE_THRESHOLD` (громкость) и `SILENCE_DURATION` (сек).
|
||||
|
||||
**Добавить третьего агента**: в `config.py::AGENTS` новый ключ, в `modes.py::run_with_porcupine` добавить `WAKE_WORD_*` и `wake_word_map.append(...)`.
|
||||
**Добавить третьего агента**: в `config.py::AGENTS` новый ключ + `WAKE_WORD_*` + раскомментировать блок в `modes.py::run_with_porcupine`.
|
||||
|
||||
**Сменить модель LLM**: `VOICE_MODEL` в `.env` — передаётся в header `x-openclaw-model`. Модель `openclaw/main` остаётся как agent (это маршрут в OpenClaw).
|
||||
**Сменить модель LLM**: `VOICE_MODEL` в `.env` — передаётся в header `x-ocplatform-model`. Поле `model` в JSON остаётся `openclaw/main` (это имя агента, а не LLM).
|
||||
|
||||
**Добавить фразу-заглушку**: в `llm.py::FILLER_PATTERNS` дополнить список. Эти фразы режутся из ответа перед TTS — агент генерит их до tool-call.
|
||||
|
||||
## Что НЕ делать
|
||||
|
||||
- Не комитить `.env` (есть в `.gitignore`)
|
||||
- Не возвращать fallback на macOS `say` — проект специально унифицирован на ElevenLabs + mpv
|
||||
- Не создавать новую сессию Conversation на каждую активацию — это было в старой версии, сейчас одна сессия на день
|
||||
- Не добавлять temp файлы для WAV/mp3 — всё идёт через `BytesIO` / stdin pipe
|
||||
- Не возвращать `say`/`espeak` — проект унифицирован на ElevenLabs + mpv
|
||||
- Не хранить историю диалога на клиенте — это делает OpenClaw по `session_key`
|
||||
- Не создавать temp файлы для WAV/mp3 — всё через `BytesIO` / stdin pipe
|
||||
- Не включать `style>0` и `speed≠1.0` в VoiceSettings — усиливают «иностранный» акцент и ломают просодию
|
||||
|
||||
## Тренировка своего wake word
|
||||
## Тренировка wake word
|
||||
|
||||
Пайплайн в `training/`:
|
||||
- `record_wav.py <model> <positive|negative>` — запись 16kHz mono PCM 16-bit в `training/own_samples/<model>/`
|
||||
- `training/step_1.py` … `step_5.py` — установка зависимостей, конвертация датасетов, генерация конфига, обучение, экспорт в `data/models/<name>.onnx`
|
||||
- `training/training_config.json` — параметры (`wake_word_list`, `use_own_samples`, штрафы, шаги)
|
||||
- `training/openwakeword/` — форк openwakeword, `examples/custom_model.yml` — базовый шаблон конфига
|
||||
- Под капотом: openwakeword (НЕ Porcupine, несмотря на легаси-имена в коде). Wake word работает через DNN-модель .onnx.
|
||||
Пайплайн в `training/` (игнорируется в git):
|
||||
- `record_wav.py <model> <positive|negative> [long <sec>]` — запись 16kHz mono PCM 16-bit
|
||||
- `remove_silent.py` — чистка + перенумерация
|
||||
- `step_1.py … step_5.py` — зависимости, датасеты, конфиг, обучение, экспорт
|
||||
- `training_config.json` — параметры (`wake_word_list`, `use_own_samples`, пенальти, шаги)
|
||||
- Под капотом: openwakeword (DNN .onnx)
|
||||
|
||||
Реалистичные цифры для своего голоса: 500+ positive и 1000+ negative wav-файлов, иначе recall/FP/hour не сходятся. Negative должны включать фонетически близкие слова.
|
||||
Реалистично для своего голоса: 500+ positive и 1000+ negative, иначе recall < 0.4. Negative должны включать фонетически близкие слова («космос», «просто»).
|
||||
|
||||
## Roadmap
|
||||
## Состояние и планы
|
||||
|
||||
### Done
|
||||
- [x] Модулизация satellite.py (audio/stt/llm/tts/modes/config)
|
||||
- [x] ElevenLabs streaming TTS + mpv pipe
|
||||
- [x] Keep-alive HTTP сессии, STT через BytesIO, barge-in
|
||||
- [x] Сессии диалога (одна на день, MAX_HISTORY, паттерны сброса)
|
||||
- [x] Пайплайн тренировки своего wake word на собственных записях
|
||||
### ✅ Done
|
||||
- [x] Модульная структура (`audio/stt/llm/tts/modes/config/text`)
|
||||
- [x] ElevenLabs streaming + mpv pipe
|
||||
- [x] Keep-alive HTTP сессии, STT через BytesIO
|
||||
- [x] Серверные сессии OpenClaw через `x-openclaw-session-key` (не клиентская история)
|
||||
- [x] Slash-команда `/new` на фразу «начни новую сессию»
|
||||
- [x] Нормализация речи: числа, единицы, время через pymorphy3 + num2words
|
||||
- [x] Пайплайн тренировки своего wake word + скрипты записи/чистки датасета
|
||||
- [x] systemd unit и setup.sh для Pi 5
|
||||
|
||||
### In progress
|
||||
- [ ] Дообучение модели cosmo (на текущем датасете 300 pos / 117 neg метрики плохие — recall 25%, FP/hr 32). Нужно дозаписать данные.
|
||||
- [ ] Подключить Люсю в `run_with_wakeword` (сейчас грузится только модель cosmo, lusya wake word не работает)
|
||||
### 🚧 In progress / нужно сделать
|
||||
- [ ] **Чистка**: удалить `start_barge_in_listener`/`was_barge_in` из `tts.py`, параметр `conv` из `llm.py`, импорты `sys`/`start_barge_in_listener`/`was_barge_in` из `modes.py`
|
||||
- [ ] **`FOLLOWUP_TIMEOUT` реально применяется** — сейчас задекларирован, но после ответа ассистент ждёт полный `MAX_DURATION=15s` если пользователь молчит
|
||||
- [ ] **Унифицировать дефолт session_key** в `config.py` и `.env.example` (сейчас `voice:home:cosmo` vs `agent:voice:voice:home`)
|
||||
- [ ] **`max_tokens` → env** (`VOICE_MAX_TOKENS`), дефолт 300
|
||||
- [ ] **Дообучить модель cosmo до recall ≥ 0.7** (нужно 500+ positive + разнообразие)
|
||||
- [ ] **Подключить Люсю в `run_with_porcupine`** (код закомментирован, готов к включению)
|
||||
- [ ] **Проверить systemd autostart на Pi в проде** — unit есть, в прод не поставлен
|
||||
- [ ] **logrotate / size-cap на `errors.log`** — растёт неограниченно
|
||||
|
||||
### Planned
|
||||
- [ ] systemd autostart на Raspberry Pi (`deploy/cosmo-satellite.service` есть, но не проверен в проде)
|
||||
- [ ] Home Assistant tool в OpenClaw воркспейсе (управление светом/температурой через голос)
|
||||
- [ ] Real-time barge-in (прерывание по голосу во время озвучки, не только по новой активации)
|
||||
- [ ] Контекст окружения в system prompt (время, погода, состояние устройств)
|
||||
- [ ] Speaker identification (определять кто говорит без разных wake words)
|
||||
- [ ] Проактивные уведомления (WebSocket от сервера → satellite сам начинает говорить)
|
||||
### 📋 Roadmap Этап 2 — качество и надёжность
|
||||
- [ ] **Автосброс OpenClaw сессии по таймауту** (>1 ч тишины → `/new`)
|
||||
- [ ] **Retry с backoff** для gateway (3 попытки с экспонентой)
|
||||
- [ ] **TTS-cache** для дежурных реплик («Начинаю новую сессию», «Не слышу», «Ошибка сервера»)
|
||||
- [ ] **Persistent PyAudio input stream** (не пересоздавать на каждый `record()`)
|
||||
- [ ] **Заменить RMS-VAD на `webrtcvad` или `silero-vad`** — RMS не работает с фоновой музыкой
|
||||
- [ ] **Whisper `prompt` параметр** с «Космо, Люся, OpenClaw» — для имён собственных
|
||||
- [ ] **SYSTEM_PROMPT опционально на клиенте** — подсказка про TTS-friendly формат чисел/дат, если OpenClaw-агент без неё
|
||||
|
||||
### 📋 Roadmap Этап 3 — новые фичи
|
||||
- [ ] **Home Assistant tool** в OpenClaw: свет, климат, медиа голосом
|
||||
- [ ] **Контекст окружения** в каждом запросе: время, комната, погода, кто говорит
|
||||
- [ ] **Proactive notifications**: OpenClaw → WebSocket/SSE → satellite сам инициирует речь (таймеры, напоминания, входящее сообщение)
|
||||
- [ ] **Realtime barge-in голосом** во время TTS (требует echo cancellation: speex AEC или SpeexDSP)
|
||||
- [ ] **No-wake mode для доверенной комнаты** — VAD + whisper + intent filter без обязательного wake word
|
||||
- [ ] **Streaming TTS пер-токен** — отправлять в TTS куски раньше чем целое предложение, с правильными интонационными точками
|
||||
|
||||
### 📋 Roadmap Этап 4 — амбициозное
|
||||
- [ ] **Speaker identification** (`pyannote.audio` / `resemblyzer`) — разные персонализации по голосу
|
||||
- [ ] **Multi-room координация** — MQTT/gRPC между сателлитами, отвечает тот, кто слышит громче
|
||||
- [ ] **Локальный fallback LLM** на Pi (phi/llama) когда gateway недоступен — базовые команды без облака
|
||||
- [ ] **Камера + vision** — агент видит кто в комнате, что происходит
|
||||
- [ ] **Voice-memory hooks UX** — голосовые команды «запомни», «забудь» (OpenClaw уже умеет, нужен голосовой слой)
|
||||
|
||||
## Известные ограничения
|
||||
|
||||
- **Нет echo cancellation** — если колонки близко к микрофону (особенно BT колонки на Pi), TTS может триггерить wake-модель. Mitigation: разносить колонку и мик, поднимать `WAKE_THRESHOLD`, использовать наушники при отладке.
|
||||
- **VAD не отличает голос от музыки/ТВ** — если что-то постоянно шумит выше `SILENCE_THRESHOLD`, ассистент «зависнет» слушать. Решение — `silero-vad`.
|
||||
- **Одна сессия = бесконечный контекст OpenClaw** пока не вызван `/new`. Нужен автотаймаут.
|
||||
- **Нет fallback для gateway-offline** — при потере связи ассистент молчит до явной ошибки.
|
||||
|
||||
Reference in New Issue
Block a user