Commit Graph
3009 Commits
Author SHA1 Message Date
erio 180cf97588 fix(ui): show token breakdown when image model uses token billing
Only display image count format when billing_mode is "image".
When channel has token pricing, show input/output/cache token details.
2026-04-02 01:45:13 +08:00
erio 95d9b2d1d0 fix: billing mode display follows cost calculation result
Instead of hardcoding BillingMode="image" when ImageCount>0,
let cost.BillingMode (set by CalculateCostUnified/CalculateImageCost)
take priority. This ensures channel token pricing shows "token" mode.
2026-04-02 01:34:19 +08:00
erio ab74dcbf9d debug: add image billing resolve logging for troubleshooting 2026-04-02 01:09:49 +08:00
erio e9586ac085 fix: validate prices must be >= 0, remove debug logs 2026-04-02 00:52:19 +08:00
erio 5fb1340681 chore: remove debug logs for candidatesTokensDetails investigation 2026-04-02 00:48:36 +08:00
erio 435f88d984 debug: print v1internal raw payload for non-stream path 2026-04-02 00:29:44 +08:00
erio 194bde4651 debug: check candidatesTokensDetails in v1internal wrapper 2026-04-02 00:24:35 +08:00
erio e772c6ba2d debug: log candidatesTokensDetails presence in extractGeminiUsage 2026-04-02 00:17:38 +08:00
erio 4a24921ca9 feat: channel token pricing takes priority over per-image billing
When ImageCount > 0, check if channel has token pricing configured:
- YES (source=channel, mode=token) → use token billing with image_output_tokens
- NO → fall back to CalculateImageCost (original per-image billing)

This allows channels to configure $/MTok pricing for image generation
models while maintaining backward compatibility for setups without
channel pricing.
2026-04-01 23:29:01 +08:00
erio 97a4adf648 chore: bump version to 0.1.105.32 2026-04-01 23:21:54 +08:00
erio 6b69e5c7cf fix(ui): also fix floating point precision in mTokToPerToken 2026-04-01 23:18:03 +08:00
erio 2646173a84 fix(ui): floating point precision in perTokenToMTok conversion 2026-04-01 23:15:59 +08:00
erio 5f48e903bf fix: address audit findings - cache sync, validation, consistency
- clearCreditsExhausted: sync Redis scheduler cache after DB update
- Image billing mode UI: write to per_request_price instead of image_output_price
- OpenAI RecordUsage: use BillingModelSourceRequested constant, add s.cfg nil guard
- Fix i18n key path: admin.channels.perRequestPriceRequired → admin.channels.form.perRequestPriceRequired
2026-04-01 23:13:58 +08:00
erio bace10ff61 test: add unit tests for channel platform matching, interval validation, credits check
- TestIsPlatformPricingMatch: 12 cases covering all platform combinations
- TestMatchingPlatforms: 4 cases for platform expansion
- TestGetChannelModelPricing_AntigravityCrossPlatform: antigravity sees anthropic pricing
- TestGetChannelModelPricing_AnthropicCannotSeeAntigravityPricing: no reverse leakage
- TestResolveChannelMapping_AntigravityCrossPlatform: antigravity uses anthropic mapping
- TestFilterValidIntervals: 8 cases for empty interval filtering
- TestHasEnoughCredits: 10 cases for credits balance threshold logic
- Extract hasEnoughCredits() pure function for testability
2026-04-01 22:41:39 +08:00
erio 8b179af2e4 fix: validate empty intervals + antigravity platform pricing match
- Backend: reject intervals with all-null price fields on save
- Backend: filterValidIntervals skips empty intervals in pricing resolver
- Frontend: red border + asterisk on empty interval rows
- Backend: antigravity groups now match anthropic/gemini channel pricing
2026-04-01 22:03:00 +08:00
erio 4d8683a115 fix: antigravity groups now match anthropic/gemini channel pricing
Antigravity platform serves both Claude and Gemini models, but channel
pricing/mapping is configured under Anthropic/Gemini tabs. The cache
builder was using strict platform equality, causing antigravity groups
to miss all channel pricing entries, resulting in $0 billing.

