-
-
Notifications
You must be signed in to change notification settings - Fork 2
uk Bench Coverage
Coverage bench — це regression-гейт для голосового класифікатора інтентів SelenaCore. Генерує тест-кейси з живого реєстру пристроїв і проганяє кожен через повний production-пайплайн (Helsinki-переклад → embedding-класифікатор → каскад пост-обробки → резолв інтента). Результат — розбивка точності по категоріях, що ловить регресії класифікатора до production.
Поточна production-baseline: 96.6% на 1114 кейсах, p50 15 ms, p95 17 ms, нульовий false-positive на distractor'ах.
Про архітектуру класифікатора — intent-routing.md. Про правила авторингу інтентів — intent-authoring.md.
Корпус збирається з двох джерел:
Для кожної комбінації (entity_type, location) у реєстрі пристроїв corpus_generator.py генерує кейси в категоріях:
-
plain — канонічна фраза (
"turn on the light in the bedroom") -
variety — 5 парафразних варіантів:
syn,polite,short,indirect,casual -
noise — 5 реальних STT-деградацій:
filler,typo,stutter,context,long -
ambiguous — той самий інтент без кімнати, щоб перевірити шлях
needs_location
Все генерується EN та UK (корпус двомовний).
Рукописні кейси для інтентів, які не можна авто-згенерувати з реєстру:
| Категорія | Розмір | Покриті інтенти |
|---|---|---|
media |
26 |
media.play_*, pause/resume/stop, next/previous, volume_*, whats_playing
|
all_off / all_on
|
15 |
house.all_off / house.all_on з опційними entity + location фільтрами |
clock |
14 |
clock.set_alarm, set_timer, set_reminder, list_alarms, stop_alarm, cancel_timer
|
weather |
6 |
weather.current, forecast, temperature
|
presence |
6 |
presence.who_home, check_user, status
|
automation |
7 |
automation.list, enable, disable
|
system |
19 |
watchdog.*, energy.*, privacy_*, device.query_temperature, set_fan_speed, media.play_search
|
distractor |
9 | chat / безглуздя — не має давати device-інтент |
Кожен інтент, що належить кожному модулю, представлений хоча б один раз.
- Core-контейнер піднятий і healthy (
sudo docker ps | grep selena-core) - Helsinki-перекладач активний (
translation.engine = helsinkiвconfig/core.yaml) - Embedding-модель присутня за
intent.embedding_model_dir(default:/var/lib/selena/models/embedding/paraphrase-multilingual-MiniLM-L12-v2/) - Реєстр заповнений типовими пристроями — запустіть scripts/seed_missing_types.py, якщо певні типи відсутні
sudo docker exec -t selena-core python3 /opt/selena-core/tests/experiments/run_coverage_bench.pyЗаймає ~20 секунд на Jetson Orin / Pi 5. Вивід:
Accuracy: 1076/1114 (96.6%)
By category:
plain 94/94 ████████████████████ 100.0%
variety 358/383 ██████████████████ 93.5%
noise 437/441 ███████████████████ 99.1%
...
JSON-підсумок потрапляє до _private/coverage_bench_results.json (container-side: /opt/selena-core/_private/coverage_bench_results.json). Копіювання на хост:
sudo docker cp selena-core:/opt/selena-core/_private/coverage_bench_results.json \
_private/coverage_bench_results.json
sudo chown $USER _private/coverage_bench_results.jsonКожен раунд тюнінгу (description / anchor / threshold) дешевий: ~20 с bench + ~30 с core-restart. Типовий цикл:
# 1. edit embedding_classifier.py anchors OR intent description
# 2. restart core
sudo docker restart selena-core
until sudo docker ps --format '{{.Names}}: {{.Status}}' | grep -q 'selena-core.*healthy'; do
sleep 3
done
# 3. run bench, tee log, copy JSON, diff against previous
TS=$(date +%H%M); LOG=_private/bench_runs/round_${TS}.log
sudo docker exec -t selena-core python3 /opt/selena-core/tests/experiments/run_coverage_bench.py 2>&1 | tee "$LOG"
sudo docker cp selena-core:/opt/selena-core/_private/coverage_bench_results.json _private/coverage_bench_results.json
sudo chown $USER _private/coverage_bench_results.json
python3 _private/compare_rounds.py # prev vs current diffscripts/render_bench_svg.py генерує scalable SVG summary із найсвіжішого JSON.
python3 scripts/render_bench_svg.py
# → _private/bench_viz/intent-bench.svgВивід живе в _private/ (gitignored), бо bench-результати машинно-локальні та змінюються разом з реєстром. Про публікацію — нижче.
Без matplotlib / rsvg-convert залежностей. Використовуйте headless Chrome:
cat > /tmp/wrap.html <<'HTML'
<!DOCTYPE html>
<html><head><style>*{margin:0;padding:0}html,body{background:#0d1117}</style></head>
<body><img src="/home/YOU/SelenaCore/_private/bench_viz/intent-bench.svg"/></body></html>
HTML
google-chrome --headless --no-sandbox --disable-gpu --hide-scrollbars \
--device-scale-factor=2 --window-size=960,560 \
--screenshot=/home/YOU/SelenaCore/_private/bench_viz/intent-bench.png \
file:///tmp/wrap.html
rm /tmp/wrap.htmlКоли потрібно опублікувати поточний score (release notes, README badge, сайт):
- Перегенеруйте SVG зі свіжого bench
- Завантажте вручну з
_private/bench_viz/на ціль публікації — не комітьте бінарі в репо, бо вони стають застарілими, щойно реєстр або класифікатор змінюються - Для документів, що посилаються на конкретне число, зазначайте "станом на v0.3.X" з commit SHA — не hardcode'те значення
| Категорія | Що означає успіх |
|---|---|
| plain | Канонічні фрази класифікуються правильно. Будь-який провал тут — критичний баг description/якорів — має бути 100%. |
| variety | Парафрази (syn / polite / short / indirect / casual) класифікуються правильно. Очікуване ~93–97%. |
| noise | Реальний STT-шум (заповнювачі, typos, stutter, контекст, довгі preambles) не ламає класифікатор. Очікуване ~99%. |
| ambiguous | Користувач не сказав кімнату, а ≥ 2 пристроя матчать — router додає ambiguous=True, модуль питає "у якій кімнаті?". Має бути 100%. |
| all_off / all_on | Whole-house команди йдуть в house.all_*, не в окремий device.off. Має бути 100%. |
| media | Bare-verb playback команди (pause, next, louder) + named-station. ~85–95% — UK bare-verb форми страждають від Helsinki-quirks. |
| clock / weather / presence / automation / system | Cross-module coverage. Clock / automation найскладніші, бо їхні інтенти ділять дієслова; очікуване 85–95%. Weather зазвичай 100%. |
| distractor | Chat / безглуздя — не має давати device-інтент. 100% — жорстка планка — будь-що нижче означає, що класифікатор вивчив false-positive якорі. |
- Overall ≥ 97.0% — поточна конфігурація; будь-яке падіння блокує PR merge (CI-проводка — TODO).
- Per-new-intent ≥ 80% на своїх кейсах (≥ 60% якщо ділить дієслова з існуючим інтентом).
- Distractors = 100% — без винятків.
- Прочитайте розбивку по категоріях. Якщо одна категорія впала — це scoped-регресія. Поверніться до останньої зміни коду, що впливала на цей namespace.
- Прочитайте повний список провалів (до 200 збережено в JSON). Паттерни:
- Той самий інтент виграє скрізь → description або якорі цього інтента занадто широкі, крадуть матчі.
-
unknownскрізь в одній категорії → пороги занадто суворі АБО Helsinki калічить UK-вхід (проженіть фразу черезget_input_translator().to_english()вручну). -
Entity extraction повертає
None→ keyword відсутній уENTITY_MAPв embedding_classifier.py.
- Для UK-провалів — порівняйте вихід Helsinki з вашими якорями. Невідповідність там — найчастіша root cause.
- Додати відсутні anchor-речення (включно з Helsinki-артефактами для UK)
- Загострити IS / IS-NOT контраст description'a
- Додати post-processing override для систематичних misroute'ів (помірно — див. intent-authoring.md)
- Підкрутити поріг (лише якщо розподіл cosine зсунувся — наприклад, після заміни моделі)
- Злити два інтенти, що ділять дієслова (див. intent-authoring.md)
Кожен фікс — одна зміна, потім re-run. Якщо точність не виросла на ≥ 0.5 pp — revert і пробуйте іншу гіпотезу. Саме ця дисципліна дала підйом 57.5 → 96.6% за 20 раундів.
Окремий runner живе в tests/experiments/run_clarification_bench.py. Тестує multi-turn clarification-шлях окремо від основного корпусу:
turn 1 router.route(utterance_1)
→ IntentResult.clarification set (ambiguous / missing_param / low_margin)
turn 2 router.route_clarification(utterance_2, pending)
→ merged intent re-fire OR canned cancel
Два runner'и роз'єднані навмисно (plan §R7): основний bench stateless single-turn, додавання two-turn логіки забруднить _verdict(). Fixture'и в clarification_fixtures.py — 13 курованих сценаріїв:
- Resolve by room (EN + UK, з morphology tolerance для UK відмінків)
- Resolve by positional reference (
"the first"/"перший") - Resolve by device name (fuzzy)
- Resolve by numeric / word-form value (
"22"/"twenty-two") - Allowed-value matching для set_mode / set_fan_speed
- Cross-language reply (EN question, UK answer)
- Fuzzy-fail → cancel
sudo docker exec -t selena-core python3 \
/opt/selena-core/tests/experiments/run_clarification_bench.py~5 секунд. JSON → _private/clarification_bench_results.json.
- ≥ 80% overall на fixture-списку (поточне 92.3%).
- Кожна нова clarification-фіча має додавати ≥ 2 fixture що її exercise'ять.
missing_param емітиться хендлером модуля (device-control _intent_to_state ValueError trap), не роутером. Fixture'и з synthetic_pending dict обходять turn 1 — dict передається в route_clarification() напряму. Зберігає покриття matcher-логіки без підняття аудіо-loop.
- Wake-word під час
AWAITING_CLARIFICATIONcancel'ить pending — це audio-loop state-machine, потребує mic-input симуляції. Тільки integration testing. - Real-time silence →
clarify.timed_out— timing аудіо-loop'а, не-benchable.
Обидва покриваються manual acceptance сценаріями з plan'у; запускайте на живому залізі перед release'ом що зачіпає цю підсистему.
🤖 This wiki is auto-synced from docs/ in the main repo. Hand-edits on the wiki UI get overwritten on the next push. Open a PR against the main repo instead.
MIT License · Sponsor · Ko-fi
SelenaCore
🇬🇧 English
Getting started
Architecture
Voice & translation
Hardware integration
Development
- Modules overview
- Module development
- System module development
- Module API guide
- Module bus protocol
- Widget development
- User manager / auth
Reference
🇺🇦 Українська
Початок
Архітектура
Голос і переклад
Інтеграція заліза
Розробка
- Розробка модулів
- Розробка системних модулів
- Module API
- Module bus
- Widget development
- User manager / auth
Довідник