feat(channel): 模型标签输入 + $/MTok 价格单位 + 左开右闭区间 + i18n
- 模型输入改为标签列表(输入回车添加,支持粘贴批量导入) - 价格显示单位改为 $/MTok(每百万 token),提交时自动转换 - Token 模式增加图片输出价格字段(适配 Gemini 图片模型按 token 计费) - 区间边界改为左开右闭 (min, max],右边界包含 - 默认价格作为未命中区间时的回退价格 - 添加完整中英文 i18n 翻译
This commit is contained in:
@@ -110,11 +110,12 @@ func (c *Channel) GetModelPricing(model string) *ChannelModelPricing {
|
||||
}
|
||||
|
||||
// FindMatchingInterval 在区间列表中查找匹配 totalTokens 的区间。
|
||||
// 通用辅助函数,供 GetIntervalForContext、ModelPricingResolver 等复用。
|
||||
// 区间为左开右闭 (min, max]:min 不含,max 包含。
|
||||
// 第一个区间 min=0 时,0 token 不匹配任何区间(回退到默认价格)。
|
||||
func FindMatchingInterval(intervals []PricingInterval, totalTokens int) *PricingInterval {
|
||||
for i := range intervals {
|
||||
iv := &intervals[i]
|
||||
if totalTokens >= iv.MinTokens && (iv.MaxTokens == nil || totalTokens < *iv.MaxTokens) {
|
||||
if totalTokens > iv.MinTokens && (iv.MaxTokens == nil || totalTokens <= *iv.MaxTokens) {
|
||||
return iv
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,10 +87,13 @@ func TestGetIntervalForContext(t *testing.T) {
|
||||
wantNil bool
|
||||
}{
|
||||
{"first interval", 50000, channelTestPtrFloat64(1e-6), false},
|
||||
{"boundary: at min of second", 128000, channelTestPtrFloat64(2e-6), false},
|
||||
{"boundary: at max of first (exclusive)", 128000, channelTestPtrFloat64(2e-6), false},
|
||||
// (min, max] — 128000 在第一个区间的 max,包含,所以匹配第一个
|
||||
{"boundary: max of first (inclusive)", 128000, channelTestPtrFloat64(1e-6), false},
|
||||
// 128001 > 128000,匹配第二个区间
|
||||
{"boundary: just above first max", 128001, channelTestPtrFloat64(2e-6), false},
|
||||
{"unbounded interval", 500000, channelTestPtrFloat64(2e-6), false},
|
||||
{"zero tokens", 0, channelTestPtrFloat64(1e-6), false},
|
||||
// (0, max] — 0 不匹配任何区间(左开)
|
||||
{"zero tokens: no match", 0, nil, true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
@@ -112,8 +115,10 @@ func TestGetIntervalForContext_NoMatch(t *testing.T) {
|
||||
{MinTokens: 10000, MaxTokens: channelTestPtrInt(50000)},
|
||||
},
|
||||
}
|
||||
require.Nil(t, p.GetIntervalForContext(5000))
|
||||
require.Nil(t, p.GetIntervalForContext(50000))
|
||||
require.Nil(t, p.GetIntervalForContext(5000)) // 5000 <= 10000, not > min
|
||||
require.Nil(t, p.GetIntervalForContext(10000)) // 10000 not > 10000 (left-open)
|
||||
require.NotNil(t, p.GetIntervalForContext(50000)) // 50000 <= 50000 (right-closed)
|
||||
require.Nil(t, p.GetIntervalForContext(50001)) // 50001 > 50000
|
||||
}
|
||||
|
||||
func TestGetIntervalForContext_Empty(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user