diff --git a/src/modules/usage.js b/src/modules/usage.js index 5cbd5f3..f49a567 100644 --- a/src/modules/usage.js +++ b/src/modules/usage.js @@ -710,29 +710,65 @@ export function renderSavedModelPrices() { container.innerHTML = `
${i18n.t('usage_stats.model_price_empty')}
`; return; } - const rows = entries.map(([model, price]) => { const prompt = Number(price?.prompt) || 0; const completion = Number(price?.completion) || 0; + const safeModel = this.escapeHtml ? this.escapeHtml(model) : model; + const editArg = JSON.stringify(model).replace(/"/g, '"'); return ` -
- ${model} - $${prompt.toFixed(4)} / 1M - $${completion.toFixed(4)} / 1M +
+
+
${safeModel}
+
+ ${i18n.t('usage_stats.model_price_prompt')}: $${prompt.toFixed(4)} / 1M + ${i18n.t('usage_stats.model_price_completion')}: $${completion.toFixed(4)} / 1M +
+
+
+ +
`; }).join(''); - container.innerHTML = ` -
-
- ${i18n.t('usage_stats.model_price_model')} - ${i18n.t('usage_stats.model_price_prompt')} - ${i18n.t('usage_stats.model_price_completion')} -
- ${rows} -
- `; + container.innerHTML = rows; +} + +export function handleModelPriceEdit(modelName) { + const model = (modelName || '').trim(); + const select = document.getElementById('model-price-model-select'); + const promptInput = document.getElementById('model-price-prompt'); + const completionInput = document.getElementById('model-price-completion'); + const form = document.getElementById('model-price-form'); + if (!select || !promptInput || !completionInput) { + return; + } + + const options = Array.from(select.options).map(opt => opt.value); + if (model && !options.includes(model)) { + const opt = document.createElement('option'); + opt.value = model; + opt.textContent = model; + select.appendChild(opt); + } + + select.disabled = false; + select.value = model; + const price = this.modelPrices?.[model]; + if (price) { + promptInput.value = Number.isFinite(price.prompt) ? price.prompt : ''; + completionInput.value = Number.isFinite(price.completion) ? price.completion : ''; + } else { + promptInput.value = ''; + completionInput.value = ''; + } + + promptInput.focus(); + if (form && typeof form.scrollIntoView === 'function') { + form.scrollIntoView({ behavior: 'smooth', block: 'center' }); + } } export function prefillModelPriceInputs() { @@ -1824,6 +1860,7 @@ export const usageModule = { persistModelPrices, renderModelPriceOptions, renderSavedModelPrices, + handleModelPriceEdit, prefillModelPriceInputs, normalizePriceValue, handleModelPriceSubmit, diff --git a/styles.css b/styles.css index 5d6a006..be633e2 100644 --- a/styles.css +++ b/styles.css @@ -3713,34 +3713,18 @@ input:checked+.slider:before { .model-price-list { margin-top: 6px; -} - -.model-price-table { display: flex; flex-direction: column; - gap: 8px; + gap: 10px; } -.model-price-header, -.model-price-row { - display: grid; - grid-template-columns: 2fr 1fr 1fr; - gap: 12px; - padding: 10px 12px; - border: 1px solid var(--border-color); - border-radius: 10px; - align-items: center; +.model-price-item { + cursor: pointer; } -.model-price-header { - font-weight: 700; - color: var(--text-primary); - background: var(--bg-secondary); -} - -.model-price-row { - background: var(--bg-primary); - color: var(--text-secondary); +.model-price-item .item-meta { + margin-bottom: 0; + gap: 10px; } .chart-placeholder { @@ -4984,6 +4968,12 @@ input:checked+.slider:before { border: 1px solid var(--success-border); } +.stat-badge.stat-neutral { + background-color: var(--bg-tertiary); + color: var(--text-secondary); + border: 1px solid var(--border-color); +} + .stat-badge.stat-success i { font-size: 13px; }