'use strict'; /** * Nebius Token Factory (formerly Nebius AI Studio) pricing fetcher. * * The public "Model endpoints" page (tokenfactory.nebius.com/endpoints) lists * every shared model with pricing to anonymous users. It loads that data from * a CSRF-protected proxy endpoint — no API key required: * * GET https://tokenfactory.nebius.com/proxy/inference/private/v1/models_info * * To call it we first load the app once to obtain an anonymous CSRF cookie * (__Host-psifi.x-csrf-token), then replay it as both the Cookie and the * x-csrf-token header. The response is richer than the authenticated * /v1/models API: each model carries huggingface_url, size_b, vendor, tags and * `flavors` with per-million-token prices. * * { models: [ { type, name, huggingface_url, size_b, flavors: [ * { model_id, model_type, label, input_price_per_million_tokens, * output_price_per_million_tokens, use_cases, tags, context_window_k } ] } ] } */ const { fetchRobust } = require('../fetch-utils'); const BOOTSTRAP_URL = 'https://tokenfactory.nebius.com/endpoints'; const MODELS_URL = 'https://tokenfactory.nebius.com/proxy/inference/private/v1/models_info'; const UA = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'; // Load the app once to mint an anonymous CSRF token (returned as a cookie). async function getCsrf() { const res = await fetchRobust(BOOTSTRAP_URL, { headers: { 'User-Agent': UA } }); const setCookie = res.headers.get('set-cookie') || ''; const m = setCookie.match(/__Host-psifi\.x-csrf-token=([^;,]+)/); if (!m) throw new Error('could not obtain CSRF cookie from Token Factory'); const cookieVal = m[1]; const headerVal = decodeURIComponent(cookieVal).split('|')[0]; return { cookieVal, headerVal }; } const getType = (modelType) => { const t = (modelType || '').toLowerCase(); if (t.includes('embedding')) return 'embedding'; if (t === 'image2text' || t.includes('vision')) return 'vision'; if (t === 'text2image' || t.includes('image_generation')) return 'image'; return 'chat'; }; const hfIdFrom = (model, flavor) => { const url = model.huggingface_url || ''; if (url.includes('huggingface.co/')) return url.split('huggingface.co/')[1].replace(/\/+$/, ''); const id = flavor.model_id || ''; return /^[^/\s]+\/[^/\s]+$/.test(id) ? id : undefined; }; function buildEntry(model, flavor, labelSuffix) { const type = getType(flavor.model_type || model.type); const input = Number(flavor.input_price_per_million_tokens); const output = Number(flavor.output_price_per_million_tokens); const caps = []; const uses = (flavor.use_cases || []).map((u) => u.toLowerCase()); const tags = (flavor.tags || model.tags || []).map((t) => t.toLowerCase()); if (type === 'vision') caps.push('vision'); if (uses.includes('function_calling') || tags.includes('tool use')) caps.push('tools'); if (uses.includes('reasoning') || tags.includes('reasoning')) caps.push('reasoning'); const entry = { name: model.name + (labelSuffix ? ` (${labelSuffix})` : ''), type, input_price_per_1m: isFinite(input) ? input : 0, output_price_per_1m: isFinite(output) ? output : 0, currency: 'USD', }; if (caps.length) entry.capabilities = caps; const hf_id = hfIdFrom(model, flavor); if (hf_id) entry.hf_id = hf_id; const size_b = Number(model.size_b) || undefined; if (size_b) entry.size_b = size_b; const ctx = Number(flavor.context_window_k || model.context_window_k); if (ctx) entry.context_window = ctx * 1000; return entry; } async function fetchNebius() { const { cookieVal, headerVal } = await getCsrf(); const res = await fetchRobust(MODELS_URL, { headers: { 'User-Agent': UA, Accept: 'application/json', 'x-csrf-token': headerVal, Cookie: `__Host-psifi.x-csrf-token=${cookieVal}`, }, }); const data = await res.json(); const list = data.models || data.data || (Array.isArray(data) ? data : []); const models = []; for (const model of list) { const flavors = Array.isArray(model.flavors) && model.flavors.length ? model.flavors : [{}]; const multi = flavors.length > 1; for (const flavor of flavors) { // Only label-suffix when a model exposes several priced variants. const suffix = multi ? (flavor.label || flavor.quantization) : ''; const entry = buildEntry(model, flavor, suffix); if (entry.input_price_per_1m > 0 || entry.output_price_per_1m > 0) models.push(entry); } } models.sort((a, b) => a.input_price_per_1m - b.input_price_per_1m); return models; } module.exports = { fetchNebius, providerName: 'Nebius' }; // Run standalone: node scripts/providers/nebius.js if (require.main === module) { fetchNebius() .then((models) => { console.log(`Fetched ${models.length} models from Nebius (public models_info):\n`); const byType = {}; models.forEach((m) => { (byType[m.type] = byType[m.type] || []).push(m); }); for (const [type, ms] of Object.entries(byType)) { console.log(` [${type}]`); ms.forEach((m) => console.log(` ${m.name.padEnd(45)} $${m.input_price_per_1m} / $${m.output_price_per_1m}`) ); } }) .catch((err) => { console.error('Error:', err.message); process.exit(1); }); }