diff --git a/tui_app.py b/tui_app.py index 3b2f46e..3f8e1d0 100644 --- a/tui_app.py +++ b/tui_app.py @@ -1,10 +1,14 @@ #!/usr/bin/env python3 """ -Text User Interface (TUI) for Voice Assistant - Simple Version +Text User Interface (TUI) for Voice Assistant with Text Input AI Now Inc - Del Mar Demo Unit Laboratory Assistant: Claw 🏭 -This version uses the existing working components from main.py +Features: +- Voice activation via "Hey Osiris" +- Text input alternative (type commands) +- Rich terminal formatting +- Conversation history """ import os @@ -13,6 +17,7 @@ import json import logging import signal import time +import threading from pathlib import Path from datetime import datetime @@ -21,6 +26,7 @@ try: from rich.console import Console from rich.panel import Panel from rich import box + from rich.prompt import Prompt RICH_AVAILABLE = True except ImportError: RICH_AVAILABLE = False @@ -29,6 +35,7 @@ except ImportError: subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'rich']) from rich.console import Console from rich.panel import Panel + from rich.prompt import Prompt from rich import box RICH_AVAILABLE = True print("Rich installed!") @@ -46,7 +53,7 @@ logger = logging.getLogger(__name__) class TUIAssistant: - """Simple TUI-based voice assistant.""" + """TUI-based voice assistant with text input support.""" def __init__(self, config_path: str = "config.json"): self.config_path = Path(config_path) @@ -62,8 +69,9 @@ class TUIAssistant: # State self.is_running = False + self.voice_mode = False # True when voice activation is active self.conversation_history = [] - self.max_history = 10 + self.max_history = 20 # Rich console self.console = Console() @@ -94,19 +102,85 @@ class TUIAssistant: def _on_hotword(self): """Callback when hotword is detected.""" self.console.print("\n[bold green]✨ Hotword detected! ✨[/bold green]") + self.voice_mode = True self.tts.speak("Yes?", "en") - def _add_to_history(self, role: str, text: str): + def _add_to_history(self, role: str, text: str, method: str = "text"): """Add message to conversation history.""" timestamp = datetime.now().strftime("%H:%M:%S") self.conversation_history.append({ 'timestamp': timestamp, 'role': role, - 'text': text + 'text': text, + 'method': method # 'text', 'voice', or 'assistant' }) if len(self.conversation_history) > self.max_history: self.conversation_history.pop(0) + def _display_history(self): + """Display recent conversation history.""" + if len(self.conversation_history) == 0: + return + + self.console.print("\n[bold]📜 Recent Conversation:[/bold]") + for msg in self.conversation_history[-10:]: # Show last 10 messages + if msg['role'] == 'user': + icon = "👤" if msg['method'] == 'text' else "🎤" + color = "green" if msg['method'] == 'text' else "yellow" + self.console.print(f"[{color}]{icon} [{msg['timestamp']}]: {msg['text']}") + else: + self.console.print(f"[cyan]🤖 [{msg['timestamp']}]: {msg['text']}") + self.console.print() + + def _process_command(self, command: str, method: str = "text"): + """Process a command from user (text or voice).""" + if not command or command.strip() == "": + return + + self._add_to_history('user', command, method) + + # Check for special commands + cmd_lower = command.lower().strip() + if cmd_lower in ['quit', 'exit', 'bye']: + self.console.print("\n[bold]Goodbye! 👋[/bold]") + self.tts.speak("Goodbye!", "en") + self.is_running = False + return + elif cmd_lower == 'history': + self._display_history() + return + elif cmd_lower == 'help': + self._show_help() + return + + # Process with assistant + self.console.print("\n[bold blue]🤔 Processing...[/bold blue]") + response = self.assistant.process(command) + + self._add_to_history('assistant', response, 'assistant') + self.console.print(f"[bold cyan]🤖:[/bold cyan] {response}") + + # Speak response + self.console.print("[bold blue]🔊 Speaking...[/bold blue]") + self.tts.speak(response, "en") + + def _show_help(self): + """Show help message.""" + help_text = """ +[bold]Voice Assistant Commands:[/bold] + • Type your command or question + • Say "Hey Osiris" for voice activation + • Type 'history' to see recent conversation + • Type 'quit' or 'exit' to stop + +[bold]Examples:[/bold] + • "What time is it?" + • "Play some music" + • "Tell me a joke" + • "What's the weather?" +""" + self.console.print(Panel(help_text, box=box.ROUNDED, border_style="green")) + def run(self): """Run the TUI voice assistant.""" logger.info("Starting TUI voice assistant...") @@ -115,32 +189,30 @@ class TUIAssistant: 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", + "Modes:\n" + " • [bold]Type commands[/bold] in the prompt\n" + " • Say '[bold]Hey Osiris[/bold]' for voice activation\n\n" + "Commands: [bold]help[/bold] | [bold]history[/bold] | [bold]quit[/bold]", box=box.ROUNDED, border_style="blue" )) + self._show_help() self.is_running = True - self.console.print("\n[bold blue]→[/bold blue] Listening for hotword...") - # Main loop - use hotword detector's blocking detect + # Start voice listener in background + voice_thread = threading.Thread(target=self._voice_listener, daemon=True) + voice_thread.start() + + # Main loop - text input while self.is_running: try: - # Wait for hotword (this blocks until detected or timeout) - detected_keyword = self.hotword_detector.detect(timeout=30) + # Get text input from user + prompt_text = "\n[bold green]👤 You:[/bold green] " if not self.voice_mode else "\n[bold yellow]🎤 Voice Mode:[/bold yellow] " + user_input = Prompt.ask(prompt_text) - 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]") + if user_input: + self._process_command(user_input, method='text') except KeyboardInterrupt: logger.info("Interrupted by user") @@ -151,6 +223,28 @@ class TUIAssistant: self.shutdown() + def _voice_listener(self): + """Background thread to listen for voice hotword.""" + logger.info("Voice listener started") + + while self.is_running: + try: + if self.voice_mode: + # Voice mode active - wait for speech + # In a full implementation, this would use speech recognition + time.sleep(0.5) + self.voice_mode = False # Reset after use + else: + # Wait for hotword + detected = self.hotword_detector.detect(timeout=5) + if detected: + self._on_hotword() + except Exception as e: + logger.error(f"Voice listener error: {e}") + time.sleep(1) + + logger.info("Voice listener stopped") + def shutdown(self): """Clean shutdown.""" logger.info("Shutting down...")