Skip to content

Commit c4f3dcd

Browse files
author
ccs-upstream-sync[bot]
committed
Merge remote-tracking branch 'upstream/main' into upstream-sync/20260503-0433
2 parents 57875eb + 56df368 commit c4f3dcd

9 files changed

Lines changed: 87 additions & 16 deletions

File tree

README.md

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,14 @@ Available tags:
104104

105105
see [MANAGEMENT_API.md](https://help.router-for.me/management/api)
106106

107+
## Usage Statistics
108+
109+
Since v6.10.0, CLIProxyAPI and [CPAMC](https://github.com/router-for-me/Cli-Proxy-API-Management-Center) no longer ship built-in usage statistics. If you need usage statistics, use:
110+
111+
### [CPA Usage Keeper](https://github.com/Willxup/cpa-usage-keeper)
112+
113+
Standalone persistence and visualization service for CLIProxyAPI, with periodic data sync, SQLite storage, aggregate APIs, and a built-in dashboard for usage and statistics.
114+
107115
## Amp CLI Support
108116

109117
CLIProxyAPI includes integrated support for [Amp CLI](https://ampcode.com) and Amp IDE extensions, enabling you to use your Google/ChatGPT/Claude OAuth subscriptions with Amp's coding tools:
@@ -213,10 +221,6 @@ Cross-platform desktop app (macOS, Windows, Linux) wrapping CLIProxyAPI with a n
213221

214222
Ready-to-use cross-platform quota inspector for CLIProxyAPI, supporting per-account codex 5h/7d quota windows, plan-based sorting, status coloring, and multi-account summary analytics.
215223

216-
### [CPA Usage Keeper](https://github.com/Willxup/cpa-usage-keeper)
217-
218-
Standalone persistence and visualization service for CLIProxyAPI, with periodic data sync, SQLite storage, aggregate APIs, and a built-in dashboard for usage and statistics.
219-
220224
### [CodexCliPlus](https://github.com/C4AL/CodexCliPlus)
221225

222226
Windows-focused, local-first desktop management platform for Codex CLI built on CLIProxyAPI, focused on simplifying local setup, account and runtime management, and providing a more complete Codex CLI experience for local users.
@@ -238,6 +242,10 @@ Never stop coding. Smart routing to FREE & low-cost AI models with automatic fal
238242

239243
OmniRoute is an AI gateway for multi-provider LLMs: an OpenAI-compatible endpoint with smart routing, load balancing, retries, and fallbacks. Add policies, rate limits, caching, and observability for reliable, cost-aware inference.
240244

245+
### [Playful Proxy API Panel (PPAP)](https://github.com/daishuge/playful-proxy-api-panel)
246+
247+
A public CLIProxyAPI-compatible fork and bundled management panel. It keeps upstream-style usage while restoring built-in usage statistics, adding cache hit rate, first-byte latency, TPS tracking, and Docker-oriented self-hosted installation docs.
248+
241249
> [!NOTE]
242250
> If you have developed a port of CLIProxyAPI or a project inspired by it, please open a PR to add it to this list.
243251

README_CN.md

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,14 @@ docker compose up -d
104104

105105
请参见 [MANAGEMENT_API_CN.md](https://help.router-for.me/cn/management/api)
106106

107+
## 使用量统计
108+
109+
自v6.10.0版本以后,CLIProxyAPI及 [CPAMC](https://github.com/router-for-me/Cli-Proxy-API-Management-Center) 项目不再预置数据统计功能,如果有数据统计需求的请使用以下项目:
110+
111+
### [CPA Usage Keeper](https://github.com/Willxup/cpa-usage-keeper)
112+
113+
独立的 CLIProxyAPI 使用量持久化与可视化服务,定期同步 CLIProxyAPI 数据,存储到 SQLite,提供聚合 API,并内置使用量分析与统计仪表盘。
114+
107115
## Amp CLI 支持
108116

109117
CLIProxyAPI 已内置对 [Amp CLI](https://ampcode.com) 和 Amp IDE 扩展的支持,可让你使用自己的 Google/ChatGPT/Claude OAuth 订阅来配合 Amp 编码工具:
@@ -209,10 +217,6 @@ Shadow AI 是一款专为受限环境设计的 AI 辅助工具。提供无窗口
209217

210218
上手即用的面向 CLIProxyAPI 跨平台配额查询工具,支持按账号展示 codex 5h/7d 配额窗口、按计划排序、状态着色及多账号汇总分析。
211219

212-
### [CPA Usage Keeper](https://github.com/Willxup/cpa-usage-keeper)
213-
214-
独立的 CLIProxyAPI 使用量持久化与可视化服务,定期同步 CPA 数据,存储到 SQLite,提供聚合 API,并内置使用量分析与统计仪表盘。
215-
216220
### [CodexCliPlus](https://github.com/C4AL/CodexCliPlus)
217221

218222
基于 CLIProxyAPI 的 Windows Codex CLI 本地优先桌面管理平台,聚焦简化本机配置、账号与运行状态管理,并为本地用户提供更完整的 Codex CLI 使用体验。
@@ -234,6 +238,10 @@ Shadow AI 是一款专为受限环境设计的 AI 辅助工具。提供无窗口
234238

235239
OmniRoute 是一个面向多供应商大语言模型的 AI 网关:它提供兼容 OpenAI 的端点,具备智能路由、负载均衡、重试及回退机制。通过添加策略、速率限制、缓存和可观测性,确保推理过程既可靠又具备成本意识。
236240

241+
### [Playful Proxy API Panel (PPAP)](https://github.com/daishuge/playful-proxy-api-panel)
242+
243+
一个公开的 CLIProxyAPI 兼容二开版本和配套管理面板,尽量保持与上游一致的使用方式,同时恢复内置使用量统计,并补充缓存命中率、首字响应时间、TPS 记录和面向 Docker 自托管的安装说明。
244+
237245
> [!NOTE]
238246
> 如果你开发了 CLIProxyAPI 的移植或衍生项目,请提交 PR 将其添加到此列表中。
239247

README_JA.md

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,14 @@ CLIProxyAPIガイド:[https://help.router-for.me/](https://help.router-for.me/
7272

7373
[MANAGEMENT_API.md](https://help.router-for.me/management/api)を参照
7474

75+
## 使用量統計
76+
77+
v6.10.0以降、CLIProxyAPIおよび [CPAMC](https://github.com/router-for-me/Cli-Proxy-API-Management-Center) プロジェクトには使用量統計機能がプリセットされなくなりました。使用量統計が必要な場合は、次のプロジェクトをご利用ください:
78+
79+
### [CPA Usage Keeper](https://github.com/Willxup/cpa-usage-keeper)
80+
81+
CLIProxyAPI向けの独立した使用量永続化・可視化サービス。CLIProxyAPIデータを定期同期してSQLiteに保存し、集計APIと、使用量や各種統計を確認できる組み込みダッシュボードを提供します。
82+
7583
## Amp CLIサポート
7684

7785
CLIProxyAPIは[Amp CLI](https://ampcode.com)およびAmp IDE拡張機能の統合サポートを含んでおり、Google/ChatGPT/ClaudeのOAuthサブスクリプションをAmpのコーディングツールで使用できます:
@@ -178,10 +186,6 @@ CLIProxyAPIをネイティブGUIでラップしたクロスプラットフォー
178186

179187
CLIProxyAPI向けのすぐに使えるクロスプラットフォームのクォータ確認ツール。アカウントごとの codex 5h/7d クォータ表示、プラン別ソート、ステータス色分け、複数アカウントの集計分析に対応。
180188

181-
### [CPA Usage Keeper](https://github.com/Willxup/cpa-usage-keeper)
182-
183-
CLIProxyAPI向けの独立した使用量永続化・可視化サービス。CPAデータを定期同期してSQLiteに保存し、集計APIと、使用量や各種統計を確認できる組み込みダッシュボードを提供します。
184-
185189
### [CodexCliPlus](https://github.com/C4AL/CodexCliPlus)
186190

187191
CLIProxyAPIを基盤にしたWindows向けのローカル優先Codex CLIデスクトップ管理プラットフォーム。ローカル設定、アカウント、実行状態の管理を簡素化し、ローカルユーザーにより包括的なCodex CLI体験を提供します。
@@ -203,6 +207,10 @@ CLIProxyAPIに触発されたNext.js実装。インストールと使用が簡
203207

204208
OmniRouteはマルチプロバイダーLLM向けのAIゲートウェイです:スマートルーティング、負荷分散、リトライ、フォールバックを備えたOpenAI互換エンドポイント。ポリシー、レート制限、キャッシュ、可観測性を追加して、信頼性が高くコストを意識した推論を実現します。
205209

210+
### [Playful Proxy API Panel (PPAP)](https://github.com/daishuge/playful-proxy-api-panel)
211+
212+
上流に近い使い方を維持する公開CLIProxyAPI互換フォーク兼管理パネルです。内蔵の使用量統計を復元し、キャッシュヒット率、初回バイト待ち時間、TPSの記録、Docker向けのセルフホスト手順を追加しています。
213+
206214
> [!NOTE]
207215
> CLIProxyAPIの移植版またはそれに触発されたプロジェクトを開発した場合は、PRを送ってこのリストに追加してください。
208216

cmd/server/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,7 @@ func main() {
472472
}
473473
usage.SetStatisticsEnabled(cfg.UsageStatisticsEnabled)
474474
redisqueue.SetUsageStatisticsEnabled(cfg.UsageStatisticsEnabled)
475+
redisqueue.SetRetentionSeconds(cfg.RedisUsageQueueRetentionSeconds)
475476
coreauth.SetQuotaCooldownDisabled(cfg.DisableCooling)
476477

477478
if err = logging.ConfigureLogOutput(cfg); err != nil {

config.example.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ error-logs-max-files: 10
7171
# When false, disable in-memory usage statistics aggregation
7272
usage-statistics-enabled: false
7373

74+
# How long (in seconds) Redis usage queue items are retained in memory for the RESP interface (LPOP/RPOP).
75+
# Default: 60. Max: 3600.
76+
redis-usage-queue-retention-seconds: 60
77+
7478
# Proxy URL. Supports socks5/http/https protocols. Example: socks5://user:pass@192.168.1.1:1080/
7579
# Per-entry proxy-url also supports "direct" or "none" to bypass both the global proxy-url and environment proxies explicitly.
7680
proxy-url: ""

internal/api/server.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,6 +1055,10 @@ func (s *Server) UpdateClients(cfg *config.Config) {
10551055
redisqueue.SetUsageStatisticsEnabled(cfg.UsageStatisticsEnabled)
10561056
}
10571057

1058+
if oldCfg == nil || oldCfg.RedisUsageQueueRetentionSeconds != cfg.RedisUsageQueueRetentionSeconds {
1059+
redisqueue.SetRetentionSeconds(cfg.RedisUsageQueueRetentionSeconds)
1060+
}
1061+
10581062
if s.requestLogger != nil && (oldCfg == nil || oldCfg.ErrorLogsMaxFiles != cfg.ErrorLogsMaxFiles) {
10591063
if setter, ok := s.requestLogger.(interface{ SetErrorLogsMaxFiles(int) }); ok {
10601064
setter.SetErrorLogsMaxFiles(cfg.ErrorLogsMaxFiles)

internal/config/config.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ type Config struct {
6565
// UsageStatisticsEnabled toggles in-memory usage aggregation; when false, usage data is discarded.
6666
UsageStatisticsEnabled bool `yaml:"usage-statistics-enabled" json:"usage-statistics-enabled"`
6767

68+
// RedisUsageQueueRetentionSeconds controls how long (in seconds) usage queue items
69+
// are retained in memory for the Redis RESP interface (LPOP/RPOP).
70+
// Default: 60. Max: 3600.
71+
RedisUsageQueueRetentionSeconds int `yaml:"redis-usage-queue-retention-seconds" json:"redis-usage-queue-retention-seconds"`
72+
6873
// DisableCooling disables quota cooldown scheduling when true.
6974
DisableCooling bool `yaml:"disable-cooling" json:"disable-cooling"`
7075

@@ -707,6 +712,7 @@ func LoadConfigOptional(configFile string, optional bool) (*Config, error) {
707712
cfg.LogsMaxTotalSizeMB = 0
708713
cfg.ErrorLogsMaxFiles = 10
709714
cfg.UsageStatisticsEnabled = false
715+
cfg.RedisUsageQueueRetentionSeconds = 60
710716
cfg.DisableCooling = false
711717
cfg.DisableImageGeneration = DisableImageGenerationOff
712718
cfg.Pprof.Enable = false
@@ -770,6 +776,13 @@ func LoadConfigOptional(configFile string, optional bool) (*Config, error) {
770776
cfg.ErrorLogsMaxFiles = 10
771777
}
772778

779+
if cfg.RedisUsageQueueRetentionSeconds <= 0 {
780+
cfg.RedisUsageQueueRetentionSeconds = 60
781+
} else if cfg.RedisUsageQueueRetentionSeconds > 3600 {
782+
log.WithField("value", cfg.RedisUsageQueueRetentionSeconds).Warn("redis-usage-queue-retention-seconds too large; clamping to 3600")
783+
cfg.RedisUsageQueueRetentionSeconds = 3600
784+
}
785+
773786
if cfg.MaxRetryCredentials < 0 {
774787
cfg.MaxRetryCredentials = 0
775788
}

internal/redisqueue/queue.go

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ import (
66
"time"
77
)
88

9-
const retentionWindow = time.Minute
9+
const (
10+
defaultRetentionSeconds int64 = 60
11+
maxRetentionSeconds int64 = 3600
12+
)
1013

1114
type queueItem struct {
1215
enqueuedAt time.Time
@@ -20,10 +23,15 @@ type queue struct {
2023
}
2124

2225
var (
23-
enabled atomic.Bool
24-
global queue
26+
enabled atomic.Bool
27+
retentionSeconds atomic.Int64
28+
global queue
2529
)
2630

31+
func init() {
32+
retentionSeconds.Store(defaultRetentionSeconds)
33+
}
34+
2735
func SetEnabled(value bool) {
2836
enabled.Store(value)
2937
if !value {
@@ -35,6 +43,16 @@ func Enabled() bool {
3543
return enabled.Load()
3644
}
3745

46+
func SetRetentionSeconds(value int) {
47+
normalized := int64(value)
48+
if normalized <= 0 {
49+
normalized = defaultRetentionSeconds
50+
} else if normalized > maxRetentionSeconds {
51+
normalized = maxRetentionSeconds
52+
}
53+
retentionSeconds.Store(normalized)
54+
}
55+
3856
func Enqueue(payload []byte) {
3957
if !Enabled() {
4058
return
@@ -110,7 +128,11 @@ func (q *queue) pruneLocked(now time.Time) {
110128
return
111129
}
112130

113-
cutoff := now.Add(-retentionWindow)
131+
windowSeconds := retentionSeconds.Load()
132+
if windowSeconds <= 0 {
133+
windowSeconds = defaultRetentionSeconds
134+
}
135+
cutoff := now.Add(-time.Duration(windowSeconds) * time.Second)
114136
for q.head < len(q.items) && q.items[q.head].enqueuedAt.Before(cutoff) {
115137
q.head++
116138
}

internal/watcher/diff/config_diff.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ func BuildConfigChangeDetails(oldCfg, newCfg *config.Config) []string {
3939
if oldCfg.UsageStatisticsEnabled != newCfg.UsageStatisticsEnabled {
4040
changes = append(changes, fmt.Sprintf("usage-statistics-enabled: %t -> %t", oldCfg.UsageStatisticsEnabled, newCfg.UsageStatisticsEnabled))
4141
}
42+
if oldCfg.RedisUsageQueueRetentionSeconds != newCfg.RedisUsageQueueRetentionSeconds {
43+
changes = append(changes, fmt.Sprintf("redis-usage-queue-retention-seconds: %d -> %d", oldCfg.RedisUsageQueueRetentionSeconds, newCfg.RedisUsageQueueRetentionSeconds))
44+
}
4245
if oldCfg.DisableCooling != newCfg.DisableCooling {
4346
changes = append(changes, fmt.Sprintf("disable-cooling: %t -> %t", oldCfg.DisableCooling, newCfg.DisableCooling))
4447
}

0 commit comments

Comments
 (0)