import React, { useState, useEffect, useCallback } from 'react'; import { Sliders, Sparkles, Send, Loader2, Info, Globe, Code, Play, Activity } from 'lucide-react'; const BACKEND_URL = process.env.REACT_APP_BACKEND_URL || ''; const PRESETS = [ { index: 2048, name: 'French Language', label: 'French Language Detector', category: 'language', icon: Globe, color: '#9B59F5', desc: 'Injects French syntactic and lexical directions, causing the model to complete sentences in French.', defaultPrompt: 'When Mary and John went to the store, John', strength: 15.0, }, { index: 847, name: 'Python Programming', label: 'Python Code Detector', category: 'code', icon: Code, color: '#00D9C0', desc: 'Redirects representations into Python programming code blocks, generating function calls or syntax.', defaultPrompt: 'When Mary and John went to the store, John', strength: 12.0, }, { index: 1580, name: 'Chess Notation', label: 'Chess Notation Detector', category: 'chess', icon: Play, color: '#4A9EFF', desc: 'Biases hidden representations toward chess tournament layouts and move notations.', defaultPrompt: 'When Mary and John went to the store, John', strength: 18.0, }, { index: 3102, name: 'Medical Terminology', label: 'Medical Terms Detector', category: 'medical', icon: Activity, color: '#FF5063', desc: 'Steers hidden states into clinical contexts, changing general words into medical formulations.', defaultPrompt: 'When Mary and John went to the store, John', strength: 14.0, }, ]; export const FeatureSteering = () => { const [activePreset, setActivePreset] = useState(PRESETS[0]); const [featureIndex, setFeatureIndex] = useState(PRESETS[0].index); const [steeringStrength, setSteeringStrength] = useState(PRESETS[0].strength); const [prompt, setPrompt] = useState(PRESETS[0].defaultPrompt); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [steerResult, setSteerResult] = useState(null); const [modelStatus, setModelStatus] = useState(() => { return sessionStorage.getItem('cs_model_status') || 'demo'; }); useEffect(() => { const handleStatusChange = (e) => { setModelStatus(e.detail); }; window.addEventListener('cs_model_status_change', handleStatusChange); return () => { window.removeEventListener('cs_model_status_change', handleStatusChange); }; }, []); const handleSelectPreset = (preset) => { setActivePreset(preset); setFeatureIndex(preset.index); setSteeringStrength(preset.strength); setPrompt(preset.defaultPrompt); setSteerResult(null); }; const handleSteer = useCallback(async () => { if (!prompt.trim()) return; setLoading(true); setError(null); try { const res = await fetch(`${BACKEND_URL}/api/steer`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt: prompt.trim(), feature_index: parseInt(featureIndex, 10), steering_strength: parseFloat(steeringStrength), layer: 6, }), }); if (!res.ok) { const errData = await res.json().catch(() => ({})); throw new Error(errData.detail || `Steering request failed (${res.status})`); } const data = await res.json(); setSteerResult(data); } catch (e) { setError(e.message || 'Failed to execute feature steering'); } finally { setLoading(false); } }, [prompt, featureIndex, steeringStrength]); return (
{/* Header */}
Phase 2: Feature Steering GPT-2 + SAELens Active

SAE Feature Steering Lab

Intervene directly in the model's computation by adding or subtracting pre-trained Sparse Autoencoder directions ({"$W_{dec}$"} decoders) scaled by strength parameters directly during generation.

{/* Preset Selector Grid */}
{PRESETS.map((preset) => { const Icon = preset.icon; const isSelected = activePreset.index === preset.index; return (
handleSelectPreset(preset)} className="research-card transition-all duration-300" style={{ borderLeft: `3px solid ${preset.color}`, cursor: 'pointer', borderColor: isSelected ? preset.color : '#1E2B45', boxShadow: isSelected ? `0 0 16px ${preset.color}15` : 'none', background: isSelected ? '#0d111d' : '#080B12', }} >

{preset.name}

Idx: {preset.index}

{preset.desc}

); })}
{/* Controls Panel */}

Intervention Parameters

{/* Feature Index */}
{ const idx = parseInt(e.target.value, 10) || 0; setFeatureIndex(idx); const matching = PRESETS.find(p => p.index === idx); if (matching) { setActivePreset(matching); } else { setActivePreset({ index: idx, name: `Custom Latent ${idx}`, label: `Feature ${idx}`, color: '#9B59F5', desc: 'Intervene with a custom dictionary element mapped from Neuronpedia API.', icon: Sparkles, defaultPrompt: prompt, strength: steeringStrength }); } }} disabled={loading} style={{ width: '100%', background: '#080B12', border: '1px solid #1E2B45', borderRadius: 6, padding: '8px 12px', color: '#E8EEF8', fontFamily: "'JetBrains Mono', monospace", fontSize: 13, outline: 'none', }} />
{/* Steering Strength */}
{steeringStrength > 0 ? `+${steeringStrength}` : steeringStrength}
setSteeringStrength(parseFloat(e.target.value))} disabled={loading} style={{ width: '100%', accentColor: activePreset.color, cursor: 'pointer', }} />
-30.0 (Ablate) 0.0 (None) +30.0 (Steer)
{/* Prompt Input */}