feat(Settings): Add token count display toggle (#6772)

* feat(Settings): add token count toggle

* fix(i18n): update token usage messages for zh-cn and zh-tw locales

* fix(InstallNpxUv): optimize checkBinaries function with useCallback for better performance

---------

Co-authored-by: Pleasurecruise <3196812536@qq.com>
This commit is contained in:
熊可狸 2025-06-05 12:46:20 +08:00 committed by GitHub
parent ca60cec30d
commit 4990c28b50
10 changed files with 31 additions and 7 deletions

View File

@ -8,6 +8,7 @@ import {
setLaunchToTray,
setPinTopicsToTop,
setSendMessageShortcut as _setSendMessageShortcut,
setShowTokens,
setSidebarIcons,
setTargetLanguage,
setTheme,
@ -83,6 +84,9 @@ export function useSettings() {
},
setAssistantIconType(assistantIconType: AssistantIconType) {
dispatch(setAssistantIconType(assistantIconType))
},
setShowTokens(showTokens: boolean) {
dispatch(setShowTokens(showTokens))
}
}
}

View File

@ -1498,6 +1498,7 @@
"advancedSettings": "Advanced Settings"
},
"messages.prompt": "Show prompt",
"messages.tokens": "Show token usage",
"messages.divider": "Show divider between messages",
"messages.grid_columns": "Message grid display columns",
"messages.grid_popover_trigger": "Grid detail trigger",

View File

@ -1494,6 +1494,7 @@
"advancedSettings": "詳細設定"
},
"messages.prompt": "プロンプト表示",
"messages.tokens": "トークン使用量を表示",
"messages.divider": "メッセージ間に区切り線を表示",
"messages.grid_columns": "メッセージグリッドの表示列数",
"messages.grid_popover_trigger": "グリッド詳細トリガー",

View File

@ -1494,6 +1494,7 @@
"advancedSettings": "Расширенные настройки"
},
"messages.prompt": "Показывать подсказки",
"messages.tokens": "Показать использование токенов",
"messages.divider": "Показывать разделитель между сообщениями",
"messages.grid_columns": "Количество столбцов сетки сообщений",
"messages.grid_popover_trigger": "Триггер для отображения подробной информации в сетке",

View File

@ -1498,6 +1498,7 @@
"advancedSettings": "高级设置"
},
"messages.prompt": "显示提示词",
"messages.tokens": "显示Token用量",
"messages.divider": "消息分割线",
"messages.grid_columns": "消息网格展示列数",
"messages.grid_popover_trigger": "网格详情触发",

View File

@ -1497,6 +1497,7 @@
"advancedSettings": "高級設定"
},
"messages.prompt": "提示詞顯示",
"messages.tokens": "Token用量顯示",
"messages.divider": "訊息間顯示分隔線",
"messages.grid_columns": "訊息網格展示列數",
"messages.grid_popover_trigger": "網格詳細資訊觸發",

View File

