1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
'use strict';
const state = { models: [], selected: null, registrationEnabled: false };
const $ = selector => document.querySelector(selector);
const esc = value => String(value ?? '').replace(/[&<>'"]/g, char => ({'&':'&','<':'<','>':'>',"'":''','"':'"'}[char]));
const integer = value => new Intl.NumberFormat().format(Number(value || 0));
const protocolName = value => ({chat_completions:'Chat Completions',responses:'Responses',messages:'Anthropic Messages'}[value] || value);
const price = (micros, currency='usd') => new Intl.NumberFormat(undefined, {style:'currency', currency:String(currency).toUpperCase(), minimumFractionDigits:2, maximumFractionDigits:6}).format(Number(micros || 0) / 1_000_000);
const date = value => value ? new Intl.DateTimeFormat(undefined, {year:'numeric',month:'short',day:'numeric'}).format(new Date(value)) : 'Not published';
function healthLabel(model) {
if (model.health_status === 'unavailable') return ['Unavailable', 'unavailable'];
if (model.health_status === 'degraded') return [`${model.available_provider_count}/${model.provider_count} routes`, 'degraded'];
return ['Available', 'available'];
}
function renderStats(models) {
const protocols = new Set(models.flatMap(model => model.supported_wire_apis || []));
$('#model-count').textContent = integer(models.length);
$('#provider-count').textContent = integer(models.reduce((sum, model) => sum + Number(model.provider_count || 0), 0));
$('#protocol-count').textContent = integer(protocols.size);
}
function renderFilters() {
const owners = [...new Set(state.models.map(model => model.owned_by).filter(Boolean))].sort();
const protocols = [...new Set(state.models.flatMap(model => model.supported_wire_apis || []))].sort();
$('#owner').innerHTML = '<option value="">All developers</option>' + owners.map(owner => `<option value="${esc(owner)}">${esc(owner)}</option>`).join('');
$('#protocol').innerHTML = '<option value="">All protocols</option>' + protocols.map(item => `<option value="${esc(item)}">${esc(protocolName(item))}</option>`).join('');
}
function filteredModels() {
const query = $('#search').value.trim().toLowerCase();
const protocol = $('#protocol').value;
const input = $('#input').value;
const owner = $('#owner').value;
const result = state.models.filter(model => {
const haystack = [model.public_id, model.display_name, model.description, model.owned_by, ...(model.capabilities || []), ...(model.aliases || [])].join(' ').toLowerCase();
return (!query || haystack.includes(query)) && (!protocol || (model.supported_wire_apis || []).includes(protocol)) && (!input || (model.input_modalities || []).includes(input)) && (!owner || model.owned_by === owner);
});
const sort = $('#sort').value;
result.sort((a,b) => {
if (sort === 'name') return String(a.display_name || a.public_id).localeCompare(String(b.display_name || b.public_id));
if (sort === 'input_price') return Number(a.input_price_micros_per_million) - Number(b.input_price_micros_per_million);
if (sort === 'output_price') return Number(a.output_price_micros_per_million) - Number(b.output_price_micros_per_million);
if (sort === 'context') return Number(b.context_window) - Number(a.context_window);
return new Date(b.released_at || 0) - new Date(a.released_at || 0) || String(a.public_id).localeCompare(String(b.public_id));
});
return result;
}
function renderCatalog() {
const models = filteredModels();
$('#catalog-empty').classList.toggle('hidden', models.length !== 0);
$('#catalog-grid').innerHTML = models.map(model => {
const [health, healthClass] = healthLabel(model);
return `<article class="model-card">
<header><div><small>${esc(model.owned_by || 'Independent')}</small><h2>${esc(model.display_name || model.public_id)}</h2></div><span class="health ${healthClass}">${esc(health)}</span></header>
<code>${esc(model.public_id)}</code>
<p>${esc(model.description || 'No description published.')}</p>
<div class="model-tags">${(model.supported_wire_apis || []).map(item => `<span>${esc(protocolName(item))}</span>`).join('')}${(model.input_modalities || []).map(item => `<span>${esc(item)}</span>`).join('')}</div>
<dl><div><dt>Input</dt><dd>${price(model.input_price_micros_per_million, model.price_currency)} / 1M</dd></div><div><dt>Output</dt><dd>${price(model.output_price_micros_per_million, model.price_currency)} / 1M</dd></div><div><dt>Context</dt><dd>${integer(model.context_window)}</dd></div></dl>
<button class="button secondary" type="button" data-model="${esc(model.public_id)}">View model</button>
</article>`;
}).join('');
}
function renderEstimate() {
if (!state.selected) return;
const input = Math.max(0, Number($('#estimate-input').value || 0));
const output = Math.max(0, Number($('#estimate-output').value || 0));
const totalMicros = (Number(state.selected.input_price_micros_per_million || 0) * input + Number(state.selected.output_price_micros_per_million || 0) * output) / 1_000_000;
$('#estimate-total').textContent = `${price(totalMicros, state.selected.price_currency)} estimated`;
}
function openModel(publicID) {
const model = state.models.find(item => item.public_id === publicID);
if (!model) return;
state.selected = model;
const [health, healthClass] = healthLabel(model);
$('#detail-owner').textContent = model.owned_by || 'Independent';
$('#detail-name').textContent = model.display_name || model.public_id;
$('#detail-id').textContent = model.public_id;
$('#detail-description').textContent = model.description || 'No description published.';
$('#detail-tags').innerHTML = [...(model.supported_wire_apis || []).map(protocolName), ...(model.capabilities || []), ...(model.input_modalities || []).map(item => `${item} input`), ...(model.output_modalities || []).map(item => `${item} output`)].map(item => `<span>${esc(item)}</span>`).join('');
const rows = [
['Status', `<span class="health ${healthClass}">${esc(health)}</span>`],
['Input price', `${price(model.input_price_micros_per_million, model.price_currency)} / 1M tokens`],
['Output price', `${price(model.output_price_micros_per_million, model.price_currency)} / 1M tokens`],
['Cached input', `${price(model.cache_read_price_micros_per_million, model.price_currency)} / 1M tokens`],
['Context window', `${integer(model.context_window)} tokens`],
['Max output', `${integer(model.max_output_tokens)} tokens`],
['Regions', esc((model.regions || []).join(', ') || 'Global')],
['Released', esc(date(model.released_at))]
];
$('#detail-grid').innerHTML = rows.map(([label,value]) => `<div><dt>${esc(label)}</dt><dd>${value}</dd></div>`).join('');
const register = $('#detail-register');
register.classList.toggle('hidden', !state.registrationEnabled);
register.href = `./?auth=register&model=${encodeURIComponent(model.public_id)}`;
renderEstimate();
$('#model-dialog').showModal();
}
async function start() {
try {
const response = await fetch('./api/public/models', {headers:{Accept:'application/json'}});
if (!response.ok) throw new Error(`Catalog request failed (${response.status})`);
const payload = await response.json();
state.models = Array.isArray(payload.data) ? payload.data : [];
state.registrationEnabled = Boolean(payload.registration_enabled);
$('#create-account').classList.toggle('hidden', !state.registrationEnabled);
renderStats(state.models);
renderFilters();
renderCatalog();
} catch (error) {
$('#catalog-error').textContent = error.message || 'The model catalog is temporarily unavailable.';
$('#catalog-error').classList.remove('hidden');
}
}
$('#catalog-filters').addEventListener('input', renderCatalog);
$('#catalog-grid').addEventListener('click', event => { const button = event.target.closest('[data-model]'); if (button) openModel(button.dataset.model); });
$('#close-dialog').addEventListener('click', () => $('#model-dialog').close());
$('#model-dialog').addEventListener('click', event => { if (event.target === $('#model-dialog')) $('#model-dialog').close(); });
$('#estimate-input').addEventListener('input', renderEstimate);
$('#estimate-output').addEventListener('input', renderEstimate);
start();
|