|
import { useState, useEffect } from 'react' |
|
import { PrimeReactProvider } from 'primereact/api' |
|
import 'primereact/resources/themes/lara-light-cyan/theme.css' |
|
import ModelTable from './components/ModelTable' |
|
import LanguageTable from './components/LanguageTable' |
|
import DatasetTable from './components/DatasetTable' |
|
import WorldMap from './components/WorldMap' |
|
import AutoComplete from './components/AutoComplete' |
|
import LanguagePlot from './components/LanguagePlot' |
|
import SpeakerPlot from './components/SpeakerPlot' |
|
import HistoryPlot from './components/HistoryPlot' |
|
import CostPlot from './components/CostPlot' |
|
import { Carousel } from 'primereact/carousel' |
|
import { Dialog } from 'primereact/dialog' |
|
import { Button } from 'primereact/button' |
|
|
|
function App () { |
|
const [data, setData] = useState(null) |
|
const [loading, setLoading] = useState(true) |
|
const [error, setError] = useState(null) |
|
const [selectedLanguages, setSelectedLanguages] = useState([]) |
|
const [dialogVisible, setDialogVisible] = useState(false) |
|
const [aboutVisible, setAboutVisible] = useState(false) |
|
const [contributeVisible, setContributeVisible] = useState(false) |
|
|
|
useEffect(() => { |
|
fetch('/api/data', { |
|
method: 'POST', |
|
body: JSON.stringify({ selectedLanguages }) |
|
}) |
|
.then(response => { |
|
if (!response.ok) { |
|
throw new Error('Network response was not ok') |
|
} |
|
return response.json() |
|
}) |
|
.then(jsonData => { |
|
setData(jsonData) |
|
setLoading(false) |
|
}) |
|
.catch(err => { |
|
setError(err.message) |
|
setLoading(false) |
|
}) |
|
}, [selectedLanguages]) |
|
|
|
const [windowWidth, setWindowWidth] = useState(window.innerWidth) |
|
const [windowHeight, setWindowHeight] = useState(window.innerHeight) |
|
useEffect(() => { |
|
const handleResize = () => { |
|
setWindowWidth(window.innerWidth) |
|
setWindowHeight(window.innerHeight) |
|
} |
|
window.addEventListener('resize', handleResize) |
|
return () => window.removeEventListener('resize', handleResize) |
|
}, []) |
|
|
|
return ( |
|
<PrimeReactProvider> |
|
<div style={{ minHeight: '100vh', display: 'flex', flexDirection: 'column', width: '100vw' }}> |
|
<div style={{backgroundColor: '#fff3cd', color: '#856404', padding: '0.75rem 1.25rem', marginBottom: '1rem', border: '1px solid #ffeeba', borderRadius: '0.25rem', textAlign: 'center'}}> |
|
<strong>Work in Progress:</strong> This dashboard is currently under active development. Evaluation results are not yet final. |
|
<a href="https://github.com/datenlabor-bmz/ai-language-monitor" target="_blank" rel="noopener noreferrer" style={{ |
|
textDecoration: 'none', |
|
color: '#856404', |
|
float: 'right', |
|
fontSize: '1.2rem', |
|
fontWeight: 'bold', |
|
padding: '0 0.5rem', |
|
borderRadius: '3px', |
|
backgroundColor: 'rgba(255,255,255,0.3)' |
|
}}> |
|
<i className="pi pi-github" title="View on GitHub" style={{ marginRight: '0.3rem' }} /> |
|
GitHub |
|
</a> |
|
</div> |
|
<header |
|
style={{ |
|
display: 'flex', |
|
flexDirection: 'column', |
|
alignItems: 'center', |
|
justifyContent: 'center', |
|
padding: '5vh 5vw', |
|
width: '100%', |
|
maxWidth: '1400px', |
|
margin: '0 auto' |
|
}} |
|
> |
|
<div> |
|
<span |
|
role='img' |
|
aria-label='Globe Emoji' |
|
style={{ fontSize: '40px' }} |
|
> |
|
π |
|
</span> |
|
</div> |
|
<h1 style={{ |
|
fontSize: '2.5rem', |
|
fontWeight: '600', |
|
margin: '1rem 0 0.5rem 0', |
|
color: '#333', |
|
letterSpacing: '-0.01em' |
|
}}> |
|
AI Language Proficiency Monitor |
|
</h1> |
|
<p style={{ |
|
fontSize: '1.1rem', |
|
color: '#666', |
|
margin: '0 0 2.5rem 0', |
|
fontWeight: '400', |
|
maxWidth: '700px', |
|
lineHeight: '1.5' |
|
}}> |
|
Comprehensive multilingual evaluation results for AI language models |
|
</p> |
|
|
|
<div style={{ display: 'flex', gap: '1rem', marginBottom: '1.5rem', flexWrap: 'wrap', justifyContent: 'center' }}> |
|
<Button |
|
label="π About this tool" |
|
className="p-button-text" |
|
onClick={() => setAboutVisible(true)} |
|
style={{ |
|
color: '#666', |
|
border: '1px solid #ddd', |
|
padding: '0.5rem 1rem', |
|
borderRadius: '4px', |
|
fontSize: '0.9rem' |
|
}} |
|
/> |
|
|
|
<Button |
|
label="π Add your model (soon)" |
|
className="p-button-text" |
|
onClick={() => setContributeVisible(true)} |
|
tooltip="This feature is on our roadmap and will be available soon." |
|
tooltipOptions={{ position: 'bottom' }} |
|
style={{ |
|
color: '#666', |
|
border: '1px solid #ddd', |
|
padding: '0.5rem 1rem', |
|
borderRadius: '4px', |
|
fontSize: '0.9rem' |
|
}} |
|
/> |
|
</div> |
|
|
|
{data && ( |
|
<AutoComplete |
|
languages={data?.language_table} |
|
onComplete={items => setSelectedLanguages(items)} |
|
/> |
|
)} |
|
</header> |
|
<main |
|
style={{ |
|
display: 'flex', |
|
flexDirection: 'column', |
|
gap: '3rem', |
|
width: '100%', |
|
paddingBottom: '5vh', |
|
padding: '1rem 15vw 5vh 15vw' |
|
}} |
|
> |
|
{loading && ( |
|
<div style={{ width: '100%', textAlign: 'center' }}> |
|
<i className='pi pi-spinner pi-spin' style={{ fontSize: '4rem' }} /> |
|
</div> |
|
)} |
|
{error && <div style={{ width: '100%', textAlign: 'center' }}><p>Error: {error}</p></div>} |
|
{data && ( |
|
<> |
|
<div style={{ width: '100%' }}> |
|
<ModelTable |
|
data={data.model_table} |
|
selectedLanguages={selectedLanguages} |
|
allLanguages={data.language_table || []} |
|
/> |
|
</div> |
|
<div style={{ width: '100%' }}> |
|
<LanguageTable |
|
data={data.language_table} |
|
selectedLanguages={selectedLanguages} |
|
setSelectedLanguages={setSelectedLanguages} |
|
totalModels={data.model_table?.length || 0} |
|
/> |
|
</div> |
|
<div style={{ width: '100%' }}> |
|
<DatasetTable data={data} /> |
|
</div> |
|
<div |
|
id='figure' |
|
style={{ |
|
width: '100%', |
|
position: 'relative' |
|
}} |
|
> |
|
<Button |
|
icon="pi pi-external-link" |
|
className="p-button-text p-button-plain" |
|
onClick={() => setDialogVisible(true)} |
|
tooltip="Open in larger view" |
|
style={{ |
|
position: 'absolute', |
|
top: '10px', |
|
right: '10px', |
|
zIndex: 1, |
|
color: '#666' |
|
}} |
|
/> |
|
<Carousel |
|
value={[ |
|
<WorldMap data={data.countries} />, |
|
<LanguagePlot data={data} />, |
|
<SpeakerPlot data={data} />, |
|
<HistoryPlot data={data} />, |
|
<CostPlot data={data} />, |
|
]} |
|
numScroll={1} |
|
numVisible={1} |
|
itemTemplate={item => item} |
|
circular |
|
style={{ width: '100%', minHeight: '650px' }} |
|
/> |
|
</div> |
|
</> |
|
)} |
|
</main> |
|
|
|
{/* About Dialog */} |
|
<Dialog |
|
visible={aboutVisible} |
|
onHide={() => setAboutVisible(false)} |
|
style={{ width: '600px' }} |
|
modal |
|
header="About this tool" |
|
> |
|
<div> |
|
<p>The <i>AI Language Proficiency Monitor</i> presents comprehensive multilingual evaluation results of AI language models.</p> |
|
<h4>Who is this for?</h4> |
|
<ul> |
|
<li><b>Practitioners</b> can pick the best model for a given language.</li> |
|
<li><b>Policymakers and funders</b> can identify and prioritize neglected languages.</li> |
|
<li><b>Model developers</b> can compete on our <i>AI Language Proficiency</i> metric.</li> |
|
</ul> |
|
<h4>β‘ Live Updates</h4> |
|
<p>Benchmark results automatically refresh every night and include the most popular models from <a href="https://openrouter.ai" target="_blank" rel="noopener noreferrer">OpenRouter</a>, plus community-submitted models.</p> |
|
<h4>Authors</h4> |
|
<p>The AI Language Proficiency Monitor is a collaboration between BMZ's <a href="https://www.bmz-digital.global/en/overview-of-initiatives/the-bmz-data-lab/" target="_blank" rel="noopener noreferrer">Data Lab</a>, the BMZ-Initiative <a href="https://www.bmz-digital.global/en/overview-of-initiatives/fair-forward/" target="_blank" rel="noopener noreferrer">Fair Forward</a> (implemented by GIZ), and the <a href="https://www.dfki.de/en/web/research/research-departments/multilinguality-and-language-technology/ee-team" target="_blank" rel="noopener noreferrer">E&E group</a> of DFKI's Multilinguality and Language Technology Lab.</p> |
|
<h4>π Links</h4> |
|
<p> |
|
<a |
|
href="https://github.com/datenlabor-bmz/ai-language-monitor" |
|
target="_blank" |
|
rel="noopener noreferrer" |
|
style={{ |
|
color: '#666', |
|
textDecoration: 'none', |
|
display: 'inline-flex', |
|
alignItems: 'center', |
|
gap: '0.5rem' |
|
}} |
|
> |
|
<i className="pi pi-github" style={{ fontSize: '1.2rem' }} /> |
|
View source code on GitHub |
|
</a> |
|
</p> |
|
</div> |
|
</Dialog> |
|
|
|
{/* Contribute Dialog */} |
|
<Dialog |
|
visible={contributeVisible} |
|
onHide={() => setContributeVisible(false)} |
|
style={{ width: '600px' }} |
|
modal |
|
header="Add your model & Contribute" |
|
> |
|
<div> |
|
<h4>π Submit Your Model</h4> |
|
<p>Have a custom fine-tuned model you'd like to see on the leaderboard?</p> |
|
<p><a href="https://forms.gle/ckvY9pS7XLcHYnaV8" target="_blank" rel="noopener noreferrer" style={{ color: '#28a745', fontWeight: 'bold' }}>β Submit your model here</a></p> |
|
|
|
<h4>π§ Contribute to Development</h4> |
|
<p>Help us expand language coverage and add new evaluation tasks:</p> |
|
<p><a href="https://github.com/datenlabor-bmz/ai-language-monitor/blob/main/CONTRIBUTING.md" target="_blank" rel="noopener noreferrer" style={{ color: '#007bff', fontWeight: 'bold' }}>β Contribution guidelines</a></p> |
|
</div> |
|
</Dialog> |
|
|
|
{/* Full-screen Dialog for Charts */} |
|
<Dialog |
|
visible={dialogVisible} |
|
onHide={() => setDialogVisible(false)} |
|
style={{ width: '90vw', height: '90vh' }} |
|
maximizable |
|
modal |
|
header={null} |
|
> |
|
{data && ( |
|
<div style={{ width: '100%', height: '100%' }}> |
|
<Carousel |
|
value={[ |
|
<WorldMap data={data.countries} width={windowWidth * 0.7} height={windowHeight * 0.6} />, |
|
<LanguagePlot data={data} width={windowWidth * 0.7} height={windowHeight * 0.6} />, |
|
<SpeakerPlot data={data} width={windowWidth * 0.7} height={windowHeight * 0.6} />, |
|
<HistoryPlot data={data} width={windowWidth * 0.7} height={windowHeight * 0.6} />, |
|
<CostPlot data={data} />, |
|
]} |
|
numScroll={1} |
|
numVisible={1} |
|
itemTemplate={item => item} |
|
circular |
|
style={{ width: '100%', height: 'calc(90vh - 120px)' }} |
|
/> |
|
</div> |
|
)} |
|
</Dialog> |
|
</div> |
|
</PrimeReactProvider> |
|
) |
|
} |
|
|
|
export default App |
|
|