"use client"; import { useState, useEffect } from 'react'; import { Play, Pause, RefreshCw, Terminal, Activity, Wifi, WifiOff, Zap, Server, Database } from 'lucide-react'; import { usePathname } from 'next/navigation'; import { getApiUrl, getLegacyWsUrl } from '@/lib/config'; interface ServiceStatus { modelService: 'running' | 'stopped' | 'checking' | 'error'; websocket: 'running' | 'stopped' | 'checking' | 'error'; frontend: 'running' | 'stopped' | 'checking' | 'error'; } interface Demo { id: string; name: string; prompt: string; description: string; } export function LocalControlPanel({ hideOnInspector = false }: { hideOnInspector?: boolean }) { const [serviceStatus, setServiceStatus] = useState({ modelService: 'checking', websocket: 'checking', frontend: 'running' }); const [demos, setDemos] = useState([]); const [isGenerating, setIsGenerating] = useState(false); const [generatingDemoId, setGeneratingDemoId] = useState(null); const [deviceInfo, setDeviceInfo] = useState(''); const [modelLoaded, setModelLoaded] = useState(false); const [minimized, setMinimized] = useState(false); const [shouldHide, setShouldHide] = useState(false); // Only show in development mode const isDevelopment = process.env.NEXT_PUBLIC_MODE === 'local' || process.env.NODE_ENV === 'development'; // Listen for activeView changes useEffect(() => { const handleViewChange = (event: CustomEvent) => { setShouldHide(event.detail.view === 'inspector'); }; window.addEventListener('viewChanged', handleViewChange as EventListener); return () => window.removeEventListener('viewChanged', handleViewChange as EventListener); }, []); useEffect(() => { if (!isDevelopment || shouldHide) return; const checkServices = async () => { // Check model service try { const response = await fetch(`${getApiUrl()}/health`); const data = await response.json(); setServiceStatus(prev => ({ ...prev, modelService: data.status === 'healthy' ? 'running' : 'error' })); setDeviceInfo(data.device || 'Unknown'); setModelLoaded(data.model_loaded || false); } catch { setServiceStatus(prev => ({ ...prev, modelService: 'stopped' })); setModelLoaded(false); } // Check WebSocket try { const ws = new WebSocket(getLegacyWsUrl()); ws.onopen = () => { setServiceStatus(prev => ({ ...prev, websocket: 'running' })); ws.close(); }; ws.onerror = () => { setServiceStatus(prev => ({ ...prev, websocket: 'stopped' })); }; ws.onclose = () => { // Connection closed event }; } catch { setServiceStatus(prev => ({ ...prev, websocket: 'stopped' })); } }; const loadDemos = async () => { try { const response = await fetch(`${getApiUrl()}/demos`); const data = await response.json(); setDemos(data.demos || []); } catch (error) { console.error('Failed to load demos:', error); setDemos([]); } }; checkServices(); loadDemos(); const interval = setInterval(checkServices, 5000); // Check every 5 seconds return () => clearInterval(interval); }, [isDevelopment, shouldHide]); if (!isDevelopment || shouldHide) { return null; } const runDemo = async (demoId: string) => { if (isGenerating) return; // Dispatch prompt variations IMMEDIATELY for PromptDiff const demoPrompts = { fibonacci: { promptA: "def fibonacci(n):\n '''Calculate fibonacci number'''", promptB: "def fibonacci(n):\n '''Calculate fibonacci number with memoization'''" }, quicksort: { promptA: "def quicksort(arr):\n '''Sort array using quicksort'''", promptB: "def quicksort(arr):\n '''Sort array using optimized quicksort with pivot selection'''" }, stack: { promptA: "class Stack:\n '''Simple stack implementation'''", promptB: "class Stack:\n '''Thread-safe stack implementation with size limit'''" }, binary_search: { promptA: "def binary_search(arr, target):\n '''Find target in sorted array'''", promptB: "def binary_search(arr, target):\n '''Find target in sorted array using iterative approach'''" } }; if (demoId in demoPrompts) { window.dispatchEvent(new CustomEvent('demo-prompts-selected', { detail: demoPrompts[demoId as keyof typeof demoPrompts] })); } // Also dispatch the primary prompt IMMEDIATELY for ConfidenceMeter const demoPrimaryPrompts = { fibonacci: "def fibonacci(n):\n '''Calculate fibonacci number'''", quicksort: "def quicksort(arr):\n '''Sort array using quicksort'''", stack: "class Stack:\n '''Simple stack implementation'''", binary_search: "def binary_search(arr, target):\n '''Find target in sorted array'''" }; if (demoId in demoPrimaryPrompts) { window.dispatchEvent(new CustomEvent('demo-prompt-selected', { detail: { prompt: demoPrimaryPrompts[demoId as keyof typeof demoPrimaryPrompts], demoId } })); } // Dispatch event to indicate demo is starting (for clearing tokens) window.dispatchEvent(new CustomEvent('demo-starting', { detail: { demoId } })); setIsGenerating(true); setGeneratingDemoId(demoId); try { const response = await fetch(`${getApiUrl()}/demos/run`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ demo_id: demoId }) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); console.log('Demo completed:', data); // Dispatch custom event to notify AttentionExplorer window.dispatchEvent(new CustomEvent('demo-completed', { detail: data })); } catch (error) { console.error('Failed to run demo:', error); alert(`Failed to run demo: ${error}`); } finally { setIsGenerating(false); setGeneratingDemoId(null); } }; if (minimized) { return (
setMinimized(false)}>
); } return (

Local Development

{/* Service Status */}
{/* Device Info */} {deviceInfo && (
Device: {deviceInfo}
Model: {modelLoaded ? "Loaded" : "Loading..."}
)} {/* Quick Actions */}
{/* Demo Runners */}

Run Demos

{demos.length > 0 ? ( demos.map(demo => { const isThisDemoGenerating = generatingDemoId === demo.id; return ( ); }) ) : (
No demos available
)}
{/* Generation Status */} {isGenerating && (
Generating code...
)}
); } function ServiceIndicator({ name, status }: { name: string; status: string }) { const colors = { running: 'text-green-400', stopped: 'text-red-400', checking: 'text-yellow-400', error: 'text-red-400' }; const icons = { running: , stopped: , checking: , error: }; return (
{name} {icons[status as keyof typeof icons]} {status}
); }