import { useState, useEffect, useCallback } from 'react'; import { Zap, Activity, Thermometer, DollarSign, TrendingDown, Cloud, HardDrive, Hash, X, } from 'lucide-react'; import { useAppStore } from '../../lib/store'; interface EnergyData { total_energy_j?: number; energy_per_token_j?: number; avg_power_w?: number; } interface TelemetryStats { total_requests?: number; total_tokens?: number; } const CLOUD_PRICING = [ { name: 'GPT-5.3', input: 2.00, output: 10.00, primary: true }, { name: 'Claude Opus 4.6', input: 5.00, output: 25.00, primary: false }, { name: 'Gemini 3.1 Pro', input: 2.00, output: 12.00, primary: false }, ]; export function SystemPanel() { const savings = useAppStore((s) => s.savings); const toggleSystemPanel = useAppStore((s) => s.toggleSystemPanel); const [energy, setEnergy] = useState(null); const [telemetry, setTelemetry] = useState(null); const fetchData = useCallback(async () => { try { const base = import.meta.env.VITE_API_URL || ''; const [energyRes, telRes] = await Promise.allSettled([ fetch(`${base}/v1/telemetry/energy`).then((r) => (r.ok ? r.json() : null)), fetch(`${base}/v1/telemetry/stats`).then((r) => (r.ok ? r.json() : null)), ]); if (energyRes.status === 'fulfilled' && energyRes.value) { setEnergy(energyRes.value as EnergyData); } if (telRes.status === 'fulfilled' && telRes.value) { setTelemetry(telRes.value as TelemetryStats); } } catch { // best-effort } }, []); useEffect(() => { fetchData(); const interval = setInterval(fetchData, 3000); return () => clearInterval(interval); }, [fetchData]); // Re-fetch energy/telemetry when savings updates (after a chat message) useEffect(() => { if (savings) fetchData(); }, [savings, fetchData]); const thermalStatus = (energy?.avg_power_w ?? 0) < 50 ? { label: 'Cool', color: 'var(--color-success)' } : (energy?.avg_power_w ?? 0) < 150 ? { label: 'Warm', color: 'var(--color-warning)' } : { label: 'Hot', color: 'var(--color-error)' }; const promptK = (savings?.total_prompt_tokens ?? 0) / 1000; const completionK = (savings?.total_completion_tokens ?? 0) / 1000; return (
{/* Header */}
System
{/* Session Stats */}

Session

{/* Energy */}

Energy

{thermalStatus.label}
{/* Cost Comparison */}

Cost Comparison

{/* Local */}
Local
${(savings?.local_cost ?? 0).toFixed(4)}
{/* Cloud providers */}
{CLOUD_PRICING.map((provider) => { const cost = (promptK * provider.input) / 1000 + (completionK * provider.output) / 1000; const saved = cost - (savings?.local_cost ?? 0); return (
{provider.name}
${cost.toFixed(4)}
{saved > 0.0001 && (
${saved.toFixed(4)}
)}
); })}
{/* Server-reported savings */} {savings && savings.per_provider.length > 0 && (
Server-reported
{savings.per_provider.map((p) => (
{p.label} ${p.total_cost.toFixed(4)}
))}
)}
); } function MiniStat({ icon: Icon, label, value, unit, }: { icon: typeof Zap; label: string; value: string; unit?: string; }) { return (
{label}
{value} {unit && ( {unit} )}
); } function formatNumber(n: number): string { if (n >= 1_000_000) return (n / 1_000_000).toFixed(1) + 'M'; if (n >= 1_000) return (n / 1_000).toFixed(1) + 'K'; return String(n); }