view-mate: болванка + концепт + эскизы + сценарии (единый коммит, история очищена от hprof/build)

This commit is contained in:
Hermes Agent
2026-08-11 11:34:50 +03:00
commit 5268a12d20
25 changed files with 1234 additions and 0 deletions
+123
View File
@@ -0,0 +1,123 @@
# ViewMate
Очки RayNeo X2 + компаньон на телефон: кино и чат с ассистентом.
## Структура
```
app-glasses/ RayNeo X2 — AR-приложение: видео (ExoPlayer), жесты, связь по WiFi
app-phone/ компаньон на телефон — каталог, дубль-управление, чат
app-host/ отладочный хост — «бэк» без UI, к которому цепляются очки
lib-core/ общий слой (KMP): режимы, состояния, команды, DTO
sketches/ эскизы UI: раскладка экранов + сценарии использования
```
## Эскизы интерфейса
- `sketches/phone-ui/index.html` — эскизы 4 экранов телефона (раскладка компонентов, открыть в браузере)
- `sketches/phone-ui/preview.png` — скриншот эскизов
- `sketches/phone-ui/FLOW.md` — **сценарии использования**: как посмотреть фильм, проверить очки, поговорить с ассистентом, что видно при не-сконвертированном/частично скачанном контенте
## Режимы
### Два режима на очках
| Режим | Состояния | Что происходит |
|-------|-----------|----------------|
| **MOVIE** (кино) | `PLAYING`, `PAUSED` | видео на очках (ExoPlayer), звук выбранной дорожки на телефоне, синхронизация по позиции |
| **CHAT** (общение) | `SESSION_SELECT`, `TALKING` | выбор сессии Hermes, затем разговор в рамках сессии |
Переключение режимов — **с телефона** (и жестом на очках). Оба дёргают один локальный агент (lib-core).
### Каталог — НЕ режим очков
Каталог контента (Jellyfin) живёт **только на телефоне** (и в будущем — у голосового ассистента, который тоже будет по нему ходить). Выбрал в каталоге → «включить» → очки переходят в режим MOVIE с готовым контентом.
Очки — «экран кинотеатра»: они ждут, когда им скажут «включи», и не листают каталог сами.
### Локальный голосовой ассистент (в будущем)
Вызывается **в любом режиме** (двойной клик в чате), поверх всего. Умеет: ходить по каталогу, включать/ставить кино, переключать режимы, переключать сессии, отвечать на вопросы (локально, без сервера).
## Жесты (распознаёт RayNeo SDK, `TempleAction`)
| Жест (SDK) | Режим КИНО | Режим ЧАТ |
|------------|-----------|-----------|
| `Click` | пауза ↔ плей | старт / стоп диктовки |
| `DoubleClick` | игнор | отмена диктовки; вне диктовки — вызов локального ассистента |
| `SlideBackward` / `SlideForward` | перемотка | в `SESSION_SELECT` — листание сессий; в `TALKING` — скролл текста ответа |
| `LongClick` | (резерв) | показать / спрятать текст последнего ответа |
| `TripleClick` | (резерв) | (резерв) |
> Жесты распознаёт сам SDK (`TempleAction.Click/DoubleClick/TripleClick/SlideBackward/SlideForward/LongClick`) — своя детекция не нужна (проверено в pair-view, `MainActivity.kt`).
## Состояния ассистента (единые для обоих ассистентов)
```
IDLE ──► LISTENING ──► THINKING ──► SPEAKING ──► IDLE
(слушает) (думает) (говорит)
```
| Состояние | Индикатор |
|-----------|-----------|
| IDLE | ничего |
| LISTENING | красная точка ● мигает + время записи (0:07, 0:23…) |
| THINKING | спиннер / точки «думает» |
| SPEAKING | «говорит» (другим цветом / без мигания) |
Один и тот же индикатор для Порфирия и локального ассистента — очкам неважно, кто за ним стоит.
## Панель индикаторов
**Всегда видна, по центру снизу.** Содержимое меняется от режима:
| Режим/состояние | Содержимое панели |
|-----------------|-------------------|
| КИНО | `просмотрено / осталось` (12:34 / 56:00) + 🔋 батарея + ⏰ часы |
| ЧАТ, диктовка | `● 0:07` (красная точка + время записи) + 🔋 + ⏰ |
| ЧАТ, думает/говорит | индикатор состояния (⏳/🔊) + 🔋 + ⏰ |
| **Потеря связи с телефоном** | **вместо времени — «связь потеряна» (⚠️)** + 🔋 |
- Часы — **время очков** (часы очков, просто время)
- Батарея — очков
- Просмотрено/осталось — из `PlaybackState` (positionMs/durationMs)
- Если связи с телефоном нет — панель показывает ⚠️ вместо времени (см. Автоматика)
## Текст ответа на экране
Длинные ответы можно показать текстом (по `LongClick`) и скроллить свайпами. Полезно, когда ответ многословный — перечитать спокойно.
## Автоматика
| Событие | Действие |
|---------|----------|
| Очки выключились / экран погас | **пауза** (видео и аудио) |
| Потеря связи очки ↔ телефон (WiFi) | **пауза** (и на очках, и на телефоне) + на панели ⚠️ «связь потеряна» вместо времени |
| Связь восстановилась | продолжить с того же места, панель — как обычно |
## Связь и поток
```
очки (RayNeo X2) телефон (компаньон) сервер
┌─────────────────┐ ┌──────────────────┐
│ режимы: │ │ каталог Jellyfin │ Jellyfin
│ MOVIE/CHAT │◄──WiFi────►│ статусы зеркал │──media-mirror API──► координатор
│ жест = switch │ │ заказ конвертации │ → воркеры → S3
│ видео ExoPlayer │ │ переключение │
│ │ │ режимов очков │
│ │ │ чат с Hermes │──assistent/chat──► Hermes API
└─────────────────┘ └──────────────────┘ → TTS → в ухо
```
- **Один локальный агент** (на телефоне) — очки и телефон два рендера одного состояния
- **WiFi-связь** очки ↔ телефон (вместо Bluetooth в старом pair-view)
- **Кино**: видео 480p H.264 из S3 (media-mirror) на очках, звук выбранной дорожки на телефоне, синхронизация по позиции (очки — мастер, телефон подстраивает аудио)
- **Чат**: с Hermes через сервер; медиа-интенты («включи сериал X») — напрямую в media-mirror API, без LLM
## Медиа-конвейер (внешний, уже живой)
- Координатор: `https://mirror.binom.pw` (X-API-Key) — заказ конвертации, статусы, файлы
- Формат зеркала: `video.mkv` (H.264/NVENC, 480p, без звука) + `audio-N.ogg` (все дорожки, мета title/language)
- S3: `https://s3.binom.pw`, bucket `media`, ключи `mirror/{itemId}/...`; клиентский ключ (read-only) — в конфиге
Полное описание API: `media-mirror-api/README.md` (https://git.binom.pw/subochev/media-mirror-api).