|
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 && ( |
|
<> |
|
<ModelTable |
|
data={data.model_table} |
|
selectedLanguages={selectedLanguages} |
|
allLanguages={data.language_table || []} |
|
/> |
|
<LanguageTable |
|
data={data.language_table} |
|
selectedLanguages={selectedLanguages} |
|
setSelectedLanguages={setSelectedLanguages} |
|
totalModels={data.model_table?.length || 0} |
|
/> |
|
<DatasetTable data={data} /> |
|
<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 |
|
|