""" Smart Speaker - Main Application Голосовой ассистент с wake word detection, STT, AI и TTS. Flow: 1. Wait for wake word ("Alexandr") 2. Listen to user speech (STT) 3. Send query to AI (Perplexity) 4. Clean response from markdown 5. Speak response (TTS) 6. Loop back to step 1 """ import signal import sys from wakeword import wait_for_wakeword, cleanup as cleanup_wakeword, check_wakeword_once from stt import listen, cleanup as cleanup_stt from ai import ask_ai from cleaner import clean_response from tts import speak, initialize as init_tts from sound_level import set_volume, parse_volume_text def signal_handler(sig, frame): """Handle Ctrl+C gracefully.""" print("\n\n👋 Завершение работы...") cleanup_wakeword() cleanup_stt() sys.exit(0) def main(): """Main application loop.""" print("=" * 50) print("🔊 УМНАЯ КОЛОНКА") print("=" * 50) print("Скажите 'Alexandr' для активации") print("Нажмите Ctrl+C для выхода") print("=" * 50) print() # Setup signal handler for graceful exit signal.signal(signal.SIGINT, signal_handler) # Pre-initialize TTS model (takes a few seconds) print("⏳ Инициализация...") init_tts() print() # Main loop skip_wakeword = False while True: try: # Step 1: Wait for wake word if not skip_wakeword: wait_for_wakeword() skip_wakeword = False # Step 2: Listen to user speech user_text = listen(timeout_seconds=7.0) if not user_text: speak("Извините, я вас не расслышал. Попробуйте ещё раз.") continue # Check for volume command if user_text.lower().startswith("громкость"): try: # Remove "громкость" prefix and strip whitespace vol_str = user_text.lower().replace("громкость", "", 1).strip() # Try to parse the number level = parse_volume_text(vol_str) if level is not None: if set_volume(level): speak(f"Громкость установлена на {level}") else: speak("Не удалось установить громкость.") else: speak("Я не понял число громкости. Скажите число от одного до десяти.") continue except Exception as e: print(f"❌ Ошибка громкости: {e}") speak("Не удалось изменить громкость.") continue # Step 3: Send to AI ai_response = ask_ai(user_text) # Step 4: Clean response clean_text = clean_response(ai_response) # Step 5: Speak response (with wake word interrupt support) completed = speak(clean_text, check_interrupt=check_wakeword_once) # If interrupted by wake word, go back to waiting for wake word if not completed: print("⏹️ Ответ прерван - слушаю следующий вопрос") skip_wakeword = True continue print() print("-" * 30) print() # Step 6: Loop continues... except KeyboardInterrupt: signal_handler(None, None) except Exception as e: print(f"❌ Ошибка: {e}") speak("Произошла ошибка. Попробуйте ещё раз.") if __name__ == "__main__": main()