Skip to content

Commit 78fe653

Browse files
fix: address bot review comments — stale credit response, a11y, indentation, race conditions, and docs
- handler: re-fetch account after UpdateAccountCredit, add DisallowUnknownFields - fast_scheduler: fix } else { indentation (was nested inside if body) - AccountUsageModal: add aria-label, focus-visible styles, disabled cursor state - ImageStudio: clamp input images in setter, decouple rerun from stale UI state - billing: simplify calculateCostBreakdown wrapper - postgres: return sql.ErrNoRows when UpdateAccountCredit affects zero rows - image_studio: validate input image count before job creation - docs: fix duplicate model ID, clarify BIND_HOST and credit_skip_usage_window - README.zh-CN: fix remaining_quota description ambiguity - locales: add missing images.mode key Co-Authored-By: Claude <noreply@anthropic.com>
1 parent a8df800 commit 78fe653

12 files changed

Lines changed: 57 additions & 36 deletions

File tree

README.zh-CN.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,7 @@ curl -X POST http://localhost:8080/api/admin/oauth/exchange-code \
525525
| 模式 | 行为 |
526526
| --- | --- |
527527
| `round_robin`(默认) | 按健康层级轮询可用账号,权重按调度分排序 |
528-
| `remaining_quota` | 优先使用用量的账号;用量相同时轮询 |
528+
| `remaining_quota` | 优先使用用量较低的账号;用量相同时轮询 |
529529

530530
**信用账号**(单账号标记):
531531

admin/handler.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,9 @@ func (h *Handler) UpdateAccountCredit(c *gin.Context) {
678678
CreditEnabled *bool `json:"credit_enabled"`
679679
CreditSkipUsageWindow *bool `json:"credit_skip_usage_window"`
680680
}
681-
if err := json.NewDecoder(c.Request.Body).Decode(&req); err != nil {
681+
decoder := json.NewDecoder(c.Request.Body)
682+
decoder.DisallowUnknownFields()
683+
if err := decoder.Decode(&req); err != nil {
682684
writeError(c, http.StatusBadRequest, "请求格式错误")
683685
return
684686
}
@@ -695,7 +697,12 @@ func (h *Handler) UpdateAccountCredit(c *gin.Context) {
695697
return
696698
}
697699

698-
c.JSON(http.StatusOK, gin.H{"message": "信用设置已更新", "credit_enabled": acc.CreditEnabled, "credit_skip_usage_window": acc.CreditSkipUsageWindow})
700+
acc = h.store.FindByID(id)
701+
if acc != nil {
702+
c.JSON(http.StatusOK, gin.H{"message": "信用设置已更新", "credit_enabled": acc.CreditEnabled, "credit_skip_usage_window": acc.CreditSkipUsageWindow})
703+
} else {
704+
c.JSON(http.StatusOK, gin.H{"message": "信用设置已更新"})
705+
}
699706
}
700707

701708
func (h *Handler) UpdateAccountScheduler(c *gin.Context) {

admin/image_studio.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,10 @@ func (h *Handler) CreateImageEditJob(c *gin.Context) {
338338
writeError(c, http.StatusBadRequest, "图生图需要上传参考图片")
339339
return
340340
}
341+
if len(req.InputImages) > proxy.MaxImageEditInputCount {
342+
writeError(c, http.StatusBadRequest, fmt.Sprintf("参考图片数量超过限制 (%d, 最多 %d)", len(req.InputImages), proxy.MaxImageEditInputCount))
343+
return
344+
}
341345
if len([]rune(req.Prompt)) > 8000 {
342346
writeError(c, http.StatusBadRequest, "提示词不能超过 8000 个字符")
343347
return

auth/fast_scheduler.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -99,17 +99,17 @@ func (s *FastScheduler) SetSchedulerMode(mode string) {
9999
}
100100
return usageI < usageJ
101101
})
102-
} else {
103-
sort.SliceStable(entries, func(i, j int) bool {
104-
if entries[i].dispatchScore == entries[j].dispatchScore {
105-
if entries[i].proven != entries[j].proven {
106-
return entries[i].proven
107-
}
108-
return entries[i].dbID < entries[j].dbID
102+
} else {
103+
sort.SliceStable(entries, func(i, j int) bool {
104+
if entries[i].dispatchScore == entries[j].dispatchScore {
105+
if entries[i].proven != entries[j].proven {
106+
return entries[i].proven
109107
}
110-
return entries[i].dispatchScore > entries[j].dispatchScore
111-
})
112-
}
108+
return entries[i].dbID < entries[j].dbID
109+
}
110+
return entries[i].dispatchScore > entries[j].dispatchScore
111+
})
112+
}
113113
s.buckets[tier] = entries
114114
s.rebuildPositionsLocked(tier)
115115
}

