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();