File size: 9,906 Bytes
544091e 9229f26 544091e 50128d8 544091e d178010 544091e 9229f26 544091e 1983d1c 9229f26 544091e 86b8b3a 9229f26 b909c3a 6b6f157 5640508 6b6f157 b909c3a 9229f26 b909c3a d178010 86b8b3a 5640508 b909c3a 6b6f157 b909c3a 86b8b3a b909c3a 86b8b3a d178010 6b6f157 b909c3a 6b6f157 d178010 86b8b3a d178010 86b8b3a d178010 6b6f157 d178010 86b8b3a d178010 6b6f157 d178010 9aa08d7 5640508 d178010 b909c3a 9229f26 0e5691e 50128d8 6b6f157 50128d8 5640508 544091e 50128d8 544091e 50128d8 9229f26 544091e 6b6f157 544091e 0e5691e 5640508 6b6f157 5640508 86b8b3a 5640508 86b8b3a 5640508 9229f26 5640508 544091e |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
<!DOCTYPE html>
<html>
<head>
<title>Local Language Monitor</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
body {
margin: 0 auto;
padding: 20px;
font-family: sans-serif;
}
.language-header {
margin-bottom: 10px;
}
.speaker-count {
font-size: 0.8em;
color: #666;
font-weight: normal;
margin: 0;
}
</style>
<link rel="icon"
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22 fill=%22black%22>π</text></svg>">
</head>
<body>
<nav class="border-b border-gray-200 bg-white">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<!-- Mobile menu button -->
<div class="sm:hidden absolute left-4 top-4">
<button onclick="toggleMobileMenu()" class="text-gray-500 hover:text-gray-700 focus:outline-none">
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
</button>
</div>
<!-- Mobile menu (hidden by default) -->
<div id="mobileMenu" class="hidden sm:hidden absolute left-0 top-16 w-full bg-white border-b border-gray-200 py-2">
<div class="flex flex-col space-y-2 px-4">
<a href="#" onclick="showSection('coverage'); toggleMobileMenu()" class="nav-link block px-3 py-2 text-base font-medium text-gray-700">
Language Coverage
</a>
<a href="#" onclick="showSection('comparison'); toggleMobileMenu()" class="nav-link block px-3 py-2 text-base font-medium text-gray-700">
LLM Comparison
</a>
<a href="#" onclick="showSection('results'); toggleMobileMenu()" class="nav-link block px-3 py-2 text-base font-medium text-gray-700">
Results by Language
</a>
</div>
</div>
<!-- Desktop menu -->
<div class="hidden sm:flex justify-center h-16">
<div class="flex">
<div class="flex space-x-8">
<a href="#" onclick="showSection('coverage')" class="nav-link active inline-flex items-center px-1 pt-1 border-b-2 border-indigo-500 text-sm font-medium text-gray-900">
Language Coverage
</a>
<a href="#" onclick="showSection('comparison')" class="nav-link inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium text-gray-500 hover:border-gray-300 hover:text-gray-700">
LLM Comparison
</a>
<a href="#" onclick="showSection('results')" class="nav-link inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium text-gray-500 hover:border-gray-300 hover:text-gray-700">
Results by Language
</a>
</div>
</div>
</div>
</div>
</nav>
<div class="p-6">
<section id="coverage" class="section">
<div id="summary-chart"></div>
</section>
<section id="comparison" class="section hidden">
<p class="text-gray-600">Coming soon...</p>
</section>
<section id="results" class="section hidden">
<div id="language-list"></div>
</section>
</div>
<script type="module">
// Import Plot using ESM
import * as Plot from "https://cdn.jsdelivr.net/npm/@observablehq/plot@0.6/+esm";
function showSection(sectionId) {
// Update nav links
document.querySelectorAll('.nav-link').forEach(link => {
link.classList.remove('border-indigo-500', 'text-gray-900');
link.classList.add('border-transparent', 'text-gray-500');
});
const activeLink = document.querySelector(`[onclick="showSection('${sectionId}')"]`);
activeLink.classList.remove('border-transparent', 'text-gray-500');
activeLink.classList.add('border-indigo-500', 'text-gray-900');
// Show/hide sections
document.querySelectorAll('.section').forEach(section => {
section.classList.add('hidden');
});
document.getElementById(sectionId).classList.remove('hidden');
}
window.showSection = showSection;
function toggleMobileMenu() {
const mobileMenu = document.getElementById('mobileMenu');
mobileMenu.classList.toggle('hidden');
}
window.toggleMobileMenu = toggleMobileMenu;
async function init() {
const scoreKey = "bleu"
const scoreName = "BLEU Score"
const summaryChartDiv = document.getElementById('summary-chart');
const languageListDiv = document.getElementById('language-list');
const response = await fetch('results.json');
const data = await response.json();
// Format captions
const formatScore = (score) => score > 0 ? score.toFixed(2) : "No benchmark available!"
const formatTitle = d => (d.language_name + "\n" + parseInt(d.speakers / 1_000_00) / 10 + "M speakers\n" + scoreName + ": " + formatScore(d[scoreKey]))
// Create summary plot
const summaryPlot = Plot.plot({
width: summaryChartDiv.clientWidth,
height: 400,
marginBottom: 100,
x: { label: "Number of speakers", axis: null },
y: { label: `${scoreName} (average across models)` },
// color: { scheme: "BrBG" },
marks: [
Plot.rectY(data, Plot.stackX({
x: "speakers",
order: scoreKey,
reverse: true,
y2: scoreKey, // y2 to avoid stacking by y
title: formatTitle,
tip: true,
fill: d => d[scoreKey] > 0 ? "black" : "pink"
})),
Plot.rectY(data, Plot.pointerX(Plot.stackX({
x: "speakers",
order: scoreKey,
reverse: true,
y2: scoreKey, // y2 to avoid stacking by y
fill: "grey",
}))),
Plot.text(data, Plot.stackX({
x: "speakers",
y2: scoreKey,
order: scoreKey,
reverse: true,
text: "language_name",
frameAnchor: "bottom",
textAnchor: "end",
dy: 10,
rotate: 270,
opacity: (d) => d.speakers > 50_000_000 ? 1 : 0,
}))
]
});
// Add summary plot to the coverage section
summaryChartDiv.appendChild(summaryPlot);
// Get unique languages with their speaker counts
const languageMap = new Map();
data.forEach(r => {
if (!languageMap.has(r.language_name)) {
languageMap.set(r.language_name, r.speakers);
}
});
// Sort languages by speaker count (descending)
const languages = [...languageMap.entries()]
.sort((a, b) => b[1] - a[1])
.map(([lang]) => lang);
// Section for each language
languages.forEach(language => {
const headerDiv = document.createElement('div');
headerDiv.className = 'language-header';
const h2 = document.createElement('h2');
h2.textContent = language;
h2.style.marginBottom = '5px';
const speakerP = document.createElement('p');
speakerP.className = 'speaker-count';
const speakerCount = (languageMap.get(language) / 1_000_000).toFixed(1);
speakerP.textContent = `${speakerCount}M speakers`;
headerDiv.appendChild(h2);
headerDiv.appendChild(speakerP);
languageListDiv.appendChild(headerDiv);
const languageData = data.filter(r => r.language_name === language)[0]["scores"];
const descriptor = code => {
let [org, model] = code.split("/")
return model.split("-")[0]
}
// Plot for how well the models perform on this language
if (languageData && languageData.length > 1) {
const plot = Plot.plot({
width: 400,
height: 200,
margin: 30,
y: {
domain: [0, 1],
label: scoreName
},
marks: [
Plot.barY(languageData, {
x: d => descriptor(d.model),
y: scoreKey
})
]
});
languageListDiv.appendChild(plot);
}
});
}
init();
</script>
</body>
</html> |