Files
Atomizer/atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx
Anto01 f76bd52894 feat: Implement Protocol 13 - Real-Time Dashboard Tracking
Complete implementation of Protocol 13 featuring real-time web dashboard
for monitoring multi-objective optimization studies.

## New Features

### Backend (Python)
- Real-time tracking system with per-trial JSON writes
- New API endpoints for metadata, optimizer state, and Pareto fronts
- Unit inference from objective descriptions
- Multi-objective support using Optuna's best_trials API

### Frontend (React + TypeScript)
- OptimizerPanel: Real-time optimizer state (phase, strategy, progress)
- ParetoPlot: Pareto front visualization with normalization toggle
  - 3 modes: Raw, Min-Max [0-1], Z-Score standardization
  - Pareto front line connecting optimal points
- ParallelCoordinatesPlot: High-dimensional interactive visualization
  - Objectives + design variables on parallel axes
  - Click-to-select, hover-to-highlight
  - Color-coded feasibility
- Dynamic units throughout all visualizations

### Documentation
- Comprehensive Protocol 13 guide with architecture, data flow, usage

## Files Added
- `docs/PROTOCOL_13_DASHBOARD.md`
- `atomizer-dashboard/frontend/src/components/OptimizerPanel.tsx`
- `atomizer-dashboard/frontend/src/components/ParetoPlot.tsx`
- `atomizer-dashboard/frontend/src/components/ParallelCoordinatesPlot.tsx`
- `optimization_engine/realtime_tracking.py`

## Files Modified
- `atomizer-dashboard/frontend/src/pages/Dashboard.tsx`
- `atomizer-dashboard/backend/api/routes/optimization.py`
- `optimization_engine/intelligent_optimizer.py`

## Testing
- Tested with bracket_stiffness_optimization_V2 (30 trials, 20 Pareto solutions)
- Dashboard running on localhost:3001
- All P1 and P2 features verified working

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 15:58:00 -05:00

156 lines
4.7 KiB
TypeScript

/**
* Intelligent Optimizer Panel - Protocol 13
* Displays real-time optimizer state: phase, strategy, progress, confidence
*/
import { useEffect, useState } from 'react';
interface OptimizerState {
available: boolean;
current_phase?: string;
current_strategy?: string;
trial_number?: number;
total_trials?: number;
is_multi_objective?: boolean;
latest_recommendation?: {
strategy: string;
confidence: number;
reasoning: string;
};
}
export function OptimizerPanel({ studyId }: { studyId: string }) {
const [state, setState] = useState<OptimizerState | null>(null);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const fetchState = async () => {
try {
const res = await fetch(`/api/optimization/studies/${studyId}/optimizer-state`);
if (!res.ok) {
throw new Error(`HTTP ${res.status}`);
}
const data = await res.json();
setState(data);
setError(null);
} catch (err) {
console.error('Failed to fetch optimizer state:', err);
setError('Failed to load');
}
};
fetchState();
const interval = setInterval(fetchState, 1000); // Update every second
return () => clearInterval(interval);
}, [studyId]);
if (error) {
return (
<div className="bg-dark-700 rounded-lg p-6 border border-dark-600">
<h3 className="text-lg font-semibold mb-4 text-dark-100">Intelligent Optimizer</h3>
<div className="text-dark-400 text-sm">
{error}
</div>
</div>
);
}
if (!state?.available) {
return null;
}
// Format phase name for display
const formatPhase = (phase?: string) => {
if (!phase) return 'Unknown';
return phase
.split('_')
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ');
};
// Format strategy name for display
const formatStrategy = (strategy?: string) => {
if (!strategy) return 'Not set';
return strategy.toUpperCase();
};
const progress = state.trial_number && state.total_trials
? (state.trial_number / state.total_trials) * 100
: 0;
return (
<div className="bg-dark-700 rounded-lg p-6 border border-dark-600">
<h3 className="text-lg font-semibold mb-4 text-dark-100 flex items-center gap-2">
Intelligent Optimizer
{state.is_multi_objective && (
<span className="text-xs bg-purple-500/20 text-purple-300 px-2 py-1 rounded">
Multi-Objective
</span>
)}
</h3>
<div className="space-y-4">
{/* Phase */}
<div>
<div className="text-sm text-dark-300 mb-1">Phase</div>
<div className="text-lg font-semibold text-primary-400">
{formatPhase(state.current_phase)}
</div>
</div>
{/* Strategy */}
<div>
<div className="text-sm text-dark-300 mb-1">Current Strategy</div>
<div className="text-lg font-semibold text-blue-400">
{formatStrategy(state.current_strategy)}
</div>
</div>
{/* Progress */}
<div>
<div className="text-sm text-dark-300 mb-1">Progress</div>
<div className="text-lg text-dark-100">
{state.trial_number || 0} / {state.total_trials || 0} trials
</div>
<div className="w-full bg-dark-500 rounded-full h-2 mt-2">
<div
className="bg-primary-400 h-2 rounded-full transition-all duration-300"
style={{ width: `${progress}%` }}
/>
</div>
</div>
{/* Confidence (if available) */}
{state.latest_recommendation && (
<div>
<div className="text-sm text-dark-300 mb-1">Confidence</div>
<div className="flex items-center gap-2">
<div className="flex-1 bg-dark-500 rounded-full h-2">
<div
className="bg-green-400 h-2 rounded-full transition-all duration-300"
style={{
width: `${state.latest_recommendation.confidence * 100}%`
}}
/>
</div>
<span className="text-sm font-mono text-dark-200 min-w-[3rem] text-right">
{(state.latest_recommendation.confidence * 100).toFixed(0)}%
</span>
</div>
</div>
)}
{/* Reasoning (if available) */}
{state.latest_recommendation && (
<div>
<div className="text-sm text-dark-300 mb-1">Reasoning</div>
<div className="text-sm text-dark-100 bg-dark-800 rounded p-3 border border-dark-600">
{state.latest_recommendation.reasoning}
</div>
</div>
)}
</div>
</div>
);
}