feat(channel): 模型标签输入 + $/MTok 价格单位 + 左开右闭区间 + i18n

- 模型输入改为标签列表(输入回车添加,支持粘贴批量导入)
- 价格显示单位改为 $/MTok(每百万 token),提交时自动转换
- Token 模式增加图片输出价格字段(适配 Gemini 图片模型按 token 计费)
- 区间边界改为左开右闭 (min, max],右边界包含
- 默认价格作为未命中区间时的回退价格
- 添加完整中英文 i18n 翻译
This commit is contained in:
erio
2026-04-04 11:01:22 +08:00
parent 983fe58959
commit dca0054e93
9 changed files with 375 additions and 224 deletions
+10 -5
View File
@@ -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) {