# Требования к модулю: 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); автоматизации не подлежит, фиксируется в журнале приёмки.