""" Command parsing helpers. """ import re from .config import WAKE_WORD, WAKE_WORD_ALIASES from ..audio.sound_level import is_volume_command, parse_volume_text _STOP_WORDS_STRICT = { "стоп", "хватит", "перестань", "замолчи", "прекрати", "тихо", "stop", } _STOP_PATTERNS_LENIENT = [ r"\bстоп\w*\b", r"\bstop\b", r"\bхватит\b", r"\bперестан\w*\b", r"\bпрекрат\w*\b", r"\bзамолч\w*\b", r"\bтише\b", r"\bтихо\b", r"\bвыключ\w*\b", r"\bотключ\w*\b", r"\bостанов\w*\b", r"\bотмен\w*\b", r"\bпауза\b", r"\bдостаточно\b", ] _STOP_PATTERNS_LENIENT_COMPILED = [re.compile(p) for p in _STOP_PATTERNS_LENIENT] _FAST_WEATHER_PHRASES = { "какая погода", "какая погода на улице", "какая сейчас погода", "какая сейчас погода на улице", "что по погоде", "погода", "погода на улице", "что на улице", "что там на улице", "че там на улице", } _FAST_MUSIC_PHRASES = { "включи музыку", "поставь музыку", "играй музыку", "play music", } _WAKEWORD_PREFIX_RE = re.compile( rf"^(?:{'|'.join(re.escape(alias) for alias in sorted({WAKE_WORD.lower(), *WAKE_WORD_ALIASES}, key=len, reverse=True))})(?:\s+|$)", re.IGNORECASE, ) def _normalize_text(text: str) -> str: text = text.lower().replace("ё", "е") text = re.sub(r"[^\w\s]+", " ", text, flags=re.UNICODE) text = re.sub(r"\s+", " ", text, flags=re.UNICODE).strip() return text def normalize_command_text(text: str) -> str: normalized = _normalize_text(text) if not normalized: return "" return _WAKEWORD_PREFIX_RE.sub("", normalized, count=1).strip() def is_stop_command(text: str, mode: str = "strict") -> bool: """ Detect stop commands in text. mode: - "strict": only exact stop words. - "lenient": broader patterns for noisy recognition. """ if not text: return False normalized = _normalize_text(text) if not normalized: return False if mode == "strict": words = normalized.split() return any(word in _STOP_WORDS_STRICT for word in words) for pattern in _STOP_PATTERNS_LENIENT_COMPILED: if pattern.search(normalized): return True return False def is_fast_command(text: str) -> bool: """ Detect short commands that can stop STT early without waiting for full utterance finalization. """ normalized = normalize_command_text(text) if not normalized: return False if is_stop_command(normalized, mode="strict"): return True if normalized in _FAST_WEATHER_PHRASES: return True if normalized in _FAST_MUSIC_PHRASES: return True if is_volume_command(normalized) and parse_volume_text(normalized) is not None: return True return False