6.3 KiB
6.3 KiB
Спецификация 01: VoiceCommandParser — грамматика Ф-1.2
Источники: Ф-1.2 (грамматика), Ф-1.3 (отклонение), О-2-Б («с половиной» → +0,5 кг), tech-req 5 (постобработка чисел). Единица 1. Чистая функция JVM — без Android-зависимостей.
1. Интерфейс
sealed interface VoiceCommand {
data class Approach(val weightKg: Double, val reps: Int) : VoiceCommand
data class Weight(val weightKg: Double) : VoiceCommand
data class Rest(val seconds: Int) : VoiceCommand
data class Rpe(val rpe: Int) : VoiceCommand
data class Rejected(val reason: String, val attempted: JsonObject?) : VoiceCommand
}
object VoiceCommandParser {
fun parse(alternatives: List<String>): VoiceCommand?
// null — ни одна гипотеза не содержит распознаваемой команды
fun semantics(cmd: VoiceCommand): JsonObject // для журнала Ф-1.5
}
parse получает список финальных гипотез Vosk (спец 02, до 3;
режим одного варианта — список из одного) и возвращает первую
успешно разобранную команду; если все гипотезы мусор — Rejected
из первой гипотезы. Отклонённая команда — тоже результат (журнал
Ф-1.3/1.5), «не было команды вообще» (тишина/чужая речь) — null,
в журнал не пишется.
2. Предобработка текста
- нижний регистр, ё→е, удаление знаков препинания, сжатие пробелов;
- нормализация аббревиатуры RPE: «эр пэ э», «эрпэ» → «рпэ» (свободное распознавание слышит буквы по отдельности);
- токены — слова и цифровые группы.
3. Числа (NumberRu, 0–999)
- словами: [сотни] [десятки] [единицы] → сумма. Словари:
ноль;один/одна/одно,два/две,три…девятнадцать; десяткидвадцать…девяносто; сотнисто, двести, триста, четыреста, пятьсот…девятьсот. Составное число — подряд стоящие разряды («сто двадцать три» → 123); постобработка «сто двадцать» → 120 (tech-req 5); - цифрами:
120, дробное120,5/120.5(= только 5 после разделителя — шаг 0,5); - «с половиной» после числа → +0,5 (О-2-Б); допустимо ТОЛЬКО
в позиции веса
W(команды Approach/Weight); «с половиной» в позицииR/S/N— грамматическая ошибка (отклонение); - порядок разрядов нарушен («двадцать сто») — грамматическая ошибка.
4. Грамматика команд (Ф-1.2)
| Команда | Шаблон | Диапазоны |
|---|---|---|
| Approach | подход W [с половиной] на R |
W 0–500 (шаг 0,5), R 1–100 |
| Weight | вес W [с половиной] |
W 0–500 (шаг 0,5) |
| Rest | отдых S [секунд / секунды] |
S 5–600 |
| Rpe | рпэ N |
N 1–10 |
- ключевые слова обязательны и однозначны;
на,секунд— по шаблону (секунды склоняются: «девяносто секунд» / «тридцать секунд» — Vosk может выдать и «секунды» — приниматьсекунд|секунды); - лишние слова до/после шаблона — грамматическая ошибка (узкая грамматика, Ф-1.3);
- число разобрано, но вне диапазона →
Rejected(reason= "out_of_range", attempted={…значения…}); - шаблон не совпал →
Rejected(reason="out_of_grammar", attempted=null).
5. Семантика для журнала (Ф-1.5, контракт m09 spec 04)
{"cmd":"set","weight_kg":120.0,"reps":8}
{"cmd":"weight","weight_kg":62.5}
{"cmd":"rest","sec":90}
{"cmd":"rpe","rpe":7}
{"cmd":"rejected","reason":"out_of_range","weight_kg":600.0,"reps":8}
semantics— объект (как в PayloadFactory.commandLog m09);rejectedсохраняет распознанные значения — разбор ошибок при анализе журнала;- исходный текст гипотезы пишется в
recognized_textисполнителем (спец 03).
6. Тесты (unit, pure JVM)
- Четыре команды — числа словами: «подход сто двадцать на восемь» → Approach(120,8); «вес шестьдесят два с половиной» → Weight(62.5); «отдых девяносто секунд» → Rest(90); «рпэ семь» / «эр пэ э семь» → Rpe(7).
- Цифрами: «подход 120 на 8», «вес 62,5», «отдых 90», «120.5».
- Границы: W=0 и W=500 приняты; W=500,5 / R=0 / R=101 / S=4 / S=601 / N=0 / N=11 → out_of_range (attempted заполнен).
- Отклонения: «погнали» → out_of_grammar; «подход сто двадцать» (нет «на») → out_of_grammar; «отдых тридцать с половиной» → out_of_grammar («с половиной» не у веса); «подход двадцать сто на пять» → out_of_grammar.
- NumberRu: крайние числа — ноль, сто, девятьсот девяносто девять, «двести двадцать два»; регистр и пунктуация («Подход 120, на 8!»); формы «два»/«две».
- Alternatives: первая гипотеза мусор, вторая валидна → команда из второй; все мусор → Rejected из первой.