Changeset 0.5.0 (#35)
This commit is contained in:
90
src/js/ui.js
90
src/js/ui.js
@@ -1,5 +1,5 @@
|
||||
// ==========================================
|
||||
// Chat Switchboard – UI (v0.5.2)
|
||||
// Chat Switchboard – UI (v0.5.4)
|
||||
// ==========================================
|
||||
|
||||
const UI = {
|
||||
@@ -187,7 +187,8 @@ const UI = {
|
||||
App.models.forEach(m => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = m.id;
|
||||
opt.textContent = m.id + (m.provider ? ` (${m.provider})` : '');
|
||||
const label = m.name || m.id;
|
||||
opt.textContent = label + (m.provider ? ` (${m.provider})` : '');
|
||||
sel.appendChild(opt);
|
||||
});
|
||||
}
|
||||
@@ -213,6 +214,56 @@ const UI = {
|
||||
}
|
||||
},
|
||||
|
||||
// ── Capability Badges ────────────────────
|
||||
|
||||
getSelectedModelCaps() {
|
||||
const modelId = document.getElementById('modelSelect').value || App.settings.model;
|
||||
if (!modelId) return {};
|
||||
const model = App.models.find(m => m.id === modelId);
|
||||
// Model in list has resolved caps; fallback to client-side lookup
|
||||
if (model?.capabilities && Object.keys(model.capabilities).length > 0) {
|
||||
return model.capabilities;
|
||||
}
|
||||
return (typeof lookupKnownCaps === 'function' ? lookupKnownCaps(modelId) : null) || {};
|
||||
},
|
||||
|
||||
updateCapabilityBadges() {
|
||||
const el = document.getElementById('modelCaps');
|
||||
if (!el) return;
|
||||
|
||||
const caps = this.getSelectedModelCaps();
|
||||
if (!caps || Object.keys(caps).length === 0) {
|
||||
el.innerHTML = '';
|
||||
return;
|
||||
}
|
||||
|
||||
const badges = [];
|
||||
|
||||
// Output tokens
|
||||
if (caps.max_output_tokens > 0) {
|
||||
const k = caps.max_output_tokens >= 1000
|
||||
? (caps.max_output_tokens / 1000).toFixed(0) + 'K'
|
||||
: caps.max_output_tokens;
|
||||
badges.push(`<span class="cap-badge cap-context" title="Max output: ${caps.max_output_tokens.toLocaleString()} tokens">${k} out</span>`);
|
||||
}
|
||||
|
||||
// Context window
|
||||
if (caps.max_context > 0) {
|
||||
const k = (caps.max_context / 1000).toFixed(0) + 'K';
|
||||
badges.push(`<span class="cap-badge cap-context" title="Context window: ${caps.max_context.toLocaleString()} tokens">${k} ctx</span>`);
|
||||
}
|
||||
|
||||
// Capability flags
|
||||
if (caps.tool_calling) badges.push('<span class="cap-badge cap-accent" title="Supports tool/function calling">🔧 tools</span>');
|
||||
if (caps.vision) badges.push('<span class="cap-badge cap-accent" title="Supports image/vision input">👁 vision</span>');
|
||||
if (caps.thinking) badges.push('<span class="cap-badge cap-accent" title="Supports extended thinking">💭 thinking</span>');
|
||||
if (caps.reasoning) badges.push('<span class="cap-badge cap-accent" title="Reasoning model (chain-of-thought)">🧠 reasoning</span>');
|
||||
if (caps.code_optimized) badges.push('<span class="cap-badge" title="Optimized for code generation">⟨/⟩ code</span>');
|
||||
if (caps.web_search) badges.push('<span class="cap-badge" title="Supports web search">🔍 search</span>');
|
||||
|
||||
el.innerHTML = badges.join('');
|
||||
},
|
||||
|
||||
// ── User / Connection ────────────────────
|
||||
|
||||
updateUser() {
|
||||
@@ -268,10 +319,23 @@ const UI = {
|
||||
openSettings() {
|
||||
document.getElementById('settingsModel').value = App.settings.model;
|
||||
document.getElementById('settingsSystemPrompt').value = App.settings.systemPrompt;
|
||||
document.getElementById('settingsMaxTokens').value = App.settings.maxTokens;
|
||||
document.getElementById('settingsMaxTokens').value = App.settings.maxTokens || '';
|
||||
document.getElementById('settingsTemp').value = App.settings.temperature;
|
||||
document.getElementById('settingsThinking').checked = App.settings.showThinking;
|
||||
document.getElementById('profileChangePwForm').style.display = 'none';
|
||||
|
||||
// Show model's max output in the hint
|
||||
const caps = this.getSelectedModelCaps();
|
||||
const hint = document.getElementById('settingsMaxHint');
|
||||
if (hint) {
|
||||
if (caps.max_output_tokens > 0) {
|
||||
const k = (caps.max_output_tokens / 1000).toFixed(0) + 'K';
|
||||
hint.textContent = `(model max: ${k})`;
|
||||
} else {
|
||||
hint.textContent = '';
|
||||
}
|
||||
}
|
||||
|
||||
UI.loadProfileIntoSettings();
|
||||
UI.loadProviderList();
|
||||
document.getElementById('settingsModal').classList.add('active');
|
||||
@@ -375,9 +439,23 @@ const UI = {
|
||||
try {
|
||||
const data = await API.adminListModels();
|
||||
const list = data.models || data.data || data || [];
|
||||
el.innerHTML = (Array.isArray(list) ? list : []).map(m => `
|
||||
<div class="admin-model-row"><span>${esc(m.model_id || m.id)}</span><span class="provider-meta">${esc(m.provider_name || '')}</span><span>${m.is_enabled ? '✅' : '⬜'}</span></div>
|
||||
`).join('') || '<div class="empty-hint">No models</div>';
|
||||
el.innerHTML = (Array.isArray(list) ? list : []).map(m => {
|
||||
const caps = m.capabilities || {};
|
||||
const badges = [];
|
||||
if (caps.max_output_tokens > 0) {
|
||||
badges.push(`<span class="cap-badge cap-context">${(caps.max_output_tokens/1000).toFixed(0)}K out</span>`);
|
||||
}
|
||||
if (caps.tool_calling) badges.push('<span class="cap-badge cap-accent">🔧</span>');
|
||||
if (caps.vision) badges.push('<span class="cap-badge cap-accent">👁</span>');
|
||||
if (caps.thinking) badges.push('<span class="cap-badge cap-accent">💭</span>');
|
||||
if (caps.reasoning) badges.push('<span class="cap-badge cap-accent">🧠</span>');
|
||||
return `<div class="admin-model-row">
|
||||
<span>${esc(m.model_id || m.id)}</span>
|
||||
<span class="model-caps-inline">${badges.join('')}</span>
|
||||
<span class="provider-meta">${esc(m.provider_name || '')}</span>
|
||||
<span>${m.is_enabled ? '✅' : '⬜'}</span>
|
||||
</div>`;
|
||||
}).join('') || '<div class="empty-hint">No models — use Fetch Models to sync from providers</div>';
|
||||
} catch (e) { el.innerHTML = `<div class="error-hint">${esc(e.message)}</div>`; }
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user