|
import React, { useState, useEffect } from 'react'; |
|
import _ from 'lodash'; |
|
|
|
const ScoreBar = ({ score }) => { |
|
const percentage = score <= 1 ? score * 100 : score; |
|
const hue = Math.min(percentage * 1.2, 120); |
|
const backgroundColor = `hsl(${hue}, 70%, 45%)`; |
|
|
|
return ( |
|
<div className="relative h-8 bg-gray-100 rounded w-full"> |
|
<div |
|
className="absolute top-0 left-0 h-full rounded transition-all duration-200" |
|
style={{ |
|
width: `${percentage}%`, |
|
backgroundColor |
|
}} |
|
/> |
|
<div className="absolute inset-0 flex items-center justify-end px-3"> |
|
<span className="text-sm font-medium text-white mix-blend-difference"> |
|
{percentage.toFixed(2)}% |
|
</span> |
|
</div> |
|
</div> |
|
); |
|
}; |
|
|
|
function App() { |
|
const [data, setData] = useState([]); |
|
const [loading, setLoading] = useState(true); |
|
const [error, setError] = useState(null); |
|
const [sortConfig, setSortConfig] = useState({ key: 'GAIA', direction: 'desc' }); |
|
|
|
useEffect(() => { |
|
const fetchData = async () => { |
|
try { |
|
setLoading(true); |
|
const response = await fetch('/api/results'); |
|
if (!response.ok) { |
|
throw new Error('Failed to fetch data'); |
|
} |
|
const jsonData = await response.json(); |
|
setData(jsonData); |
|
} catch (err) { |
|
console.error('Error fetching data:', err); |
|
setError(err.message); |
|
} finally { |
|
setLoading(false); |
|
} |
|
}; |
|
|
|
fetchData(); |
|
}, []); |
|
|
|
const handleSort = (key) => { |
|
const direction = sortConfig.key === key && sortConfig.direction === 'desc' ? 'asc' : 'desc'; |
|
setSortConfig({ key, direction }); |
|
}; |
|
|
|
const sortedData = _.orderBy( |
|
data, |
|
[item => item.scores[sortConfig.key] || 0], |
|
[sortConfig.direction] |
|
); |
|
|
|
const getSortIcon = (key) => { |
|
if (sortConfig.key === key) { |
|
return sortConfig.direction === 'desc' ? ' β' : ' β'; |
|
} |
|
return ' β'; |
|
}; |
|
|
|
if (loading) { |
|
return ( |
|
<div className="flex items-center justify-center min-h-screen"> |
|
<div className="text-lg">Loading benchmark results...</div> |
|
</div> |
|
); |
|
} |
|
|
|
if (error) { |
|
return ( |
|
<div className="flex items-center justify-center min-h-screen text-red-600"> |
|
Error: {error} |
|
</div> |
|
); |
|
} |
|
|
|
return ( |
|
<div className="p-6"> |
|
<div className="mb-6"> |
|
<h1 className="text-2xl font-bold mb-2">Model Benchmark Results</h1> |
|
<p className="text-gray-600">Comparing model performance across different benchmarks</p> |
|
</div> |
|
|
|
<div className="overflow-x-auto"> |
|
<table className="w-full border-collapse"> |
|
<thead> |
|
<tr className="border-b border-gray-200"> |
|
<th className="py-3 text-left font-medium text-gray-700 w-1/4">Model</th> |
|
{["GAIA", "MATH", "SimpleQA"].map(benchmark => ( |
|
<th |
|
key={benchmark} |
|
onClick={() => handleSort(benchmark)} |
|
className="py-3 px-4 text-left font-medium text-gray-700 cursor-pointer hover:text-blue-600" |
|
> |
|
<div className="flex items-center gap-1"> |
|
{benchmark} |
|
<span className="text-gray-500">{getSortIcon(benchmark)}</span> |
|
</div> |
|
</th> |
|
))} |
|
</tr> |
|
</thead> |
|
<tbody> |
|
{sortedData.map((item, index) => ( |
|
<tr key={index} className="border-b border-gray-100"> |
|
<td className="py-3 pr-4 font-medium truncate" title={item.model_id}> |
|
{item.model_id} |
|
</td> |
|
<td className="py-3 px-4"> |
|
<ScoreBar score={item.scores.GAIA} /> |
|
</td> |
|
<td className="py-3 px-4"> |
|
<ScoreBar score={item.scores.MATH} /> |
|
</td> |
|
<td className="py-3 px-4"> |
|
<ScoreBar score={item.scores.SimpleQA} /> |
|
</td> |
|
</tr> |
|
))} |
|
</tbody> |
|
</table> |
|
</div> |
|
</div> |
|
); |
|
} |
|
|
|
export default App; |