Add text input prompt to TUI - alternative to voice commands

This commit is contained in:
Claw - AI Now Inc 2026-03-01 12:42:01 -08:00
parent 4f662ee81b
commit 530944f166

View File

@ -1,10 +1,14 @@
#!/usr/bin/env python3 #!/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 AI Now Inc - Del Mar Demo Unit
Laboratory Assistant: Claw 🏭 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 import os
@ -13,6 +17,7 @@ import json
import logging import logging
import signal import signal
import time import time
import threading
from pathlib import Path from pathlib import Path
from datetime import datetime from datetime import datetime
@ -21,6 +26,7 @@ try:
from rich.console import Console from rich.console import Console
from rich.panel import Panel from rich.panel import Panel
from rich import box from rich import box
from rich.prompt import Prompt
RICH_AVAILABLE = True RICH_AVAILABLE = True
except ImportError: except ImportError:
RICH_AVAILABLE = False RICH_AVAILABLE = False
@ -29,6 +35,7 @@ except ImportError:
subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'rich']) subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'rich'])
from rich.console import Console from rich.console import Console
from rich.panel import Panel from rich.panel import Panel
from rich.prompt import Prompt
from rich import box from rich import box
RICH_AVAILABLE = True RICH_AVAILABLE = True
print("Rich installed!") print("Rich installed!")
@ -46,7 +53,7 @@ logger = logging.getLogger(__name__)
class TUIAssistant: class TUIAssistant:
"""Simple TUI-based voice assistant.""" """TUI-based voice assistant with text input support."""
def __init__(self, config_path: str = "config.json"): def __init__(self, config_path: str = "config.json"):
self.config_path = Path(config_path) self.config_path = Path(config_path)
@ -62,8 +69,9 @@ class TUIAssistant:
# State # State
self.is_running = False self.is_running = False
self.voice_mode = False # True when voice activation is active
self.conversation_history = [] self.conversation_history = []
self.max_history = 10 self.max_history = 20
# Rich console # Rich console
self.console = Console() self.console = Console()
@ -94,19 +102,85 @@ class TUIAssistant:
def _on_hotword(self): def _on_hotword(self):
"""Callback when hotword is detected.""" """Callback when hotword is detected."""
self.console.print("\n[bold green]✨ Hotword detected! ✨[/bold green]") self.console.print("\n[bold green]✨ Hotword detected! ✨[/bold green]")
self.voice_mode = True
self.tts.speak("Yes?", "en") 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.""" """Add message to conversation history."""
timestamp = datetime.now().strftime("%H:%M:%S") timestamp = datetime.now().strftime("%H:%M:%S")
self.conversation_history.append({ self.conversation_history.append({
'timestamp': timestamp, 'timestamp': timestamp,
'role': role, 'role': role,
'text': text 'text': text,
'method': method # 'text', 'voice', or 'assistant'
}) })
if len(self.conversation_history) > self.max_history: if len(self.conversation_history) > self.max_history:
self.conversation_history.pop(0) 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): def run(self):
"""Run the TUI voice assistant.""" """Run the TUI voice assistant."""
logger.info("Starting TUI voice assistant...") logger.info("Starting TUI voice assistant...")
@ -115,32 +189,30 @@ class TUIAssistant:
self.console.print(Panel.fit( self.console.print(Panel.fit(
"[bold]🎤 Voice Assistant - AI Now Inc[/bold]\n" "[bold]🎤 Voice Assistant - AI Now Inc[/bold]\n"
"[cyan]Laboratory Assistant: Claw 🏭[/cyan]\n\n" "[cyan]Laboratory Assistant: Claw 🏭[/cyan]\n\n"
"Say '[bold]Hey Osiris[/bold]' or '[bold]你好 Osiris[/bold]' to activate\n" "Modes:\n"
"Press [bold]Ctrl+C[/bold] to stop", " • [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, box=box.ROUNDED,
border_style="blue" border_style="blue"
)) ))
self._show_help()
self.is_running = True 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: while self.is_running:
try: try:
# Wait for hotword (this blocks until detected or timeout) # Get text input from user
detected_keyword = self.hotword_detector.detect(timeout=30) 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: if user_input:
self.console.print(f"\n[bold green]✓[/bold green] Heard: '{detected_keyword}'") self._process_command(user_input, method='text')
# 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: except KeyboardInterrupt:
logger.info("Interrupted by user") logger.info("Interrupted by user")
@ -151,6 +223,28 @@ class TUIAssistant:
self.shutdown() 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): def shutdown(self):
"""Clean shutdown.""" """Clean shutdown."""
logger.info("Shutting down...") logger.info("Shutting down...")