Spaces:
Running
Running
// get-metrics-new.ts - Updated version using direct provider APIs | |
import * as fs from "node:fs"; | |
import { parseArgs } from "util"; | |
import { ProviderAggregator } from "./providers"; | |
import type { ProviderEntry } from "./providers"; | |
import { extractHFRouterData } from "./providers/huggingface-router"; | |
/* -------------------------------------------------------------------------- */ | |
/* CONSTANTS */ | |
/* -------------------------------------------------------------------------- */ | |
const HUGGINGFACE_API = "https://router.huggingface.co/v1/models"; | |
const HUGGINGFACE_ROUTER_API = | |
"https://router.huggingface.co/v1/chat/completions"; | |
/* -------------------------------------------------------------------------- */ | |
/* TYPE DEFINITIONS */ | |
/* -------------------------------------------------------------------------- */ | |
interface HFModel { | |
id: string; | |
[key: string]: any; | |
providers?: ProviderEntry[]; | |
} | |
interface Statistics { | |
total_models: number; | |
models_enriched: number; | |
providers_enriched: number; | |
new_capabilities_added: number; | |
providers_fetched: Record<string, number>; | |
} | |
interface PerformanceTestResult { | |
total_tested: number; | |
successful: number; | |
errors: number; | |
status_distribution: Record<string, number>; | |
} | |
/* -------------------------------------------------------------------------- */ | |
/* FETCH HELPERS */ | |
/* -------------------------------------------------------------------------- */ | |
async function fetchHuggingfaceModels(): Promise<HFModel[]> { | |
const resp = await fetch(HUGGINGFACE_API).then( | |
(r) => r.json() as Promise<{ data: HFModel[] }> | |
); | |
return resp.data; | |
} | |
/* -------------------------------------------------------------------------- */ | |
/* PROVIDER ENRICHMENT */ | |
/* -------------------------------------------------------------------------- */ | |
function normalizeModelId(modelId: string): string { | |
// Convert HF model ID to a normalized form for matching | |
// Remove organization prefix for common patterns | |
const patterns = [ | |
/^meta-llama\/Meta-Llama-(.+)$/, | |
/^meta-llama\/Llama-(.+)$/, | |
/^mistralai\/(.+)$/, | |
/^google\/(.+)$/, | |
/^anthropic\/(.+)$/, | |
]; | |
for (const pattern of patterns) { | |
const match = modelId.match(pattern); | |
if (match) { | |
return match[1].toLowerCase(); | |
} | |
} | |
// For other models, just use the part after the last slash | |
const parts = modelId.split("/"); | |
return parts[parts.length - 1].toLowerCase(); | |
} | |
function matchProviderModel( | |
hfModelId: string, | |
providerEntries: Map<string, ProviderEntry[]> | |
): Map<string, ProviderEntry[]> { | |
const normalizedHfId = normalizeModelId(hfModelId); | |
const matches = new Map<string, ProviderEntry[]>(); | |
for (const [provider, entries] of providerEntries) { | |
const matchingEntries = entries.filter((entry) => { | |
// This would need to be enhanced with provider-specific matching logic | |
// For now, we'll use simple substring matching | |
const entryId = (entry as any).id || (entry as any).model_id || ""; | |
const normalizedEntryId = normalizeModelId(entryId); | |
return ( | |
normalizedEntryId.includes(normalizedHfId) || | |
normalizedHfId.includes(normalizedEntryId) | |
); | |
}); | |
if (matchingEntries.length > 0) { | |
matches.set(provider, matchingEntries); | |
} | |
} | |
return matches; | |
} | |
async function enrichHuggingfaceModels( | |
hfModels: HFModel[], | |
aggregator: ProviderAggregator | |
): Promise<{ | |
enriched: HFModel[]; | |
stats: Statistics; | |
matchedProviderData: any[]; | |
}> { | |
console.log("\nFetching data from all providers..."); | |
const providerData = await aggregator.fetchAllProviders(); | |
const stats: Statistics = { | |
total_models: hfModels.length, | |
models_enriched: 0, | |
providers_enriched: 0, | |
new_capabilities_added: 0, | |
providers_fetched: {}, | |
}; | |
// Count models per provider | |
for (const [provider, entries] of providerData) { | |
stats.providers_fetched[provider] = entries.length; | |
} | |
const enrichedModels: HFModel[] = []; | |
const matchedProviderData: any[] = []; | |
const matchedProviderKeys = new Set<string>(); // Track unique model-provider combinations | |
console.log( | |
`\nProcessing ${hfModels.length} models from HuggingFace Router API...` | |
); | |
for (const hfModel of hfModels) { | |
const enrichedModel = structuredClone(hfModel); | |
// Extract HF router data first (this is already in the model) | |
const hfRouterData = extractHFRouterData(enrichedModel); | |
// Find matches from provider APIs | |
const matches = matchProviderModel(hfModel.id, providerData); | |
// Ensure providers array exists | |
if (!enrichedModel.providers) { | |
enrichedModel.providers = []; | |
} | |
let modelEnriched = false; | |
// Process HF router data first (prioritize it) | |
for (const [providerName, hfProviderData] of hfRouterData) { | |
const normalizedProvider = normalizeProviderName(providerName); | |
// Check if provider already exists in the model | |
let existingProvider = enrichedModel.providers.find( | |
(p) => normalizeProviderName(p.provider) === normalizedProvider | |
); | |
if (existingProvider) { | |
// HF router data is already there, just count it | |
if (hfProviderData.pricing) { | |
stats.providers_enriched++; | |
modelEnriched = true; | |
} | |
// Track this provider data as matched (avoid duplicates) | |
const matchKey = `${hfModel.id}:${providerName}`; | |
if (!matchedProviderKeys.has(matchKey)) { | |
matchedProviderKeys.add(matchKey); | |
matchedProviderData.push({ | |
...hfProviderData, | |
provider: providerName, | |
id: hfModel.id, | |
}); | |
} | |
} | |
} | |
// Then enrich with provider API data where missing | |
if (matches.size > 0) { | |
for (const [provider, providerEntries] of matches) { | |
for (const providerEntry of providerEntries) { | |
// Find existing provider entry | |
let existingProvider = enrichedModel.providers.find( | |
(p) => normalizeProviderName(p.provider) === provider.toLowerCase() | |
); | |
if (!existingProvider) { | |
// No HF router data for this provider | |
// Skip - we only want providers that are listed in HF Router | |
continue; | |
} else { | |
// Merge data, but prioritize HF router data | |
const hadPricing = !!existingProvider.pricing; | |
const hadTools = existingProvider.supports_tools !== undefined; | |
const hadStructured = | |
existingProvider.supports_structured_output !== undefined; | |
const hadContext = !!existingProvider.context_length; | |
// Only add provider API data for missing fields | |
const mergedData: any = {}; | |
// Add provider API data only if HF router doesn't have it | |
if (!hadPricing && providerEntry.pricing) { | |
mergedData.pricing = providerEntry.pricing; | |
stats.providers_enriched++; | |
modelEnriched = true; | |
} | |
if (!hadContext && providerEntry.context_length) { | |
mergedData.context_length = providerEntry.context_length; | |
} | |
if (!hadTools && providerEntry.supports_tools !== undefined) { | |
mergedData.supports_tools = providerEntry.supports_tools; | |
} | |
if ( | |
!hadStructured && | |
providerEntry.supports_structured_output !== undefined | |
) { | |
mergedData.supports_structured_output = | |
providerEntry.supports_structured_output; | |
} | |
// Add other capabilities from provider API | |
for (const key of Object.keys(providerEntry)) { | |
if ( | |
key.startsWith("supports_") && | |
!["supports_tools", "supports_structured_output"].includes( | |
key | |
) && | |
!(key in existingProvider) | |
) { | |
mergedData[key] = (providerEntry as any)[key]; | |
stats.new_capabilities_added++; | |
} | |
} | |
// Apply merged data | |
Object.assign(existingProvider, mergedData); | |
// Track the enriched data (avoid duplicates) | |
const matchKey = `${hfModel.id}:${provider}`; | |
if (!matchedProviderKeys.has(matchKey)) { | |
matchedProviderKeys.add(matchKey); | |
matchedProviderData.push({ | |
...existingProvider, | |
provider, | |
id: hfModel.id, | |
}); | |
} | |
} | |
} | |
} | |
} | |
if (modelEnriched) { | |
stats.models_enriched++; | |
} | |
enrichedModels.push(enrichedModel); | |
} | |
// Log models from provider APIs that weren't matched | |
let unmatchedCount = 0; | |
for (const [provider, entries] of providerData) { | |
for (const entry of entries) { | |
const modelId = (entry as any).model_id || (entry as any).id || ""; | |
if (modelId) { | |
const matchKey = `${modelId}:${provider}`; | |
if (!matchedProviderKeys.has(matchKey)) { | |
unmatchedCount++; | |
} | |
} | |
} | |
} | |
if (unmatchedCount > 0) { | |
console.log( | |
`\nNote: ${unmatchedCount} models from provider APIs were not included (not in HF Router).` | |
); | |
} | |
return { enriched: enrichedModels, stats, matchedProviderData }; | |
} | |
// Helper function to normalize provider names for comparison | |
function normalizeProviderName(providerName: string): string { | |
const providerMap: Record<string, string> = { | |
"featherless-ai": "featherless", | |
"fireworks-ai": "fireworks", | |
"hf-inference": "huggingface", | |
}; | |
return (providerMap[providerName] || providerName).toLowerCase(); | |
} | |
/* -------------------------------------------------------------------------- */ | |
/* PERFORMANCE TESTING */ | |
/* -------------------------------------------------------------------------- */ | |
async function testModelProvider( | |
modelId: string, | |
providerName: string, | |
hfToken: string | |
): Promise<Partial<ProviderEntry>> { | |
const nonce = crypto.randomUUID().slice(0, 8); | |
const prompt = `What is the capital of France?\n<!-- nonce:${nonce} -->`; | |
const payload = { | |
model: `${modelId}:${providerName}`, | |
messages: [{ role: "user", content: prompt }], | |
stream: false, | |
temperature: 0.7, | |
}; | |
const headers = { | |
Authorization: `Bearer ${hfToken}`, | |
"Content-Type": "application/json", | |
}; | |
const start = performance.now(); | |
try { | |
const controller = new AbortController(); | |
const timeoutId = setTimeout(() => controller.abort(), 30_000); | |
const resp = await fetch(HUGGINGFACE_ROUTER_API, { | |
method: "POST", | |
headers, | |
body: JSON.stringify(payload), | |
signal: controller.signal, | |
}); | |
clearTimeout(timeoutId); | |
const latency = (performance.now() - start) / 1000; | |
if (resp.ok) { | |
const data = await resp.json(); | |
const usage = data.usage ?? {}; | |
const totalTokens = | |
usage.total_tokens ?? | |
(usage.prompt_tokens ?? 0) + (usage.completion_tokens ?? 0); | |
const tps = totalTokens ? totalTokens / latency : 0; | |
return { | |
latency_s: Number(latency.toFixed(2)), | |
throughput_tps: Number(tps.toFixed(2)), | |
status: "live", | |
}; | |
} | |
const data = await resp.json().catch(() => ({})); | |
const msg = | |
data?.error?.message ?? `HTTP ${resp.status} ${resp.statusText}`; | |
return { performance_error: msg, status: "offline" }; | |
} catch (err: any) { | |
const msg = err.name === "AbortError" ? "Request timeout" : err.message; | |
return { performance_error: msg, status: "offline" }; | |
} | |
} | |
async function testProvidersBatch( | |
triplets: [string, string, ProviderEntry][], | |
hfToken: string | |
): Promise<void> { | |
await Promise.all( | |
triplets.map(async ([modelId, providerName, prov]) => { | |
const res = await testModelProvider(modelId, providerName, hfToken); | |
Object.assign(prov, res, { | |
performance_tested_at: new Date().toISOString(), | |
}); | |
}) | |
); | |
} | |
async function testAllProviders( | |
models: HFModel[], | |
hfToken: string, | |
limit: number | undefined, | |
batchSize: number, | |
filter: string[] | undefined | |
): Promise<PerformanceTestResult> { | |
const subset = typeof limit === "number" ? models.slice(0, limit) : models; | |
const allPairs: [string, string, ProviderEntry][] = []; | |
for (const m of subset) { | |
for (const p of m.providers ?? []) { | |
if (filter && !filter.includes(p.provider)) continue; | |
allPairs.push([m.id, p.provider, p]); | |
} | |
} | |
console.log( | |
`\nTesting performance for ${allPairs.length} model-provider combinations...` | |
); | |
let tested = 0; | |
let errors = 0; | |
const statusDist: Record<string, number> = { | |
live: 0, | |
offline: 0, | |
not_tested: 0, | |
}; | |
for (let i = 0; i < allPairs.length; i += batchSize) { | |
const batch = allPairs.slice(i, i + batchSize); | |
console.log( | |
`Testing batch ${i / batchSize + 1}/${Math.ceil( | |
allPairs.length / batchSize | |
)}...` | |
); | |
await testProvidersBatch(batch, hfToken); | |
batch.forEach(([_, __, prov]) => { | |
tested += 1; | |
if (prov.performance_error) errors += 1; | |
switch (prov.status) { | |
case "live": | |
statusDist.live += 1; | |
break; | |
case "offline": | |
statusDist.offline += 1; | |
break; | |
default: | |
statusDist.not_tested += 1; | |
} | |
}); | |
if (i + batchSize < allPairs.length) { | |
await new Promise((resolve) => setTimeout(resolve, 1000)); | |
} | |
} | |
return { | |
total_tested: tested, | |
successful: tested - errors, | |
errors, | |
status_distribution: statusDist, | |
}; | |
} | |
/* -------------------------------------------------------------------------- */ | |
/* PRINT HELPERS */ | |
/* -------------------------------------------------------------------------- */ | |
function printStatistics(s: Statistics): void { | |
console.log("\n" + "=".repeat(60)); | |
console.log("ENRICHMENT STATISTICS"); | |
console.log("=".repeat(60)); | |
console.log(`Total models processed: ${s.total_models}`); | |
console.log(`Models enriched with pricing: ${s.models_enriched}`); | |
console.log(`Provider entries enriched: ${s.providers_enriched}`); | |
console.log(`New capability fields added: ${s.new_capabilities_added}`); | |
console.log("\nProvider data fetched:"); | |
Object.entries(s.providers_fetched) | |
.sort(([a], [b]) => a.localeCompare(b)) | |
.forEach(([provider, count]) => { | |
console.log(` ${provider}: ${count} models`); | |
}); | |
} | |
/* -------------------------------------------------------------------------- */ | |
/* CLI PARSER */ | |
/* -------------------------------------------------------------------------- */ | |
const { values: opts } = parseArgs({ | |
args: Bun.argv.slice(2), | |
options: { | |
"test-performance": { type: "boolean" }, | |
"test-limit": { type: "string" }, | |
"test-providers": { type: "string", multiple: true }, | |
"batch-size": { type: "string" }, | |
providers: { type: "string", multiple: true }, | |
"skip-providers": { type: "string", multiple: true }, | |
}, | |
strict: false, | |
}); | |
const testLimit = | |
opts["test-limit"] && typeof opts["test-limit"] === "string" | |
? parseInt(opts["test-limit"], 10) | |
: undefined; | |
const batchSize = | |
opts["batch-size"] && typeof opts["batch-size"] === "string" | |
? parseInt(opts["batch-size"], 10) | |
: 20; | |
/* -------------------------------------------------------------------------- */ | |
/* MAIN */ | |
/* -------------------------------------------------------------------------- */ | |
(async () => { | |
console.log("Fetching HuggingFace models..."); | |
const hfModels = await fetchHuggingfaceModels(); | |
console.log(`Found ${hfModels.length} HuggingFace models.`); | |
// Configure provider aggregator | |
const apiKeys: Record<string, string> = {}; | |
// Only add API keys that are defined | |
if (process.env.NOVITA_API_KEY) apiKeys.novita = process.env.NOVITA_API_KEY; | |
if (process.env.SAMBANOVA_API_KEY) apiKeys.sambanova = process.env.SAMBANOVA_API_KEY; | |
if (process.env.GROQ_API_KEY) apiKeys.groq = process.env.GROQ_API_KEY; | |
if (process.env.FEATHERLESS_API_KEY) apiKeys.featherless = process.env.FEATHERLESS_API_KEY; | |
if (process.env.TOGETHER_API_KEY) apiKeys.together = process.env.TOGETHER_API_KEY; | |
if (process.env.COHERE_API_KEY) apiKeys.cohere = process.env.COHERE_API_KEY; | |
if (process.env.FIREWORKS_API_KEY) apiKeys.fireworks = process.env.FIREWORKS_API_KEY; | |
if (process.env.NEBIUS_API_KEY) apiKeys.nebius = process.env.NEBIUS_API_KEY; | |
if (process.env.HYPERBOLIC_API_KEY) apiKeys.hyperbolic = process.env.HYPERBOLIC_API_KEY; | |
if (process.env.CEREBRAS_API_KEY) apiKeys.cerebras = process.env.CEREBRAS_API_KEY; | |
if (process.env.NSCALE_API_KEY) apiKeys.nscale = process.env.NSCALE_API_KEY; | |
const config = { | |
providers: opts["providers"] as string[] | undefined, | |
apiKeys, | |
}; | |
// Remove skip-providers if specified | |
if (opts["skip-providers"]) { | |
const skipProviders = opts["skip-providers"] as string[]; | |
if (!config.providers) { | |
config.providers = [ | |
"novita", | |
"sambanova", | |
"groq", | |
"featherless", | |
"together", | |
"cohere", | |
"fireworks", | |
"nebius", | |
"hyperbolic", | |
"cerebras", | |
"nscale", | |
].filter((p) => !skipProviders.includes(p)); | |
} | |
} | |
const aggregator = new ProviderAggregator(config); | |
console.log("\nEnriching HuggingFace models with provider data..."); | |
const { enriched, stats, matchedProviderData } = | |
await enrichHuggingfaceModels(hfModels, aggregator); | |
// Optional performance tests | |
if (opts["test-performance"]) { | |
const hfToken = process.env.HF_TOKEN; | |
if (!hfToken) { | |
console.error( | |
"ERROR: HF_TOKEN environment variable not set. Skipping performance tests." | |
); | |
} else { | |
console.log("\n" + "=".repeat(60)); | |
console.log("PERFORMANCE TESTING"); | |
console.log("=".repeat(60)); | |
const perfStats = await testAllProviders( | |
enriched, | |
hfToken, | |
testLimit, | |
batchSize, | |
opts["test-providers"] as string[] | undefined | |
); | |
console.log("\nPerformance testing complete:"); | |
console.log(` Total tested: ${perfStats.total_tested}`); | |
console.log(` Successful: ${perfStats.successful}`); | |
console.log(` Errors: ${perfStats.errors}`); | |
console.log("\nProvider status distribution:"); | |
Object.entries(perfStats.status_distribution) | |
.sort() | |
.forEach(([k, v]) => console.log(` ${k}: ${v}`)); | |
} | |
} | |
// Save enriched data | |
const outFile = "enriched_models_enhanced.json"; | |
fs.writeFileSync( | |
outFile, | |
JSON.stringify( | |
{ | |
data: enriched, | |
generated_at: new Date().toISOString(), | |
metadata: { | |
total_models: enriched.length, | |
models_enriched: stats.models_enriched, | |
providers_enriched: stats.providers_enriched, | |
performance_tested: !!opts["test-performance"], | |
providers_fetched: stats.providers_fetched, | |
}, | |
}, | |
null, | |
2 | |
) | |
); | |
console.log(`\nEnriched data saved → ${outFile}`); | |
// Save only matched provider data (models that exist in HF Router) | |
fs.writeFileSync( | |
"provider_models_raw.json", | |
JSON.stringify({ data: matchedProviderData }, null, 2) | |
); | |
console.log( | |
`Matched provider models saved → provider_models_raw.json (${matchedProviderData.length} entries)` | |
); | |
printStatistics(stats); | |
})(); | |