VEU.WathBody/1-docs/4-modules/m11-voice-input
virus-home 28445f28b9 m11-voice-input (итерация 5): голосовой офлайн-учёт Ф-1 — Vosk-STT (грамматика-список слов + fallback на свободный разбор, n-best 3), парсер Ф-1.2 (NumberRu 0–999 словами/цифрами, «с половиной» → +0,5 кг только у веса, «эр пэ э»→«рпэ», Rejected out_of_grammar/out_of_range), executor через WorkoutCore 🛡 + журнал каждой команды (Ф-1.5), TTS-подтверждения + сигналы BEEP/NACK, Mic-кнопка (RECORD_AUDIO runtime, диалог загрузки модели ~44 МБ alphacephei → filesDir, не в APK/репо), «текущее упражнение» тапом в плане, блок «Распознавание речи» в настройках (URL/статус/загрузка/Проверить TTS); расширения: WorkoutCore.setLastSetRpe + DAO lastSet (m09), AppSettings.voiceModelUrl + https-валидатор (m10); unit 63/63 (m11 — 27), APK 57,3 МБ (vosk JNI ×4 ABI); errata vosk-android 0.3.47 (stop/shutdown, onResult/onFinalResult, TONE_PROP_NACK); распознавание на устройстве — приёмка владельца, КУ-1 вручную 2026-10-19 10:37:51 +05:00
..
api_specs m11-voice-input (итерация 5): голосовой офлайн-учёт Ф-1 — Vosk-STT (грамматика-список слов + fallback на свободный разбор, n-best 3), парсер Ф-1.2 (NumberRu 0–999 словами/цифрами, «с половиной» → +0,5 кг только у веса, «эр пэ э»→«рпэ», Rejected out_of_grammar/out_of_range), executor через WorkoutCore 🛡 + журнал каждой команды (Ф-1.5), TTS-подтверждения + сигналы BEEP/NACK, Mic-кнопка (RECORD_AUDIO runtime, диалог загрузки модели ~44 МБ alphacephei → filesDir, не в APK/репо), «текущее упражнение» тапом в плане, блок «Распознавание речи» в настройках (URL/статус/загрузка/Проверить TTS); расширения: WorkoutCore.setLastSetRpe + DAO lastSet (m09), AppSettings.voiceModelUrl + https-валидатор (m10); unit 63/63 (m11 — 27), APK 57,3 МБ (vosk JNI ×4 ABI); errata vosk-android 0.3.47 (stop/shutdown, onResult/onFinalResult, TONE_PROP_NACK); распознавание на устройстве — приёмка владельца, КУ-1 вручную 2026-10-19 10:37:51 +05:00
SKILL.md m11-voice-input (итерация 5): голосовой офлайн-учёт Ф-1 — Vosk-STT (грамматика-список слов + fallback на свободный разбор, n-best 3), парсер Ф-1.2 (NumberRu 0–999 словами/цифрами, «с половиной» → +0,5 кг только у веса, «эр пэ э»→«рпэ», Rejected out_of_grammar/out_of_range), executor через WorkoutCore 🛡 + журнал каждой команды (Ф-1.5), TTS-подтверждения + сигналы BEEP/NACK, Mic-кнопка (RECORD_AUDIO runtime, диалог загрузки модели ~44 МБ alphacephei → filesDir, не в APK/репо), «текущее упражнение» тапом в плане, блок «Распознавание речи» в настройках (URL/статус/загрузка/Проверить TTS); расширения: WorkoutCore.setLastSetRpe + DAO lastSet (m09), AppSettings.voiceModelUrl + https-валидатор (m10); unit 63/63 (m11 — 27), APK 57,3 МБ (vosk JNI ×4 ABI); errata vosk-android 0.3.47 (stop/shutdown, onResult/onFinalResult, TONE_PROP_NACK); распознавание на устройстве — приёмка владельца, КУ-1 вручную 2026-10-19 10:37:51 +05:00
module_reqs.md m11-voice-input (итерация 5): голосовой офлайн-учёт Ф-1 — Vosk-STT (грамматика-список слов + fallback на свободный разбор, n-best 3), парсер Ф-1.2 (NumberRu 0–999 словами/цифрами, «с половиной» → +0,5 кг только у веса, «эр пэ э»→«рпэ», Rejected out_of_grammar/out_of_range), executor через WorkoutCore 🛡 + журнал каждой команды (Ф-1.5), TTS-подтверждения + сигналы BEEP/NACK, Mic-кнопка (RECORD_AUDIO runtime, диалог загрузки модели ~44 МБ alphacephei → filesDir, не в APK/репо), «текущее упражнение» тапом в плане, блок «Распознавание речи» в настройках (URL/статус/загрузка/Проверить TTS); расширения: WorkoutCore.setLastSetRpe + DAO lastSet (m09), AppSettings.voiceModelUrl + https-валидатор (m10); unit 63/63 (m11 — 27), APK 57,3 МБ (vosk JNI ×4 ABI); errata vosk-android 0.3.47 (stop/shutdown, onResult/onFinalResult, TONE_PROP_NACK); распознавание на устройстве — приёмка владельца, КУ-1 вручную 2026-10-19 10:37:51 +05:00
readme.md m11-voice-input (итерация 5): голосовой офлайн-учёт Ф-1 — Vosk-STT (грамматика-список слов + fallback на свободный разбор, n-best 3), парсер Ф-1.2 (NumberRu 0–999 словами/цифрами, «с половиной» → +0,5 кг только у веса, «эр пэ э»→«рпэ», Rejected out_of_grammar/out_of_range), executor через WorkoutCore 🛡 + журнал каждой команды (Ф-1.5), TTS-подтверждения + сигналы BEEP/NACK, Mic-кнопка (RECORD_AUDIO runtime, диалог загрузки модели ~44 МБ alphacephei → filesDir, не в APK/репо), «текущее упражнение» тапом в плане, блок «Распознавание речи» в настройках (URL/статус/загрузка/Проверить TTS); расширения: WorkoutCore.setLastSetRpe + DAO lastSet (m09), AppSettings.voiceModelUrl + https-валидатор (m10); unit 63/63 (m11 — 27), APK 57,3 МБ (vosk JNI ×4 ABI); errata vosk-android 0.3.47 (stop/shutdown, onResult/onFinalResult, TONE_PROP_NACK); распознавание на устройстве — приёмка владельца, КУ-1 вручную 2026-10-19 10:37:51 +05:00

readme.md

m11-voice-input — план работ (d-dev)

Модуль: VoiceInput — офлайн-STT (Vosk) + грамматика Ф-1.2 + TTS-подтверждения + интеграция в экран «Тренировка». Алгоритм: std1\_rules\d\d-dev.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.