voice: локальный агент (fast-path), tool control_light, смелая тема, RUNBOOK
All checks were successful
Deploy / deploy (push) Successful in 3m43s
All checks were successful
Deploy / deploy (push) Successful in 3m43s
- lib/agent-local.ts + route.ts: команды-действия исполняет локальная intent-служба (под AGENT_URL, с fallback на LLM); инфо-запросы остаются у LLM - lib/tools/lights.ts: голосовое управление светом через HA (control_light) - app/globals.css + page.tsx: космическая indigo/aurora тема (токены, kiosk-safe) - agent/: sidecar-служба (Dockerfile, predict.py), веса монтируются томом - RUNBOOK.md: вывод в продакшен на мини-ПК
This commit is contained in:
213
RUNBOOK.md
Normal file
213
RUNBOOK.md
Normal file
@@ -0,0 +1,213 @@
|
||||
# RUNBOOK — вывод голосового помощника в продакшен
|
||||
|
||||
Пошаговая инструкция, чтобы всё завелось на мини-ПК (где развёрнут
|
||||
`https://tablet.digital-home.site`). Рассчитана на то, что её выполняет
|
||||
Claude-сессия **на мини-ПК** (`cosmo@192.168.31.60`), с пометками, что делается
|
||||
на рабочей машине (Windows), а что — на мини-ПК.
|
||||
|
||||
## TL;DR — что это добавляет
|
||||
|
||||
1. **Локальный агент (intent+slots)** — sidecar-служба, распознаёт команды
|
||||
офлайн за ~2 мс и исполняет действия (таймеры, свет, музыка, очиститель),
|
||||
минуя облачный LLM. Инфо-запросы (погода/календарь) по-прежнему у LLM.
|
||||
Модель обучена: **интент 40/40, слоты 40/40**.
|
||||
2. **Голосовое управление светом** — новый tool `control_light` (2 лампы).
|
||||
3. **Смелый визуал** — обновлённая тема (космический индиго/aurora), деплоится
|
||||
с обычным билдом.
|
||||
4. **Wake «Эй, космо»** — пайплайн переобучения готов и проверен end-to-end;
|
||||
боевая модель требует досбора данных (см. раздел D).
|
||||
|
||||
Всё под фиче-флагами: без `AGENT_URL` планшет работает ровно как раньше →
|
||||
безопасно для kiosk.
|
||||
|
||||
---
|
||||
|
||||
## Изменения в репозитории (уже в коде)
|
||||
|
||||
| Файл | Что |
|
||||
|---|---|
|
||||
| `lib/tools/lights.ts` | новый tool `control_light` (свет через HA) |
|
||||
| `lib/tools/_registry.ts` | регистрация `control_light` |
|
||||
| `lib/agent-local.ts` | быстрый путь: вызов агент-службы + исполнение действий |
|
||||
| `app/api/voice/chat/route.ts` | вставка fast-path (под `AGENT_URL`, с fallback) |
|
||||
| `app/globals.css`, `app/page.tsx` | смелый визуал (токены/aurora) |
|
||||
| `agent/` | sidecar агента: `Dockerfile`, `predict.py`, `joint_model_def.py`, `tablet_map.py`, `requirements.txt` |
|
||||
|
||||
⚠️ **Эти изменения надо закоммитить и запушить** (с рабочей машины), чтобы мини-ПК
|
||||
их подтянул `git pull`. Веса моделей в git НЕ идут (переносятся отдельно, ниже).
|
||||
|
||||
---
|
||||
|
||||
## Архитектура продакшена
|
||||
|
||||
```
|
||||
Планшет (Android, kiosk-браузер)
|
||||
├─ wake «Эй, космо» (public/wake/cosmo.onnx, WASM) ─┐
|
||||
└─ UI (Next.js) │
|
||||
▼
|
||||
tablet-контейнер (мини-ПК, network coolify) ── /api/voice/chat
|
||||
│ fast-path: AGENT_URL задан?
|
||||
│ ├─ да → POST http://tablet-agent:8091/predict
|
||||
│ │ интент-действие + score≥0.7 → executeTool → короткий ответ
|
||||
│ └─ нет/инфо/none → облачный LLM (Anthropic/Groq) как раньше
|
||||
▼
|
||||
tablet-agent-контейнер (sidecar, network coolify)
|
||||
└─ predict.py --serve (joint_model смонтирован томом)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## A. Агент (sidecar) — главный шаг
|
||||
|
||||
### A1. Перенести модель на мини-ПК (с рабочей машины)
|
||||
|
||||
Веса `joint_model/` (~115 МБ) в git нет. Скопировать на мини-ПК:
|
||||
|
||||
```bash
|
||||
# на рабочей машине (Windows, Git Bash):
|
||||
scp -i ~/.ssh/id_ed25519 -r "/d/Digital home/tablet-agent/joint_model" \
|
||||
cosmo@192.168.31.60:/opt/digital-home/agent-model
|
||||
```
|
||||
|
||||
Должно получиться `/opt/digital-home/agent-model/joint.pt` (+ tokenizer, config).
|
||||
|
||||
> Переобучить модель заново (если правил `tablet-agent/templates.txt`):
|
||||
> `cd tablet-agent && python train_joint.py && python test_joint.py`, затем scp.
|
||||
|
||||
### A2. Собрать и запустить sidecar (на мини-ПК)
|
||||
|
||||
```bash
|
||||
cd /opt/digital-home/smart-home-tablet
|
||||
git pull origin main # подтянуть код (после пуша с рабочей машины)
|
||||
|
||||
docker build -t tablet-agent:latest ./agent
|
||||
docker rm -f tablet-agent || true
|
||||
docker run -d --name tablet-agent \
|
||||
--network coolify \
|
||||
--restart unless-stopped \
|
||||
-v /opt/digital-home/agent-model:/app/joint_model \
|
||||
tablet-agent:latest
|
||||
|
||||
# проверка службы:
|
||||
docker exec tablet-agent python -c "import urllib.request,json; \
|
||||
r=urllib.request.urlopen(urllib.request.Request('http://127.0.0.1:8091/predict', \
|
||||
data=json.dumps({'text':'поставь таймер на 5 минут'}).encode(), \
|
||||
headers={'Content-Type':'application/json'})); print(r.read().decode())"
|
||||
# ждём: {"intent":"timer_set","slots":{"duration":"5 минут"},"score":...,"tool":{...}}
|
||||
```
|
||||
|
||||
### A3. Включить fast-path в планшете
|
||||
|
||||
Добавить в `/opt/digital-home/tablet.env`:
|
||||
|
||||
```
|
||||
AGENT_URL=http://tablet-agent:8091
|
||||
AGENT_THRESHOLD=0.7
|
||||
```
|
||||
|
||||
Пере-задеплоить планшет (push любой коммит ИЛИ вручную пере-`docker run` по
|
||||
`deploy.yml`). После рестарта `route.ts` увидит `AGENT_URL` и начнёт использовать
|
||||
агента.
|
||||
|
||||
> Откат агента: убрать `AGENT_URL` из `tablet.env`, пере-деплой. Мгновенно вернёт
|
||||
> облачный LLM на все команды. Контейнер `tablet-agent` можно оставить.
|
||||
|
||||
---
|
||||
|
||||
## B. Свет — реальные entity Home Assistant
|
||||
|
||||
`control_light` по умолчанию шлёт на `light.bedside` / `light.reading` (заглушки).
|
||||
Указать реальные entity_id твоих ламп в `/opt/digital-home/tablet.env`:
|
||||
|
||||
```
|
||||
LIGHT_ENTITIES_JSON={"bedside":"light.ВАШ_СВЕТ_У_КРОВАТИ","reading":"light.ВАША_ЛАМПА_ДЛЯ_ЧТЕНИЯ","default":"light.ВАШ_СВЕТ_У_КРОВАТИ"}
|
||||
```
|
||||
|
||||
Найти id ламп: HA → Developer Tools → States, отфильтровать `light.`. Ключи
|
||||
`bedside`/`reading` соответствуют фразам «свет у кровати» / «лампа для чтения»
|
||||
(маппинг в `lib/tools/lights.ts`, `DEVICE_ALIASES`). Пере-деплой планшета.
|
||||
|
||||
Без этой переменной команды света пройдут как mock (HA вернёт success, лампа не
|
||||
переключится) — то есть безопасно, но не управляет реальным светом.
|
||||
|
||||
---
|
||||
|
||||
## C. Дизайн (смелый визуал)
|
||||
|
||||
Ничего дополнительно — тема живёт в `app/globals.css` (токены) и деплоится
|
||||
обычным билдом. Раскладка/логика не менялись, kiosk не затронут. Если визуал не
|
||||
зайдёт — откат = `git revert` коммита с globals.css.
|
||||
|
||||
---
|
||||
|
||||
## D. Wake «Эй, космо» — статус и деплой
|
||||
|
||||
Проект `tablet-wake` (на рабочей машине). Пайплайн переобучения **готов и
|
||||
проверен end-to-end**: smoke-модель разделяет фразу (pos 0.96 / neg 0.01) через
|
||||
тот же WASM-рантайм, что у планшета. Но это **не боевая модель** — нужен досбор
|
||||
данных:
|
||||
|
||||
1. Реальная речь в негативах (корпус Golos) — главный убийца ложняков.
|
||||
2. Фон Android-мика (запись, где планшет стоит).
|
||||
3. Held-out тест своим голосом + подбор порога.
|
||||
|
||||
Полный прогон (на рабочей машине) — см. `tablet-wake/README.md`. Итог —
|
||||
`tablet-wake/out/cosmo.onnx`.
|
||||
|
||||
**Деплой wake-модели** (когда готова): заменить файл в репозитории и запушить —
|
||||
инференс планшета НЕ меняется (окно 25 сохранено), только веса:
|
||||
|
||||
```bash
|
||||
# на рабочей машине:
|
||||
cp "/d/Digital home/tablet-wake/out/cosmo.onnx" \
|
||||
"/d/Digital home/smart-home-tablet/public/wake/cosmo.onnx"
|
||||
# затем commit + push → Gitea пересоберёт планшет
|
||||
```
|
||||
|
||||
Порог срабатывания подстраивается в клиенте (`WAKE_THRESHOLD` в
|
||||
`components/VoiceController.tsx`). Также обнови фразу-подпись в UI: сейчас
|
||||
«Космо» → «Эй, космо».
|
||||
|
||||
---
|
||||
|
||||
## Сводка новых переменных `tablet.env`
|
||||
|
||||
```
|
||||
AGENT_URL=http://tablet-agent:8091 # включает локального агента
|
||||
AGENT_THRESHOLD=0.7 # порог уверенности (опц.)
|
||||
LIGHT_ENTITIES_JSON={"bedside":"...","reading":"...","default":"..."}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Проверка (после деплоя)
|
||||
|
||||
```bash
|
||||
# планшет жив:
|
||||
curl -sk -o /dev/null -w "%{http_code}\n" https://tablet.digital-home.site/
|
||||
|
||||
# агент отвечает изнутри сети:
|
||||
docker exec tablet-yfh53kixpwkjlo4zibglx4n2 \
|
||||
wget -qO- --post-data='{"text":"выключи свет у кровати"}' \
|
||||
--header='Content-Type: application/json' http://tablet-agent:8091/predict
|
||||
|
||||
# логи планшета: fast-path пишет "[voice/chat] local-agent intent=..."
|
||||
docker logs --tail 50 tablet-yfh53kixpwkjlo4zibglx4n2 | grep local-agent
|
||||
```
|
||||
|
||||
Живой тест голосом: сказать «поставь таймер на 5 минут» (действие → агент,
|
||||
мгновенно), затем «какая погода» (инфо → LLM). В логах у первой команды —
|
||||
`local-agent`, у второй — обычный LLM-раунд.
|
||||
|
||||
---
|
||||
|
||||
## Откат всего
|
||||
|
||||
| Что | Откат |
|
||||
|---|---|
|
||||
| Агент | убрать `AGENT_URL` из `tablet.env`, пере-деплой |
|
||||
| Свет | убрать `control_light` из `_registry.ts` ИЛИ просто не задавать `LIGHT_ENTITIES_JSON` |
|
||||
| Дизайн | `git revert` коммита globals.css |
|
||||
| Wake | вернуть прежний `public/wake/cosmo.onnx` из git-истории |
|
||||
|
||||
Каждая часть независима — можно катить и откатывать по отдельности.
|
||||
Reference in New Issue
Block a user