Skip to content

Commit cb4ab16

Browse files
committed
feat: add compact usage number setting
1 parent 95d25aa commit cb4ab16

9 files changed

Lines changed: 146 additions & 42 deletions

File tree

admin/handler.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4226,6 +4226,7 @@ type settingsResponse struct {
42264226
StreamFlushPolicy string `json:"stream_flush_policy"`
42274227
StreamFlushIntervalMS int `json:"stream_flush_interval_ms"`
42284228
FirstTokenTimeoutSeconds int `json:"first_token_timeout_seconds"`
4229+
ShowFullUsageNumbers bool `json:"show_full_usage_numbers"`
42294230
ImageStorageBackend string `json:"image_storage_backend"`
42304231
ImageS3Endpoint string `json:"image_s3_endpoint"`
42314232
ImageS3Region string `json:"image_s3_region"`
@@ -4289,6 +4290,7 @@ type updateSettingsReq struct {
42894290
StreamFlushPolicy *string `json:"stream_flush_policy"`
42904291
StreamFlushIntervalMS *int `json:"stream_flush_interval_ms"`
42914292
FirstTokenTimeoutSeconds *int `json:"first_token_timeout_seconds"`
4293+
ShowFullUsageNumbers *bool `json:"show_full_usage_numbers"`
42924294
ImageStorageBackend *string `json:"image_storage_backend"`
42934295
ImageS3Endpoint *string `json:"image_s3_endpoint"`
42944296
ImageS3Region *string `json:"image_s3_region"`
@@ -4770,12 +4772,14 @@ func (h *Handler) GetSettings(c *gin.Context) {
47704772
adminSecret := ""
47714773
var resinURL, resinPlatformName string
47724774
branding := brandingFromSettings(dbSettings)
4775+
showFullUsageNumbers := false
47734776
if dbSettings != nil && adminAuthSource != "env" {
47744777
adminSecret = dbSettings.AdminSecret
47754778
}
47764779
if dbSettings != nil {
47774780
resinURL = dbSettings.ResinURL
47784781
resinPlatformName = dbSettings.ResinPlatformName
4782+
showFullUsageNumbers = dbSettings.ShowFullUsageNumbers
47794783
}
47804784
promptFilterCfg := h.store.GetPromptFilterConfig()
47814785
runtimeCfg := proxy.CurrentRuntimeSettings()
@@ -4843,6 +4847,7 @@ func (h *Handler) GetSettings(c *gin.Context) {
48434847
StreamFlushPolicy: runtimeCfg.StreamFlushPolicy,
48444848
StreamFlushIntervalMS: runtimeCfg.StreamFlushIntervalMS,
48454849
FirstTokenTimeoutSeconds: runtimeCfg.FirstTokenTimeoutSec,
4850+
ShowFullUsageNumbers: showFullUsageNumbers,
48464851
ImageStorageBackend: imgCfg.Backend,
48474852
ImageS3Endpoint: imgCfg.Endpoint,
48484853
ImageS3Region: imgCfg.Region,
@@ -4866,12 +4871,14 @@ func (h *Handler) UpdateSettings(c *gin.Context) {
48664871
siteName := database.DefaultSiteName
48674872
siteLogo := ""
48684873
bgCfg := defaultBackgroundConfig()
4874+
showFullUsageNumbers := false
48694875
existingSettings, _ := h.db.GetSystemSettings(c.Request.Context())
48704876
if existingSettings != nil {
48714877
currentAdminSecret = existingSettings.AdminSecret
48724878
siteName = database.NormalizeSiteName(existingSettings.SiteName)
48734879
siteLogo = strings.TrimSpace(existingSettings.SiteLogo)
48744880
bgCfg = decodeBackgroundConfig(existingSettings.BackgroundConfig)
4881+
showFullUsageNumbers = existingSettings.ShowFullUsageNumbers
48754882
}
48764883
if req.AdminSecret != nil {
48774884
if h.adminSecretEnv == "" {
@@ -5163,6 +5170,10 @@ func (h *Handler) UpdateSettings(c *gin.Context) {
51635170
runtimeCfg.FirstTokenTimeoutSec = *req.FirstTokenTimeoutSeconds
51645171
log.Printf("设置已更新: first_token_timeout_seconds = %d", runtimeCfg.FirstTokenTimeoutSec)
51655172
}
5173+
if req.ShowFullUsageNumbers != nil {
5174+
showFullUsageNumbers = *req.ShowFullUsageNumbers
5175+
log.Printf("设置已更新: show_full_usage_numbers = %t", showFullUsageNumbers)
5176+
}
51665177
runtimeCfg = proxy.ApplyRuntimeSettings(runtimeCfg)
51675178

51685179
usageLogChanged := false
@@ -5375,6 +5386,7 @@ func (h *Handler) UpdateSettings(c *gin.Context) {
53755386
StreamFlushPolicy: runtimeCfg.StreamFlushPolicy,
53765387
StreamFlushIntervalMS: runtimeCfg.StreamFlushIntervalMS,
53775388
FirstTokenTimeoutSeconds: runtimeCfg.FirstTokenTimeoutSec,
5389+
ShowFullUsageNumbers: showFullUsageNumbers,
53785390
ImageStorageConfig: imgConfigJSON,
53795391
BackgroundConfig: encodeBackgroundConfig(bgCfg),
53805392
})
@@ -5454,6 +5466,7 @@ func (h *Handler) UpdateSettings(c *gin.Context) {
54545466
StreamFlushPolicy: runtimeCfg.StreamFlushPolicy,
54555467
StreamFlushIntervalMS: runtimeCfg.StreamFlushIntervalMS,
54565468
FirstTokenTimeoutSeconds: runtimeCfg.FirstTokenTimeoutSec,
5469+
ShowFullUsageNumbers: showFullUsageNumbers,
54575470
ImageStorageBackend: imgCfg.Backend,
54585471
ImageS3Endpoint: imgCfg.Endpoint,
54595472
ImageS3Region: imgCfg.Region,

database/postgres.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,7 @@ func (db *DB) migrate(ctx context.Context) error {
695695
ALTER TABLE system_settings ADD COLUMN IF NOT EXISTS stream_flush_interval_ms INT DEFAULT 20;
696696
ALTER TABLE system_settings ADD COLUMN IF NOT EXISTS first_token_timeout_seconds INT DEFAULT 0;
697697
ALTER TABLE system_settings ADD COLUMN IF NOT EXISTS image_storage_config TEXT DEFAULT '{}';
698+
ALTER TABLE system_settings ADD COLUMN IF NOT EXISTS show_full_usage_numbers BOOLEAN DEFAULT FALSE;
698699
699700
CREATE TABLE IF NOT EXISTS prompt_filter_logs (
700701
id SERIAL PRIMARY KEY,
@@ -1233,6 +1234,7 @@ type SystemSettings struct {
12331234
StreamFlushIntervalMS int
12341235
FirstTokenTimeoutSeconds int
12351236
ImageStorageConfig string // JSON: {"backend":"s3","endpoint":"...","region":"...","bucket":"...","access_key":"...","secret_key":"...","prefix":"...","force_path_style":false}
1237+
ShowFullUsageNumbers bool
12361238
}
12371239

12381240
// GetSystemSettings 加载全局设置
@@ -1277,7 +1279,8 @@ func (db *DB) GetSystemSettings(ctx context.Context) (*SystemSettings, error) {
12771279
COALESCE(stream_flush_interval_ms, 20),
12781280
COALESCE(first_token_timeout_seconds, 0),
12791281
COALESCE(image_storage_config, '{}'),
1280-
COALESCE(background_config, '{}')
1282+
COALESCE(background_config, '{}'),
1283+
COALESCE(show_full_usage_numbers, false)
12811284
FROM system_settings WHERE id = 1
12821285
`).Scan(
12831286
&s.SiteName, &s.SiteLogo,
@@ -1297,6 +1300,7 @@ func (db *DB) GetSystemSettings(ctx context.Context) (*SystemSettings, error) {
12971300
&s.FirstTokenTimeoutSeconds,
12981301
&s.ImageStorageConfig,
12991302
&s.BackgroundConfig,
1303+
&s.ShowFullUsageNumbers,
13001304
)
13011305
if errors.Is(err, sql.ErrNoRows) {
13021306
return nil, nil
@@ -1324,9 +1328,10 @@ func (db *DB) UpdateSystemSettings(ctx context.Context, s *SystemSettings) error
13241328
image_storage_config,
13251329
scheduler_mode,
13261330
affinity_mode,
1327-
background_config
1331+
background_config,
1332+
show_full_usage_numbers
13281333
)
1329-
VALUES (1, $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)
1334+
VALUES (1, $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)
13301335
ON CONFLICT (id) DO UPDATE SET
13311336
site_name = EXCLUDED.site_name,
13321337
site_logo = EXCLUDED.site_logo,
@@ -1376,7 +1381,8 @@ func (db *DB) UpdateSystemSettings(ctx context.Context, s *SystemSettings) error
13761381
image_storage_config = EXCLUDED.image_storage_config,
13771382
scheduler_mode = EXCLUDED.scheduler_mode,
13781383
affinity_mode = EXCLUDED.affinity_mode,
1379-
background_config = EXCLUDED.background_config
1384+
background_config = EXCLUDED.background_config,
1385+
show_full_usage_numbers = EXCLUDED.show_full_usage_numbers
13801386
`, NormalizeSiteName(s.SiteName), strings.TrimSpace(s.SiteLogo),
13811387
s.MaxConcurrency, s.GlobalRPM, s.TestModel, s.TestConcurrency, s.ProxyURL, s.PgMaxConns, s.RedisPoolSize,
13821388
s.AutoCleanUnauthorized, s.AutoCleanRateLimited, s.AdminSecret, s.AutoCleanFullUsage, s.ProxyPoolEnabled,
@@ -1388,7 +1394,7 @@ func (db *DB) UpdateSystemSettings(ctx context.Context, s *SystemSettings) error
13881394
s.PromptFilterSensitiveWords, s.PromptFilterCustomPatterns, s.PromptFilterDisabledPatterns,
13891395
s.ClientCompatMode, s.CodexMinCLIVersion, s.UsageLogMode, s.UsageLogBatchSize,
13901396
s.UsageLogFlushIntervalSeconds, s.StreamFlushPolicy, s.StreamFlushIntervalMS,
1391-
s.FirstTokenTimeoutSeconds, s.ImageStorageConfig, s.SchedulerMode, normalizeAffinityMode(s.AffinityMode), s.BackgroundConfig)
1397+
s.FirstTokenTimeoutSeconds, s.ImageStorageConfig, s.SchedulerMode, normalizeAffinityMode(s.AffinityMode), s.BackgroundConfig, s.ShowFullUsageNumbers)
13921398
return err
13931399
}
13941400

database/sqlite.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ func (db *DB) migrateSQLite(ctx context.Context) error {
143143
stream_flush_interval_ms INTEGER DEFAULT 20,
144144
first_token_timeout_seconds INTEGER DEFAULT 0,
145145
image_storage_config TEXT DEFAULT '{}',
146+
show_full_usage_numbers INTEGER DEFAULT 0,
146147
scheduler_mode TEXT DEFAULT 'round_robin',
147148
affinity_mode TEXT DEFAULT 'bounded'
148149
);`,
@@ -341,6 +342,7 @@ func (db *DB) migrateSQLite(ctx context.Context) error {
341342
{"system_settings", "stream_flush_interval_ms", "INTEGER DEFAULT 20"},
342343
{"system_settings", "first_token_timeout_seconds", "INTEGER DEFAULT 0"},
343344
{"system_settings", "image_storage_config", "TEXT DEFAULT '{}'"},
345+
{"system_settings", "show_full_usage_numbers", "INTEGER DEFAULT 0"},
344346
{"system_settings", "scheduler_mode", "TEXT DEFAULT 'round_robin'"},
345347
{"system_settings", "affinity_mode", "TEXT DEFAULT 'bounded'"},
346348
{"accounts", "enabled", "INTEGER DEFAULT 1"},

database/sqlite_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,7 @@ func TestSQLiteSystemSettingsPersistsFirstTokenTimeoutSeconds(t *testing.T) {
595595
SchedulerMode: "round_robin",
596596
AffinityMode: "bounded",
597597
BackgroundConfig: "{}",
598+
ShowFullUsageNumbers: true,
598599
}); err != nil {
599600
t.Fatalf("UpdateSystemSettings 返回错误: %v", err)
600601
}
@@ -609,6 +610,9 @@ func TestSQLiteSystemSettingsPersistsFirstTokenTimeoutSeconds(t *testing.T) {
609610
if settings.FirstTokenTimeoutSeconds != 17 {
610611
t.Fatalf("FirstTokenTimeoutSeconds = %d, want 17", settings.FirstTokenTimeoutSeconds)
611612
}
613+
if !settings.ShowFullUsageNumbers {
614+
t.Fatal("ShowFullUsageNumbers = false, want true")
615+
}
612616
}
613617

614618
func TestDeleteAccountGroupDoesNotBroadenScopedAPIKey(t *testing.T) {

frontend/src/locales/en.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,6 +1181,8 @@
11811181
"timezone": "System Timezone",
11821182
"timezoneDesc": "Controls date/time display in the frontend. The page will reload automatically after changing.",
11831183
"timezoneAuto": "Auto (Browser Timezone)",
1184+
"showFullUsageNumbers": "Show full usage numbers",
1185+
"showFullUsageNumbersDesc": "When enabled, the Usage page shows full request and token counts. When disabled, it uses compact units like 1.2M and 3.4B.",
11841186
"fastSchedulerEnabled": "Fast Scheduler",
11851187
"fastSchedulerEnabledDesc": "Uses an in-memory fast scheduling algorithm, significantly reducing dispatch latency under high concurrency. Recommended for large account pools (100+).",
11861188
"schedulerMode": "Scheduler Mode",

frontend/src/locales/zh.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,6 +1181,8 @@
11811181
"timezone": "系统时区",
11821182
"timezoneDesc": "控制前端日期/时间显示。修改后页面自动刷新生效。",
11831183
"timezoneAuto": "自动(浏览器时区)",
1184+
"showFullUsageNumbers": "显示完整用量数字",
1185+
"showFullUsageNumbersDesc": "开启后 Usage 页请求数、Tokens 等统计显示完整数字;关闭时默认显示 1.2M、3.4B 等紧凑单位。",
11841186
"fastSchedulerEnabled": "快速调度器",
11851187
"fastSchedulerEnabledDesc": "启用后,账号选择将使用内存快速调度算法,大幅降低高并发场景下的调度延迟。适合大号池(100+ 账号)场景。",
11861188
"schedulerMode": "调度模式",

frontend/src/pages/Settings.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,7 @@ export default function Settings() {
451451
stream_flush_policy: 'immediate',
452452
stream_flush_interval_ms: 20,
453453
first_token_timeout_seconds: 0,
454+
show_full_usage_numbers: false,
454455
image_storage_backend: 'local',
455456
image_s3_endpoint: '',
456457
image_s3_region: '',
@@ -1202,6 +1203,13 @@ export default function Settings() {
12021203
]}
12031204
/>
12041205
</SettingField>
1206+
<SettingField label={t('settings.showFullUsageNumbers')} description={t('settings.showFullUsageNumbersDesc')}>
1207+
<Select
1208+
value={settingsForm.show_full_usage_numbers ? 'true' : 'false'}
1209+
onValueChange={(value) => setSettingsForm((f) => ({ ...f, show_full_usage_numbers: value === 'true' }))}
1210+
options={booleanOptions}
1211+
/>
1212+
</SettingField>
12051213
</div>
12061214
</SettingsCard>
12071215
</div>

0 commit comments

Comments
 (0)