database/billing.go

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -355,15 +355,5 @@ func calculateCost(inputTokens, outputTokens, cachedTokens int, model string, se
355355
}
356356

357357
func calculateCostBreakdown(inputTokens, outputTokens, cachedTokens int, model string, serviceTier string) CostBreakdown {
358-
bd := CalculateCostBreakdown(inputTokens, outputTokens, cachedTokens, model, serviceTier)
359-
return CostBreakdown{
360-
InputCost: bd.InputCost,
361-
OutputCost: bd.OutputCost,
362-
CacheReadCost: bd.CacheReadCost,
363-
TotalCost: bd.TotalCost,
364-
InputPricePerMToken: bd.InputPricePerMToken,
365-
OutputPricePerMToken: bd.OutputPricePerMToken,
366-
CacheReadPricePerMToken: bd.CacheReadPricePerMToken,
367-
ServiceTierCostMultiplier: bd.ServiceTierCostMultiplier,
368-
}
358+
return CalculateCostBreakdown(inputTokens, outputTokens, cachedTokens, model, serviceTier)
369359
}

database/postgres.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3390,8 +3390,18 @@ func (db *DB) UpdateAccountCredit(ctx context.Context, id int64, creditEnabled,
33903390
query := "UPDATE accounts SET " + strings.Join(setClauses, ", ") + fmt.Sprintf(" WHERE id = $%d", argIdx)
33913391
args = append(args, id)
33923392

3393-
_, err := db.conn.ExecContext(ctx, query, args...)
3394-
return err
3393+
res, err := db.conn.ExecContext(ctx, query, args...)
3394+
if err != nil {
3395+
return err
3396+
}
3397+
affected, err := res.RowsAffected()
3398+
if err != nil {
3399+
return err
3400+
}
3401+
if affected == 0 {
3402+
return sql.ErrNoRows
3403+
}
3404+
return nil
33953405
}
33963406

33973407
// UpdateCredentials 原子合并更新账号的 credentials(JSONB || 运算符,不覆盖已有字段)

