first commit
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
"""Тест М5.3: свободный режим с ПРОБЕЛОМ-тумблером диалога.
|
||||
|
||||
Запуск:
|
||||
python modules/assistant/test_free.py
|
||||
python modules/assistant/test_free.py --silence 1.5 # короче пауза конца фразы
|
||||
|
||||
Схема (целевая для отца):
|
||||
ПРОБЕЛ (в консоли: d + Enter) — НАЧАТЬ диалог: куи «Ассистент готов к диалогу»
|
||||
→ просто говори, пауза 2 c = фраза закончена → ответ.
|
||||
ПРОБЕЛ в диалоге — ЗАВЕРШИТЬ: куи «Спасибо. До новых встреч».
|
||||
Или скажи «до свидания» — то же самое + запомнит разговор.
|
||||
Вне диалога микрофон заглушен. Выход: q + Enter.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import threading
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
from modules.assistant import Assistant
|
||||
from modules.audio_io import HandsFreeRecorder, Player
|
||||
from modules.brain import get_provider as get_brain
|
||||
from modules.hotkeys import KeyEvents, get_backend
|
||||
from modules.stt import get_provider as get_stt
|
||||
from modules.tts import make_tts
|
||||
except ImportError:
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
|
||||
from modules.assistant import Assistant
|
||||
from modules.audio_io import HandsFreeRecorder, Player
|
||||
from modules.brain import get_provider as get_brain
|
||||
from modules.hotkeys import KeyEvents, get_backend
|
||||
from modules.stt import get_provider as get_stt
|
||||
from modules.tts import make_tts
|
||||
|
||||
VAD_STATE_RU = {
|
||||
"listening": "👂 слушаю тебя",
|
||||
"speech_start": "🎙 начало фразы",
|
||||
"speech_end": "✅ фраза собрана, обрабатываю",
|
||||
"too_short": "⚠ слишком коротко — пропускаю",
|
||||
"paused": "⏸ не слушаю (сама говорю)",
|
||||
}
|
||||
|
||||
ASSISTANT_STATE_RU = {
|
||||
"idle": "⏸ ожидание",
|
||||
"listening": "🎙 запись",
|
||||
"thinking": "🧠 думаю…",
|
||||
"speaking": "🔊 говорю",
|
||||
}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
p = argparse.ArgumentParser(description="Свободный режим ассистента (VAD)")
|
||||
p.add_argument("--silence", type=float, default=2.0,
|
||||
help="пауза тишины, считающаяся концом фразы (сек)")
|
||||
p.add_argument("--threshold", type=float, default=0.5,
|
||||
help="порог VAD: больше — строже, меньше — чувствительнее")
|
||||
p.add_argument("--min-speech", type=float, default=0.3,
|
||||
help="минимальная доля голоса во фразе, сек")
|
||||
p.add_argument("--stt-model", default="small")
|
||||
args = p.parse_args()
|
||||
|
||||
print("Загружаю модули…")
|
||||
stt = get_stt("faster-whisper", model_size=args.stt_model)
|
||||
brain = get_brain("openrouter")
|
||||
tts = make_tts() # провайдер/скорость из .env (TTS_PROVIDER, TTS_RATE)
|
||||
player = Player()
|
||||
|
||||
quit_event = threading.Event()
|
||||
|
||||
def on_vad_state(state: str) -> None:
|
||||
print(f"\n [микрофон] {VAD_STATE_RU.get(state, state)}")
|
||||
|
||||
def on_assistant_state(state: str, note: str) -> None:
|
||||
print(f"\n[{ASSISTANT_STATE_RU.get(state, state)}]" + (f" {note}" if note else ""))
|
||||
|
||||
def on_log(msg: str) -> None:
|
||||
print(f" {msg}")
|
||||
|
||||
recorder = HandsFreeRecorder(
|
||||
silence_sec=args.silence,
|
||||
speech_threshold=args.threshold,
|
||||
min_speech_sec=args.min_speech,
|
||||
on_state=on_vad_state,
|
||||
on_error=lambda m: print(f" [ОШИБКА] {m}"),
|
||||
)
|
||||
assistant = Assistant(stt, brain, tts, recorder, player,
|
||||
on_state_change=on_assistant_state, on_log=on_log)
|
||||
|
||||
print(f"\nУПРАВЛЕНИЕ (голосом, без клавиатуры):")
|
||||
print(f" «{assistant.wake_word.wake_word.capitalize()}» — начать диалог (куи «готова к диалогу»)")
|
||||
print(" «До свидания» — завершить диалог (куи «до новых встреч»)")
|
||||
print(" Вне диалога ассистент слушает тихо и отвечает только на wake-word.")
|
||||
print(" Консоль: s — «Замолчи», r — «Повтори», ПРОБЕЛ — тоже тумблер диалога, q — выход.\n")
|
||||
|
||||
quit_event = threading.Event()
|
||||
|
||||
events = KeyEvents(
|
||||
on_talk_down=lambda: None,
|
||||
on_talk_up=lambda: None,
|
||||
on_stop=assistant.on_stop,
|
||||
on_repeat=assistant.on_repeat,
|
||||
on_quit=lambda: quit_event.set(),
|
||||
on_dialog_toggle=assistant.on_dialog_toggle,
|
||||
)
|
||||
backend = get_backend("console", events)
|
||||
backend.start()
|
||||
recorder.start() # микрофон открыт, но заглушен до начала диалога
|
||||
|
||||
try:
|
||||
while not quit_event.wait(timeout=0.2):
|
||||
pass
|
||||
except KeyboardInterrupt:
|
||||
print("\n(Ctrl+C)")
|
||||
finally:
|
||||
backend.stop()
|
||||
recorder.stop()
|
||||
try:
|
||||
player.stop()
|
||||
except Exception:
|
||||
pass
|
||||
print("Выход.")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user