Этап 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>
This commit is contained in:
co-authored by
Claude Opus 5
parent
fec52dd1c2
commit
513d010c19
@@ -25,7 +25,7 @@ from PySide6.QtWidgets import (
|
||||
)
|
||||
|
||||
from agr_assistent import APP_NAME
|
||||
from agr_assistent.core.assistant import Assistant
|
||||
from agr_assistent.core.assistant import Assistant, AssistantState
|
||||
from agr_assistent.ui.icons import state_icon
|
||||
|
||||
_ROLE_STYLES = {
|
||||
@@ -34,6 +34,11 @@ _ROLE_STYLES = {
|
||||
"error": ("Ошибка", "#e53935"),
|
||||
}
|
||||
|
||||
_VOICE_BUTTON_TEXTS = {
|
||||
AssistantState.LISTENING: "Готово",
|
||||
AssistantState.RECOGNIZING: "Распознаю…",
|
||||
}
|
||||
|
||||
# Во время стриминга перерисовываем историю не чаще, чем раз в N мс
|
||||
_RENDER_INTERVAL_MS = 50
|
||||
|
||||
@@ -85,13 +90,23 @@ class ChatWindow(QWidget):
|
||||
self._send_button.setMinimumWidth(100)
|
||||
self._send_button.clicked.connect(self._on_send_clicked)
|
||||
|
||||
self._voice_button = QPushButton()
|
||||
self._voice_button.setMinimumWidth(100)
|
||||
self._voice_button.clicked.connect(assistant.toggle_listening)
|
||||
self._voice_button.setVisible(assistant.voice_available)
|
||||
|
||||
header = QHBoxLayout()
|
||||
header.addWidget(self._provider_label, 1)
|
||||
header.addWidget(new_chat_button)
|
||||
|
||||
buttons = QVBoxLayout()
|
||||
buttons.addWidget(self._send_button)
|
||||
buttons.addWidget(self._voice_button)
|
||||
buttons.addStretch()
|
||||
|
||||
input_row = QHBoxLayout()
|
||||
input_row.addWidget(self._input, 1)
|
||||
input_row.addWidget(self._send_button)
|
||||
input_row.addLayout(buttons)
|
||||
|
||||
layout = QVBoxLayout(self)
|
||||
layout.addLayout(header)
|
||||
@@ -146,8 +161,11 @@ class ChatWindow(QWidget):
|
||||
self._submit()
|
||||
|
||||
def _on_state_changed(self, state: object) -> None:
|
||||
current = self._assistant.state
|
||||
self._send_button.setText("Стоп" if self._assistant.is_busy else "Отправить")
|
||||
self.setWindowIcon(state_icon(self._assistant.state))
|
||||
self._voice_button.setText(_VOICE_BUTTON_TEXTS.get(current, "Говорить"))
|
||||
self._voice_button.setEnabled(current is not AssistantState.RECOGNIZING)
|
||||
self.setWindowIcon(state_icon(current))
|
||||
|
||||
def _update_provider_label(self) -> None:
|
||||
self._provider_label.setText(
|
||||
|
||||
Reference in New Issue
Block a user