#!/usr/bin/env python """ Atomizer Dashboard Launcher Starts both backend (FastAPI) and frontend (Vite) with a single command. Usage: python launch_dashboard.py Access dashboard at: http://localhost:3003 """ import subprocess import sys import time import os import signal from pathlib import Path # Colors for terminal output class Colors: GREEN = '\033[92m' BLUE = '\033[94m' YELLOW = '\033[93m' RED = '\033[91m' END = '\033[0m' BOLD = '\033[1m' def print_banner(): print(f""" {Colors.BLUE}{Colors.BOLD}============================================ ATOMIZER DASHBOARD LAUNCHER ============================================{Colors.END} """) def main(): print_banner() root_dir = Path(__file__).parent backend_dir = root_dir / "atomizer-dashboard" / "backend" frontend_dir = root_dir / "atomizer-dashboard" / "frontend" # Verify directories exist if not backend_dir.exists(): print(f"{Colors.RED}Error: Backend directory not found at {backend_dir}{Colors.END}") sys.exit(1) if not frontend_dir.exists(): print(f"{Colors.RED}Error: Frontend directory not found at {frontend_dir}{Colors.END}") sys.exit(1) processes = [] try: # Start backend - use conda run to ensure atomizer environment print(f"{Colors.YELLOW}Starting backend server (FastAPI on port 8000)...{Colors.END}") backend_proc = subprocess.Popen( ["conda", "run", "-n", "atomizer", "python", "-m", "uvicorn", "api.main:app", "--port", "8000"], cwd=str(backend_dir), shell=True, creationflags=subprocess.CREATE_NEW_PROCESS_GROUP if sys.platform == "win32" else 0 ) processes.append(("Backend", backend_proc)) time.sleep(2) # Give backend time to start # Start frontend print(f"{Colors.YELLOW}Starting frontend server (Vite on port 3003)...{Colors.END}") frontend_proc = subprocess.Popen( ["npm", "run", "dev"], cwd=str(frontend_dir), shell=True, creationflags=subprocess.CREATE_NEW_PROCESS_GROUP if sys.platform == "win32" else 0 ) processes.append(("Frontend", frontend_proc)) time.sleep(3) # Give frontend time to start print(f""" {Colors.GREEN}{Colors.BOLD}Dashboard is running!{Colors.END} {Colors.BLUE}Access at:{Colors.END} http://localhost:3003 {Colors.YELLOW}Press Ctrl+C to stop both servers{Colors.END} """) # Wait for processes while True: for name, proc in processes: if proc.poll() is not None: print(f"{Colors.RED}{name} server stopped unexpectedly{Colors.END}") time.sleep(1) except KeyboardInterrupt: print(f"\n{Colors.YELLOW}Shutting down servers...{Colors.END}") finally: # Clean up processes for name, proc in processes: try: if sys.platform == "win32": proc.terminate() else: os.killpg(os.getpgid(proc.pid), signal.SIGTERM) proc.wait(timeout=5) print(f"{Colors.GREEN}{name} stopped{Colors.END}") except Exception as e: print(f"{Colors.RED}Error stopping {name}: {e}{Colors.END}") proc.kill() print(f"{Colors.GREEN}Dashboard shutdown complete{Colors.END}") if __name__ == "__main__": main()