yigagilbert's picture
Update frontend/src/App.tsx
431d901 verified
import React, { useState, useMemo } from 'react';
import { useResults } from './hooks/useResults';
import ModelSelector from './components/ModelSelector';
import MetricCard from './components/MetricCard';
import BarChartView from './components/BarChartView';
import RadarView from './components/RadarView';
import LineTrendView from './components/LineTrendView';
import ComparisonTable from './components/ComparisonTable';
import AddModelForm from './components/AddModelForm';
import LanguageLevelTable from './components/LanguageLevelTable';
import { ChartRow, ModelMetrics } from './types';
import axios from 'axios';
const colors = ['#4F46E5', '#059669', '#DC2626', '#7C3AED', '#EA580C', '#0891B2'];
const metrics = ['bleu','chrf','cer','wer','rouge1','rouge2','rougeL','quality_score'];
function App() {
const { data, error } = useResults();
const [selectedMetric, setSelectedMetric] = useState(metrics[0]);
const [selectedModel, setSelectedModel] = useState('');
const [selectedModels, setSelectedModels] = useState<string[]>([]);
const [comparisonMode, setComparisonMode] = useState(false);
const [viewMode, setViewMode] = useState<'overview' | 'detailed'>('overview');
const [activeTab, setActiveTab] = useState<'dashboard' | 'addModel' | 'comparison'>('dashboard');
const [newModelName, setNewModelName] = useState('');
const [isEvaluating, setIsEvaluating] = useState(false);
const [evaluationError, setEvaluationError] = useState<string | null>(null);
const handleEvaluate = async () => {
if (!newModelName.trim()) {
setEvaluationError('Model name cannot be empty.');
return;
}
setIsEvaluating(true);
setEvaluationError(null);
try {
const response = await axios.post('http://localhost:8000/evaluate', {
model_name: newModelName,
});
// Handle success
alert(`Evaluation successful! Metrics: ${JSON.stringify(response.data.metrics)}`);
setNewModelName(''); // Clear the input field
} catch (error: any) {
// Handle error
setEvaluationError(error.response?.data?.detail || 'An error occurred during evaluation.');
} finally {
setIsEvaluating(false);
}
};
const modelNames = data ? Object.keys(data) : [];
const languagePairs = data && selectedModel && data[selectedModel]
? Object.keys(data[selectedModel]).filter(k => k !== 'averages')
: [];
const barChartData: ChartRow[] = useMemo(() => {
if (!data || !selectedModel || !data[selectedModel]) return [];
return languagePairs.map(pair => {
const row: any = { name: pair.toUpperCase() };
if (comparisonMode) {
selectedModels.forEach((m, i) => {
row[m] = data[m]?.[pair]?.[selectedMetric as keyof ModelMetrics] ?? 0;
});
} else {
row[selectedMetric] = data[selectedModel]?.[pair]?.[selectedMetric as keyof ModelMetrics] ?? 0;
}
return row;
});
}, [data, languagePairs, selectedMetric, comparisonMode, selectedModels]);
const radarData: ChartRow[] = useMemo(() => {
if (!data || !selectedModel || !data[selectedModel]) return [];
return metrics.map(metric => {
const point: any = { metric: metric.toUpperCase() };
if (comparisonMode) {
selectedModels.forEach((m, i) => {
point[m] = data[m]?.averages?.[metric as keyof ModelMetrics] ?? 0;
});
} else {
point.value = data[selectedModel]?.averages?.[metric as keyof ModelMetrics] ?? 0;
}
return point;
});
}, [data, selectedModel, selectedModels, comparisonMode]);
if (error) return <div className="p-6 text-red-600">Error: {error}</div>;
if (!data) return <div className="p-6">Loading...</div>;
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
{/* Main Navigation Tabs */}
<div className="bg-white shadow-sm border-b">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between items-center py-6">
<h1 className="text-3xl font-bold text-gray-900">Translation Leaderboard</h1>
<div className="flex space-x-4">
<button
onClick={() => setActiveTab('dashboard')}
className={`px-4 py-2 rounded-lg font-medium ${
activeTab === 'dashboard' ? 'bg-indigo-600 text-white' : 'bg-gray-200 text-gray-700 hover:bg-gray-300'
}`}
>
Dashboard
</button>
<button
onClick={() => setActiveTab('comparison')}
className={`px-4 py-2 rounded-lg font-medium ${
activeTab === 'comparison' ? 'bg-indigo-600 text-white' : 'bg-gray-200 text-gray-700 hover:bg-gray-300'
}`}
>
Comparison
</button>
<button
onClick={() => setActiveTab('addModel')}
className={`px-4 py-2 rounded-lg font-medium ${
activeTab === 'addModel' ? 'bg-indigo-600 text-white' : 'bg-gray-200 text-gray-700 hover:bg-gray-300'
}`}
>
Add Model
</button>
</div>
</div>
</div>
</div>
{/* Content Based on Active Tab */}
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
{activeTab === 'dashboard' && (
<div>
<h2 className="text-2xl font-bold mb-4">Dashboard</h2>
{/* Toggle Button for Comparison Mode */}
<div className="mb-6">
<button
onClick={() => setComparisonMode(!comparisonMode)}
className={`px-4 py-2 rounded-lg font-medium ${
comparisonMode ? 'bg-red-600 text-white' : 'bg-indigo-600 text-white'
}`}
>
{comparisonMode ? 'Disable Comparison Mode' : 'Enable Comparison Mode'}
</button>
</div>
<ModelSelector
modelNames={modelNames}
selectedModel={selectedModel}
selectedModels={selectedModels}
comparisonMode={comparisonMode}
onSelectModel={setSelectedModel}
onToggleModel={m =>
setSelectedModels(prev =>
prev.includes(m) ? prev.filter(x => x !== m) : [...prev, m]
)
}
/>
<div className="grid grid-cols-1 lg:grid-cols-4 gap-6 mb-8">
{/* Summary cards */}
{!comparisonMode ? (
<>
{data[selectedModel]?.averages && (
<MetricCard
title="Average BLEU"
value={data[selectedModel].averages.bleu}
description="Translation quality"
colorHex={colors[0]}
/>
)}
{/* Other cards */}
</>
) : (
selectedModels.map((m, i) => (
data[m]?.averages && (
<MetricCard
key={m}
title="Avg BLEU"
value={data[m].averages.bleu}
description={m}
colorHex={colors[i]}
/>
)
))
)}
</div>
{viewMode === 'overview' ? (
<>
<ComparisonTable data={data} metrics={metrics} />
<BarChartView
data={barChartData}
metrics={metrics}
selectedMetric={selectedMetric}
onMetricChange={setSelectedMetric}
comparisonMode={comparisonMode}
colors={colors}
selectedModels={selectedModels}
/>
</>
) : (
<>
<RadarView data={radarData} comparisonMode={comparisonMode} colors={colors} />
<LineTrendView data={barChartData} selectedModels={selectedModels} comparisonMode={comparisonMode} colors={colors} />
</>
)}
</div>
)}
{activeTab === 'addModel' && (
<div>
<h2 className="text-2xl font-bold mb-4">Add a New Model</h2>
<AddModelForm
newModelName={newModelName}
isEvaluating={isEvaluating}
onNameChange={setNewModelName}
onEvaluate={handleEvaluate}
/>
{evaluationError && <p className="text-red-600 mt-4">{evaluationError}</p>}
</div>
)}
{activeTab === 'comparison' && (
<div>
<h2 className="text-2xl font-bold mb-4">Comparison</h2>
<ModelSelector
modelNames={modelNames}
selectedModel={selectedModel}
selectedModels={selectedModels}
comparisonMode={comparisonMode}
onSelectModel={setSelectedModel}
onToggleModel={m =>
setSelectedModels(prev =>
prev.includes(m) ? prev.filter(x => x !== m) : [...prev, m]
)
}
/>
<RadarView data={radarData} comparisonMode={comparisonMode} colors={colors} />
<ComparisonTable data={data} metrics={metrics} />
<LineTrendView data={barChartData} selectedModels={selectedModels} comparisonMode={comparisonMode} colors={colors} />
</div>
)}
{activeTab === 'dashboard' && (
<div>
<h2 className="text-2xl font-bold mb-4">Dashboard</h2>
<LanguageLevelTable
data={data}
selectedModels={selectedModels}
metrics={metrics}
colors={colors}
/>
</div>
)}
{activeTab === 'comparison' && (
<div>
<h2 className="text-2xl font-bold mb-4">Comparison</h2>
<LanguageLevelTable
data={data}
selectedModels={selectedModels}
metrics={metrics}
colors={colors}
/>
</div>
)}
</div>
</div>
);
}
export default App;