local-frontier / scripts /generate-model-data.mjs
Onur Solmaz
fix: use leaderboard model discovery
8493200
Raw
History Blame Contribute Delete
31 kB
import fs from "node:fs";
import path from "node:path";
const root = path.resolve(import.meta.dirname, "..");
const outputPath = path.join(root, "assets", "local-frontier-model-data.js");
const threshold = 100_000;
const hfBase = "https://huggingface.co";
const apiBase = `${hfBase}/api/models`;
const routerModelsApi = "https://router.huggingface.co/v1/models";
const requestHeaders = {
"user-agent": "local-frontier-model-generator",
...(process.env.HF_TOKEN
? { authorization: `Bearer ${process.env.HF_TOKEN}` }
: {}),
};
const cache = new Map();
const defaultCreators = [
"CohereLabs",
"EssentialAI",
"MiniMaxAI",
"Qwen",
"Sao10K",
"aisingapore",
"allenai",
"alpindale",
"baidu",
"deepcogito",
"deepseek-ai",
"google",
"inclusionAI",
"meta-llama",
"moonshotai",
"nvidia",
"openai",
"pearl-ai",
"stepfun-ai",
"swiss-ai",
"utter-project",
"zai-org",
];
const expandFields = [
"author",
"cardData",
"createdAt",
"downloads",
"downloadsAllTime",
"evalResults",
"gated",
"gguf",
"inferenceProviderMapping",
"lastModified",
"library_name",
"likes",
"model-index",
"pipeline_tag",
"private",
"safetensors",
"sha",
"siblings",
"tags",
"transformersInfo",
"trendingScore",
];
const llmPipelines = new Set([
"text-generation",
"image-text-to-text",
"video-text-to-text",
"audio-text-to-text",
"any-to-any",
"text-to-audio",
]);
const excludedPipelines = new Set([
"feature-extraction",
"sentence-similarity",
"text-ranking",
"text-classification",
"token-classification",
"fill-mask",
"automatic-speech-recognition",
"text-to-speech",
"voice-activity-detection",
"image-classification",
"image-segmentation",
"object-detection",
"zero-shot-image-classification",
"zero-shot-object-detection",
"image-text-to-image",
"text-to-image",
"image-to-image",
"image-to-video",
"text-to-video",
"unconditional-image-generation",
"image-to-3d",
"text-to-3d",
"robotics",
"time-series-forecasting",
"graph-ml",
]);
const textModelTerms = [
"instruct",
"chat",
"assistant",
"reasoning",
"thinking",
"coder",
"code",
"llm",
"vlm",
"omni",
"gpt-oss",
"kimi",
"glm",
"llama",
"qwen",
"gemma",
"deepseek",
"nemotron",
"olmo",
"apertus",
"eurollm",
];
const excludedTerms = [
"embedding",
"embed",
"reranker",
"rerank",
"whisper",
"wav2vec",
"speaker",
"stable-diffusion",
"diffusers",
"flux",
"sdxl",
"clip",
"siglip",
"depth-anything",
"ocr",
"optical-character-recognition",
"document-parse",
"document-parser",
"document-understanding",
"pdf-parser",
"receipt",
];
const excludedTokenTerms = new Set(["asr", "encoder"]);
const excludedAudioTokenTerms = new Set(["speech"]);
const globalArtifactSearchQueries = [
"gguf",
"awq",
"gptq",
"fp8",
"fp4",
"nvfp4",
"quantized",
"mlx",
"llama.cpp",
];
const relatedArtifactSuffixes = [
"gguf",
"awq",
"gptq",
"fp8",
"fp4",
"nvfp4",
"mlx",
];
const relatedVariantTokens = new Set([
"base",
"chat",
"flash",
"instruct",
"it",
"pro",
]);
const modelFamilyTokens = new Set([
"apertus",
"deepseek",
"ernie",
"gemma",
"glm",
"gpt",
"kimi",
"llama",
"minimax",
"mistral",
"mixtral",
"nemotron",
"olmo",
"phi",
"qwen",
"qwen2",
"qwen3",
"step",
]);
const codingModelNameRe =
/(^|[-_/])(?:coder|coding|code)(?:$|[-_/])|(^|[-_/])(?:codellama|codeqwen|opencoder|starcoder)[a-z0-9.]*($|[-_/])/;
const assumptions = {
default_overhead_gb: 8,
default_l_alloc_tokens: 100000,
default_l_read_tokens: 32000,
default_r_star_toks: 20,
default_rho: 1,
unit: "decimal GB",
hf_pipeline_filter:
"leaderboard-compatible LLM and multimodal candidate filter",
hf_llm_pipeline_tags: [...llmPipelines],
min_hf_downloads: threshold,
generated_by: "scripts/generate-model-data.mjs",
};
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function fetchJson(url, optional = false) {
const { payload } = await fetchJsonWithHeaders(url, optional);
return payload;
}
async function fetchJsonWithHeaders(url, optional = false) {
for (let attempt = 1; attempt <= 3; attempt++) {
const response = await fetch(url, { headers: requestHeaders });
if (response.ok) {
return { payload: await response.json(), headers: response.headers };
}
if (optional && [401, 403, 404].includes(response.status)) {
return { payload: null, headers: response.headers };
}
if (response.status === 429 || response.status >= 500) {
await sleep(500 * attempt);
continue;
}
throw new Error(`${response.status} ${response.statusText}: ${url}`);
}
if (optional) return { payload: null, headers: new Headers() };
throw new Error(`failed after retries: ${url}`);
}
function parseNextLink(link) {
if (!link) return null;
for (const part of link.split(",")) {
const match = part.match(/<([^>]+)>;\s*rel="next"/);
if (match) return match[1];
}
return null;
}
function apiUrl(params) {
const search = new URLSearchParams();
for (const [key, value] of params) {
search.append(key, String(value));
}
return `${apiBase}?${search}`;
}
function detailApiUrl(id) {
const search = new URLSearchParams();
for (const field of expandFields) search.append("expand", field);
return `${apiBase}/${encodeURIComponent(id).replace(/%2F/g, "/")}?${search}`;
}
async function modelInfo(id) {
const key = `model:${id}`;
if (!cache.has(key)) {
cache.set(key, fetchJson(detailApiUrl(id), true));
}
return cache.get(key);
}
async function rawConfig(id) {
const key = `config:${id}`;
if (!cache.has(key)) {
cache.set(
key,
fetchJson(`${hfBase}/${id}/raw/main/config.json`, true).catch(() => null),
);
}
return cache.get(key);
}
function uniquePreserveOrder(values) {
const seen = new Set();
const result = [];
for (const value of values) {
if (!value || seen.has(value)) continue;
seen.add(value);
result.push(value);
}
return result;
}
function repoIdFrom(model) {
const id = model?.id || model?.modelId;
return typeof id === "string" ? id : "";
}
function downloadCount(model) {
return Number.isInteger(model?.downloads) ? model.downloads : 0;
}
async function fetchRouterModels() {
try {
const payload = await fetchJson(routerModelsApi, true);
const records = payload && Array.isArray(payload.data) ? payload.data : [];
return records.filter(
(record) => record && typeof record.id === "string" && record.id,
);
} catch (error) {
console.error(`router model fetch failed: ${error.message}`);
return [];
}
}
function routerCreators(routerRecords) {
return uniquePreserveOrder(
routerRecords.map((record) => {
if (typeof record.owned_by === "string" && record.owned_by) {
return record.owned_by;
}
return record.id?.includes("/") ? record.id.split("/", 1)[0] : "";
}),
);
}
async function listCreatorModels(creator) {
const params = [
["author", creator],
["limit", 100],
["sort", "downloads"],
["direction", -1],
...expandFields.map((field) => ["expand", field]),
];
let url = apiUrl(params);
const rows = [];
while (url) {
const { payload, headers } = await fetchJsonWithHeaders(url);
if (!Array.isArray(payload)) {
throw new Error(`expected model list for creator ${creator}`);
}
rows.push(...payload.filter((item) => item && typeof item === "object"));
const minDownloads = Math.min(
...payload.map((model) => downloadCount(model)),
);
if (payload.length === 0 || minDownloads < threshold) break;
url = parseNextLink(headers.get("link"));
}
return rows;
}
async function listSearchModels(query) {
const params = [
["search", query],
["limit", 100],
["sort", "downloads"],
["direction", -1],
...expandFields.map((field) => ["expand", field]),
];
let url = apiUrl(params);
const rows = [];
while (url && rows.length < 500) {
const { payload, headers } = await fetchJsonWithHeaders(url);
if (!Array.isArray(payload)) {
throw new Error(`expected model list for search ${query}`);
}
let stop = false;
for (const item of payload) {
if (!item || typeof item !== "object") continue;
if (downloadCount(item) < threshold) {
stop = true;
break;
}
rows.push(item);
if (rows.length >= 500) break;
}
if (stop || rows.length >= 500) break;
url = parseNextLink(headers.get("link"));
}
return rows;
}
function fileCounts(record) {
const counts = new Map();
for (const sibling of record.siblings || []) {
const name = sibling?.rfilename;
if (typeof name !== "string") continue;
const lower = name.toLowerCase();
for (const [key, suffix] of [
["safetensors", ".safetensors"],
["gguf", ".gguf"],
["bin", ".bin"],
]) {
if (lower.endsWith(suffix)) {
counts.set(key, (counts.get(key) || 0) + 1);
}
}
if (
lower.endsWith("tokenizer.json") ||
lower.endsWith("tokenizer_config.json")
) {
counts.set("tokenizer", (counts.get("tokenizer") || 0) + 1);
}
if (lower.endsWith("chat_template.jinja")) {
counts.set("chat_template", (counts.get("chat_template") || 0) + 1);
}
}
return counts;
}
function providerSummary(mapping) {
const rows = Array.isArray(mapping) ? mapping : [];
let supportsTools = false;
let supportsStructured = false;
for (const item of rows) {
if (!item || typeof item !== "object") continue;
supportsTools = supportsTools || item.features?.toolCalling === true;
supportsStructured =
supportsStructured || item.features?.structuredOutput === true;
}
return { supportsTools, supportsStructured };
}
function routerSummary(routerEntry) {
const providers = Array.isArray(routerEntry?.providers)
? routerEntry.providers
: [];
return {
routerServed: Boolean(routerEntry),
supportsTools: providers.some((provider) => provider?.supports_tools),
supportsStructured: providers.some(
(provider) => provider?.supports_structured_output,
),
};
}
function textTokens(text) {
return new Set(
text
.toLowerCase()
.split(/[^a-z0-9]+/)
.filter(Boolean),
);
}
function hasExcludedTerm(row) {
const text = `${row.id} ${row.pipeline_tag} ${row.tags}`.toLowerCase();
if (excludedTerms.some((term) => text.includes(term))) return true;
const tokens = textTokens(text);
if ([...excludedTokenTerms].some((token) => tokens.has(token))) return true;
if (
!llmPipelines.has(row.pipeline_tag) &&
[...excludedAudioTokenTerms].some((token) => tokens.has(token))
) {
return true;
}
return false;
}
function hasTextModelSignal(modelId) {
if (codingModelNameRe.test(modelId)) return true;
const boundaryTerms = new Set([
"assistant",
"chat",
"code",
"coder",
"coding",
"instruct",
"reasoning",
"thinking",
]);
for (const term of textModelTerms) {
if (boundaryTerms.has(term)) {
const boundaryRe = new RegExp(`(^|[-_/])${term}($|[-_/])`);
if (boundaryRe.test(modelId)) return true;
continue;
}
if (modelId.includes(term)) return true;
}
return false;
}
function normalizeCandidateRecord(record, routerEntry = null) {
const counts = fileCounts(record);
const provider = providerSummary(record.inferenceProviderMapping);
const router = routerSummary(routerEntry);
const id = repoIdFrom(record);
const tags = asArray(record.tags).filter((tag) => typeof tag === "string");
return {
id,
downloads: downloadCount(record),
pipeline_tag: record.pipeline_tag || "",
private: record.private,
tags: tags.join(","),
has_chat_template: counts.get("chat_template") > 0,
supports_tools_any: provider.supportsTools,
supports_structured_output_any: provider.supportsStructured,
router_supports_tools_any: router.supportsTools,
router_supports_structured_output_any: router.supportsStructured,
router_served: router.routerServed,
};
}
function candidateDecision(row) {
const modelId = row.id.toLowerCase();
const text = `${row.id} ${row.pipeline_tag} ${row.tags}`.toLowerCase();
if (row.private === true) return [false, "private"];
if (excludedPipelines.has(row.pipeline_tag)) {
return [false, `excluded pipeline: ${row.pipeline_tag}`];
}
if (hasExcludedTerm(row)) return [false, "excluded narrow/non-LLM term"];
if (llmPipelines.has(row.pipeline_tag)) {
return [true, `LLM pipeline: ${row.pipeline_tag}`];
}
if (row.has_chat_template) return [true, "chat template"];
if (row.supports_tools_any || row.router_supports_tools_any) {
return [true, "tool support"];
}
if (
row.supports_structured_output_any ||
row.router_supports_structured_output_any
) {
return [true, "structured output support"];
}
if (text.includes("conversational")) return [true, "conversational tag"];
if (hasTextModelSignal(modelId)) return [true, "model-name signal"];
return [false, "no LLM signal"];
}
function normalizedRepoSlug(modelId) {
return modelId
.split("/")
.at(-1)
.toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-|-$/g, "");
}
function slugTokens(slug) {
return slug.split("-").filter(Boolean);
}
function hasModelShape(slug) {
const tokens = slugTokens(slug);
return tokens.some((token) => modelFamilyTokens.has(token));
}
function slugDedupeKey(modelId) {
let slug = normalizedRepoSlug(modelId);
let previous = null;
while (slug && slug !== previous) {
previous = slug;
slug = slug.replace(/-(?:gguf|awq|gptq|fp8|fp4|mxfp8|nvfp4)-v[0-9]+$/, "");
slug = slug.replace(
/-(?:gguf|awq|gptq|fp8|fp4|mxfp8|nvfp4|bf16|fp16|int2|int3|int4|int8|q[2-8](?:-(?:0|1|k|m|s|l))*|4bit|8bit|bnb|bitsandbytes|mlx|exl2|onnx|openvino|tensorrt|modelopt|qat|quantized|quant|compressed|safetensors|hf)$/,
"",
);
slug = slug.replace(/-qat-w[0-9]+a[0-9]+-ct$/, "");
}
return slug || normalizedRepoSlug(modelId);
}
function shortenedVariantSlug(slug) {
const tokens = slugTokens(slug);
while (tokens.length > 2 && relatedVariantTokens.has(tokens.at(-1))) {
tokens.pop();
}
return tokens.join("-");
}
function discoveryQueries(seedRows) {
const queries = [...globalArtifactSearchQueries];
const ordered = [...seedRows].sort(
(a, b) => b.downloads - a.downloads || a.id.localeCompare(b.id),
);
for (const row of ordered.slice(0, 12)) {
const slug = slugDedupeKey(row.id);
if (!hasModelShape(slug)) continue;
for (const candidateSlug of uniquePreserveOrder([
slug,
shortenedVariantSlug(slug),
])) {
if (!candidateSlug || !hasModelShape(candidateSlug)) continue;
for (const suffix of relatedArtifactSuffixes) {
queries.push(`${candidateSlug}-${suffix}`);
}
}
}
return uniquePreserveOrder(queries);
}
async function discoverAdditionalModels(seedRows, existingIds) {
const discovered = new Map();
for (const query of discoveryQueries(seedRows)) {
try {
const rows = await listSearchModels(query);
console.error(`discovery ${query}: ${rows.length}`);
for (const row of rows) {
const id = repoIdFrom(row);
if (!id || existingIds.has(id)) continue;
discovered.set(id, row);
}
} catch (error) {
console.error(`discovery ${query} failed: ${error.message}`);
}
}
return [...discovered.values()];
}
async function downloadedModels() {
const routerRecords = await fetchRouterModels();
const routerById = new Map(
routerRecords.map((record) => [record.id, record]),
);
const creators = uniquePreserveOrder([
...defaultCreators,
...routerCreators(routerRecords),
]);
const deduped = new Map();
for (const creator of creators) {
try {
const rows = await listCreatorModels(creator);
console.error(`creator ${creator}: ${rows.length}`);
for (const row of rows) {
const id = repoIdFrom(row);
if (id) deduped.set(id, row);
}
} catch (error) {
console.error(`creator ${creator} failed: ${error.message}`);
}
}
for (const record of routerRecords) {
if (deduped.has(record.id)) continue;
const detail = await modelInfo(record.id);
if (detail) deduped.set(record.id, detail);
}
const seedRows = [...deduped.values()]
.map((row) =>
normalizeCandidateRecord(row, routerById.get(repoIdFrom(row))),
)
.filter((row) => row.downloads >= threshold && candidateDecision(row)[0]);
const discoveredRows = await discoverAdditionalModels(
seedRows,
new Set(deduped.keys()),
);
for (const row of discoveredRows) {
const id = repoIdFrom(row);
if (id) deduped.set(id, row);
}
return [...deduped.values()].filter((model) => {
if (downloadCount(model) < threshold) return false;
const row = normalizeCandidateRecord(
model,
routerById.get(repoIdFrom(model)),
);
return candidateDecision(row)[0];
});
}
function asArray(value) {
if (Array.isArray(value)) return value;
return value === undefined || value === null ? [] : [value];
}
function licenseFrom(model) {
return (
model.cardData?.license ||
model.tags?.find((tag) => tag.startsWith("license:"))?.slice(8) ||
"unknown"
);
}
function baseModelIds(model) {
const ids = new Set();
for (const value of asArray(model.cardData?.base_model)) {
if (typeof value === "string" && value.includes("/")) ids.add(value);
}
for (const tag of model.tags || []) {
if (!tag.startsWith("base_model:")) continue;
const parts = tag.split(":");
const id = parts.at(-1);
if (id?.includes("/")) ids.add(id);
}
return [...ids].filter((id) => id !== model.id);
}
function numberFrom(...values) {
for (const value of values) {
const number = Number(value);
if (Number.isFinite(number) && number > 0) return number;
}
return null;
}
function intFrom(...values) {
const number = numberFrom(...values);
return number === null ? null : Math.trunc(number);
}
function parseParamB(text) {
const normalized = text.replace(/_/g, "-");
const moe = normalized.match(
/(?:^|[-/])(\d+(?:\.\d+)?)x(\d+(?:\.\d+)?)([bm])(?:$|[-/])/i,
);
if (moe) {
const count = Number(moe[1]);
const size = Number(moe[2]);
return count * size * (moe[3].toLowerCase() === "m" ? 0.001 : 1);
}
const match = normalized.match(/(?:^|[-/])(\d+(?:\.\d+)?)([bm])(?:$|[-/])/i);
if (!match) return null;
return Number(match[1]) * (match[2].toLowerCase() === "m" ? 0.001 : 1);
}
function parseActiveParamB(text) {
const match = text.match(/(?:^|[-_/])A(\d+(?:\.\d+)?)([BM])(?:$|[-_/])/);
if (!match) return null;
return Number(match[1]) * (match[2] === "M" ? 0.001 : 1);
}
function round(value, digits = 6) {
return Number(value.toFixed(digits));
}
function paramCountB(model, baseInfo, id) {
const totals = [
model.safetensors?.total,
baseInfo?.safetensors?.total,
model.safetensors?.parameters?.F16,
model.safetensors?.parameters?.BF16,
model.safetensors?.parameters?.F32,
].filter((value) => Number.isFinite(value) && value > 0);
if (totals.length) return round(Math.max(...totals) / 1e9, 4);
const parsed = parseParamB(id) ?? parseParamB(baseInfo?.id ?? "");
return round(parsed && parsed > 0 ? parsed : 0.1, 4);
}
function quantizationBits(config, model) {
const quant = config?.quantization_config;
const explicitBits = numberFrom(quant?.bits, quant?.nbits, quant?.num_bits);
if (explicitBits) return explicitBits;
const groupBits = Object.values(quant?.config_groups || {})
.map((group) => numberFrom(group?.weights?.num_bits, group?.num_bits))
.filter(Boolean);
if (groupBits.length) return Math.min(...groupBits);
const haystack = `${model.id} ${(model.tags || []).join(" ")}`.toLowerCase();
if (haystack.includes("2-bit") || haystack.includes("q2")) return 2;
if (
haystack.includes("4-bit") ||
haystack.includes("q4") ||
haystack.includes("int4") ||
haystack.includes("gptq") ||
haystack.includes("awq") ||
haystack.includes("mxfp4") ||
haystack.includes("nvfp4") ||
haystack.includes("fp4")
) {
return 4;
}
if (
haystack.includes("8-bit") ||
haystack.includes("int8") ||
haystack.includes("fp8") ||
haystack.includes("q8")
) {
return 8;
}
return null;
}
function dtypeBytes(model) {
const parameters = model.safetensors?.parameters || {};
const weighted = Object.entries(parameters)
.map(([dtype, count]) => {
const key = dtype.toUpperCase();
const bytes =
key.includes("F64") || key.includes("I64")
? 8
: key.includes("F32") || key.includes("I32")
? 4
: key.includes("F16") || key.includes("BF16") || key.includes("I16")
? 2
: key.includes("I8")
? 1
: null;
return bytes ? { bytes, count: Number(count) } : null;
})
.filter(Boolean);
const total = weighted.reduce((sum, row) => sum + row.count, 0);
if (!total) return null;
return weighted.reduce((sum, row) => sum + row.bytes * row.count, 0) / total;
}
function precision(config, model) {
const bits = quantizationBits(config, model);
const haystack = `${model.id} ${(model.tags || []).join(" ")}`.toLowerCase();
if (haystack.includes("gguf")) return bits ? `GGUF ${bits}-bit` : "GGUF";
if (haystack.includes("nvfp4")) return "NVFP4";
if (haystack.includes("mxfp4")) return "MXFP4";
if (haystack.includes("fp8")) return "FP8";
if (bits) return `${bits}-bit`;
const dtypes = Object.keys(model.safetensors?.parameters || {});
if (dtypes.length) return dtypes.join("/");
return "metadata-estimated";
}
function bytesPerParam(config, model) {
const bits = quantizationBits(config, model);
if (bits) return round(bits / 8, 4);
return round(dtypeBytes(model) ?? 2, 4);
}
function contextTokens(config) {
const rope = config?.rope_scaling || {};
const value = numberFrom(
config?.max_position_embeddings,
config?.max_sequence_length,
config?.max_seq_len,
config?.seq_length,
config?.n_positions,
config?.n_ctx,
rope?.original_max_position_embeddings,
);
if (value && value < 100_000_000) return Math.trunc(value);
return 2048;
}
function effectiveConfig(config) {
if (!config || typeof config !== "object") return {};
for (const key of [
"text_config",
"language_config",
"llm_config",
"model_config",
]) {
if (config[key] && typeof config[key] === "object") return config[key];
}
return config;
}
function architectureKind(config) {
const modelType = String(config?.model_type || "").toLowerCase();
if (
modelType.includes("mamba") ||
modelType.includes("rwkv") ||
modelType.includes("recurrent")
) {
return "recurrent";
}
if (
config?.num_local_experts ||
config?.num_experts ||
config?.n_routed_experts ||
config?.num_experts_per_tok ||
modelType.includes("moe")
) {
return "moe";
}
return "dense";
}
function architectureType(kind) {
if (kind === "moe") return "MoE transformer";
if (kind === "recurrent") return "Recurrent state-space model";
return "Dense transformer";
}
function headDim(config, attentionHeads) {
return intFrom(
config?.head_dim,
config?.hidden_size && attentionHeads
? Number(config.hidden_size) / attentionHeads
: null,
config?.n_embd && attentionHeads
? Number(config.n_embd) / attentionHeads
: null,
);
}
function kvGbPer1k(config, kind, layers, kvHeads, dim) {
if (kind === "recurrent") return 0;
if (!layers) return 0;
const heads = kvHeads || intFrom(config?.num_attention_heads, config?.n_head);
const width =
dim ||
(numberFrom(config?.hidden_size, config?.n_embd) && heads
? numberFrom(config?.hidden_size, config?.n_embd) / heads
: null);
if (!heads || !width) return 0;
return round((layers * 2 * heads * width * 2 * 1000) / 1e9, 6);
}
function shortName(id) {
return id
.split("/")
.at(-1)
.replace(/[-_](Instruct|Chat|Base|HF|GGUF|AWQ|GPTQ)$/i, "")
.replace(/[-_]/g, " ")
.slice(0, 48);
}
function dataQuality(config, model, baseInfo) {
const parts = [];
parts.push(config ? "config" : "no-config");
parts.push(
model.safetensors?.total || baseInfo?.safetensors?.total
? "params"
: "estimated-params",
);
if (baseInfo && baseInfo.id !== model.id) parts.push(`base:${baseInfo.id}`);
return parts.join(", ");
}
async function buildModel(model) {
const fullModel = (await modelInfo(model.id)) || model;
model = {
...fullModel,
downloads: model.downloads ?? fullModel.downloads,
pipeline_tag: model.pipeline_tag ?? fullModel.pipeline_tag,
tags: fullModel.tags || model.tags,
cardData: fullModel.cardData || model.cardData,
};
const baseIds = baseModelIds(model);
const baseInfo = baseIds.length ? await modelInfo(baseIds[0]) : null;
const ownConfig = await rawConfig(model.id);
const baseConfig =
!ownConfig && baseInfo ? await rawConfig(baseInfo.id) : null;
const apiConfig =
model.config && Object.keys(model.config).length ? model.config : null;
const rawConfigData =
ownConfig || baseConfig || apiConfig || baseInfo?.config || {};
const config = effectiveConfig(rawConfigData);
const configSource = ownConfig
? model.id
: baseConfig
? baseInfo.id
: apiConfig
? model.id
: baseInfo?.id;
const kind = architectureKind(config);
const totalParams = paramCountB(model, baseInfo, model.id);
const activeFromName =
parseActiveParamB(model.id) ?? parseActiveParamB(baseInfo?.id ?? "");
const recordedExperts = intFrom(
config?.num_local_experts,
config?.num_experts,
config?.n_routed_experts,
);
const recordedExpertsPerToken = intFrom(
config?.num_experts_per_tok,
config?.num_experts_per_token,
config?.moe_top_k,
config?.num_selected_experts,
);
const fallbackExperts =
kind === "moe" && activeFromName && totalParams > activeFromName
? Math.max(1, Math.round(totalParams / activeFromName))
: 1;
const experts = kind === "moe" ? (recordedExperts ?? fallbackExperts) : null;
const expertsPerToken =
kind === "moe" ? (recordedExpertsPerToken ?? 1) : null;
const activeParams =
kind === "moe"
? round(
activeFromName ??
(experts && expertsPerToken
? Math.max(totalParams * (expertsPerToken / experts), 0.1)
: totalParams),
4,
)
: totalParams;
const layers = intFrom(
config?.num_hidden_layers,
config?.n_layer,
config?.num_layers,
config?.decoder_layers,
);
const attentionHeads = intFrom(
config?.num_attention_heads,
config?.n_head,
config?.num_heads,
);
const kvHeads = intFrom(
config?.num_key_value_heads,
config?.n_kv_heads,
config?.multi_query_group_num,
);
const dim = headDim(config, attentionHeads);
const bytes = bytesPerParam(config, model);
const kvGb = kvGbPer1k(config, kind, layers, kvHeads, dim);
const modelType = config?.model_type || model.config?.model_type || "unknown";
const archName = asArray(config?.architectures || model.config?.architectures)
.filter(Boolean)
.join(", ");
const quality = dataQuality(configSource ? config : null, model, baseInfo);
const sources = [
{ label: "Hugging Face model card", url: `${hfBase}/${model.id}` },
];
if (configSource) {
sources.push({
label: configSource === model.id ? "Model config" : "Base model config",
url: `${hfBase}/${configSource}/raw/main/config.json`,
});
}
if (baseInfo && baseInfo.id !== model.id) {
sources.push({
label: "Base model card",
url: `${hfBase}/${baseInfo.id}`,
});
}
return {
id: model.id,
name: `${model.id.split("/").at(-1)} ${precision(config, model)}`,
short_name: shortName(model.id),
license: licenseFrom(model),
hf_pipeline_tag: model.pipeline_tag || "unknown",
hf_downloads: model.downloads ?? 0,
tags: (model.tags || []).filter((tag) => !tag.startsWith("region:")),
architecture: {
type: architectureType(kind),
detail: `${modelType}${archName ? ` (${archName})` : ""}`,
total_params_b: totalParams,
active_params_b: activeParams,
layers,
attention_heads: attentionHeads,
kv_heads: kvHeads,
head_dim: dim,
max_context_tokens: contextTokens(config),
routed_experts: kind === "moe" ? experts : null,
routed_experts_per_token: kind === "moe" ? expertsPerToken : null,
shared_experts_per_token:
kind === "moe" ? (intFrom(config?.n_shared_experts) ?? 0) : null,
},
adapter: {
kind,
weight_precision: precision(config, model),
weight_bytes_per_param: bytes,
resident_weight_gb: round(totalParams * bytes, 4),
active_weight_gb: round(activeParams * bytes, 4),
kv_alloc_gb_per_1k_tokens: kvGb,
kv_read_gb_per_1k_tokens: kvGb,
...(kind === "recurrent"
? { kv_alloc_fixed_gb: 0.02, kv_read_fixed_gb: 0.002 }
: {}),
notes: `Generated from Hugging Face metadata on ${new Date().toISOString().slice(0, 10)}; downloads=${model.downloads ?? 0}; data quality: ${quality}. Bound weights use recorded repo precision when detectable, otherwise metadata-estimated precision.`,
},
sources,
};
}
function escapeNonAscii(text) {
return text.replace(
/[^\x00-\x7F]/g,
(char) => `\\u${char.charCodeAt(0).toString(16).padStart(4, "0")}`,
);
}
async function main() {
const candidates = await downloadedModels();
console.error(
`found ${candidates.length} leaderboard-compatible models >= ${threshold} downloads`,
);
const models = [];
for (const [index, model] of candidates.entries()) {
if (
!/^[A-Za-z0-9][A-Za-z0-9._-]*\/[A-Za-z0-9][A-Za-z0-9._-]*$/.test(model.id)
) {
console.error(`skipping unsupported repo id: ${model.id}`);
continue;
}
try {
models.push(await buildModel(model));
} catch (error) {
console.error(`failed ${model.id}: ${error.message}`);
}
if ((index + 1) % 25 === 0) {
console.error(`processed ${index + 1}/${candidates.length}`);
}
}
models.sort(
(a, b) => b.hf_downloads - a.hf_downloads || a.id.localeCompare(b.id),
);
const data = {
schema_version: "2",
generated_at: new Date().toISOString(),
assumptions,
models,
};
const body = `window.LOCAL_FRONTIER_MODEL_DATA = ${JSON.stringify(data, null, 2)};\n`;
fs.writeFileSync(outputPath, escapeNonAscii(body));
console.error(`wrote ${models.length} models to ${outputPath}`);
}
await main();