Files
agr-assistent/tests/test_recorder.py
T
mrleo1nidandClaude Opus 5 513d010c19 Этап 3: голосовой ввод по горячей клавише
- Глобальная горячая клавиша через RegisterHotKey (по умолчанию Win+Alt+Space)
- Запись с микрофона, конец фразы по паузе через Silero VAD, звуковые сигналы
- Распознавание faster-whisper large-v3-turbo на GPU, CUDA-библиотеки из pip-пакетов nvidia-*
- Состояния «слушаю» и «распознаю», кнопка «Говорить» в чате и пункт в трее
- Голосовая команда прерывает текущий ответ и озвучку
- Тесты горячей клавиши, детектора конца фразы и сеанса голосового ввода

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 03:34:09 +03:00

44 lines
1.4 KiB
Python

from agr_assistent.audio.recorder import UtteranceDetector, UtteranceStatus
# Частота 100 отсчётов в секунду, окно — 10 отсчётов (0.1 с): так проще считать
_WINDOW = 10
def _detector(**overrides: float) -> UtteranceDetector:
settings = dict(threshold=0.5, start_timeout_seconds=1, silence_seconds=0.3, max_seconds=5)
settings.update(overrides)
return UtteranceDetector(sample_rate=100, **settings)
def _feed(detector: UtteranceDetector, probabilities: list[float]) -> list[UtteranceStatus]:
return [detector.update(p, _WINDOW) for p in probabilities]
def test_phrase_completes_after_silence() -> None:
statuses = _feed(_detector(), [0.1, 0.9, 0.8, 0.2, 0.1, 0.1])
assert statuses[:-1] == [UtteranceStatus.CONTINUE] * 5
assert statuses[-1] is UtteranceStatus.COMPLETE
def test_short_pause_does_not_end_phrase() -> None:
statuses = _feed(_detector(), [0.9, 0.1, 0.1, 0.9, 0.1, 0.1])
assert UtteranceStatus.COMPLETE not in statuses
def test_no_speech_before_timeout() -> None:
statuses = _feed(_detector(), [0.1] * 10)
assert statuses[-1] is UtteranceStatus.NO_SPEECH
assert statuses[:-1] == [UtteranceStatus.CONTINUE] * 9
def test_max_duration_completes_ongoing_speech() -> None:
detector = _detector(max_seconds=0.5)
statuses = _feed(detector, [0.9] * 5)
assert statuses[-1] is UtteranceStatus.COMPLETE
assert detector.speech_detected