erio
6c718578a5
refactor(ui): extract formatCacheTokens and formatMultiplier to shared utils
2026-04-04 11:21:11 +08:00
erio
0d241d52eb
refactor: replace magic strings with named constants
...
- PricingSourceChannel/LiteLLM/Fallback for resolver source
- MediaTypeImage/Video/Prompt for result.MediaType
- Reuse BillingModeToken/BillingModeImage for billing mode
- Reuse BillingModelSourceChannelMapped/PlatformAnthropic in handler
2026-04-04 11:20:43 +08:00
erio
212eaa3a05
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-04 11:19:55 +08:00
erio
f3ab3fe5e2
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-04 11:19:36 +08:00
erio
b8c56ff940
fix: validate prices must be >= 0, remove debug logs
2026-04-04 11:17:49 +08:00
erio
38da737e6c
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-04 11:17:49 +08:00
erio
1b2ea7a1df
fix(ui): also fix floating point precision in mTokToPerToken
2026-04-04 11:17:49 +08:00
erio
a9e5fc8539
fix(ui): floating point precision in perTokenToMTok conversion
2026-04-04 11:17:49 +08:00
erio
9b213115e7
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-04 11:17:49 +08:00
erio
5534347328
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-04 11:17:49 +08:00
erio
2355029dc1
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-04 11:17:49 +08:00
erio
8d25335b01
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-04 11:17:48 +08:00
erio
c0b5900a37
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-04 11:17:48 +08:00
erio
35a9290528
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-04 11:17:48 +08:00
erio
c9145ad4d8
fix: golangci-lint test assertion and gofmt
2026-04-04 11:17:48 +08:00
erio
3851628a43
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-04 11:17:24 +08:00
erio
d72ac92694
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-04 11:15:59 +08:00
erio
2555951be4
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-04 11:13:58 +08:00
erio
669bff78c4
fix(ui): 模型映射改用平台色字体,删除多余的边框色函数
2026-04-04 11:13:57 +08:00
erio
c90d1f2527
fix(ui): 模型映射输入框改为平台色字体,保持默认边框
2026-04-04 11:13:57 +08:00
erio
40cebc250f
feat(ui): 渠道表单模型标签和映射输入框显示平台对应颜色
...
- PricingEntryCard 折叠态模型 tag 按平台着色
- ModelTagInput 模型标签按平台着色
- 模型映射输入框边框按平台着色
2026-04-04 11:13:57 +08:00
erio
ddd495fb48
feat(ui): 渠道列表状态列改为 Toggle 开关,支持直接启用/禁用
2026-04-04 11:13:57 +08:00
erio
58f2044637
fix(ui): 渠道定价折叠态模型名完整展示,不再截断
...
去掉 max-w-[120px] truncate 限制,改用 flex-wrap 允许换行,
充分利用空白区域展示完整模型名。
2026-04-04 11:13:57 +08:00
erio
dfe3fdc1cc
fix(channel): 模型限制以原始请求模型检查定价列表,而非映射后模型
...
开启 restrict_models 时,应用原始模型名查定价列表;
定价列表未命中即拒绝,不因通配符映射而绕过限制。
2026-04-04 11:13:57 +08:00
erio
705131e172
fix(channel): 前端重复模型校验改为按平台检查
...
后端 validateNoDuplicateModels 使用 platform:model 复合键,
前端之前跨平台扁平化检查导致不同平台下的同名模型误报重复。
2026-04-04 11:13:57 +08:00
erio
88759407c7
feat(channel): 模型映射源支持通配符匹配
...
与定价通配符一致,映射源支持 * 后缀通配符(最长前缀优先):
- `*` 匹配所有模型
- `claude-*` 匹配 claude- 开头的模型
- 精确匹配优先于通配符
2026-04-04 11:13:57 +08:00
erio
6c99cc611c
fix(channel): 渠道表单校验增强 — 空模型定价报错 + 必填标记
...
- 保存时校验:定价条目有但模型列表为空时报错并跳转到对应平台 tab,
不再静默跳过导致数据丢失
- 保存时校验:启用的平台必须至少选择一个分组
- 分组关联标签增加红色 * 必填标记
2026-04-04 11:13:57 +08:00
erio
3457bcbfcd
fix(channel): 修复 invalidateCache 存入 typed nil 导致 loadCache panic
...
invalidateCache 存入 (*channelCache)(nil),类型断言 ok=true 但
指针为 nil,后续 cached.loadedAt 导致 nil pointer dereference。
在 loadCache 双重检查处增加 cached != nil 防御。
2026-04-04 11:13:56 +08:00
erio
eb385457b2
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-04-04 11:13:56 +08:00
erio
4ea8b4cb4f
refactor(channel): 抽取渠道映射公共函数 + OpenAI映射到body + 空响应修复 + 清理日志
...
- 抽取 ResolveChannelMappingAndRestrict 统一入口(5处→1个方法)
- 抽取 BuildModelMappingChain 到 ChannelMappingResult 方法(5处→1行调用)
- OpenAI 三入口 Forward 前应用渠道映射到请求体
- OpenAI Responses/Messages 限制检查添加错误响应
- 清理前端 3 处 console.log 调试日志
2026-04-04 11:13:56 +08:00
erio
91bdcf8994
fix(channel): 模型限制用映射后模型检查 + 平台开关保留配置不删除
...
- OpenAI 网关三处 IsModelRestricted 改用 channelMapping.MappedModel
- 前端平台勾选改为 enabled 开关,取消勾选不清空配置数据
- formToAPI/校验只处理 enabled 的平台
2026-04-04 11:13:56 +08:00
erio
8d03c52e15
feat(channel): 通配符定价匹配 + OpenAI BillingModelSource + 按次价格校验 + 用户端计费模式展示
...
- 定价查找支持通配符(suffix *),最长前缀优先匹配
- 模型限制(restrict_models)同样支持通配符匹配
- OpenAI 网关接入渠道映射/BillingModelSource/模型限制
- 按次/图片计费模式创建时强制要求价格或层级(前后端)
- 用户使用记录列表增加计费模式 badge 列
2026-04-04 11:13:43 +08:00
erio
0fbc9a44d3
fix(billing): 按次计费回退到默认 PerRequestPrice
...
ResolvedPricing 新增 DefaultPerRequestPrice,当无层级匹配时使用渠道的默认按次价格
2026-04-04 11:12:47 +08:00
erio
632035aabd
feat(billing): 网关计费迁移到 CalculateCostUnified + 模型限制错误统一
...
- GatewayService/OpenAIGatewayService 注入 ModelPricingResolver
- RecordUsage 从旧路径迁移到 CalculateCostUnified(支持 per_request/image 模式)
- 无渠道时自动回退旧路径,保持原有行为
- 长上下文双倍计费仅在无渠道定价时生效
- CostBreakdown 新增 BillingMode 字段,使用日志记录实际计费模式
- 模型限制错误改为与"无可用账号"相同的 503 响应
2026-04-04 11:12:21 +08:00
erio
a51e0047b7
feat(usage): 使用记录增加计费模式字段 — 记录/展示/筛选 token/按次/图片
...
- DB: usage_logs 表新增 billing_mode VARCHAR(20) 列
- 后端: RecordUsage 写入时根据 image_count 判定计费模式
- 前端: 使用记录表格新增计费模式 badge 列 + 筛选下拉
2026-04-04 11:11:06 +08:00
erio
726730bb0e
fix(channel): splice替换model_pricing条目 + 增强调试日志
2026-04-04 11:09:59 +08:00
erio
faff1771c4
debug(channel): 添加 formToAPI 调试日志 + 移除 Sora 平台
2026-04-04 11:09:58 +08:00
erio
b06cd06ec1
feat(channel): 平台配置改为勾选式,勾选后出现 Tab 但不自动跳转
2026-04-04 11:09:58 +08:00
erio
95751d8009
feat(channel): 对话框 Tab 布局 — 基础设置 + 平台独立 Tab + 固定高度
2026-04-04 11:09:58 +08:00
erio
14e565a004
fix(channel): 分组加载时序修复 — 预加载 + await 确保分组数据就绪
2026-04-04 11:09:58 +08:00
erio
ce694701a9
fix(i18n): 渠道管理页面标题国际化
2026-04-04 11:09:57 +08:00
erio
12d03e4030
feat(channel): 模型价格自动填充 + 默认定价 API
...
- 新增 GET /admin/channels/model-pricing?model=xxx API
- 从 BillingService 查询 LiteLLM/Fallback 默认定价
- 前端添加模型时自动查询并填充价格($/MTok)
- 仅在所有价格字段为空时才自动填充,不覆盖手动配置
2026-04-04 11:09:28 +08:00
erio
0b1ce6be8f
feat(channel): 缓存扁平化 + 网关映射集成 + 计费模式统一 + 模型限制
...
- 缓存按 (groupID, platform, model) 三维 key 扁平化,避免跨平台同名模型冲突
- buildCache 批量查询 group platform,按平台过滤展开定价和映射
- model_mapping 改为嵌套格式 {platform: {src: dst}}
- channel_model_pricing 新增 platform 列
- 前端按平台维度重构:每个平台独立配置分组/映射/定价
- 迁移 086: platform 列 + model_mapping 嵌套格式迁移
2026-04-04 11:09:28 +08:00
erio
28a6adaaa4
fix(channel): 分组紧凑布局+平台颜色名称+计费基准重命名+表单排序调整
2026-04-04 11:09:28 +08:00
erio
36990a0514
fix: revert ent schema change to fix runtime panic
2026-04-04 11:09:27 +08:00
erio
ebac0dc628
feat(channel): 缓存扁平化 + 网关映射集成 + 计费模式统一 + 模型限制
...
- 缓存重构为 O(1) 哈希结构 (pricingByGroupModel, mappingByGroupModel)
- 渠道模型映射接入网关流程 (Forward 前应用, a→b→c 映射链)
- 新增 billing_model_source 配置 (请求模型/最终模型计费)
- usage_logs 新增 channel_id, model_mapping_chain, billing_tier 字段
- 每种计费模式统一支持默认价格 + 区间定价
- 渠道模型限制开关 (restrict_models)
- 分组按平台分类展示 + 彩色图标
- 必填字段红色星号 + 模型映射 UI
- 去除模型通配符支持
2026-04-04 11:09:01 +08:00
erio
29d58f2414
feat(channel): 模型映射 + 分组搜索 + 卡片折叠 + 冲突校验
...
- 渠道模型映射:新增 model_mapping JSONB 字段,在账号映射之前执行
- 分组选择:添加搜索过滤 + 平台图标
- 定价卡片:支持折叠/展开,已有数据默认折叠
- 模型冲突校验:前后端均禁止同一渠道内重复模型
- 迁移 083: channels 表添加 model_mapping 列
2026-04-04 11:06:36 +08:00
erio
dca0054e93
feat(channel): 模型标签输入 + $/MTok 价格单位 + 左开右闭区间 + i18n
...
- 模型输入改为标签列表(输入回车添加,支持粘贴批量导入)
- 价格显示单位改为 $/MTok(每百万 token),提交时自动转换
- Token 模式增加图片输出价格字段(适配 Gemini 图片模型按 token 计费)
- 区间边界改为左开右闭 (min, max],右边界包含
- 默认价格作为未命中区间时的回退价格
- 添加完整中英文 i18n 翻译
2026-04-04 11:01:22 +08:00
erio
983fe58959
fix: CI lint/test fixes — gofmt, errcheck, handler test args
2026-04-04 11:01:22 +08:00
erio
91c9b8d062
feat(channel): 渠道管理系统 — 多模式定价 + 统一计费解析
...
Cherry-picked from release/custom-0.1.106: a9117600
2026-04-04 11:00:55 +08:00