#!/usr/bin/env python3 """ Text User Interface (TUI) for Voice Assistant - Simple Version AI Now Inc - Del Mar Demo Unit Laboratory Assistant: Claw 🏭 This version uses the existing working components from main.py """ import os import sys import json import logging import signal import time from pathlib import Path from datetime import datetime # Try to import rich for beautiful TUI try: from rich.console import Console from rich.panel import Panel from rich import box RICH_AVAILABLE = True except ImportError: RICH_AVAILABLE = False print("Installing rich for TUI...") import subprocess subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'rich']) from rich.console import Console from rich.panel import Panel from rich import box RICH_AVAILABLE = True print("Rich installed!") from assistant import VoiceAssistant from tts_engine import TTSEngine from hotword_detector import HotwordDetector # Configure logging logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) logger = logging.getLogger(__name__) class TUIAssistant: """Simple TUI-based voice assistant.""" def __init__(self, config_path: str = "config.json"): self.config_path = Path(config_path) self.config = self._load_config() # Initialize components logger.info("Initializing TUI voice assistant...") self.assistant = VoiceAssistant(str(self.config_path)) self.tts = TTSEngine(str(self.config_path)) self.hotword_detector = HotwordDetector( str(self.config_path).replace("config.json", "hotword_config.json") ) # State self.is_running = False self.conversation_history = [] self.max_history = 10 # Rich console self.console = Console() # Setup signal handlers signal.signal(signal.SIGINT, self._signal_handler) signal.signal(signal.SIGTERM, self._signal_handler) # Set callback for hotword detection self.hotword_detector.set_callback(self._on_hotword) logger.info("TUI Voice assistant initialized") def _load_config(self) -> dict: """Load configuration.""" try: with open(self.config_path, 'r') as f: return json.load(f) except FileNotFoundError: logger.warning("Config not found, using defaults") return {} def _signal_handler(self, sig, frame): """Handle shutdown signals.""" logger.info("Shutdown signal received") self.is_running = False def _on_hotword(self): """Callback when hotword is detected.""" self.console.print("\n[bold green]✨ Hotword detected! ✨[/bold green]") self.tts.speak("Yes?", "en") def _add_to_history(self, role: str, text: str): """Add message to conversation history.""" timestamp = datetime.now().strftime("%H:%M:%S") self.conversation_history.append({ 'timestamp': timestamp, 'role': role, 'text': text }) if len(self.conversation_history) > self.max_history: self.conversation_history.pop(0) def run(self): """Run the TUI voice assistant.""" logger.info("Starting TUI voice assistant...") # Display welcome screen self.console.print(Panel.fit( "[bold]🎤 Voice Assistant - AI Now Inc[/bold]\n" "[cyan]Laboratory Assistant: Claw 🏭[/cyan]\n\n" "Say '[bold]Hey Osiris[/bold]' or '[bold]你好 Osiris[/bold]' to activate\n" "Press [bold]Ctrl+C[/bold] to stop", box=box.ROUNDED, border_style="blue" )) self.is_running = True self.console.print("\n[bold blue]→[/bold blue] Listening for hotword...") # Main loop - use hotword detector's blocking detect while self.is_running: try: # Wait for hotword (this blocks until detected or timeout) detected_keyword = self.hotword_detector.detect(timeout=30) if detected_keyword: self.console.print(f"\n[bold green]✓[/bold green] Heard: '{detected_keyword}'") # For now, just respond with a simple message # In a full implementation, you'd use speech recognition here response = "I heard you! What would you like me to do?" self._add_to_history('assistant', response) self.console.print(f"[bold cyan]🤖:[/bold cyan] {response}") self.tts.speak(response, "en") else: self.console.print("[yellow]⏰ Timeout - trying again...[/yellow]") except KeyboardInterrupt: logger.info("Interrupted by user") break except Exception as e: logger.error(f"Error: {e}") time.sleep(1) self.shutdown() def shutdown(self): """Clean shutdown.""" logger.info("Shutting down...") self.is_running = False if hasattr(self, 'hotword_detector'): self.hotword_detector.stop() self.console.print("\n[bold red]Voice Assistant stopped.[/bold red]") logger.info("Shutdown complete") def main(): """Main entry point.""" import argparse parser = argparse.ArgumentParser(description='TUI Voice Assistant') parser.add_argument('--config', default='config.json', help='Config file path') args = parser.parse_args() app = TUIAssistant(config_path=args.config) app.run() if __name__ == '__main__': main()