@ -1,4 +1,5 @@
// import { useRuntime } from '@renderer/hooks/useRuntime'
import { useSettings } from '@renderer/hooks/useSettings'
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
import type { Message } from '@renderer/types/newMessage'
import { Popover } from 'antd'
@ -11,6 +12,7 @@ interface MessageTokensProps {
}
const MessgeTokens: React.FC<MessageTokensProps> = ({ message }) => {
const { showTokens } = useSettings()
// const { generating } = useRuntime()
const locateMessage = () => {
EventEmitter.emit(EVENT_NAMES.LOCATE_MESSAGE + ':' + message.id, false)
@ -23,7 +25,7 @@ const MessgeTokens: React.FC<MessageTokensProps> = ({ message }) => {
if (message.role === 'user') {
return (
<MessageMetadata className="message-tokens" onClick={locateMessage}>
Tokens: {message?.usage?.total_tokens}
{showTokens && `Tokens: ${message?.usage?.total_tokens}`}
</MessageMetadata>
)
}
@ -54,7 +56,7 @@ const MessgeTokens: React.FC<MessageTokensProps> = ({ message }) => {
<MessageMetadata className="message-tokens" onClick={locateMessage}>
{hasMetrics ? (
<Popover content={metrixs} placement="top" trigger="hover" styles={{ root: { fontSize: 11 } }}>
{tokensInfo}
{showTokens && tokensInfo}
</Popover>
) : (
tokensInfo

View File

@ -46,6 +46,7 @@ import {
setShowInputEstimatedTokens,
setShowMessageDivider,
setShowPrompt,
setShowTokens,
setShowTranslateConfirm,
setThoughtAutoCollapse
} from '@renderer/store/settings'
@ -113,7 +114,8 @@ const SettingsTab: FC<Props> = (props) => {
messageNavigation,
enableQuickPanelTriggers,
enableBackspaceDeleteModel,
showTranslateConfirm
showTranslateConfirm,
showTokens
} = useSettings()
const onUpdateAssistantSettings = (settings: Partial<AssistantSettings>) => {
@ -336,6 +338,11 @@ const SettingsTab: FC<Props> = (props) => {
<Switch size="small" checked={showPrompt} onChange={(checked) => dispatch(setShowPrompt(checked))} />
</SettingRow>
<SettingDivider />
<SettingRow>
<SettingRowTitleSmall>{t('settings.messages.tokens')}</SettingRowTitleSmall>
<Switch size="small" checked={showTokens} onChange={(checked) => dispatch(setShowTokens(checked))} />
</SettingRow>
<SettingDivider />
<SettingRow>
<SettingRowTitleSmall>{t('settings.messages.divider')}</SettingRowTitleSmall>
<Switch

View File

@ -3,7 +3,7 @@ import { Center, VStack } from '@renderer/components/Layout'
import { useAppDispatch, useAppSelector } from '@renderer/store'
import { setIsBunInstalled, setIsUvInstalled } from '@renderer/store/mcp'
import { Alert, Button } from 'antd'
import { FC, useEffect, useState } from 'react'
import { FC, useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router'
import styled from 'styled-components'
@ -26,7 +26,7 @@ const InstallNpxUv: FC<Props> = ({ mini = false }) => {
const [binariesDir, setBinariesDir] = useState<string | null>(null)
const { t } = useTranslation()
const navigate = useNavigate()
const checkBinaries = async () => {
const checkBinaries = useCallback(async () => {
const uvExists = await window.api.isBinaryExist('uv')
const bunExists = await window.api.isBinaryExist('bun')
const { uvPath, bunPath, dir } = await window.api.mcp.getInstallInfo()
@ -36,7 +36,7 @@ const InstallNpxUv: FC<Props> = ({ mini = false }) => {
setUvPath(uvPath)
setBunPath(bunPath)
setBinariesDir(dir)
}
}, [dispatch])
const installUV = async () => {
try {
@ -69,7 +69,7 @@ const InstallNpxUv: FC<Props> = ({ mini = false }) => {
useEffect(() => {
checkBinaries()
}, [])
}, [checkBinaries])
if (mini) {
const installed = isUvInstalled && isBunInstalled

View File

@ -47,6 +47,7 @@ export interface SettingsState {
proxyUrl?: string
userName: string
showPrompt: boolean
showTokens: boolean
showMessageDivider: boolean
messageFont: 'system' | 'serif'
showInputEstimatedTokens: boolean
@ -191,6 +192,7 @@ export const initialState: SettingsState = {
proxyUrl: undefined,
userName: '',
showPrompt: true,
showTokens: true,
showMessageDivider: true,
messageFont: 'system',
showInputEstimatedTokens: false,
@ -355,6 +357,9 @@ const settingsSlice = createSlice({
setShowPrompt: (state, action: PayloadAction<boolean>) => {
state.showPrompt = action.payload
},
setShowTokens: (state, action: PayloadAction<boolean>) => {
state.showTokens = action.payload
},
setShowMessageDivider: (state, action: PayloadAction<boolean>) => {
state.showMessageDivider = action.payload
},
@ -672,6 +677,7 @@ export const {
setProxyUrl,
setUserName,
setShowPrompt,
setShowTokens,
setShowMessageDivider,
setMessageFont,
setShowInputEstimatedTokens,