docs/API.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ data: [DONE]
288288
"object": "list",
289289
"data": [
290290
{ "id": "gpt-5.5", "object": "model", "owned_by": "openai" },
291-
{ "id": "gpt-5.5", "object": "model", "owned_by": "openai" },
291+
{ "id": "gpt-5.4", "object": "model", "owned_by": "openai" },
292292
{ "id": "gpt-5.4-mini", "object": "model", "owned_by": "openai" },
293293
{ "id": "gpt-5.3-codex", "object": "model", "owned_by": "openai" },
294294
{ "id": "gpt-5.3-codex-spark", "object": "model", "owned_by": "openai" },
@@ -484,7 +484,7 @@ data: [DONE]
484484
| 参数 | 类型 | 必填 | 说明 |
485485
| -------------------------- | ----- | ---- | ---------------------------------------- |
486486
| credit_enabled | bool || 标记账号为信用计费模式,省略时保持原值 |
487-
| credit_skip_usage_window | bool || 跳过 7 天/5 小时用量窗口惩罚,省略时保持原值 |
487+
| credit_skip_usage_window | bool || 跳过 7 天/5 小时用量窗口惩罚(仅在 `credit_enabled=true` 时生效),省略时保持原值 |
488488

489489
**响应:**
490490

docs/CONFIGURATION.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ Codex2API 采用三层配置架构:
4343
| 变量 | 必填 | 默认值 | 说明 |
4444
|------|------|--------|------|
4545
| `CODEX_PORT` || 8080 | HTTP 服务端口 |
46-
| `BIND_HOST` || `127.0.0.1`(SQLite)/ `0.0.0.0`(PostgreSQL) | HTTP 绑定地址。SQLite compose 默认 `127.0.0.1` 仅本机访问;标准 compose 默认 `0.0.0.0` 所有网络接口 |
46+
| `BIND_HOST` || `127.0.0.1`(SQLite)/ `0.0.0.0`(PostgreSQL) | Docker 端口发布绑定地址(非进程监听地址,由 `CODEX_BIND` 控制)。SQLite compose 默认 `127.0.0.1` 仅本机访问;标准 compose 默认 `0.0.0.0` 所有网络接口 |
4747
| `ADMIN_SECRET` || - | 管理后台登录密钥 |
4848
| `CODEX_ALLOW_ANONYMOUS` || `false` | 设为 `true` 时,未配置任何对外 API Key 也允许 `/v1/*` 直接调用(仅限内网测试场景) |
4949
| `FAST_SCHEDULER_ENABLED` || `false` | 通过环境变量启用快速调度器(也可在管理后台运行时开启) |

frontend/src/components/AccountUsageModal.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,11 @@ export default function AccountUsageModal({ account, onClose }: Props) {
140140
<button
141141
type="button"
142142
role="switch"
143+
aria-label={t("accounts.creditEnabled")}
143144
aria-checked={creditEnabled}
144145
disabled={savingCredit}
145146
onClick={() => handleCreditToggle('credit_enabled', !creditEnabled)}
146-
className={`relative inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus:outline-none ${creditEnabled ? 'bg-primary' : 'bg-muted'}`}
147+
className={`relative inline-flex h-5 w-9 shrink-0 ${savingCredit ? "cursor-not-allowed opacity-60" : "cursor-pointer"} items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60 focus-visible:ring-offset-2 ${creditEnabled ? 'bg-primary' : 'bg-muted'}`}
147148
>
148149
<span className={`pointer-events-none block size-4 rounded-full bg-white shadow transition-transform ${creditEnabled ? 'translate-x-4' : 'translate-x-0'}`} />
149150
</button>
@@ -157,10 +158,11 @@ export default function AccountUsageModal({ account, onClose }: Props) {
157158
<button
158159
type="button"
159160
role="switch"
161+
aria-label={t("accounts.creditSkipWindow")}
160162
aria-checked={creditSkipWindow}
161163
disabled={savingCredit}
162164
onClick={() => handleCreditToggle('credit_skip_usage_window', !creditSkipWindow)}
163-
className={`relative inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus:outline-none ${creditSkipWindow ? 'bg-primary' : 'bg-muted'}`}
165+
className={`relative inline-flex h-5 w-9 shrink-0 ${savingCredit ? "cursor-not-allowed opacity-60" : "cursor-pointer"} items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60 focus-visible:ring-offset-2 ${creditSkipWindow ? 'bg-primary' : 'bg-muted'}`}
164166
>
165167
<span className={`pointer-events-none block size-4 rounded-full bg-white shadow transition-transform ${creditSkipWindow ? 'translate-x-4' : 'translate-x-0'}`} />
166168
</button>

frontend/src/locales/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,6 +1261,7 @@
12611261
"images": {
12621262
"title": "Image Studio",
12631263
"description": "Text-to-image generation, prompt templates, and server gallery",
1264+
"mode": "Mode",
12641265
"views": {
12651266
"studio": "Studio",
12661267
"prompts": "Prompts",

0 commit comments

Comments
 (0)