97 lines
9.0 KiB
Markdown
97 lines
9.0 KiB
Markdown
# 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.
|