import React, { useState, useEffect, useMemo } from 'react'; const UrologyLeaderboard = () => { const [searchTerm, setSearchTerm] = useState(''); const [filterLicense, setFilterLicense] = useState('all'); const [sortBy, setSortBy] = useState('accuracy'); const [sortOrder, setSortOrder] = useState('desc'); const [data, setData] = useState([]); const [loading, setLoading] = useState(true); const [refreshing, setRefreshing] = useState(false); const [lastUpdated, setLastUpdated] = useState(null); const [error, setError] = useState(null); const loadData = async () => { try { const response = await fetch('https://datasets-server.huggingface.co/rows?dataset=SASLeaderboard/results&config=default&split=train'); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const data = await response.json(); console.log('Raw HuggingFace data:', data); if (!data.rows || data.rows.length === 0) { throw new Error('No data found in the dataset'); } // Agrupar por modelo y calcular estadísticas const modelStats = {}; data.rows.forEach(row => { const rowData = row.row; const model = rowData.model; const isCorrect = rowData.is_correct; const timestamp = rowData.timestamp; if (!modelStats[model]) { modelStats[model] = { model: model, baseModel: model.split('/')[1] || model, totalQuestions: 0, correctAnswers: 0, submittedTime: timestamp, license: "Unknown", submitType: "unknown", params: 0, precision: "unknown", status: "FINISHED" }; } modelStats[model].totalQuestions++; if (isCorrect) { modelStats[model].correctAnswers++; } // Mantener el timestamp más reciente if (new Date(timestamp) > new Date(modelStats[model].submittedTime)) { modelStats[model].submittedTime = timestamp; } }); // Convertir a array y calcular accuracy const processedData = Object.values(modelStats).map(stats => ({ ...stats, accuracy: stats.totalQuestions > 0 ? stats.correctAnswers / stats.totalQuestions : 0 })); console.log('Processed data:', processedData); return processedData; } catch (error) { console.error('Error loading data from HuggingFace:', error); throw error; } }; const refreshData = async () => { setRefreshing(true); setError(null); try { const newData = await loadData(); setData(newData); setLastUpdated(new Date()); } catch (error) { setError(`Failed to load data: ${error.message}`); setData([]); } finally { setRefreshing(false); } }; useEffect(() => { const initializeData = async () => { try { const initialData = await loadData(); setData(initialData); setLastUpdated(new Date()); } catch (error) { setError(`Failed to load data: ${error.message}`); setData([]); } finally { setLoading(false); } }; initializeData(); }, []); const filteredAndSortedData = useMemo(() => { // Si hay error, no procesar datos if (error) { return []; } let filtered = data.filter(item => { const matchesSearch = item.model.toLowerCase().includes(searchTerm.toLowerCase()) || item.baseModel.toLowerCase().includes(searchTerm.toLowerCase()); const matchesFilter = filterLicense === 'all' || item.license === filterLicense; return matchesSearch && matchesFilter; }); return filtered.sort((a, b) => { let aValue = a[sortBy]; let bValue = b[sortBy]; if (sortBy === 'submittedTime') { aValue = new Date(aValue); bValue = new Date(bValue); } if (sortOrder === 'desc') { return bValue > aValue ? 1 : -1; } else { return aValue > bValue ? 1 : -1; } }); }, [data, searchTerm, filterLicense, sortBy, sortOrder, error]); const getRankIcon = (index) => { switch(index) { case 0: return React.createElement('span', { style: { fontSize: '24px' } }, '🏆'); case 1: return React.createElement('span', { style: { fontSize: '24px' } }, '🥈'); case 2: return React.createElement('span', { style: { fontSize: '24px' } }, '🥉'); default: return React.createElement('span', { style: { fontSize: '20px', fontWeight: 'bold', color: '#9ca3af' } }, `#${index + 1}`); } }; const formatAccuracy = (accuracy) => { return `${(accuracy * 100).toFixed(2)}%`; }; const formatParams = (params) => { if (params === 0) return 'API'; if (params >= 1e9) return `${(params / 1e9).toFixed(1)}B`; if (params >= 1e6) return `${(params / 1e6).toFixed(1)}M`; return params.toLocaleString(); }; const formatDate = (dateString) => { return new Date(dateString).toLocaleDateString('en-US', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }); }; const getSortIcon = (column) => { if (sortBy !== column) { return React.createElement('span', { style: { color: '#9ca3af' } }, '↕️'); } return sortOrder === 'desc' ? React.createElement('span', { style: { color: '#3b82f6' } }, '⬇️') : React.createElement('span', { style: { color: '#3b82f6' } }, '⬆️'); }; const styles = { container: { minHeight: '100vh', background: 'linear-gradient(135deg, #0f172a 0%, #1e3a8a 50%, #3730a3 100%)', padding: '32px 16px' }, innerContainer: { maxWidth: '1200px', margin: '0 auto' }, header: { textAlign: 'center', marginBottom: '32px' }, title: { fontSize: '48px', fontWeight: 'bold', color: 'white', marginBottom: '16px', background: 'linear-gradient(to right, #60a5fa, #a78bfa)', WebkitBackgroundClip: 'text', backgroundClip: 'text', color: 'transparent' }, subtitle: { fontSize: '20px', color: '#d1d5db', marginBottom: '24px' }, statsContainer: { display: 'flex', justifyContent: 'center', gap: '32px', textAlign: 'center', flexWrap: 'wrap' }, statCard: { background: 'rgba(255, 255, 255, 0.1)', backdropFilter: 'blur(10px)', border: '1px solid rgba(255, 255, 255, 0.2)', borderRadius: '12px', padding: '16px' }, statNumber: { fontSize: '24px', fontWeight: 'bold', color: 'white' }, statLabel: { fontSize: '14px', color: '#d1d5db' }, controlsContainer: { marginBottom: '24px', display: 'flex', flexWrap: 'wrap', gap: '16px', alignItems: 'center', justifyContent: 'space-between' }, inputGroup: { display: 'flex', flexWrap: 'wrap', gap: '16px', alignItems: 'center' }, inputContainer: { position: 'relative' }, inputIcon: { position: 'absolute', left: '12px', top: '50%', transform: 'translateY(-50%)', color: '#9ca3af' }, input: { background: 'rgba(255, 255, 255, 0.1)', backdropFilter: 'blur(10px)', border: '1px solid rgba(255, 255, 255, 0.2)', borderRadius: '8px', color: 'white', padding: '8px 12px 8px 40px', outline: 'none', fontSize: '14px' }, select: { background: 'rgba(255, 255, 255, 0.1)', backdropFilter: 'blur(10px)', border: '1px solid rgba(255, 255, 255, 0.2)', borderRadius: '8px', color: 'white', padding: '8px 32px 8px 40px', outline: 'none', fontSize: '14px' }, updateButton: { background: '#059669', color: 'white', border: 'none', borderRadius: '8px', padding: '8px 16px', cursor: 'pointer', display: 'flex', alignItems: 'center', gap: '8px', fontSize: '14px' }, tableCard: { background: 'rgba(255, 255, 255, 0.1)', backdropFilter: 'blur(10px)', border: '1px solid rgba(255, 255, 255, 0.2)', borderRadius: '12px', overflow: 'hidden' }, tableContainer: { overflowX: 'auto' }, scrollContainer: { maxHeight: '384px', overflowY: 'auto' }, table: { width: '100%', borderCollapse: 'collapse' }, tableHeader: { position: 'sticky', top: 0, background: 'rgba(255, 255, 255, 0.1)', backdropFilter: 'blur(10px)', borderBottom: '1px solid rgba(255, 255, 255, 0.1)' }, th: { padding: '16px 24px', textAlign: 'left', color: 'white', fontWeight: '600' }, thClickable: { padding: '16px 24px', textAlign: 'left', color: 'white', fontWeight: '600', cursor: 'pointer' }, tr: { borderBottom: '1px solid rgba(255, 255, 255, 0.05)' }, td: { padding: '16px 24px' }, progressBar: { width: '100%', background: '#374151', borderRadius: '4px', height: '8px' }, progressFill: { background: 'linear-gradient(to right, #3b82f6, #8b5cf6)', height: '8px', borderRadius: '4px', transition: 'width 0.5s ease' }, badge: { padding: '4px 8px', borderRadius: '12px', fontSize: '12px', fontWeight: '500' }, badgeBlue: { background: 'rgba(59, 130, 246, 0.2)', color: '#93c5fd' }, badgeGreen: { background: 'rgba(34, 197, 94, 0.2)', color: '#86efac' }, badgePurple: { background: 'rgba(147, 51, 234, 0.2)', color: '#c4b5fd' }, infoSection: { marginTop: '32px', display: 'flex', flexDirection: 'column', gap: '24px' }, infoCard: { background: 'rgba(255, 255, 255, 0.1)', backdropFilter: 'blur(10px)', border: '1px solid rgba(255, 255, 255, 0.2)', borderRadius: '12px', padding: '24px' }, academicCard: { background: 'rgba(255, 255, 255, 0.1)', backdropFilter: 'blur(10px)', border: '1px solid rgba(255, 255, 255, 0.2)', borderRadius: '12px', padding: '16px', textAlign: 'center' }, loadingContainer: { minHeight: '100vh', background: 'linear-gradient(135deg, #0f172a 0%, #1e3a8a 50%, #3730a3 100%)', display: 'flex', alignItems: 'center', justifyContent: 'center' }, spinner: { width: '64px', height: '64px', border: '2px solid transparent', borderBottom: '2px solid white', borderRadius: '50%', animation: 'spin 1s linear infinite', margin: '0 auto 16px' } }; if (loading) { return React.createElement('div', { style: styles.loadingContainer }, React.createElement('div', { style: { textAlign: 'center' } }, React.createElement('div', { style: styles.spinner }), React.createElement('p', { style: { color: 'white', fontSize: '20px' } }, 'Loading leaderboard...') ) ); } return React.createElement('div', null, React.createElement('style', null, ` @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .rotate { animation: spin 1s linear infinite; } .hover-row:hover { background: rgba(255, 255, 255, 0.05); } input::placeholder { color: #9ca3af; } select option { background: #1f2937; color: white; } `), React.createElement('div', { style: styles.container }, React.createElement('div', { style: styles.innerContainer }, React.createElement('div', { style: styles.header }, React.createElement('h1', { style: styles.title }, '🏆 Urology AI Leaderboard'), React.createElement('p', { style: styles.subtitle }, 'Evaluating Natural Language Models on Urology Knowledge Assessment'), React.createElement('div', { style: styles.statsContainer }, React.createElement('div', { style: styles.statCard }, React.createElement('div', { style: styles.statNumber }, data.length), React.createElement('div', { style: styles.statLabel }, 'Models') ), React.createElement('div', { style: styles.statCard }, React.createElement('div', { style: styles.statNumber }, '151'), React.createElement('div', { style: styles.statLabel }, 'Questions') ), React.createElement('div', { style: styles.statCard }, React.createElement('div', { style: styles.statNumber }, 'SAS Urology'), React.createElement('div', { style: styles.statLabel }, 'Specialty') ) ) ), React.createElement('div', { style: styles.controlsContainer }, React.createElement('div', { style: styles.inputGroup }, React.createElement('div', { style: styles.inputContainer }, React.createElement('span', { style: styles.inputIcon }, '🔍'), React.createElement('input', { type: 'text', placeholder: 'Search model...', value: searchTerm, onChange: (e) => setSearchTerm(e.target.value), style: styles.input }) ), React.createElement('div', { style: styles.inputContainer }, React.createElement('span', { style: styles.inputIcon }, '📋'), React.createElement('select', { value: filterLicense, onChange: (e) => setFilterLicense(e.target.value), style: styles.select }, React.createElement('option', { value: 'all' }, 'All licenses'), React.createElement('option', { value: 'API Service' }, 'API Service'), React.createElement('option', { value: 'Apache 2.0' }, 'Apache 2.0'), React.createElement('option', { value: 'MIT' }, 'MIT') ) ) ), React.createElement('button', { onClick: refreshData, disabled: refreshing, style: { ...styles.updateButton, opacity: refreshing ? 0.5 : 1 } }, React.createElement('span', { className: refreshing ? 'rotate' : '' }, '🔄'), React.createElement('span', null, refreshing ? 'Updating...' : 'Update') ) ), React.createElement('div', { style: styles.tableCard }, React.createElement('div', { style: styles.tableContainer }, React.createElement('div', { style: styles.scrollContainer }, React.createElement('table', { style: styles.table }, React.createElement('thead', { style: styles.tableHeader }, React.createElement('tr', null, React.createElement('th', { style: styles.th }, 'Rank'), React.createElement('th', { style: styles.th }, 'Model'), React.createElement('th', { style: styles.thClickable, onClick: () => { if (sortBy === 'accuracy') { setSortOrder(sortOrder === 'desc' ? 'asc' : 'desc'); } else { setSortBy('accuracy'); setSortOrder('desc'); } } }, React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: '4px' } }, React.createElement('span', null, '🎯'), React.createElement('span', null, 'Accuracy'), getSortIcon('accuracy') ) ), React.createElement('th', { style: styles.th }, 'Answers'), React.createElement('th', { style: styles.th }, 'Parameters'), React.createElement('th', { style: styles.th }, 'License'), React.createElement('th', { style: styles.thClickable, onClick: () => { if (sortBy === 'submittedTime') { setSortOrder(sortOrder === 'desc' ? 'asc' : 'desc'); } else { setSortBy('submittedTime'); setSortOrder('desc'); } } }, React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: '4px' } }, React.createElement('span', null, '🕒'), React.createElement('span', null, 'Date'), getSortIcon('submittedTime') ) ) ) ), React.createElement('tbody', null, filteredAndSortedData.map((item, index) => React.createElement('tr', { key: item.model, style: styles.tr, className: 'hover-row' }, React.createElement('td', { style: styles.td }, getRankIcon(index)), React.createElement('td', { style: styles.td }, React.createElement('div', { style: { display: 'flex', flexDirection: 'column' } }, React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: '8px' } }, React.createElement('span', { style: { color: 'white', fontWeight: '500' } }, item.model.split('/').pop()), React.createElement('span', { style: { color: '#9ca3af', cursor: 'pointer' } }, '🔗') ), React.createElement('span', { style: { fontSize: '14px', color: '#9ca3af' } }, item.model.split('/')[0]) ) ), React.createElement('td', { style: styles.td }, React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: '12px' } }, React.createElement('div', { style: { flex: 1 } }, React.createElement('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '4px' } }, React.createElement('span', { style: { color: 'white', fontWeight: '600' } }, formatAccuracy(item.accuracy)) ), React.createElement('div', { style: styles.progressBar }, React.createElement('div', { style: { ...styles.progressFill, width: `${item.accuracy * 100}%` } }) ) ) ) ), React.createElement('td', { style: styles.td }, React.createElement('div', { style: { textAlign: 'center' } }, React.createElement('div', { style: { color: 'white', fontWeight: '600' } }, `${item.correctAnswers}/${item.totalQuestions}`), React.createElement('div', { style: { fontSize: '14px', color: '#9ca3af' } }, 'correct') ) ), React.createElement('td', { style: styles.td }, React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: '8px' } }, React.createElement('span', null, '⚡'), React.createElement('span', { style: { color: 'white' } }, formatParams(item.params)) ) ), React.createElement('td', { style: styles.td }, React.createElement('span', { style: { ...styles.badge, ...(item.license === 'API Service' ? styles.badgeBlue : item.license === 'Apache 2.0' ? styles.badgeGreen : styles.badgePurple) } }, item.license) ), React.createElement('td', { style: styles.td }, React.createElement('div', { style: { fontSize: '14px', color: '#d1d5db' } }, formatDate(item.submittedTime)) ) ) ) ) ) ) ) ), React.createElement('div', { style: styles.infoSection }, React.createElement('div', { style: styles.infoCard }, React.createElement('h3', { style: { fontSize: '20px', fontWeight: '600', color: 'white', marginBottom: '12px' } }, '📊 About This Evaluation'), React.createElement('p', { style: { color: '#d1d5db', marginBottom: '12px' } }, 'This leaderboard evaluates natural language models on their ability to answer urology questions. Models must respond to multiple-choice questions about urological knowledge, demonstrating their understanding and mastery of this medical specialty.'), React.createElement('p', { style: { color: '#d1d5db', marginBottom: '16px' } }, 'Questions are from the ', React.createElement('a', { href: 'https://www.sspa.juntadeandalucia.es/servicioandaluzdesalud/', target: '_blank', rel: 'noopener noreferrer', style: { color: '#60a5fa', textDecoration: 'none', fontWeight: '600' } }, 'SAS (Servicio Andaluz de Salud)'), ' for the ', React.createElement('a', { href: 'https://www.sspa.juntadeandalucia.es/servicioandaluzdesalud/profesionales/ofertas-de-empleo/oferta-de-empleo-publico-puestos-base/oep-extraordinaria-decreto-ley-122022-centros-sas/cuadro-de-evolucion-concurso-oposicion-centros-sas/fea-urologia', target: '_blank', rel: 'noopener noreferrer', style: { color: '#60a5fa', textDecoration: 'none', fontWeight: '600' } }, React.createElement('strong', null, 'Convocatoria Concurso Oposición')), ' - specialized medical examination for urology residents.' ), React.createElement('div', { style: { display: 'flex', justifyContent: 'center', color: '#d1d5db' } }, React.createElement('span', null, 'Dataset: ', React.createElement('a', { href: 'https://huggingface.co/datasets/SASLeaderboard/results', style: { color: '#60a5fa', textDecoration: 'none' }, target: '_blank', rel: 'noopener noreferrer' }, 'SASLeaderboard/results')) ) ), React.createElement('div', { style: styles.academicCard }, React.createElement('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: '20px', flexWrap: 'wrap' } }, React.createElement('a', { href: 'https://iesrafaelalberti.es/', target: '_blank', rel: 'noopener noreferrer', style: { textDecoration: 'none', flexShrink: 0 } }, React.createElement('img', { src: 'https://avatars.githubusercontent.com/u/79144080?s=200&v=4', alt: 'IES Rafael Alberti Logo', style: { width: '80px', height: '80px', cursor: 'pointer', background: 'white', borderRadius: '8px', padding: '4px' } }) ), React.createElement('div', { style: { textAlign: 'center', flex: 1, minWidth: '200px' } }, React.createElement('h4', { style: { fontSize: '18px', fontWeight: '600', color: 'white', marginBottom: '16px', margin: '0 0 16px 0' } }, '🎓 Academic Project'), React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: '8px' } }, React.createElement('p', { style: { color: '#d1d5db', fontSize: '14px', margin: 0 } }, 'Final project for ', React.createElement('a', { href: 'https://iesrafaelalberti.es/', target: '_blank', rel: 'noopener noreferrer', style: { color: '#60a5fa', textDecoration: 'none', fontWeight: '600' } }, 'IES Rafael Alberti') ), React.createElement('p', { style: { color: '#d1d5db', fontSize: '14px', margin: 0 } }, 'Course: ', React.createElement('a', { href: 'https://iesrafaelalberti.es/curso-especializacion-inteligencia-artificial-y-big-datatarde/', target: '_blank', rel: 'noopener noreferrer', style: { color: '#60a5fa', textDecoration: 'none', fontWeight: '600' } }, 'Artificial Intelligence and Big Data') ), React.createElement('p', { style: { color: '#d1d5db', fontSize: '14px', margin: 0 } }, 'Subject: Artificial Intelligence Models' ) ) ), React.createElement('a', { href: 'https://iesrafaelalberti.es/curso-especializacion-inteligencia-artificial-y-big-datatarde/', target: '_blank', rel: 'noopener noreferrer', style: { textDecoration: 'none', flexShrink: 0 } }, React.createElement('img', { src: '/IA-Big-Data-cuadrado.png', alt: 'AI and Big Data Course Logo', style: { width: '80px', height: '80px', cursor: 'pointer', background: 'white', borderRadius: '8px', padding: '4px' }, onError: (e) => { console.log('Error loading course image from public folder'); }, onLoad: () => { console.log('Course image loaded successfully from public folder'); } }) ) ) ) ) ) ) ); }; export default UrologyLeaderboard;