133 lines
12 KiB
Markdown
133 lines
12 KiB
Markdown
# Требования к модулю: m11-voice-input
|
||
|
||
> Модуль — **VoiceInput** телефона `Phone.WatchBody` (архитектура
|
||
> разд. 1.2): офлайн-STT Vosk + грамматика команд Ф-1.2 + TTS-подтверждения
|
||
> + интеграция в экран «Тренировка» (m10) поверх ядра m09. Самодостаточная
|
||
> копия требований (d-dev-6). Источники: Ф-1, Ф-3.3 (таймер), Ф-13.3
|
||
> («РПЭ N»), открытый вопрос 2 (закрыт шагом 5: Vosk, малая ru-модель,
|
||
> TTS — системный Android), tech-req 4.1/5 (`VoiceInput`, модель ~50 МБ,
|
||
> постобработка чисел), 7 п. 3 (прототип точности), ui-ux разд. 3.
|
||
|
||
## 1. Назначение и границы
|
||
|
||
Голосовой офлайн-учёт подходов: атлет на экране активной тренировки
|
||
включает микрофон и говорит команды; команды разбираются офлайн,
|
||
применяются к текущей тренировке и журналируются (🛡 Ф-1.5).
|
||
|
||
**В границах модуля:**
|
||
|
||
- **грамматика команд Ф-1.2** (разбор — чистая функция):
|
||
- «Подход **W** на **R**» → подход: вес `W` кг × `R` повторений
|
||
(вес — целые кг либо «…с половиной» → +0,5 кг; `W` — 0–500,
|
||
`R` — 1–100; решение владельца О-2-Б);
|
||
- «Вес **W**» → рабочий вес `W` кг для следующих подходов;
|
||
- «Отдых **S** (секунд)» → таймер отдыха `S` секунд (5–600);
|
||
- «РПЭ **N**» → RPE последнего подхода, `N` — 1–10 (Ф-13.3);
|
||
- числа — словами («сто двадцать») и цифрами («120»); слова «секунд»
|
||
после `S` — необязательны; постобработка «сто двадцать» → 120 —
|
||
tech-req 5;
|
||
- команда вне грамматики или число вне диапазона — **отклоняется**:
|
||
короткий сигнал ошибки, состояние не меняется, в журнал пишется
|
||
распознанный текст с `accepted=false` (Ф-1.3);
|
||
- **STT-движок**: Vosk (`com.alphacephei:vosk-android`), малая
|
||
русская модель (`vosk-model-small-ru-0.22`, ~45 МБ); распознавание
|
||
только офлайн — сеть не используется (Ф-1.1, ОВ-2); ограничение
|
||
словаря грамматикой Vosk (`setGrammar`, JSON-словарь: «подход», «вес»,
|
||
«отдых», «на», «секунд», «с половиной», числительные 0–999) —
|
||
применяется, если модель поддерживает; обязательна строгая
|
||
постобработка финальной гипотезы парсером (малые модели Vosk не
|
||
гарантируют поддержку грамматики — деградация до свободного
|
||
распознавания, лишнее отклоняет парсер по Ф-1.3);
|
||
- **доставка модели**: модель НЕ входит в APK и в репозиторий;
|
||
загружается zip-архивом по https в папку приложения при первом
|
||
включении микрофона (или из «Настроек»), распаковывается в
|
||
`filesDir`; URL — настройка `Voice.ModelUrl` (умолчание — официальный
|
||
хост alphacephei.com); статус модели и кнопка «Загрузить» — в
|
||
«Настройках» (решение гейта 1.3);
|
||
- **применение команд** (исполнитель): «Подход» → `WorkoutCore.logSet`
|
||
(source=`voice`, текущее упражнение экрана); «Вес» → рабочий вес
|
||
текущего упражнения (состояние экрана, умолчание формы); «Отдых» →
|
||
старт таймера отдыха (переиспользуется таймер m10); «РПЭ» → RPE
|
||
последнего подхода тренировки (`WorkoutCore.setLastSetRpe` —
|
||
расширение m09, как `renameExercise` в m10);
|
||
- **журнал команд 🛡** (Ф-1.5): каждая команда — принятая и отклонённая —
|
||
через `WorkoutCore.logCommand` (текст, семантика, `t_offset_s` от
|
||
начала тренировки, `accepted`); журнал не редактируется; уходит sync
|
||
`command_log` (контракт m09 spec 04);
|
||
- **подтверждения** (Ф-1.4): принятая команда — короткий «щелчок»
|
||
(ToneGenerator) + голосовое TTS-подтверждение офлайн («Принято,
|
||
подход 120 на 8» / «…вес 100» / «…отдых 90 секунд» / «…РПЭ 8»);
|
||
TTS — системный Android TTS (ru-RU, tech-req 4.1); при отсутствии
|
||
TTS-движка/русского голоса — деградация: щелчок/сигнал + текст
|
||
подтверждения на экране, работа не блокируется;
|
||
- **активация** (Ф-1.1): кнопка микрофона на экране «Тренировка»;
|
||
повторное нажатие выключает прослушивание; прослушивание активно,
|
||
пока открыт экран активной тренировки и микрофон включён — выход
|
||
с экрана останавливает; разрешение `RECORD_AUDIO` запрашивается
|
||
при первом включении (runtime);
|
||
- **текущее упражнение**: голос пишет подходы в «текущее упражнение»
|
||
экрана «Тренировка» — выбор тапом в блоке плана (подсветка),
|
||
умолчание — первый пункт плана сессии дня, иначе последнее
|
||
введённое вручную; голосовой выбор упражнения по имени в v1
|
||
отсутствует (имена произвольные — распознавание ненадёжно;
|
||
решение гейта 1.3);
|
||
- **экран «Тренировка»**: индикатор «слушаю/выключено» (иконка +
|
||
текст 🛡), строка последней команды (принято/отклонено — текстом,
|
||
не только цветом), «Вес W» меняет отображаемый рабочий вес;
|
||
- **«Настройки»** (расширение m10): блок «Распознавание речи» — статус
|
||
модели (не загружена / загружена, размер), кнопка «Загрузить»
|
||
(по `Voice.ModelUrl`, прогресс/ошибка текстом), «Проверить TTS» —
|
||
наличие ru-голоса;
|
||
- unit-тесты (pure JVM): парсер (4 команды, числа словами 0–999
|
||
и цифрами, «с половиной», границы диапазонов, мусор, регистр),
|
||
семантика журнала, NumberRu; исполнитель — на фейках ядра.
|
||
|
||
**Вне границ модуля:** wake-word (опросник 4.5 — v2), голосовой выбор
|
||
упражнения по имени (v1 нет — решение гейта), распознавание на часах,
|
||
запись аудио (только живой поток в движок, хранения нет), шумовой
|
||
профиль зала, метрики точности в БД (КУ-1 фиксируется вручную
|
||
владельцем), m12 канал часов, m13 поле данных.
|
||
|
||
## 2. Решения интерфейса (ui-ux разд. 3, tech-req 6)
|
||
|
||
- Кнопка микрофона — нижняя треть экрана, цель ≥ 48 dp, состояние
|
||
дублируется текстом («Слушаю…» / «Голос выключен»);
|
||
- строка последней команды — текстом: «Принято: подход 120 на 8» /
|
||
«Не распознано» (цвет — только дублирование);
|
||
- сигнал ошибки — короткий, не пугающий; формулировки спокойные;
|
||
- TTS-подтверждения короткие (≤ 3–4 слов + числа).
|
||
|
||
## 3. Инварианты (🛡 — нарушать запрещено)
|
||
|
||
1. **Офлайн-first** (Ф-1.1, КУ-3): распознавание и применение команд
|
||
работают без сети; сеть — только доставка модели (один раз) и
|
||
SyncQueue как обычно.
|
||
2. **Журнал команд полон и неизменяем** (Ф-1.5): каждая распознанная
|
||
фраза (принятая и отклонённая) фиксируется с исходным текстом,
|
||
семантикой и `t_offset_s`; удаление/правка журнала невозможны.
|
||
3. **Голос не обходит ядро**: применение команд — только через
|
||
`WorkoutCore` (единственный писатель LocalDb, инвариант m09);
|
||
`VoiceInput` не пишет в БД напрямую.
|
||
4. **Допуск Safety не снимается голосом**: команды работают только
|
||
в уже начатой (допущенной) тренировке; блокировки допуска —
|
||
контур m09/m10.
|
||
5. **Тайны**: `Voice.ModelUrl` может содержать URL сервера владельца —
|
||
ключи/пароли в неё не попадают; API-ключ не логируется (З-6).
|
||
|
||
## 4. Критерии приёмки модуля
|
||
|
||
1. `assembleDebug` собирается; unit-тесты парсера/исполнителя зелёные.
|
||
2. Ручной смок на устройстве владельца (модель загружена): включить
|
||
микрофон → «Подход 60 на 10» → щелчок + «Принято, подход 60 на 10»
|
||
→ подход записан (источник «голос», метка плана); «Вес 62
|
||
с половиной» → рабочий вес 62,5; «Отдых 90» → таймер; «РПЭ 7» →
|
||
RPE у последнего подхода; фраза вне грамматики → сигнал ошибки,
|
||
состояние не изменилось, в журнале `accepted=false`.
|
||
3. Смок синхронизации (живой docker-сервер): журнал команд уходит
|
||
`command_log`-пакетом, строка в `src.command_log` содержит текст
|
||
и семантику.
|
||
4. КУ-1 (контрольная тренировка ≥ 4 упражнений, ≥ 16 подходов,
|
||
≥ 90 % команд с первого раза) — ручная приёмка владельца в зале
|
||
(tech-req 7 п. 3); автоматизации не подлежит, фиксируется
|
||
в журнале приёмки.
|