export const CANONICAL_DATASETS = [ '일반 상식', '멀티 모달', '수치 정보', '팩트 체크', '소버린 벤치마크', 'K-Prism (Text, Intact)', 'K-Prism (Text, Perturbed)', 'K-Prism (Image, Intact)', 'K-Prism (Image, Perturbed)', ]; const isText = value => typeof value === 'string' && value.trim().length > 0; // Accept both the original benchmark.json array and a published {models} snapshot. // Validate before replacing the visible results so failed refreshes keep good data. export function normalizeBenchmark(payload) { const source = Array.isArray(payload) ? payload : payload?.models; if (!Array.isArray(source)) throw new Error('Expected a model array or an object with models.'); const modelKeys = new Set(); const models = source.map((model, index) => { if (!model || !isText(model.provider) || !isText(model.name)) { throw new Error(`Model ${index + 1} is missing its provider or name.`); } const key = JSON.stringify([model.provider, model.name]); if (modelKeys.has(key)) throw new Error(`Duplicate model: ${model.provider} / ${model.name}.`); modelKeys.add(key); if (!Array.isArray(model.scores)) throw new Error(`Invalid scores for ${model.name}.`); if (model.is_multimodal != null && typeof model.is_multimodal !== 'boolean') { throw new Error(`Invalid model type for ${model.name}.`); } const scoreNames = new Set(); const scores = model.scores.map(score => { if (!score || !isText(score.dataset_name) || !Number.isFinite(score.score)) { throw new Error(`Invalid score for ${model.name}.`); } if (scoreNames.has(score.dataset_name)) { throw new Error(`Duplicate dataset score for ${model.name}: ${score.dataset_name}.`); } scoreNames.add(score.dataset_name); return { dataset_name: score.dataset_name, metric_type: score.metric_type === 'llm-as-judge' ? 'llm-as-judge' : 'raw', score: score.score, }; }); return { provider: model.provider, name: model.name, repo: typeof model.repo === 'string' ? model.repo : '', is_multimodal: model.is_multimodal ?? false, status: typeof model.status === 'string' ? model.status : 'completed', updated_at: typeof model.updated_at === 'string' ? model.updated_at : '', scores, }; }); const publishedDatasets = Array.isArray(payload) ? undefined : payload.datasets; if (publishedDatasets !== undefined && (!Array.isArray(publishedDatasets) || !publishedDatasets.every(isText))) { throw new Error('Invalid dataset list.'); } // A published list preserves the curator's selection and order. Legacy arrays // include the canonical datasets plus any additional scored datasets. const datasets = [...new Set(publishedDatasets ?? [ ...CANONICAL_DATASETS, ...models.flatMap(model => model.scores.map(score => score.dataset_name)), ])]; return { models, datasets }; } export async function loadBenchmark(url, timeoutMs = 15000) { const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), timeoutMs); try { const response = await fetch(url, { cache: 'no-store', credentials: 'omit', signal: controller.signal, }); if (!response.ok) throw new Error(`Score data request failed (HTTP ${response.status}).`); return normalizeBenchmark(await response.json()); } finally { clearTimeout(timeout); } }