#!/usr/bin/env python3 """ Trixy Voice Assistant - Main Entry Point This module serves as the entry point for the Trixy voice assistant application, supporting three deployment modes: server, client/satellite, and standalone. Usage: python3 main.py [server|client|standalone] [--debug] [--config custom_config.json] Modes: server - Central hub with event handler, plugins, satellite management client - Satellite mode with wakeword detection and audio streaming standalone - Full system that can optionally connect to server for sync Arguments: --debug - Enable development mode (no TUI, print statements enabled) --config - Specify custom configuration file path Author: Generated with Claude Code """ import sys import os import argparse import signal import logging import traceback from pathlib import Path from typing import Optional, Dict, Any # Global application container reference for cleanup _application_container = None _debug_mode = False def pprint(message: str) -> None: """ Adaptive print function that behaves differently in debug vs production mode. In debug mode: Prints directly to stdout In production mode: Uses logging system with Textual TUI Args: message: The message to print/log """ if _debug_mode: print(f"[TRIXY] {message}") else: # In production mode, use logging system # The TUI will capture and display log messages appropriately logging.info(message) def create_directory_structure() -> None: """ Create the required directory structure for Trixy if it doesn't exist. Creates all necessary directories as specified in CLAUDE.md: - trixy_core/ with all component subdirectories - plugins/ - models/ with subdirectories - config/ - assets/ with default profile - trainer/ with data subdirectories """ directories = [ # Core system modules "trixy_core", "trixy_core/events", "trixy_core/network", "trixy_core/network/cmd", "trixy_core/satellites", "trixy_core/plugins", "trixy_core/config", "trixy_core/assets", "trixy_core/scheduler", "trixy_core/conversation", "trixy_core/arbitration", # Plugin directory "plugins", # ML model storage "models", "models/wakeword", "models/voice_recognition", # Configuration files "config", # Profile-based assets "assets", "assets/default", # ML training system "trainer", "trainer/data", "trainer/data/wakeword", "trainer/data/wakeword/raw", "trainer/data/voice_recognition", "trainer/data/voice_recognition/raw", "trainer/wakeword", "trainer/voice_recognition", ] base_path = Path.cwd() created_dirs = [] for directory in directories: dir_path = base_path / directory if not dir_path.exists(): try: dir_path.mkdir(parents=True, exist_ok=True) created_dirs.append(str(dir_path)) pprint(f"Created directory: {dir_path}") except OSError as e: pprint(f"Failed to create directory {dir_path}: {e}") sys.exit(1) if created_dirs: pprint(f"Successfully created {len(created_dirs)} directories") else: pprint("All required directories already exist") def setup_logging(debug: bool = False) -> None: """ Initialize the logging system based on the mode. In debug mode: Basic console logging In production mode: Structured logging for TUI integration Args: debug: Whether debug mode is enabled """ global _debug_mode _debug_mode = debug if debug: # Debug mode: Simple console logging logging.basicConfig( level=logging.DEBUG, format='[%(asctime)s] [%(levelname)s] %(name)s: %(message)s', datefmt='%H:%M:%S' ) pprint("Debug mode enabled - console logging active") else: # Production mode: Structured logging for TUI logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', handlers=[ logging.StreamHandler(sys.stdout) ] ) pprint("Production mode enabled - TUI logging active") def parse_arguments() -> argparse.Namespace: """ Parse command line arguments. Returns: Parsed arguments namespace """ parser = argparse.ArgumentParser( description="Trixy Voice Assistant - Professional voice assistant system", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" Examples: python3 main.py server --debug python3 main.py client --config /path/to/client_config.json python3 main.py standalone """ ) parser.add_argument( 'mode', choices=['server', 'client', 'standalone'], help='Deployment mode: server (central hub), client (satellite), or standalone (full system)' ) parser.add_argument( '--debug', action='store_true', help='Enable debug mode (no TUI, print statements enabled)' ) parser.add_argument( '--config', type=str, metavar='CONFIG_FILE', help='Path to custom configuration file (overrides default config)' ) return parser.parse_args() def validate_environment() -> None: """ Validate the runtime environment and dependencies. Raises: SystemExit: If critical dependencies are missing """ python_version = sys.version_info if python_version < (3, 8): pprint(f"Error: Python 3.8+ required, found {python_version.major}.{python_version.minor}") sys.exit(1) pprint(f"Python {python_version.major}.{python_version.minor}.{python_version.micro} detected") # Check for write permissions in current directory try: test_file = Path.cwd() / ".trixy_write_test" test_file.touch() test_file.unlink() pprint("Write permissions verified") except (OSError, PermissionError) as e: pprint(f"Error: No write permissions in current directory: {e}") sys.exit(1) def initialize_application_container(mode: str, config_path: Optional[str] = None): """ Initialize and return the application container based on the deployment mode. This is a placeholder for the actual application container implementation. The container will be implemented in trixy_core/ modules. Args: mode: Deployment mode (server, client, standalone) config_path: Optional path to custom configuration file Returns: Application container instance Raises: ImportError: If core modules are not yet implemented """ try: # This import will be available once the core modules are implemented from trixy_core.application import ApplicationContainer pprint(f"Initializing {mode} mode application container") container = ApplicationContainer(mode=mode, config_path=config_path) pprint("Application container initialized successfully") return container except ImportError as e: pprint(f"Core modules not yet implemented: {e}") pprint("This is expected during initial setup phase") pprint("The application container will be available once core modules are created") return None def setup_signal_handlers() -> None: """ Setup signal handlers for graceful shutdown. """ def signal_handler(signum, frame): pprint(f"Received signal {signum}, initiating graceful shutdown...") shutdown_application() sys.exit(0) # Handle common termination signals signal.signal(signal.SIGINT, signal_handler) # Ctrl+C signal.signal(signal.SIGTERM, signal_handler) # Termination signal # Handle SIGQUIT on Unix systems if hasattr(signal, 'SIGQUIT'): signal.signal(signal.SIGQUIT, signal_handler) pprint("Signal handlers configured for graceful shutdown") def shutdown_application() -> None: """ Perform graceful shutdown of the application. This function will: 1. Stop all running services 2. Close network connections 3. Save state and configuration 4. Clean up resources """ global _application_container pprint("Starting graceful shutdown sequence...") if _application_container: try: # Call the application container's shutdown method # This will be implemented when the container is created if hasattr(_application_container, 'shutdown'): _application_container.shutdown() pprint("Application container shutdown completed") else: pprint("Application container shutdown method not available") except Exception as e: pprint(f"Error during application shutdown: {e}") if _debug_mode: traceback.print_exc() pprint("Graceful shutdown completed") def main() -> None: """ Main entry point for the Trixy voice assistant application. This function: 1. Parses command line arguments 2. Validates the environment 3. Creates directory structure 4. Initializes logging 5. Sets up signal handlers 6. Initializes the application container 7. Starts the application 8. Handles graceful shutdown """ global _application_container try: # Parse command line arguments args = parse_arguments() # Setup logging early setup_logging(args.debug) # Print startup banner pprint("="*50) pprint("Trixy Voice Assistant") pprint("Professional Voice Assistant System") pprint("="*50) pprint(f"Mode: {args.mode.upper()}") pprint(f"Debug: {'ENABLED' if args.debug else 'DISABLED'}") if args.config: pprint(f"Config: {args.config}") pprint("="*50) # Validate environment pprint("Validating runtime environment...") validate_environment() # Create directory structure pprint("Creating directory structure...") create_directory_structure() # Setup signal handlers for graceful shutdown pprint("Setting up signal handlers...") setup_signal_handlers() # Initialize application container pprint("Initializing application container...") _application_container = initialize_application_container( mode=args.mode, config_path=args.config ) if _application_container: # Start the application pprint(f"Starting Trixy {args.mode} mode...") # The actual application start will be implemented # when the application container is created if hasattr(_application_container, 'start'): _application_container.start() else: pprint("Application container start method not available") pprint("Core system implementation is required") pprint("This main.py serves as the foundation for future development") else: pprint("Application container not available") pprint("Core modules need to be implemented") pprint("This main.py is ready for integration with core system") except KeyboardInterrupt: pprint("Received keyboard interrupt") shutdown_application() sys.exit(0) except Exception as e: pprint(f"Fatal error during startup: {e}") if _debug_mode: traceback.print_exc() shutdown_application() sys.exit(1) if __name__ == "__main__": main()