From 02f13db1f3cd7bb50e653ed28743dda1f09c1e97 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 21 Jun 2026 01:25:11 +0300 Subject: [PATCH] =?UTF-8?q?docs(domain=20D):=20v2=20=E2=80=94=20=D1=80?= =?UTF-8?q?=D0=B5=D1=82=D1=80=D0=BE-=D1=80=D0=B5=D0=B2=D1=8C=D1=8E=20pass-?= =?UTF-8?q?2=20(9=20=D0=BD=D0=B0=D1=85=D0=BE=D0=B4=D0=BE=D0=BA)=20+=20?= =?UTF-8?q?=D0=BA=D1=80=D0=BE=D1=81=D1=81-=D0=B4=D0=BE=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AEC (эхоподавление, loopback-ref из PipeWire) добавлен в пайплайн — нужен для wake-word во время воспроизведения и barge-in (был полностью пропущен) - auto-fallback: v1 = online degradation UX, офлайн-фолбэк (llama.cpp) = v3 (раньше фолбэкать в v1 было некуда); offline-first (#3) в v1 частично, полный — v3 - инференс: ONNX (Silero) + Vosk через нативный Kaldi (не «всё через ONNX») - vehicle-context: контракт инъектора — только quality=valid, гейт по состоянию машины, ассистент декларирует vehicle_read через прокси; деградация на простых авто - wake-word по состояниям питания (не безусловно always-on, риск разряда; Stage 2; гейт Power/B) - distraction: owner Shell §7, скорость K(GPS v1)/E(OBD v2); журнал wake-word/mic - кросс-док: tech-stack (Porcupine отвергнут), principles #3 (фазировка офлайн-диалога) Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/domains/d-assistant.md | 79 ++++++++++++++++++++++++------------- docs/principles.md | 2 +- docs/tech-stack.md | 2 +- 3 files changed, 53 insertions(+), 30 deletions(-) diff --git a/docs/domains/d-assistant.md b/docs/domains/d-assistant.md index 873f6f4..b3f2eea 100644 --- a/docs/domains/d-assistant.md +++ b/docs/domains/d-assistant.md @@ -4,8 +4,8 @@ > их по-человечески. Интегрирован в UI лаконично (как Grok в Tesla). Вторая половина > killer-фичи. First-party ап на SDK (Rust + ONNX Runtime). -Статус: **v1 (на ревью).** -Связано с: домен E (Vehicle-Data) · [ipc.md](../contracts/ipc.md) (`Assistant`) · [plugin-sdk.md](../contracts/plugin-sdk.md) (интенты) · [security-privacy.md](../contracts/security-privacy.md) (mic, приватность) · [tech-stack.md](../tech-stack.md) · [principles.md](../principles.md) (#3,#6,#7,#8) +Статус: **v2 (на ревью).** v2 — после ретро-ревью (9 находок). +Связано с: домены E (Vehicle-Data), **K (GPS/Location)**, **B (power-гейт wake-word)** · [ipc.md](../contracts/ipc.md) (`Assistant`) · [plugin-sdk.md](../contracts/plugin-sdk.md) (интенты) · [security-privacy.md](../contracts/security-privacy.md) · [tech-stack.md](../tech-stack.md) · [principles.md](../principles.md) (#3,#5,#6,#7,#8) --- @@ -19,16 +19,19 @@ ## 2. Пайплайн ``` -Mic-массив → Wake-word → VAD → STT(RU) → Intent router +Mic-массив → AEC → Wake-word → VAD → STT(RU) → Intent router → [локальные интенты] (громче/домой/… — без LLM, низкая латентность) → [LLM backend] (свободный диалог + объяснения + контекст машины) → TTS(RU) → Audio out ``` +*(AEC = эхоподавление с loopback-референсом TTS/медиа-выхода из PipeWire — нужно для +wake-word во время воспроизведения и для barge-in.)* -Компоненты: wake-word (**openWakeWord**, Apache-2.0, RU-фраза «Штурман»; Porcupine — -коммерческий/проприетарный → конфликт с принципом #12, избегаем) · VAD (Silero) · -STT (Vosk/Silero, **офлайн**) · intent router · LLM backend (pluggable) · TTS (Silero, офлайн). -Инференс — через ONNX Runtime (`ort`); см. [tech-stack.md](../tech-stack.md). +Компоненты: **AEC** (loopback-ref выхода) · wake-word (**openWakeWord**, Apache-2.0, RU-фраза +«Штурман»; Porcupine проприетарный → #12, избегаем) · VAD (Silero) · STT (Vosk/Silero, **офлайн**) · +intent router · LLM backend (pluggable) · TTS (Silero, офлайн). +**Инференс:** ONNX-модели (Silero VAD/STT/TTS) — через ONNX Runtime (`ort`); **Vosk — нативный +движок Kaldi** (крейт `vosk`). См. [tech-stack.md](../tech-stack.md). ## 3. Функции @@ -44,12 +47,12 @@ STT (Vosk/Silero, **офлайн**) · intent router · LLM backend (pluggable) | LLM online (GigaChat/YandexGPT) | **MVP** | Connectivity | v1 | | Multi-turn контекст | **MVP** | — | v1 | | **Vehicle-context injection** | **MVP (killer)** | E, data-model | v2 | -| Provider auto-fallback | **MVP** | — | v1 | -| Driver-distraction (приоритет голосу на скорости) | **MVP** | Shell, E(speed) | v1/v2 | -| LLM offline fallback (локальная модель) | later | — | v3 | +| Online degradation/timeout UX («думаю…»/«нет сети») | **MVP** | — | v1 | +| Driver-distraction (приоритет голосу) | **MVP** | Shell (owner); K (GPS) v1; E (OBD) v2 | v1/v2 | +| Provider switch + офлайн-фолбэк (llama.cpp) | later | — | v3 | | Память о водителе (`.md`) | later | storage | v3 | | Plugin-интенты (dispatch в IntentHandler) | later | plugin-sdk | v3 | -| Barge-in (прерывание TTS голосом) | later | — | later | +| Barge-in (прерывание TTS голосом) | later | **AEC**, PipeWire loopback | later | ## 4. Vehicle-context injection (killer-фича) @@ -59,17 +62,27 @@ STT (Vosk/Silero, **офлайн**) · intent router · LLM backend (pluggable) ``` [SYSTEM] Ты — Штурман, голосовой со-пилот. Кратко, по-русски, для водителя в движении. Не давай советов, опасных для вождения. -Данные машины (только чтение, могут быть неточны): +Данные машины (только валидные/свежие; недоступные опущены): Скорость 64 км/ч · Обороты 2100 · Охлаждайка 92°C · Бортсеть 14.1В Лампа Check: горит · Ошибки: P0420 (катализатор, банк 1 — низкая эффективность) + (расход: нет данных) [Память о водителе]: … [USER] Почему горит чек? [ASSISTANT] Из-за P0420 — система считает, что катализатор работает неэффективно. Часто это датчик кислорода или сам катализатор. Машина поедет, но на диагностику стоит заехать. ``` -Снимок берётся из `VehicleData` (E); коды → стандартное описание из базы, человеческое -объяснение — LLM. +Снимок берётся из `VehicleData` (E); коды → стандартное описание из базы, человеческое объяснение — LLM. + +**Контракт инъектора контекста:** +- Ассистент — first-party SDK-ап, **декларирует `vehicle_read:[…]`** (speed, rpm, coolant_temp, + module_voltage, fuel_level, **mil_on, dtc_count**) + `GetDtcs()`; доступ гейтится тем же + VehicleData-прокси, что и у плагинов (ipc §5) — first-party = авто-грант, не «свободный доступ». +- В промпт — **только сигналы `quality=valid`** (data-model §2/§3); `stale`/`unavailable` — + исключаются или помечаются «нет данных» (LLM не утверждает устаревшее). +- Состав гейтится **состоянием машины** (`off`/`accessory`/`running`). +- **Деградация на простых авто (Lada):** богатые PID часто Unavailable → снимок схлопывается + до `mil_on` + DTC — это всегда-доступный MVP-базис. ## 5. LLM backend (pluggable, provider-agnostic) @@ -79,9 +92,11 @@ STT (Vosk/Silero, **офлайн**) · intent router · LLM backend (pluggable) - **Авто-fallback:** ошибка/нет сети → офлайн; восстановилась — обратно. - **Креды — свои у пользователя:** проект не шипит ключи; пользователь подключает свой GigaChat/YandexGPT (токены в защищённом хранилище, refresh; облако — за его счёт). -- **До офлайн-фолбэка (v1 online-only):** сеть в движении нестабильна → мягкая - деградация: «думаю…», таймаут → «нет сети», без зависаний. Офлайн-фолбэк (v3) и - делает ассистента по-настоящему надёжным. +- **До офлайн-фолбэка (v1 online-only):** сеть в движении нестабильна → мягкая деградация: + «думаю…», таймаут → «нет сети», без зависаний. Офлайн-фолбэк (v3) делает ассистента надёжным. +- **Принцип #3 (offline-first) в v1 — частично:** wake-word, STT/TTS и локальные интенты + (громче/домой) работают офлайн, ассистент не немеет без сети; офлайн-**диалог** (llama.cpp) — v3. + (Полное #3-соответствие — v3; см. principles #3.) ## 6. Интенты (routing) @@ -103,15 +118,19 @@ STT (Vosk/Silero, **офлайн**) · intent router · LLM backend (pluggable) ## 8. Приватность - Голос обрабатывается **локально** (STT) до отправки чего-либо; в облако — только - **текст запроса** при онлайн-LLM. Микрофон always-on для wake-word, но локально + - **видимый индикатор** прослушки. Контекст машины уходит провайдеру только онлайн и - по запросу (security-privacy §7). + **текст запроса** при онлайн-LLM. Контекст машины уходит провайдеру только онлайн и по запросу (security-privacy §7). +- **Wake-word по состояниям питания (не безусловно always-on):** работает при заведённом / + ACC-on; в sleep/off — выключен (риск разряда АКБ на стоянке, принцип #5). Доступен только с + **Stage 2** (в boot-окне голоса нет). Гейтится сигналами Power (`AccChanged`/`Sleep`/`Wake`, ipc). + Включённый микрофон — **видимый индикатор**. Политика прослушки на ACC-off + бюджет разряда — ◻️ домен B/hardware. ## 9. Зависимости -- **Вниз/вбок:** E (контекст машины), Connectivity (online LLM), PipeWire (`audio_in`/`audio_out`), - Settings, Shell (UI-интеграция, driver-distraction), security-privacy (mic-индикатор), - tech-stack (ONNX Runtime, llama.cpp), data-model (коды/сигналы для контекста). +- **Вниз/вбок:** E (контекст машины, `vehicle_read`+`GetDtcs` через прокси), **K** (GPS-скорость + для distraction v1), Connectivity (online LLM), **PipeWire** (`audio_in`/`audio_out` + + **loopback-tap выхода для AEC**), **Power/B** (гейт wake-word по ACC/sleep), Settings, Shell + (UI; политику distraction владеет Shell §7), security-privacy (mic-индикатор), tech-stack + (ONNX Runtime, `vosk`, llama.cpp), data-model (коды/сигналы/quality для контекста). ## 10. Открытые вопросы @@ -123,8 +142,10 @@ STT (Vosk/Silero, **офлайн**) · intent router · LLM backend (pluggable) - ◻️ **Barge-in** (прерывание TTS) — later. - ◻️ **Размер контекста:** машина + память + история → токены (особенно у офлайн-модели с маленьким окном); нужна обрезка/суммаризация. → реализация. -- ◻️ **Точность офлайн-STT в шуме:** приватность фиксирует офлайн-STT → критичен - **mic-массив** (beamforming/шумоподавление). → этот домен + [hardware.md](../contracts/hardware.md). +- ◻️ **AEC (эхоподавление):** подавление собственного TTS/медиа-выхода (loopback-ref из + PipeWire) — нужно для wake-word во время воспроизведения и barge-in; место (WirePlumber/ + filter-chain vs внутри ассистента). → этот домен + architecture (audio plane). +- ◻️ **Beamforming/денойз** (внешний шум салона): mic-массив; офлайн-STT фиксирован приватностью. → [hardware.md](../contracts/hardware.md). - ◻️ **Plugin-интенты как function-calling** (tool-use LLM) vs фразы — зависит от поддержки провайдером (у GigaChat/YandexGPT может быть ограничена). → реализация. - ◻️ **Обучение wake-word «Штурман»** (openWakeWord) — сбор данных/тренировка. → реализация. @@ -135,8 +156,10 @@ STT (Vosk/Silero, **офлайн**) · intent router · LLM backend (pluggable) | Решение | Выбор | Дата | |---------|-------|------| -| Пайплайн | wake→VAD→STT→router→(локальные/LLM)→TTS; ONNX Runtime | 2026-06-16 | -| LLM | provider-agnostic; online GigaChat/YandexGPT + offline llama.cpp; авто-fallback | 2026-06-16 | -| Контекст машины | live-снимок из E в системный промпт (killer-фича) | 2026-06-16 | +| Пайплайн | Mic→AEC→wake→VAD→STT→router→(локальные/LLM)→TTS; ONNX (Silero) + Vosk (Kaldi) | 2026-06-16 | +| LLM | provider-agnostic; online (v1) + офлайн-диалог (v3, llama.cpp); деградация UX в v1 | 2026-06-16 | +| Контекст-инъекция | только `quality=valid`, гейт по состоянию машины; `vehicle_read` через прокси | 2026-06-16 | | Память о водителе | локальные `.md` в приватном хранилище; не в облако без согласия | 2026-06-16 | | Локальные интенты | латентно-критичные — без LLM | 2026-06-16 | +| Wake-word | openWakeWord (Apache-2.0); Porcupine отвергнут (проприетарный, #12) | 2026-06-16 | +| Микрофон | wake-word по состояниям питания (не always-on), с Stage 2; AEC обязателен | 2026-06-16 | diff --git a/docs/principles.md b/docs/principles.md index b8a16cb..3419f01 100644 --- a/docs/principles.md +++ b/docs/principles.md @@ -34,7 +34,7 @@ ### 3. Offline-first - **Почему:** салон часто без сети (тоннели, глушь); ассистент не должен умолкать, навигация — теряться. -- **Как держим:** STT/TTS локальны; у ассистента офлайн-LLM фолбэк; карты офлайн; ключевые функции **деградируют, а не падают** без сети. +- **Как держим:** STT/TTS локальны; у ассистента офлайн-LLM фолбэк; карты офлайн; ключевые функции **деградируют, а не падают** без сети. *(Фазировка: STT/TTS-офлайн + локальные интенты держат принцип с v1; офлайн-**диалог** LLM — v3, см. домен D §5.)* ### 4. Изоляция и graceful degradation - **Почему:** устойчивость; падение одного компонента не должно ронять систему. diff --git a/docs/tech-stack.md b/docs/tech-stack.md index 8c7c8bb..b3dda6f 100644 --- a/docs/tech-stack.md +++ b/docs/tech-stack.md @@ -43,7 +43,7 @@ | **OS base** | Armbian/Debian (RK3588), ядро ближе к mainline | read-only rootfs + overlay | | **Init / lifecycle** | **systemd** | ядро; апы/плагины — App-Host | | **CAN/OBD (read-only)** | **SocketCAN** (крейт `socketcan`) | ELM327 на старте; `python-OBD` — только в симуляторе | -| **Wake-word** | openWakeWord / Porcupine | кастомная RU-фраза | +| **Wake-word** | **openWakeWord** | RU-фраза «Штурман»; Porcupine отвергнут (проприетарный, #12) | | **VAD** | Silero VAD | через ONNX Runtime | | **STT** | Vosk · Silero | офлайн, RU; через биндинги / `ort` | | **TTS** | Silero | офлайн, RU |