Documentation: - Add docs/06_PHYSICS/ with Zernike fundamentals and OPD method docs - Add docs/guides/CMA-ES_EXPLAINED.md optimization guide - Update CLAUDE.md and ATOMIZER_CONTEXT.md with current architecture - Update OP_01_CREATE_STUDY protocol Planning: - Add DYNAMIC_RESPONSE plans for random vibration/PSD support - Add OPTIMIZATION_ENGINE_MIGRATION_PLAN for code reorganization Insights System: - Update design_space, modal_analysis, stress_field, thermal_field insights - Improve error handling and data validation NX Journals: - Add analyze_wfe_zernike.py for Zernike WFE analysis - Add capture_study_images.py for automated screenshots - Add extract_expressions.py and introspect_part.py utilities - Add user_generated_journals/journal_top_view_image_taking.py Tests & Tools: - Add comprehensive Zernike OPD test suite - Add audit_v10 tests for WFE validation - Add tools for Pareto graphs and mirror data extraction - Add migrate_studies_to_topics.py utility Knowledge Base: - Initialize LAC (Learning Atomizer Core) with failure/success patterns Dashboard: - Update Setup.tsx and launch_dashboard.py - Add restart-dev.bat helper script 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
110 lines
3.4 KiB
Python
110 lines
3.4 KiB
Python
#!/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", "--reload"],
|
|
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()
|