Play STT start sound after wake word
This commit is contained in:
@@ -125,6 +125,20 @@ os.environ["TZ"] = "Europe/Moscow"
|
||||
time.tzset()
|
||||
|
||||
# --- Настройки синтеза речи (TTS) ---
|
||||
|
||||
# --- Sound effects (SFX) ---
|
||||
# Короткий "beep" после wake word и перед запуском STT, чтобы пользователь понял:
|
||||
# можно начинать говорить. Поддерживает wav/mp3 (если pygame mixer поддерживает mp3),
|
||||
# иначе будет использован mpg123 как fallback.
|
||||
_stt_sfx_default = Path.home() / "Music" / "alisa-golosovoj-pomoschnik.mp3"
|
||||
STT_START_SOUND_PATH = os.getenv("STT_START_SOUND_PATH", "").strip() or str(
|
||||
_stt_sfx_default
|
||||
)
|
||||
try:
|
||||
STT_START_SOUND_VOLUME = float(os.getenv("STT_START_SOUND_VOLUME", "0.25"))
|
||||
except Exception:
|
||||
STT_START_SOUND_VOLUME = 0.25
|
||||
STT_START_SOUND_VOLUME = max(0.0, min(1.0, STT_START_SOUND_VOLUME))
|
||||
# Голос для русского языка (eugene - мужской голос)
|
||||
TTS_SPEAKER = "eugene" # Доступные (ru): aidar, baya, kseniya, xenia, eugene
|
||||
# Голос для английского языка
|
||||
|
||||
71
app/main.py
71
app/main.py
@@ -7,6 +7,8 @@ import signal
|
||||
import sys
|
||||
import time
|
||||
from collections import deque
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
|
||||
# Для воспроизведения звуков (mp3)
|
||||
try:
|
||||
@@ -34,7 +36,12 @@ from .audio.wakeword import (
|
||||
stop_monitoring as stop_wakeword_monitoring,
|
||||
)
|
||||
from .core.ai import ask_ai_stream, interpret_assistant_intent, translate_text
|
||||
from .core.config import BASE_DIR, WAKE_WORD
|
||||
from .core.config import (
|
||||
BASE_DIR,
|
||||
STT_START_SOUND_PATH,
|
||||
STT_START_SOUND_VOLUME,
|
||||
WAKE_WORD,
|
||||
)
|
||||
from .core.cleaner import clean_response
|
||||
from .core.commands import is_stop_command
|
||||
from .core.smalltalk import get_smalltalk_response
|
||||
@@ -221,6 +228,7 @@ def main():
|
||||
|
||||
# Инициализация звуковой системы для эффектов (опционально)
|
||||
ding_sound = None
|
||||
stt_start_sound_path = Path(STT_START_SOUND_PATH).expanduser()
|
||||
if mixer is None:
|
||||
print(
|
||||
"Warning: pygame mixer not available; sound effects disabled."
|
||||
@@ -232,12 +240,58 @@ def main():
|
||||
except Exception as exc:
|
||||
print(f"Warning: pygame mixer init failed; sound effects disabled. ({exc})")
|
||||
else:
|
||||
ding_sound_path = BASE_DIR / "assets" / "sounds" / "ding.wav"
|
||||
if ding_sound_path.exists():
|
||||
ding_sound = mixer.Sound(str(ding_sound_path))
|
||||
ding_sound.set_volume(0.3)
|
||||
else:
|
||||
print(f"⚠️ Звук {ding_sound_path} не найден")
|
||||
# Приоритет: внешний звук для старта STT (обычно в ~/Music),
|
||||
# fallback: assets/sounds/ding.wav
|
||||
candidate_paths = [
|
||||
stt_start_sound_path,
|
||||
BASE_DIR / "assets" / "sounds" / "ding.wav",
|
||||
]
|
||||
for candidate in candidate_paths:
|
||||
if not candidate or not Path(candidate).exists():
|
||||
continue
|
||||
try:
|
||||
ding_sound = mixer.Sound(str(candidate))
|
||||
ding_sound.set_volume(float(STT_START_SOUND_VOLUME))
|
||||
break
|
||||
except Exception as exc:
|
||||
print(f"⚠️ Не удалось загрузить звук {candidate}: {exc}")
|
||||
ding_sound = None
|
||||
|
||||
def _play_stt_start_sfx_fallback():
|
||||
"""Fallback для систем без pygame/mixer или без поддержки mp3."""
|
||||
if not stt_start_sound_path.exists():
|
||||
return False
|
||||
# mpg123 scale factor: 0..32768 (примерно). Делаем тихо.
|
||||
scale = int(32768 * float(STT_START_SOUND_VOLUME))
|
||||
scale = max(0, min(32768, scale))
|
||||
try:
|
||||
subprocess.run(
|
||||
["mpg123", "-q", "-f", str(scale), str(stt_start_sound_path)],
|
||||
check=False,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
return True
|
||||
except FileNotFoundError:
|
||||
return False
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def play_stt_start_sfx():
|
||||
"""Проиграть короткий звук старта STT синхронно (чтобы не попасть в распознавание)."""
|
||||
if ding_sound is not None:
|
||||
try:
|
||||
ch = ding_sound.play()
|
||||
# Если pygame не вернул канал, ничего не ждем.
|
||||
if ch is None:
|
||||
return True
|
||||
# Ждем завершения звука.
|
||||
while ch.get_busy():
|
||||
time.sleep(0.01)
|
||||
return True
|
||||
except Exception:
|
||||
pass
|
||||
return _play_stt_start_sfx_fallback()
|
||||
|
||||
get_recognizer().initialize() # Подключение к Deepgram
|
||||
init_tts() # Загрузка нейросети для синтеза речи (Silero)
|
||||
@@ -298,8 +352,7 @@ def main():
|
||||
continue
|
||||
|
||||
# Звук активации
|
||||
if ding_sound:
|
||||
ding_sound.play()
|
||||
play_stt_start_sfx()
|
||||
|
||||
# Слушаем команду
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user