pappitti's picture
upgrade for v3 of dataset, adding family and provider filters, improving responsiveness. Still needs polishing
f263c36
import { useState, useEffect} from 'react';
// import Waterfall from './components/Waterfall.js';
import SankeyDiagram from './components/Sankey.js';
import Heatmap from './components/Heatmap.js';
import AssessmentItems from './components/itemList.js';
import { getThemes, getJudges, getModelFamilies, getProviders, getReclassificationData, getAssessmentItems, getModels } from './utils/apiUtils.js';
import { modelSort } from './utils/chartUtils.js';
import type { Theme, Judges, Model, ModelFamily, Provider, SelectedJudge, TransitionMatrix, AssessmentItem } from './types';
import FilterBar from './components/Filterbar';
function App() {
const [themes, setThemes] = useState<Theme[]>([]);
const [judges, setJudges] = useState<Judges[]>([]);
const [models, setModels] = useState<Model[]>([]);
const [modelFamilies, setModelFamilies] = useState<ModelFamily[]>([]);
const [providers, setProviders] = useState<Provider[]>([]);
const [matrix, setMatrix] = useState<TransitionMatrix | null>(null);
const [error, setError] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(false);
const [loadingItems, setLoadingItems] = useState(false);
const [selectedTheme, setSelectedTheme] = useState<string>('');
const [selectedModel, setSelectedModel] = useState<string>('');
const [selectedModelFamily, setSelectedModelFamily] = useState<string>('');
const [selectedProvider, setSelectedProvider] = useState<string>('');
const [selectedJudge1, setSelectedJudge1] = useState<SelectedJudge | null >(null);
const [selectedJudge2, setSelectedJudge2] = useState<SelectedJudge | null >(null);
const [selectedCategory, setSelectedCategory] = useState<string[] | null>(null);
const [selectedItems, setSelectedItems] = useState<AssessmentItem[]>([]);
const getFirstClassification = (judge: Judges): string => {
return Object.keys(judge.classifications).filter(key => judge.classifications[key] > 0)[0] || '';
};
// Fetch initial data when the component mounts
useEffect(() => {
const loadFilters = async () => {
try {
const [themesData, judgesData, modelsData, modelFamiliesData, providersData] = await Promise.all([
getThemes(),
getJudges(),
getModels(),
getModelFamilies(),
getProviders(),
]);
setThemes(themesData);
setJudges(judgesData.sort(modelSort));
setModels(modelsData);
setModelFamilies(modelFamiliesData);
setProviders(providersData);
// Set default selections
if (judgesData.length >= 2) {
setSelectedJudge1({
name: judgesData[0].name,
classification: getFirstClassification(judgesData[0]),
});
setSelectedJudge2({
name: judgesData[1].name,
classification: getFirstClassification(judgesData[1]),
});
}
} catch (err) {
setError('Failed to load filter data. Is the backend server running?');
console.error(err);
}
};
loadFilters();
}, []);
// Data fetching logic
useEffect(() => {
if (!selectedJudge1 || !selectedJudge2) return;
const fetchData = async () => {
setIsLoading(true);
setError(null);
setMatrix(null);
try {
const result = await getReclassificationData(
selectedJudge1.name,
selectedJudge1.classification,
selectedJudge2.name,
selectedJudge2.classification,
selectedTheme,
selectedModel,
selectedModelFamily,
selectedProvider
);
setMatrix(result);
setSelectedItems([]);
setSelectedCategory(null);
} catch (err) {
setError(err instanceof Error ? err.message : 'An unknown error occurred.');
} finally {
setIsLoading(false);
}
};
fetchData();
}, [selectedTheme, selectedJudge1, selectedJudge2, selectedModel, selectedModelFamily, selectedProvider]);
const handleJudge1NameChange = (newName: string) => {
const newJudge = judges.find(j => j.name === newName);
if (newJudge) {
// When judge changes, reset classification to the first available one
setSelectedJudge1({
name: newName,
classification: getFirstClassification(newJudge),
});
}
};
const handleJudge1ClassificationChange = (newClassification: string) => {
if (selectedJudge1) {
setSelectedJudge1({ ...selectedJudge1, classification: newClassification });
}
};
const handleJudge2NameChange = (newName: string) => {
const newJudge = judges.find(j => j.name === newName);
if (newJudge) {
setSelectedJudge2({
name: newName,
classification: getFirstClassification(newJudge),
});
}
};
const handleJudge2ClassificationChange = (newClassification: string) => {
if (selectedJudge2) {
setSelectedJudge2({ ...selectedJudge2, classification: newClassification });
}
};
// Handle cell click to fetch assessment items
const handleCellClick = async (fromCategory: string, toCategory: string) => {
if (selectedJudge1 && selectedJudge2 && fromCategory && toCategory) {
setLoadingItems(true);
try {
const items = await getAssessmentItems(
selectedJudge1.name,
selectedJudge1.classification,
fromCategory,
selectedJudge2.name,
selectedJudge2.classification,
toCategory,
selectedTheme,
selectedModel,
selectedModelFamily,
selectedProvider
)
setSelectedItems(items);
setSelectedCategory([fromCategory, toCategory]);
} catch (err) {
setError(err instanceof Error ? err.message : 'An unknown error occurred.');
} finally {
setLoadingItems(false);
};
}
return;
};
return (
<div className="app">
<header className="app-header">
<div className="header-content">
<div className="logo-section">
<svg width="40" height="40" viewBox="0 0 40 40" className="logo">
<circle cx="20" cy="20" r="18" fill="#10b981" />
<path d="M12 20l6 6 10-12" stroke="white" strokeWidth="3" fill="none" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
<h1 className="app-title">LLM Assessment Explorer</h1>
</div>
</div>
</header>
<main className="main-content">
<FilterBar
themes={themes}
judges={judges}
models={models}
modelFamilies={modelFamilies}
providers={providers}
selectedTheme={selectedTheme}
onThemeChange={setSelectedTheme}
selectedModel={selectedModel}
onModelChange={setSelectedModel}
selectedModelFamily={selectedModelFamily}
onModelFamilyChange={setSelectedModelFamily}
selectedProvider={selectedProvider}
onProviderChange={setSelectedProvider}
selectedJudge1={selectedJudge1}
selectedJudge2={selectedJudge2}
onJudge1NameChange={handleJudge1NameChange}
onJudge1ClassificationChange={handleJudge1ClassificationChange}
onJudge2NameChange={handleJudge2NameChange}
onJudge2ClassificationChange={handleJudge2ClassificationChange}
/>
{isLoading && (
<div className="loading-indicator">
<div className="loading-spinner"></div>
<p>Loading data...</p>
</div>
)}
{!isLoading && matrix && (
<div className="charts-container">
<SankeyDiagram
matrix={matrix}
judge1={selectedJudge1!.name}
judge2={selectedJudge2!.name}
onCellClick={handleCellClick}
/>
<Heatmap
matrix={matrix}
judge1={selectedJudge1!.name}
judge2={selectedJudge2!.name}
onCellClick={handleCellClick}
/>
</div>
)}
{!loadingItems && selectedItems.length > 0 && (
<AssessmentItems
judge1={selectedJudge1!.name}
judge2={selectedJudge2!.name}
items={selectedItems}
selectedCategory={selectedCategory}
/>
)}
{loadingItems && (
<div className="loading-indicator">
<div className="loading-spinner"></div>
<p>Loading data...</p>
</div>
)}
</main>
</div>
);
}
export default App;