Add isPlatformPricingMatch() to treat antigravity as superset of
anthropic+gemini for pricing and mapping cache indexing.
2026-04-01 21:47:47 +08:00
erio 72731a81cf feat(ui): display three-level model mapping chain in usage logs
- Show channel + account mapping steps using model_mapping_chain field
- Add model_mapping_chain to AdminUsageLog TypeScript type
- Fallback to two-level display when chain is not available
- Fix cost nil guard in Anthropic/Antigravity RecordUsage paths
- Bump version to 0.1.105.31
2026-04-01 17:57:11 +08:00
erio eff0ceb14a fix: add cost nil guard to Anthropic/Antigravity RecordUsage paths
- Apply same nil-pointer protection as OpenAI path
- Remove unused accessToken/proxyURL params from checkAccountCredits
2026-04-01 17:13:31 +08:00
erio 327a4fb248 fix: golangci-lint test assertion and gofmt 2026-04-01 16:39:38 +08:00
erio 6af5b9ff9c fix: resolve golangci-lint issues
- Fix errcheck: defer rows.Close() with nolint
- Fix errcheck: type assertion with ok check in channel cache
- Fix staticcheck ST1005: lowercase error string
- Fix staticcheck SA5011: nil check cost before use in openai gateway
- Fix gofmt: format chatcompletions_to_responses.go
2026-04-01 16:30:47 +08:00
erio a1216b8839 feat: image output token billing, channel-mapped billing source, credits balance precheck
- Parse candidatesTokensDetails from Gemini API to separate image/text output tokens
- Add image_output_tokens and image_output_cost to usage_log (migration 089)
- Support per-image-token pricing via output_cost_per_image_token from model pricing data
- Channel pricing ImageOutputPrice override works in token billing mode
- Auto-fill image_output_price in channel pricing form from model defaults
- Add "channel_mapped" billing model source as new default (migration 088)
- Bills by model name after channel mapping, before account mapping
- Fix channel cache error TTL sign error (115s → 5s)
- Fix Update channel only invalidating new groups, not removed groups
- Fix frontend model_mapping clearing sending undefined instead of {}
- Credits balance precheck via shared AccountUsageService cache before injection
- Skip credits injection for accounts with insufficient balance
- Don't mark credits exhausted for "exhausted your capacity on this model" 429s
2026-04-01 15:08:57 +08:00
erio dc0870ad0a chore: bump version to 0.1.105.29 2026-04-01 02:41:00 +08:00
erio 47266e03e6 fix(antigravity): 积分注入后仍 429 直接标记 credits exhausted
旧逻辑中 shouldMarkCreditsExhausted 因 parseAntigravitySmartRetryInfo
能解析出 retry info 就 return false,导致 free 账号注入积分后上游返回
429 也永远不标记 exhausted,形成无限重试死循环。

修复:429 直接标记 exhausted,其他 4xx 保留关键词匹配(如 403 积分不足)。
2026-04-01 02:40:52 +08:00
erio 9a9eadeba0 chore: bump version to 0.1.105.28 2026-04-01 01:51:25 +08:00
erio 7abc6e02f4 feat(channel): 渠道管理全链路集成 — 模型映射、定价、限制、用量统计
- 渠道模型映射:支持精确匹配和通配符映射,按平台隔离
- 渠道模型定价:支持 token/按次/图片三种计费模式,区间分层定价
- 模型限制:渠道可限制仅允许定价列表中的模型
- 计费模型来源:支持 requested/upstream 两种计费模型选择
- 用量统计:usage_logs 新增 channel_id/model_mapping_chain/billing_tier/billing_mode 字段
- Dashboard 支持 model_source 维度(requested/upstream/mapping)查看模型统计
- 全部 gateway handler 统一接入 ResolveChannelMappingAndRestrict
- 修复测试:同步 SoraGenerationRepository 接口、SQL INSERT 参数、scan 字段
2026-04-01 01:51:19 +08:00
erio 34267c0395 fix(ui): 模型映射改用平台色字体,删除多余的边框色函数 2026-03-31 21:36:45 +08:00
erio ae3c6b5881 chore: bump version to 0.1.105.27 2026-03-31 21:35:31 +08:00
erio ddef383903 fix(ui): 模型映射输入框改为平台色字体,保持默认边框 2026-03-31 21:35:31 +08:00
erio 68fb629280 chore: bump version to 0.1.105.26 2026-03-31 21:27:32 +08:00
erio 1b6b3cf2fa feat(ui): 渠道表单模型标签和映射输入框显示平台对应颜色
- PricingEntryCard 折叠态模型 tag 按平台着色
- ModelTagInput 模型标签按平台着色
- 模型映射输入框边框按平台着色
2026-03-31 21:27:32 +08:00
erio 513da0f4f7 chore: bump version to 0.1.105.25 2026-03-31 21:21:03 +08:00
erio 5631c5f20c feat(ui): 渠道列表状态列改为 Toggle 开关,支持直接启用/禁用 2026-03-31 21:21:03 +08:00
erio 729530dfa6 chore: bump version to 0.1.105.24 2026-03-31 20:48:18 +08:00
erio 963c3b5dd6 fix(ui): 渠道定价折叠态模型名完整展示,不再截断
去掉 max-w-[120px] truncate 限制,改用 flex-wrap 允许换行,
充分利用空白区域展示完整模型名。
2026-03-31 20:48:18 +08:00
erio 493fa9d4c2 chore: bump version to 0.1.105.23 2026-03-31 20:38:02 +08:00
erio 9df5d90e78 fix(channel): 模型限制以原始请求模型检查定价列表,而非映射后模型
开启 restrict_models 时,应用原始模型名查定价列表;
定价列表未命中即拒绝,不因通配符映射而绕过限制。
2026-03-31 20:38:02 +08:00
erio 5a2d423d02 chore: bump version to 0.1.105.22 2026-03-31 20:11:46 +08:00
erio adcf6328b4 fix(openai): 非 OAuth 账号 Chat Completions 也提取 system 消息并注入 instructions
GPT-5/Codex 等模型要求请求中必须包含 instructions 字段。
之前 extractSystemMessagesFromInput + applyInstructions 仅在
OAuth 路径执行,API Key 账号走 Chat Completions 时 system 消息
保留在 input 中但缺少 instructions,导致上游返回 400。

