(function() {
'use strict';
var TYPE_LABELS = { llm:'Language', image:'Image', video:'Video', tts:'Voice', composition:'Music', transcription:'Transcription', embedding:'Embedding', rerank:'Rerank', capability:'Capability', stem_separation:'Audio', '3d':'3D' };
var TYPE_ICONS = { llm:'icon-messages-square', image:'icon-image', video:'icon-video', tts:'icon-mic', composition:'icon-music', transcription:'icon-captions', embedding:'icon-brain', rerank:'icon-arrow-up-down', capability:'icon-sparkles', stem_separation:'icon-sliders-horizontal', '3d':'icon-box' };
var MAX_CTX = 2000000; // for bar scaling
var allModels = [], allProviders = [], data = null;
var currentView = 'grid', currentSort = { field: 'name', dir: 'asc' };
var compareSet = new Set();
var providerIcons = {}; // key -> icon URL
// ── Helpers ──
function esc(s) { if (!s) return ''; var d = document.createElement('div'); d.textContent = s; return d.innerHTML; }
function formatCtx(n) {
if (!n) return '';
if (n >= 1000000) return (n/1000000).toFixed(n%1000000===0?0:1)+'M';
if (n >= 1000) return (n/1000)+'K';
return n.toString();
}
function formatPrice(rate) {
if (!rate) return '-';
var perM = rate * 1000;
if (perM < 0.01) return '<$0.01/M';
return '$' + perM.toFixed(2) + '/M';
}
function formatDate(d) { return d ? d.substring(0,10) : ''; }
function speedDots(speed) {
if (!speed) return '';
var h = '';
for (var i=1;i<=5;i++) h += '';
return h+'';
}
function ctxBar(ctx) {
if (!ctx) return '';
var MID = 1000000;
var pct = ctx <= MID ? Math.sqrt(ctx/MID)*50 : 50+(ctx-MID)/(MAX_CTX-MID)*50;
pct = Math.min(100, Math.max(2, pct));
return '
'+formatCtx(ctx)+' tokens'+formatCtx(MAX_CTX)+'
';
}
function provIcon(m) {
var icon = m.provider_icon || providerIcons[m.provider];
if (!icon) return '';
return '';
}
function getModalities(m) {
if (!m.modalities) return '';
var inp = (m.modalities.input || []).join(', ');
var out = (m.modalities.output || []).join(', ');
return inp + ' → ' + out;
}
// ── URL Params (Deep Links) ──
function readParams() {
var p = new URLSearchParams(window.location.search);
return { type: p.get('type')||'', provider: p.get('provider')||'', status: p.get('status')||'', search: p.get('search')||'', view: p.get('view')||'grid' };
}
function writeParams() {
var p = new URLSearchParams();
var search = (document.getElementById('dir-search')||{}).value||'';
var provider = (document.getElementById('dir-provider')||{}).value||'';
var typePill = document.querySelector('.ai-dir-pill.active');
var type = typePill ? typePill.dataset.type : '';
var statusPill = document.querySelector('.ai-dir-status-pill.active');
var status = statusPill ? statusPill.dataset.status : '';
if (type) p.set('type', type);
if (provider) p.set('provider', provider);
if (status) p.set('status', status);
if (search) p.set('search', search);
if (currentView !== 'grid') p.set('view', currentView);
var qs = p.toString();
history.replaceState(null, '', qs ? '?'+qs : window.location.pathname);
}
// ── Card Rendering ──
function renderCard(m) {
var badges = [];
badges.push(''+(TYPE_LABELS[m.type]||m.type)+'');
if (m.status==='deprecated') badges.push('Deprecated');
if (m.status==='sunset') badges.push('Sunset');
if (m.is_new && m.status==='active') badges.push('New');
if (m.vision) badges.push('Vision');
if (m.tools) badges.push('Tools');
if (m.capabilities && m.capabilities.indexOf('reasoning')!==-1) badges.push('Reasoning');
if (m.capabilities && m.capabilities.indexOf('search')!==-1) badges.push('Search');
var meta = [];
if (m.context_window) meta.push(' '+formatCtx(m.context_window)+' ctx');
if (m.max_output) meta.push(' '+formatCtx(m.max_output)+' out');
if (m.speed) meta.push(''+speedDots(m.speed)+'');
var pricing = '';
if (m.pricing) {
var p = m.pricing;
if (p.input || p.output) {
pricing = '
';
if (p.input) pricing += '
Input'+formatPrice(p.input)+'
';
if (p.output) pricing += '
Output'+formatPrice(p.output)+'
';
pricing += '
';
} else if (p.unit) {
pricing = '
Per unit$'+p.unit.toFixed(4)+'
';
}
}
var statusClass = m.status!=='active' ? ' status-'+m.status : '';
var statusDate = '';
if (m.deprecated_at) statusDate = '
Deprecated '+formatDate(m.deprecated_at)+'
';
if (m.sunset_at) statusDate = '
Sunset '+formatDate(m.sunset_at)+'
';
var checked = compareSet.has(m.key);
var checkHtml = '
';
}
// ── Table Rendering ──
function renderTable(models) {
var html = '
';
html += '
' +
'
Model
' +
'
Provider
' +
'
Type
' +
'
Context
' +
'
Input
Output
Features
';
models.forEach(function(m) {
var features = [];
if (m.vision) features.push('Vision');
if (m.tools) features.push('Tools');
if (m.capabilities && m.capabilities.indexOf('reasoning')!==-1) features.push('Reasoning');
if (m.streaming) features.push('Stream');
var inputP = m.pricing&&m.pricing.input ? formatPrice(m.pricing.input) : '-';
var outputP = m.pricing&&m.pricing.output ? formatPrice(m.pricing.output) : '-';
var rowStyle = (m.status==='sunset'||!m.enabled) ? ' style="opacity:0.5"' : '';
var badge = '';
if (m.status==='deprecated') badge = ' Deprecated';
else if (m.status==='sunset') badge = ' Sunset';
else if (m.is_new) badge = ' New';
var checked = compareSet.has(m.key);
html += '
' +
'
'+(checked?'':'')+'
' +
'
'+esc(m.name)+''+badge+'
' +
'
'+(m.provider_icon?'':'')+esc(m.provider_name)+'
' +
'
'+(TYPE_LABELS[m.type]||m.type)+'
' +
'
'+formatCtx(m.context_window)+'
' +
'
'+inputP+'
' +
'
'+outputP+'
' +
'
'+features.join(', ')+'
';
});
html += '
';
return html;
}
// ── Detail Panel ──
function openDetail(key) {
var m = allModels.find(function(x){return x.key===key;});
if (!m) return;
var panel = document.getElementById('detail-panel');
var overlay = document.getElementById('detail-overlay');
var modHtml = '';
if (m.modalities) {
var inp = (m.modalities.input||[]).map(function(x){return ''+x+'';}).join(' ');
var out = (m.modalities.output||[]).map(function(x){return ''+x+'';}).join(' ');
modHtml = '
'+inp+'→'+out+'
';
}
var capsHtml = '';
if (m.capabilities && m.capabilities.length) {
capsHtml = m.capabilities.map(function(c){return ''+c+'';}).join('');
}
var html = '';
html += '
'+esc(m.name)+'
';
html += '
'+provIcon(m)+esc(m.provider_name)+'
';
html += '
';
html += ''+(TYPE_LABELS[m.type]||m.type)+'';
if (m.status==='deprecated') html += 'Deprecated';
if (m.status==='sunset') html += 'Sunset';
if (m.is_new&&m.status==='active') html += 'New';
if (m.vision) html += 'Vision';
if (m.tools) html += 'Tools';
if (m.capabilities&&m.capabilities.indexOf('reasoning')!==-1) html += 'Reasoning';
html += '
';
if (m.description) html += '
'+esc(m.description)+'
';
if (modHtml) html += '
Modalities
'+modHtml+'
';
html += '
Specifications
';
if (m.context_window) html += '
Context Window
'+formatCtx(m.context_window)+' tokens
';
if (m.max_output) html += '
Max Output
'+formatCtx(m.max_output)+' tokens
';
if (m.speed) html += '
Speed
'+speedDots(m.speed)+'
';
html += '
Status
'+(m.status||'active')+'
';
html += '
';
if (m.context_window) html += '
Context Window
'+ctxBar(m.context_window)+'
';
if (m.pricing) {
html += '
Pricing
';
var p = m.pricing;
if (p.input) html += '
Input
'+formatPrice(p.input)+'
';
if (p.output) html += '
Output
'+formatPrice(p.output)+'
';
if (p.unit) html += '
Per Unit
$'+p.unit.toFixed(4)+'
';
if (p.per_1k) html += '
Per 1K Chars
$'+p.per_1k.toFixed(4)+'
';
if (p.per_second) html += '
Per Second
$'+p.per_second.toFixed(6)+'
';
html += '
';
}
html += '
Dates
';
html += '
Added
'+formatDate(m.created_at)+'
';
if (m.updated_at) html += '
Updated
'+formatDate(m.updated_at)+'
';
if (m.deprecated_at) html += '
Deprecated
'+formatDate(m.deprecated_at)+'
';
html += '
';
html += '
'+esc(m.key)+'Click to copy
';
html += 'Use on Zubnet ';
panel.innerHTML = html;
panel.classList.add('open');
overlay.classList.add('open');
document.body.style.overflow = 'hidden';
document.getElementById('detail-close').onclick = closeDetail;
overlay.onclick = closeDetail;
document.getElementById('detail-key-box').onclick = function() {
var key = this.dataset.key;
navigator.clipboard.writeText(key).then(function() {
var hint = document.querySelector('.detail-key .copy-hint');
if (hint) { hint.textContent = 'Copied!'; setTimeout(function(){ hint.textContent = 'Click to copy'; }, 1500); }
});
};
}
function closeDetail() {
document.getElementById('detail-panel').classList.remove('open');
document.getElementById('detail-overlay').classList.remove('open');
document.body.style.overflow = '';
}
// ── Compare Mode ──
function toggleCompare(key) {
if (compareSet.has(key)) { compareSet.delete(key); }
else if (compareSet.size < 4) { compareSet.add(key); }
updateCompareBar();
render();
}
function updateCompareBar() {
var bar = document.getElementById('compare-bar');
var chips = document.getElementById('compare-chips');
var btn = document.getElementById('compare-go');
if (compareSet.size === 0) { bar.classList.remove('visible'); return; }
bar.classList.add('visible');
var html = '';
compareSet.forEach(function(key) {
var m = allModels.find(function(x){return x.key===key;});
html += ''+esc(m?m.name:key)+' ×';
});
chips.innerHTML = html;
btn.disabled = compareSet.size < 2;
chips.querySelectorAll('.remove').forEach(function(el) {
el.onclick = function(e) { e.stopPropagation(); toggleCompare(el.dataset.key); };
});
}
function openCompare() {
if (compareSet.size < 2) return;
var models = [];
compareSet.forEach(function(k){ var m=allModels.find(function(x){return x.key===k;}); if(m)models.push(m); });
var modal = document.getElementById('compare-modal');
var inner = document.getElementById('compare-modal-inner');
var html = '';
html += '