VEU.WathBody/1-docs/4-modules/m11-voice-input/readme.md

97 lines
9.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# m11-voice-input — план работ (d-dev)
> Модуль: VoiceInput — офлайн-STT (Vosk) + грамматика Ф-1.2 +
> TTS-подтверждения + интеграция в экран «Тренировка».
> Алгоритм: `std1\_rules\d\d-dev.md`. Требования:
> [module_reqs.md](module_reqs.md).
> Зависимости: m09 (WorkoutCore/LocalDb/SyncQueue — DONE), m10
> (экран «Тренировка», таймер отдыха, «Настройки» — DONE); часы — m12.
| Шаг | Что делаем | Статус |
|---|---|---|
| 0 | Модульные документы: module_reqs.md / readme.md / SKILL.md | ✅ 2026-10-19 |
| 1 | Список единиц (парсер/движок/модель/исполнитель/UI/тесты) | ✅ 2026-10-19 |
| 1.3 | **Пользователь!** утверждение списка (+ решения по объёму v1) | ✅ 2026-10-19 |
| 2 | Спецификации: api_specs (парсер, движок/модель, исполнитель, UI) | ✅ 2026-10-19 |
| 2.4 | **Пользователь!** утверждение спецификаций | ✅ 2026-10-19 |
| 3 | Реализация + тесты + сборка | ✅ 2026-10-19 |
| 3.4 | **Пользователь!** утверждение реализации (закрытие модуля) | ✅ 2026-10-19 |
| 4 | Завершение: план, примечания | ✅ 2026-10-19 |
Статусы: ⬜ не начат · 🔄 в работе · ✅ готов.
## Список единиц (шаг 1)
| # | Единица | Что делает |
|---|---|---|
| 1 | `VoiceCommandParser` (+ `NumberRu`) | чистая функция: текст → `VoiceCommand` (Approach/Weight/Rest/Rpe) или `Unknown`; числа словами 0–999 и цифрами, «с половиной» → +0,5; диапазоны Ф-1.2; semantics для журнала |
| 2 | `SttEngine`/`VoskEngine` | обёртка Vosk `SpeechService`: инициализация модели из `filesDir`, старт/стоп прослушивания, финальные гипотезы в колбэк; опциональный `setGrammar` (JSON-словарь); интерфейс — для тестов |
| 3 | `ModelStore` | загрузка zip модели по `Voice.ModelUrl` (OkHttp, уже в проекте), распаковка в `filesDir`, идемпотентность, статус (нет/загружена, МБ) |
| 4 | `VoiceCommandExecutor` | применение команды: Approach → `logSet(source=voice)`, Weight → рабочий вес экрана, Rest → старт таймера m10, Rpe → `WorkoutCore.setLastSetRpe`; журнал `logCommand` (принято/отклонено 🛡); будит SyncWorker |
| 5 | `TtsFeedback` | системный Android TTS (ru-RU) + ToneGenerator (щелчок/сигнал ошибки); деградация без TTS (текст на экране) |
| 6 | UI «Тренировка» | кнопка микрофона (toggle, индикатор «Слушаю…»), runtime-разрешение `RECORD_AUDIO`, строка последней команды, «текущее упражнение» (тап в блоке плана), рабочий вес от «Вес W» |
| 7 | UI «Настройки» | блок «Распознавание речи»: статус модели, «Загрузить», «Проверить TTS»; `Voice.ModelUrl` |
| 8 | `WorkoutCore.setLastSetRpe` | расширение m09 (errata, как `renameExercise` в m10): RPE последнего подхода + повторная отправка в sync |
| 9 | unit-тесты | парсер (4 команды × формы чисел, границы, мусор), NumberRu, исполнитель на фейках |
## Решения на гейт 1.3 (для владельца)
1. **Доставка модели Vosk** (~45 МБ, `vosk-model-small-ru-0.22`):
рекомендуем (а) — загрузка zip по https при первом включении
микрофона / из «Настроек» (`Voice.ModelUrl`, умолчание
alphacephei.com; можно указать свой сервер), модель живёт в
`filesDir`, в APK и репозиторий не входит. Альтернативы: (б) вшить
в APK assets (+45 МБ и бинарник в git); (в) ручной сайдлоад adb.
2. **Текущее упражнение для голоса** — выбор тапом в блоке плана
(умолчание — первый пункт плана); голосовой выбор упражнения по
имени в v1 отсутствует (имена произвольные, распознавание
ненадёжно). Форма ручного ввода m10 сохраняется (правка ≤ 2 касаний,
Ф-1.6).
3. **«РПЭ N»** — новый метод `WorkoutCore.setLastSetRpe` (расширение
m09 по образцу `renameExercise`: обновление строки + повторный
enqueue; сервер идемпотентен по client_guid).
4. **Грамматика Vosk** — `setGrammar` применяется при поддержке
моделью; обязательна строгая постобработка парсером (малые модели
не гарантируют грамматику; лишнее отклоняется по Ф-1.3).
5. **TTS** — системный Android TTS; на устройстве владельца должен
быть ru-голос (Google TTS); при отсутствии — деградация до
щелчка/сигнала + текст на экране.
## Примечания по ходу работ
1. **Состав реализации** (`app/src/main/java/com/watchbody/phone/voice/`):
`VoiceCommandParser.kt` (sealed VoiceCommand + NumberRu 0–999 + tokenize
с «эр пэ э»→«рпэ» + semantics), `VoskResult.kt` (разбор JSON Vosk),
`SttEngine.kt` (интерфейс + VoskEngine: грамматика-список слов с
откатом на свободный разбор, n-best 3), `ModelStore.kt` (zip→filesDir,
zip-slip, single-root срезка, no-op при готовой модели),
`VoiceCommandExecutor.kt` (VoiceCoreGateway/эффекты/отклонения),
`TtsFeedback.kt` (TTS ru + ToneGenerator BEEP/NACK, деградация).
Расширения: `WorkoutCore.setLastSetRpe` + DAO `lastSet` (m09),
`AppSettings.voiceModelUrl` + валидатор https (m10), контейнер
(modelStore/ttsFeedback), WorkoutScreen (Mic-кнопка, RECORD_AUDIO,
диалог модели, «текущее упражнение» тапом в плане, строка голоса),
SettingsScreen (блок «Распознавание речи»: URL/статус/загрузка/
«Проверить TTS»), манифест RECORD_AUDIO, gradle: vosk-android
0.3.47 + icons-extended + MockWebServer (test).
2. **Сборка/тесты**: BUILD SUCCESSFUL; APK 57,3 МБ (рост с 12 МБ —
JNI Vosk по 4 ABI + icons-extended; debug без минификации — release
c R8/abiFilters сожмёт, кандидат оптимизации); unit **63/63**
(m09 18 + m10 18 + m11 27: парсер 9, исполнитель 10, модель+валидатор 8).
3. **Живой URL модели проверен** (2026-10-19): alphacephei.com →
200 OK, 46 236 750 байт (~44 МБ) — умолчание `Voice.ModelUrl` рабочее.
4. **Errata API vosk-android 0.3.47** (вскрыты компиляцией, spec 02
скорректирован по факту): `SpeechService` управляется `stop()`/
`shutdown()` (stopListening/destroy нет); `RecognitionListener` —
5 методов, команды приходят в `onResult` (onFinalResult — при
остановке); сигнал ошибки — `TONE_PROP_NACK` (TONE_PROP_ERR нет).
5. **Решения по ходу**: парсер в approach при out_of_range пишет ОБА
значения ({"weight_kg":100.0,"reps":101} — информативнее для разбора
журнала); `syncRequest`_executor срабатывает после ЛЮБОЙ журналируемой
команды (журнал отклонённых тоже уходит в sync; spec 03 п.8 уточнён
по смыслу); инициализация Model Vosk — в Dispatchers.IO (не main).
6. **Не проверено в среде** (нет устройства/микрофона): живое
распознавание, TTS-озвучка, щелчки/сигналы, загрузка модели на
устройстве, точность КУ-1 — критерии 2/4 приёмки на стороне
владельца; сетевой контур модели проверен MockWebServer + живым URL.