同时在 ChatCompletionsRequest 和 ResponsesRequest 中增加
Instructions 字段,支持客户端直接传入 instructions 透传到上游。
2026-03-31 20:11:39 +08:00
erio 788288c86b chore: bump version to 0.1.105.21 2026-03-31 19:40:18 +08:00
erio 9311ca31fc fix(channel): 前端重复模型校验改为按平台检查
后端 validateNoDuplicateModels 使用 platform:model 复合键,
前端之前跨平台扁平化检查导致不同平台下的同名模型误报重复。
2026-03-31 19:40:07 +08:00
erio 72b9d198a1 feat(channel): 模型映射源支持通配符匹配
与定价通配符一致,映射源支持 * 后缀通配符(最长前缀优先):
- `*` 匹配所有模型
- `claude-*` 匹配 claude- 开头的模型
- 精确匹配优先于通配符
2026-03-31 19:32:14 +08:00
erio da72cf670a fix(channel): 渠道表单校验增强 — 空模型定价报错 + 必填标记
- 保存时校验:定价条目有但模型列表为空时报错并跳转到对应平台 tab,
  不再静默跳过导致数据丢失
- 保存时校验:启用的平台必须至少选择一个分组
- 分组关联标签增加红色 * 必填标记
2026-03-31 19:22:48 +08:00
erio 3840dc8787 fix(channel): 修复 invalidateCache 存入 typed nil 导致 loadCache panic
invalidateCache 存入 (*channelCache)(nil),类型断言 ok=true 但
指针为 nil,后续 cached.loadedAt 导致 nil pointer dereference。
在 loadCache 双重检查处增加 cached != nil 防御。
2026-03-31 18:37:30 +08:00
erio c8eec9c076 chore: bump version to 0.1.105.20 2026-03-31 17:50:39 +08:00
erio bd17bde19c Merge branch 'feature/channel' into release/custom-0.1.105 2026-03-31 17:23:31 +08:00
erio d058e5c112 fix(channel): 全平台渠道映射覆盖 + 公共函数抽取 + 死代码清理
- 4个缺失handler入口添加渠道映射+限制检查(ChatCompletions/Responses/Gemini)
- 模型限制错误信息优化,区分"模型不可用"和"无账号"
- OpenAI RecordUsage RequestedModel 改用 OriginalModel
- ResolveChannelMappingAndRestrict/ReplaceModelInBody 抽取到 ChannelService 消除跨service重复
- validateNoDuplicateModels 按 platform:model 去重
- 删除 Channel.ResolveMappedModel 死代码和 CalculateCostWithChannel Deprecated方法
- 移除冗余nil检查,抽取 validatePricingBillingMode 公共校验
2026-03-31 15:26:20 +08:00
erio b4514501dd Merge remote-tracking branch 'origin/feature/channel' into release/custom-0.1.105 2026-03-31 02:11:52 +08:00
erio d1791f43f8 refactor(channel): 抽取渠道映射公共函数 + OpenAI映射到body + 空响应修复 + 清理日志
- 抽取 ResolveChannelMappingAndRestrict 统一入口(5处→1个方法)
- 抽取 BuildModelMappingChain 到 ChannelMappingResult 方法(5处→1行调用)
- OpenAI 三入口 Forward 前应用渠道映射到请求体
- OpenAI Responses/Messages 限制检查添加错误响应
- 清理前端 3 处 console.log 调试日志
2026-03-31 02:11:24 +08:00
erio 8741864b79 Merge remote-tracking branch 'origin/feature/channel' into release/custom-0.1.105 2026-03-31 01:34:37 +08:00
erio 946180ef0d fix(channel): 模型限制用映射后模型检查 + 平台开关保留配置不删除
- OpenAI 网关三处 IsModelRestricted 改用 channelMapping.MappedModel
- 前端平台勾选改为 enabled 开关,取消勾选不清空配置数据
- formToAPI/校验只处理 enabled 的平台
2026-03-31 01:34:16 +08:00