Этап 4: слово активации через Vosk

- Фоновое прослушивание микрофона маленькой моделью Vosk, фразы настраиваются
- Свободное распознавание + требование устойчивой гипотезы: грамматика давала массу ложных срабатываний
- Пауза прослушивания, пока ассистент слушает команду, думает или говорит
- Модель скачивается с зеркала HuggingFace, проверка слов по словарю модели
- Переключатель в меню трея
- Тесты поиска фразы и фонового слушателя

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mrleo1nid
2026-09-17 03:56:32 +03:00
co-authored by Claude Opus 5
parent 513d010c19
commit a719980d74
12 changed files with 931 additions and 5 deletions
+15 -1
View File
@@ -15,7 +15,14 @@ _NOTIFICATION_TIMEOUT_MS = 6000
class TrayIcon(QSystemTrayIcon):
def __init__(self, assistant: Assistant, window: ChatWindow, hotkey: str = "") -> None:
def __init__(
self,
assistant: Assistant,
window: ChatWindow,
hotkey: str = "",
wake_phrases: list[str] | None = None,
) -> None:
wake_phrases = wake_phrases or []
super().__init__(state_icon(assistant.state))
self._assistant = assistant
self._window = window
@@ -26,6 +33,13 @@ class TrayIcon(QSystemTrayIcon):
# Текст после табуляции QMenu выравнивает по правому краю, как подсказку клавиши
label = f"Говорить\t{hotkey.title()}" if hotkey else "Говорить"
menu.addAction(label, assistant.toggle_listening)
if assistant.wake_word_available:
phrases = ", ".join(f"«{phrase}»" for phrase in wake_phrases)
wake_action = QAction(f"Слушать слово активации: {phrases}", self, checkable=True)
wake_action.setChecked(assistant.wake_word_enabled)
wake_action.toggled.connect(assistant.set_wake_word_enabled)
assistant.wake_word_enabled_changed.connect(wake_action.setChecked)
menu.addAction(wake_action)
menu.addSeparator()
provider_menu = menu.addMenu("Провайдер LLM")