From 79e4cac19b59dce45e43e3af9660270297cdb37c Mon Sep 17 00:00:00 2001 From: thzxx Date: Tue, 7 Apr 2026 02:00:27 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20header=20=E5=A2=9E=E5=8A=A0=E5=BD=93?= =?UTF-8?q?=E5=89=8D=E4=BC=9A=E8=AF=9D=E6=80=BB=20token=20=E6=B6=88?= =?UTF-8?q?=E8=80=97=E7=BB=9F=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 totalTokens 元素(帮助按钮右侧,🪙 图标 + 数字) - chat-area.ts 新增 updateTotalTokens() 函数 - 四个触发点:新消息完成、新建会话、加载历史、应用初始化 - 数字自动格式化(toLocaleString) --- src/renderer/components/chat-area.ts | 12 ++++++++++++ src/renderer/components/history-modal.ts | 3 ++- src/renderer/components/input-area.ts | 4 +++- src/renderer/index.html | 1 + src/renderer/main.ts | 4 +++- src/renderer/styles/style.css | 14 ++++++++++++++ 6 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/renderer/components/chat-area.ts b/src/renderer/components/chat-area.ts index 351e4fa..15c4a0f 100644 --- a/src/renderer/components/chat-area.ts +++ b/src/renderer/components/chat-area.ts @@ -384,6 +384,18 @@ export function enableAutoScroll(): void { if (scrollBtnEl) scrollBtnEl.style.display = 'none'; } +/** 统计当前会话总 token 消耗并更新 header 显示 */ +export function updateTotalTokens(): void { + const session = state.get(KEYS.CURRENT_SESSION); + const el = document.querySelector('#totalTokensValue'); + if (!el) return; + if (!session) { el.textContent = '0'; return; } + const total = session.messages + .filter(m => m.role === 'assistant' && m.eval_count) + .reduce((sum, m) => sum + (m.eval_count || 0), 0); + el.textContent = total > 0 ? total.toLocaleString() : '0'; +} + // ── 导出功能 ── async function nativeSaveFile(defaultName: string, content: string): Promise { diff --git a/src/renderer/components/history-modal.ts b/src/renderer/components/history-modal.ts index e946646..7ce706b 100644 --- a/src/renderer/components/history-modal.ts +++ b/src/renderer/components/history-modal.ts @@ -4,7 +4,7 @@ import { state, KEYS } from '../state/state.js'; import { debounce, escapeHtml, formatTime } from '../utils/utils.js'; -import { exportAsMarkdown, exportAsHtml, exportAsTxt, renderMessages, clearMessages } from './chat-area.js'; +import { exportAsMarkdown, exportAsHtml, exportAsTxt, renderMessages, clearMessages, updateTotalTokens } from './chat-area.js'; import { showConfirm } from './prompt-modal.js'; import { ChatDB } from '../db/chat-db.js'; import { logSession, logWarn } from '../services/log-service.js'; @@ -181,6 +181,7 @@ async function loadHistorySession(sessionId: string): Promise { clearMessages(); renderMessages(); + updateTotalTokens(); closeHistoryModal(); } diff --git a/src/renderer/components/input-area.ts b/src/renderer/components/input-area.ts index 81b1bac..7dc7662 100644 --- a/src/renderer/components/input-area.ts +++ b/src/renderer/components/input-area.ts @@ -7,7 +7,7 @@ import { detectLanguage, truncate, escapeHtml, formatSize } from '../utils/utils import { getSelectedModel, isThinkEnabled, isVisionAvailable, isToolCallingSupported } from './model-bar.js'; import { renderMessages, appendAssistantPlaceholder, appendSystemMessage, - updateLastAssistantMessage, clearMessages, safeMarkdown, enableAutoScroll + updateLastAssistantMessage, clearMessages, safeMarkdown, enableAutoScroll, updateTotalTokens } from './chat-area.js'; import { showToast } from './toast.js'; import { isRagEnabled, performRagRetrieval } from './kb-modal.js'; @@ -521,6 +521,7 @@ export async function sendMessage(): Promise { } await saveCurrentSession(); + updateTotalTokens(); // ── 自动提取记忆(非阻塞)── if (isMemoryEnabled() && freshSession.messages.length >= 6) { @@ -738,6 +739,7 @@ async function sendMessageWithAgentLoop(text: string, currentSession: ChatSessio updateLastAssistantMessage(assistantContent, thinkContent || null, loopStats || null); renderMessages(); await saveCurrentSession(); + updateTotalTokens(); } }); } catch (err) { diff --git a/src/renderer/index.html b/src/renderer/index.html index 4d5f700..535f7ed 100644 --- a/src/renderer/index.html +++ b/src/renderer/index.html @@ -34,6 +34,7 @@ + 🪙 0
diff --git a/src/renderer/main.ts b/src/renderer/main.ts index 2b6efbc..0f4e02b 100644 --- a/src/renderer/main.ts +++ b/src/renderer/main.ts @@ -15,7 +15,7 @@ import { initToast, showToast } from './components/toast.js'; import { initLightbox, closeLightbox } from './components/lightbox.js'; import { initHeader, checkConnection } from './components/header.js'; import { initModelBar, loadModels, setSelectedModel } from './components/model-bar.js'; -import { initChatArea, renderMessages, clearMessages, enableAutoScroll } from './components/chat-area.js'; +import { initChatArea, renderMessages, clearMessages, enableAutoScroll, updateTotalTokens } from './components/chat-area.js'; import { initInputArea } from './components/input-area.js'; import { initSettingsModal, closeSettingsModal } from './components/settings-modal.js'; import { initHistoryModal, closeHistoryModal } from './components/history-modal.js'; @@ -148,6 +148,7 @@ async function startNewSession(): Promise { clearMessages(); enableAutoScroll(); renderMessages(); + updateTotalTokens(); (document.querySelector('#chatInput') as HTMLElement)?.focus(); } @@ -242,6 +243,7 @@ async function init(): Promise { state.set('memoryEnabled', memoryEnabled); (document.querySelector('#chatInput') as HTMLElement)?.focus(); + updateTotalTokens(); logSuccess('应用初始化完成'); } catch (err) { diff --git a/src/renderer/styles/style.css b/src/renderer/styles/style.css index 996923c..acf060c 100644 --- a/src/renderer/styles/style.css +++ b/src/renderer/styles/style.css @@ -369,6 +369,20 @@ html, body { opacity: 1; } +.total-tokens { + display: inline-flex; + align-items: center; + gap: 4px; + margin-left: 8px; + padding: 2px 8px; + font-size: 11px; + color: var(--text-secondary); + background: var(--bg-subtle, rgba(255,255,255,0.04)); + border-radius: 10px; + white-space: nowrap; + user-select: none; +} + /* ═══ 模型选择栏 ═══ */ .model-bar { display: flex;