From bc9cb8c41a3090cbcd9849cc80ac5a1775ef980c Mon Sep 17 00:00:00 2001 From: zijiren233 Date: Thu, 28 May 2026 00:42:33 +0800 Subject: [PATCH] feat: add ali qwen models --- core/model/usage.go | 19 +- core/model/usage_test.go | 29 + core/relay/adaptor/ali/chat.go | 158 ++ core/relay/adaptor/ali/constants.go | 2039 ++++++++++++++++- core/relay/adaptor/ali/constants_test.go | 143 ++ web/public/locales/en/translation.json | 5 + web/public/locales/zh/translation.json | 5 + web/src/components/price/PriceDisplay.tsx | 4 + web/src/components/price/PriceFormFields.tsx | 19 + .../log/components/ExpandedLogContent.tsx | 1 + .../model/components/BuiltinModelsDialog.tsx | 75 +- .../feature/model/components/ModelTable.tsx | 22 +- web/src/types/log.ts | 1 + web/src/types/model.ts | 1 + web/src/validation/model.ts | 1 + 15 files changed, 2463 insertions(+), 59 deletions(-) diff --git a/core/model/usage.go b/core/model/usage.go index 36b6db90..040b0ec7 100644 --- a/core/model/usage.go +++ b/core/model/usage.go @@ -21,6 +21,7 @@ type PriceCondition struct { Resolution []string `json:"resolution,omitempty"` Quality []string `json:"quality,omitempty"` ServiceTier string `json:"service_tier,omitempty"` + InputMedia *bool `json:"input_media,omitempty"` InputVideo *bool `json:"input_video,omitempty"` OutputAudio *bool `json:"output_audio,omitempty"` } @@ -157,6 +158,10 @@ func priceConditionSpecificity(condition PriceCondition) int { specificity++ } + if condition.InputMedia != nil { + specificity++ + } + if condition.OutputAudio != nil { specificity++ } @@ -398,7 +403,8 @@ func (p *Price) ValidateConditionalPrices() error { continue } - if !boolConditionOverlap(condition.InputVideo, otherCondition.InputVideo) || + if !boolConditionOverlap(condition.InputMedia, otherCondition.InputMedia) || + !boolConditionOverlap(condition.InputVideo, otherCondition.InputVideo) || !boolConditionOverlap(condition.OutputAudio, otherCondition.OutputAudio) { continue } @@ -696,6 +702,7 @@ type UsageContext struct { NativeResolution string `gorm:"size:32" json:"native_resolution,omitempty"` Quality string `gorm:"size:32" json:"quality,omitempty"` ServiceTier string `gorm:"size:32" json:"service_tier,omitempty"` + InputMedia *bool ` json:"input_media,omitempty"` InputVideo *bool ` json:"input_video,omitempty"` OutputAudio *bool ` json:"output_audio,omitempty"` } @@ -733,6 +740,12 @@ func (c UsageContext) priceConditionMatches( return false } + if condition.InputMedia != nil { + if c.InputMedia == nil || *c.InputMedia != *condition.InputMedia { + return false + } + } + if condition.InputVideo != nil { if c.InputVideo == nil || *c.InputVideo != *condition.InputVideo { return false @@ -765,6 +778,10 @@ func (c UsageContext) WithFallback(fallback UsageContext) UsageContext { c.Quality = fallback.Quality } + if c.InputMedia == nil { + c.InputMedia = fallback.InputMedia + } + if c.InputVideo == nil { c.InputVideo = fallback.InputVideo } diff --git a/core/model/usage_test.go b/core/model/usage_test.go index 7ee460c2..fea6f32b 100644 --- a/core/model/usage_test.go +++ b/core/model/usage_test.go @@ -1146,6 +1146,12 @@ func TestPrice_SelectConditionalPrice_WithMediaFlags(t *testing.T) { price := model.Price{ OutputPrice: 0.20, ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{ + InputMedia: new(false), + }, + Price: model.Price{OutputPrice: 0.012}, + }, { Condition: model.PriceCondition{ Resolution: []string{"720p"}, @@ -1190,6 +1196,13 @@ func TestPrice_SelectConditionalPrice_WithMediaFlags(t *testing.T) { t.Fatalf("expected text-only price 0.046, got %v", textOnlyPrice.OutputPrice) } + pureTextPrice := price.SelectConditionalPrice(model.Usage{}, model.UsageContext{ + InputMedia: new(false), + }) + if float64(pureTextPrice.OutputPrice) != 0.012 { + t.Fatalf("expected pure text price 0.012, got %v", pureTextPrice.OutputPrice) + } + unknownInputVideoPrice := price.SelectConditionalPrice(model.Usage{}, model.UsageContext{ Resolution: "720p", }) @@ -1615,6 +1628,22 @@ func TestPrice_ValidateConditionalPrices_WithMediaConditions(t *testing.T) { }, wantErr: false, }, + { + name: "same ranges with different input media flags are allowed", + price: model.Price{ + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{InputMedia: new(false)}, + Price: model.Price{OutputPrice: 0.08}, + }, + { + Condition: model.PriceCondition{InputMedia: new(true)}, + Price: model.Price{OutputPrice: 0.04}, + }, + }, + }, + wantErr: false, + }, { name: "same ranges with different output audio flags are allowed", price: model.Price{ diff --git a/core/relay/adaptor/ali/chat.go b/core/relay/adaptor/ali/chat.go index 8c43a2bf..a28d2c47 100644 --- a/core/relay/adaptor/ali/chat.go +++ b/core/relay/adaptor/ali/chat.go @@ -9,6 +9,7 @@ import ( "github.com/bytedance/sonic/ast" "github.com/gin-gonic/gin" "github.com/labring/aiproxy/core/common" + coremodel "github.com/labring/aiproxy/core/model" "github.com/labring/aiproxy/core/relay/adaptor" "github.com/labring/aiproxy/core/relay/adaptor/openai" "github.com/labring/aiproxy/core/relay/meta" @@ -189,5 +190,162 @@ func ChatHandler( result.Usage.WebSearchCount++ } + result.UsageContext = aliChatUsageContextWithDefaults( + aliChatUsageContext(result.Usage). + WithFallback(aliChatRequestUsageContext(&node)). + WithFallback(result.UsageContext), + ) + return result, nil } + +func aliChatUsageContext(usage coremodel.Usage) coremodel.UsageContext { + usageContext := coremodel.UsageContext{} + + if usage.ImageInputTokens > 0 || usage.AudioInputTokens > 0 || usage.VideoInputTokens > 0 { + usageContext.InputMedia = new(bool) + *usageContext.InputMedia = true + } + + if usage.VideoInputTokens > 0 { + usageContext.InputVideo = new(bool) + *usageContext.InputVideo = true + } + + if usage.AudioOutputTokens > 0 { + usageContext.OutputAudio = new(bool) + *usageContext.OutputAudio = true + } + + return usageContext +} + +func aliChatRequestUsageContext(node *ast.Node) coremodel.UsageContext { + usageContext := coremodel.UsageContext{} + + if aliChatRequestHasInputMedia(node) { + usageContext.InputMedia = new(bool) + *usageContext.InputMedia = true + } + + if aliChatRequestHasInputVideo(node) { + usageContext.InputVideo = new(bool) + *usageContext.InputVideo = true + } + + if aliChatRequestWantsOutputAudio(node) { + usageContext.OutputAudio = new(bool) + *usageContext.OutputAudio = true + } + + return usageContext +} + +func aliChatUsageContextWithDefaults(usageContext coremodel.UsageContext) coremodel.UsageContext { + if usageContext.InputMedia == nil { + usageContext.InputMedia = new(bool) + } + + if usageContext.OutputAudio == nil { + usageContext.OutputAudio = new(bool) + } + + return usageContext +} + +func aliChatRequestHasInputMedia(node *ast.Node) bool { + return aliChatRequestContentMatches(node, func(content *ast.Node) bool { + return aliChatContentHasField(content, "image_url") || + aliChatContentHasField(content, "input_audio") || + aliChatContentHasField(content, "audio") || + aliChatContentHasField(content, "video") || + aliChatContentHasField(content, "video_url") || + aliChatContentTypeContains(content, "image") || + aliChatContentTypeContains(content, "audio") || + aliChatContentTypeContains(content, "video") + }) +} + +func aliChatRequestHasInputVideo(node *ast.Node) bool { + return aliChatRequestContentMatches(node, func(content *ast.Node) bool { + return aliChatContentHasField(content, "video") || + aliChatContentHasField(content, "video_url") || + aliChatContentTypeContains(content, "video") + }) +} + +func aliChatRequestWantsOutputAudio(node *ast.Node) bool { + modalities := node.Get("modalities") + if modalities.Exists() && modalities.TypeSafe() == ast.V_ARRAY { + hasAudio := false + _ = modalities.ForEach(func(_ ast.Sequence, item *ast.Node) bool { + value, err := item.String() + if err == nil && strings.EqualFold(value, "audio") { + hasAudio = true + return false + } + + return true + }) + + if hasAudio { + return true + } + } + + return node.Get("audio").Exists() +} + +func aliChatRequestContentMatches(node *ast.Node, match func(*ast.Node) bool) bool { + messages := node.Get("messages") + if !messages.Exists() || messages.TypeSafe() != ast.V_ARRAY { + return false + } + + matched := false + _ = messages.ForEach(func(_ ast.Sequence, message *ast.Node) bool { + content := message.Get("content") + if !content.Exists() { + return true + } + + if content.TypeSafe() == ast.V_ARRAY { + _ = content.ForEach(func(_ ast.Sequence, item *ast.Node) bool { + if match(item) { + matched = true + return false + } + + return true + }) + + return !matched + } + + if match(content) { + matched = true + return false + } + + return true + }) + + return matched +} + +func aliChatContentHasField(content *ast.Node, field string) bool { + return content.TypeSafe() == ast.V_OBJECT && content.Get(field).Exists() +} + +func aliChatContentTypeContains(content *ast.Node, pattern string) bool { + if content.TypeSafe() != ast.V_OBJECT { + return false + } + + contentType, err := content.Get("type").String() + if err != nil { + return false + } + + return strings.Contains(strings.ToLower(contentType), pattern) +} diff --git a/core/relay/adaptor/ali/constants.go b/core/relay/adaptor/ali/constants.go index 1998d7ae..5f232bfa 100644 --- a/core/relay/adaptor/ali/constants.go +++ b/core/relay/adaptor/ali/constants.go @@ -9,111 +9,1769 @@ import ( // https://help.aliyun.com/zh/model-studio/model-pricing var ModelList = []model.ModelConfig{ + { + Model: "qwen3.7-max", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.012, + OutputPrice: 0.036, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3.7-max-2026-05-20", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.012, + OutputPrice: 0.036, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3.7-max-preview", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.012, + OutputPrice: 0.036, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3.7-2026-05-17", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.012, + OutputPrice: 0.036, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3.6-max-preview", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.015, + OutputPrice: 0.09, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{InputTokenMax: 128000}, + Price: model.Price{ + InputPrice: 0.009, + OutputPrice: 0.054, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 128001, InputTokenMax: 256000}, + Price: model.Price{ + InputPrice: 0.015, + OutputPrice: 0.09, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-max", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.007, + OutputPrice: 0.028, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{InputTokenMax: 32000}, + Price: model.Price{ + InputPrice: 0.0025, + OutputPrice: 0.01, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 32001, InputTokenMax: 128000}, + Price: model.Price{ + InputPrice: 0.004, + OutputPrice: 0.016, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 128001, InputTokenMax: 256000}, + Price: model.Price{ + InputPrice: 0.007, + OutputPrice: 0.028, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-max-2026-01-23", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.007, + OutputPrice: 0.028, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{InputTokenMax: 32000}, + Price: model.Price{ + InputPrice: 0.0025, + OutputPrice: 0.01, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 32001, InputTokenMax: 128000}, + Price: model.Price{ + InputPrice: 0.004, + OutputPrice: 0.016, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 128001, InputTokenMax: 256000}, + Price: model.Price{ + InputPrice: 0.007, + OutputPrice: 0.028, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-max-2025-09-23", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.015, + OutputPrice: 0.06, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{InputTokenMax: 32000}, + Price: model.Price{ + InputPrice: 0.006, + OutputPrice: 0.024, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 32001, InputTokenMax: 128000}, + Price: model.Price{ + InputPrice: 0.01, + OutputPrice: 0.04, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 128001, InputTokenMax: 256000}, + Price: model.Price{ + InputPrice: 0.015, + OutputPrice: 0.06, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-max-preview", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.015, + OutputPrice: 0.06, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{InputTokenMax: 32000}, + Price: model.Price{ + InputPrice: 0.006, + OutputPrice: 0.024, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 32001, InputTokenMax: 128000}, + Price: model.Price{ + InputPrice: 0.01, + OutputPrice: 0.04, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 128001, InputTokenMax: 256000}, + Price: model.Price{ + InputPrice: 0.015, + OutputPrice: 0.06, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, // 通义千问-Max { - Model: "qwen-max", + Model: "qwen-max", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0024, + OutputPrice: 0.0096, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(32768), + model.WithModelConfigMaxInputTokens(30720), + model.WithModelConfigMaxOutputTokens(8192), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen-max-latest", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0024, + OutputPrice: 0.0096, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(32768), + model.WithModelConfigMaxInputTokens(30720), + model.WithModelConfigMaxOutputTokens(8192), + model.WithModelConfigToolChoice(true), + ), + }, + + // 通义千问-Plus + { + Model: "qwen3.6-plus", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.008, + OutputPrice: 0.048, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{InputTokenMax: 256000}, + Price: model.Price{ + InputPrice: 0.002, + OutputPrice: 0.012, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 256001, InputTokenMax: 1000000}, + Price: model.Price{ + InputPrice: 0.008, + OutputPrice: 0.048, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3.6-plus-2026-04-02", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.008, + OutputPrice: 0.048, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{InputTokenMax: 256000}, + Price: model.Price{ + InputPrice: 0.002, + OutputPrice: 0.012, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 256001, InputTokenMax: 1000000}, + Price: model.Price{ + InputPrice: 0.008, + OutputPrice: 0.048, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3.5-plus", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.004, + OutputPrice: 0.024, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{InputTokenMax: 128000}, + Price: model.Price{ + InputPrice: 0.0008, + OutputPrice: 0.0048, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 128001, InputTokenMax: 256000}, + Price: model.Price{ + InputPrice: 0.002, + OutputPrice: 0.012, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 256001, InputTokenMax: 1000000}, + Price: model.Price{ + InputPrice: 0.004, + OutputPrice: 0.024, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3.5-plus-2026-04-20", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.004, + OutputPrice: 0.024, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{InputTokenMax: 128000}, + Price: model.Price{ + InputPrice: 0.0008, + OutputPrice: 0.0048, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 128001, InputTokenMax: 256000}, + Price: model.Price{ + InputPrice: 0.002, + OutputPrice: 0.012, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 256001, InputTokenMax: 1000000}, + Price: model.Price{ + InputPrice: 0.004, + OutputPrice: 0.024, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3.5-plus-2026-02-15", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.004, + OutputPrice: 0.024, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{InputTokenMax: 128000}, + Price: model.Price{ + InputPrice: 0.0008, + OutputPrice: 0.0048, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 128001, InputTokenMax: 256000}, + Price: model.Price{ + InputPrice: 0.002, + OutputPrice: 0.012, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 256001, InputTokenMax: 1000000}, + Price: model.Price{ + InputPrice: 0.004, + OutputPrice: 0.024, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen-plus", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0048, + OutputPrice: 0.048, + ThinkingModeOutputPrice: 0.064, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{InputTokenMax: 128000}, + Price: model.Price{ + InputPrice: 0.0008, + OutputPrice: 0.002, + ThinkingModeOutputPrice: 0.008, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 128001, InputTokenMax: 256000}, + Price: model.Price{ + InputPrice: 0.0024, + OutputPrice: 0.02, + ThinkingModeOutputPrice: 0.024, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 256001, InputTokenMax: 1000000}, + Price: model.Price{ + InputPrice: 0.0048, + OutputPrice: 0.048, + ThinkingModeOutputPrice: 0.064, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(131072), + model.WithModelConfigMaxInputTokens(129024), + model.WithModelConfigMaxOutputTokens(8192), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen-plus-latest", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0048, + OutputPrice: 0.048, + ThinkingModeOutputPrice: 0.064, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{InputTokenMax: 128000}, + Price: model.Price{ + InputPrice: 0.0008, + OutputPrice: 0.002, + ThinkingModeOutputPrice: 0.008, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 128001, InputTokenMax: 256000}, + Price: model.Price{ + InputPrice: 0.0024, + OutputPrice: 0.02, + ThinkingModeOutputPrice: 0.024, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 256001, InputTokenMax: 1000000}, + Price: model.Price{ + InputPrice: 0.0048, + OutputPrice: 0.048, + ThinkingModeOutputPrice: 0.064, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(32000), + model.WithModelConfigMaxInputTokens(30000), + model.WithModelConfigMaxOutputTokens(8000), + model.WithModelConfigToolChoice(true), + ), + }, + + // 通义千问-Turbo + { + Model: "qwen3.6-flash", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0048, + OutputPrice: 0.0288, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{InputTokenMax: 256000}, + Price: model.Price{ + InputPrice: 0.0012, + OutputPrice: 0.0072, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 256001, InputTokenMax: 1000000}, + Price: model.Price{ + InputPrice: 0.0048, + OutputPrice: 0.0288, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3.6-flash-2026-04-16", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0048, + OutputPrice: 0.0288, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{InputTokenMax: 256000}, + Price: model.Price{ + InputPrice: 0.0012, + OutputPrice: 0.0072, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 256001, InputTokenMax: 1000000}, + Price: model.Price{ + InputPrice: 0.0048, + OutputPrice: 0.0288, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3.5-flash", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0012, + OutputPrice: 0.012, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{InputTokenMax: 128000}, + Price: model.Price{ + InputPrice: 0.0002, + OutputPrice: 0.002, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 128001, InputTokenMax: 256000}, + Price: model.Price{ + InputPrice: 0.0008, + OutputPrice: 0.008, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 256001, InputTokenMax: 1000000}, + Price: model.Price{ + InputPrice: 0.0012, + OutputPrice: 0.012, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3.5-flash-2026-02-23", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0012, + OutputPrice: 0.012, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{InputTokenMax: 128000}, + Price: model.Price{ + InputPrice: 0.0002, + OutputPrice: 0.002, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 128001, InputTokenMax: 256000}, + Price: model.Price{ + InputPrice: 0.0008, + OutputPrice: 0.008, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 256001, InputTokenMax: 1000000}, + Price: model.Price{ + InputPrice: 0.0012, + OutputPrice: 0.012, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen-flash", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0012, + OutputPrice: 0.012, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{InputTokenMax: 128000}, + Price: model.Price{ + InputPrice: 0.00015, + OutputPrice: 0.0015, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 128001, InputTokenMax: 256000}, + Price: model.Price{ + InputPrice: 0.0006, + OutputPrice: 0.006, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 256001, InputTokenMax: 1000000}, + Price: model.Price{ + InputPrice: 0.0012, + OutputPrice: 0.012, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen-flash-2025-07-28", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0012, + OutputPrice: 0.012, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{InputTokenMax: 128000}, + Price: model.Price{ + InputPrice: 0.00015, + OutputPrice: 0.0015, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 128001, InputTokenMax: 256000}, + Price: model.Price{ + InputPrice: 0.0006, + OutputPrice: 0.006, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 256001, InputTokenMax: 1000000}, + Price: model.Price{ + InputPrice: 0.0012, + OutputPrice: 0.012, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen-turbo", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0003, + OutputPrice: 0.0006, + ThinkingModeOutputPrice: 0.003, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(131072), + model.WithModelConfigMaxInputTokens(129024), + model.WithModelConfigMaxOutputTokens(8192), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen-turbo-latest", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0003, + OutputPrice: 0.0006, + ThinkingModeOutputPrice: 0.003, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(8192), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen-turbo-2025-07-15", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0003, + OutputPrice: 0.0006, + ThinkingModeOutputPrice: 0.003, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(8192), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen-turbo-2025-04-28", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0003, + OutputPrice: 0.0006, + ThinkingModeOutputPrice: 0.003, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(8192), + model.WithModelConfigToolChoice(true), + ), + }, + + // Qwen-Long + { + Model: "qwen-long", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0005, + OutputPrice: 0.002, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(6000), + model.WithModelConfigToolChoice(true), + ), + }, + + // 通义千问Omni + { + Model: "qwen3.5-omni-plus", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.007, + ImageInputPrice: 0.007, + AudioInputPrice: 0.053, + VideoInputPrice: 0.007, + OutputPrice: 0.04, + AudioOutputPrice: 0.213, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{OutputAudio: new(true)}, + Price: model.Price{ + InputPrice: 0.007, + ImageInputPrice: 0.007, + AudioInputPrice: 0.053, + VideoInputPrice: 0.007, + OutputPrice: 0, + AudioOutputPrice: 0.213, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3.5-omni-plus-2026-03-15", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.007, + ImageInputPrice: 0.007, + AudioInputPrice: 0.053, + VideoInputPrice: 0.007, + OutputPrice: 0.04, + AudioOutputPrice: 0.213, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{OutputAudio: new(true)}, + Price: model.Price{ + InputPrice: 0.007, + ImageInputPrice: 0.007, + AudioInputPrice: 0.053, + VideoInputPrice: 0.007, + OutputPrice: 0, + AudioOutputPrice: 0.213, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3.5-omni-flash", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0022, + ImageInputPrice: 0.0022, + AudioInputPrice: 0.018, + VideoInputPrice: 0.0022, + OutputPrice: 0.0133, + AudioOutputPrice: 0.072, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{OutputAudio: new(true)}, + Price: model.Price{ + InputPrice: 0.0022, + ImageInputPrice: 0.0022, + AudioInputPrice: 0.018, + VideoInputPrice: 0.0022, + OutputPrice: 0, + AudioOutputPrice: 0.072, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3.5-omni-flash-2026-03-15", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0022, + ImageInputPrice: 0.0022, + AudioInputPrice: 0.018, + VideoInputPrice: 0.0022, + OutputPrice: 0.0133, + AudioOutputPrice: 0.072, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{OutputAudio: new(true)}, + Price: model.Price{ + InputPrice: 0.0022, + ImageInputPrice: 0.0022, + AudioInputPrice: 0.018, + VideoInputPrice: 0.0022, + OutputPrice: 0, + AudioOutputPrice: 0.072, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-omni-flash", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0018, + ImageInputPrice: 0.0033, + AudioInputPrice: 0.0158, + VideoInputPrice: 0.0033, + OutputPrice: 0.0127, + AudioOutputPrice: 0.0626, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{ + InputMedia: new(false), + OutputAudio: new(false), + }, + Price: model.Price{ + InputPrice: 0.0018, + ImageInputPrice: 0.0033, + AudioInputPrice: 0.0158, + VideoInputPrice: 0.0033, + OutputPrice: 0.0069, + AudioOutputPrice: 0.0626, + }, + }, + { + Condition: model.PriceCondition{OutputAudio: new(true)}, + Price: model.Price{ + InputPrice: 0.0018, + ImageInputPrice: 0.0033, + AudioInputPrice: 0.0158, + VideoInputPrice: 0.0033, + OutputPrice: 0, + AudioOutputPrice: 0.0626, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-omni-flash-2025-12-01", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0018, + ImageInputPrice: 0.0033, + AudioInputPrice: 0.0158, + VideoInputPrice: 0.0033, + OutputPrice: 0.0127, + AudioOutputPrice: 0.0626, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{ + InputMedia: new(false), + OutputAudio: new(false), + }, + Price: model.Price{ + InputPrice: 0.0018, + ImageInputPrice: 0.0033, + AudioInputPrice: 0.0158, + VideoInputPrice: 0.0033, + OutputPrice: 0.0069, + AudioOutputPrice: 0.0626, + }, + }, + { + Condition: model.PriceCondition{OutputAudio: new(true)}, + Price: model.Price{ + InputPrice: 0.0018, + ImageInputPrice: 0.0033, + AudioInputPrice: 0.0158, + VideoInputPrice: 0.0033, + OutputPrice: 0, + AudioOutputPrice: 0.0626, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-omni-flash-2025-09-15", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0018, + ImageInputPrice: 0.0033, + AudioInputPrice: 0.0158, + VideoInputPrice: 0.0033, + OutputPrice: 0.0127, + AudioOutputPrice: 0.0626, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{ + InputMedia: new(false), + OutputAudio: new(false), + }, + Price: model.Price{ + InputPrice: 0.0018, + ImageInputPrice: 0.0033, + AudioInputPrice: 0.0158, + VideoInputPrice: 0.0033, + OutputPrice: 0.0069, + AudioOutputPrice: 0.0626, + }, + }, + { + Condition: model.PriceCondition{OutputAudio: new(true)}, + Price: model.Price{ + InputPrice: 0.0018, + ImageInputPrice: 0.0033, + AudioInputPrice: 0.0158, + VideoInputPrice: 0.0033, + OutputPrice: 0, + AudioOutputPrice: 0.0626, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen-omni-turbo", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0004, + ImageInputPrice: 0.0015, + AudioInputPrice: 0.025, + VideoInputPrice: 0.0015, + OutputPrice: 0.0045, + AudioOutputPrice: 0.05, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{ + InputMedia: new(false), + OutputAudio: new(false), + }, + Price: model.Price{ + InputPrice: 0.0004, + ImageInputPrice: 0.0015, + AudioInputPrice: 0.025, + VideoInputPrice: 0.0015, + OutputPrice: 0.0016, + AudioOutputPrice: 0.05, + }, + }, + { + Condition: model.PriceCondition{OutputAudio: new(true)}, + Price: model.Price{ + InputPrice: 0.0004, + ImageInputPrice: 0.0015, + AudioInputPrice: 0.025, + VideoInputPrice: 0.0015, + OutputPrice: 0, + AudioOutputPrice: 0.05, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen-omni-turbo-latest", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0004, + ImageInputPrice: 0.0015, + AudioInputPrice: 0.025, + VideoInputPrice: 0.0015, + OutputPrice: 0.0045, + AudioOutputPrice: 0.05, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{ + InputMedia: new(false), + OutputAudio: new(false), + }, + Price: model.Price{ + InputPrice: 0.0004, + ImageInputPrice: 0.0015, + AudioInputPrice: 0.025, + VideoInputPrice: 0.0015, + OutputPrice: 0.0016, + AudioOutputPrice: 0.05, + }, + }, + { + Condition: model.PriceCondition{OutputAudio: new(true)}, + Price: model.Price{ + InputPrice: 0.0004, + ImageInputPrice: 0.0015, + AudioInputPrice: 0.025, + VideoInputPrice: 0.0015, + OutputPrice: 0, + AudioOutputPrice: 0.05, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen-omni-turbo-2025-03-26", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0004, + ImageInputPrice: 0.0015, + AudioInputPrice: 0.025, + VideoInputPrice: 0.0015, + OutputPrice: 0.0045, + AudioOutputPrice: 0.05, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{ + InputMedia: new(false), + OutputAudio: new(false), + }, + Price: model.Price{ + InputPrice: 0.0004, + ImageInputPrice: 0.0015, + AudioInputPrice: 0.025, + VideoInputPrice: 0.0015, + OutputPrice: 0.0016, + AudioOutputPrice: 0.05, + }, + }, + { + Condition: model.PriceCondition{OutputAudio: new(true)}, + Price: model.Price{ + InputPrice: 0.0004, + ImageInputPrice: 0.0015, + AudioInputPrice: 0.025, + VideoInputPrice: 0.0015, + OutputPrice: 0, + AudioOutputPrice: 0.05, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen-omni-turbo-2025-01-19", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0004, + ImageInputPrice: 0.0015, + AudioInputPrice: 0.025, + VideoInputPrice: 0.0015, + OutputPrice: 0.0045, + AudioOutputPrice: 0.05, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{ + InputMedia: new(false), + OutputAudio: new(false), + }, + Price: model.Price{ + InputPrice: 0.0004, + ImageInputPrice: 0.0015, + AudioInputPrice: 0.025, + VideoInputPrice: 0.0015, + OutputPrice: 0.0016, + AudioOutputPrice: 0.05, + }, + }, + { + Condition: model.PriceCondition{OutputAudio: new(true)}, + Price: model.Price{ + InputPrice: 0.0004, + ImageInputPrice: 0.0015, + AudioInputPrice: 0.025, + VideoInputPrice: 0.0015, + OutputPrice: 0, + AudioOutputPrice: 0.05, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen2.5-omni-7b", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0006, + ImageInputPrice: 0.002, + AudioInputPrice: 0.038, + VideoInputPrice: 0.002, + OutputPrice: 0.006, + AudioOutputPrice: 0.076, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{ + InputMedia: new(false), + OutputAudio: new(false), + }, + Price: model.Price{ + InputPrice: 0.0006, + ImageInputPrice: 0.002, + AudioInputPrice: 0.038, + VideoInputPrice: 0.002, + OutputPrice: 0.0024, + AudioOutputPrice: 0.076, + }, + }, + { + Condition: model.PriceCondition{OutputAudio: new(true)}, + Price: model.Price{ + InputPrice: 0.0006, + ImageInputPrice: 0.002, + AudioInputPrice: 0.038, + VideoInputPrice: 0.002, + OutputPrice: 0, + AudioOutputPrice: 0.076, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-omni-30b-a3b-captioner", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0158, + OutputPrice: 0.0127, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), + model.WithModelConfigToolChoice(true), + ), + }, + + // 通义千问VL + { + Model: "qwen3-vl-plus", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.003, + OutputPrice: 0.03, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{InputTokenMax: 32000}, + Price: model.Price{ + InputPrice: 0.001, + OutputPrice: 0.01, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 32001, InputTokenMax: 128000}, + Price: model.Price{ + InputPrice: 0.0015, + OutputPrice: 0.015, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 128001, InputTokenMax: 256000}, + Price: model.Price{ + InputPrice: 0.003, + OutputPrice: 0.03, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-vl-plus-2025-12-19", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.003, + OutputPrice: 0.03, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{InputTokenMax: 32000}, + Price: model.Price{ + InputPrice: 0.001, + OutputPrice: 0.01, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 32001, InputTokenMax: 128000}, + Price: model.Price{ + InputPrice: 0.0015, + OutputPrice: 0.015, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 128001, InputTokenMax: 256000}, + Price: model.Price{ + InputPrice: 0.003, + OutputPrice: 0.03, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-vl-plus-2025-09-23", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.003, + OutputPrice: 0.03, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{InputTokenMax: 32000}, + Price: model.Price{ + InputPrice: 0.001, + OutputPrice: 0.01, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 32001, InputTokenMax: 128000}, + Price: model.Price{ + InputPrice: 0.0015, + OutputPrice: 0.015, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 128001, InputTokenMax: 256000}, + Price: model.Price{ + InputPrice: 0.003, + OutputPrice: 0.03, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-vl-flash", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0006, + OutputPrice: 0.006, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{InputTokenMax: 32000}, + Price: model.Price{ + InputPrice: 0.00015, + OutputPrice: 0.0015, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 32001, InputTokenMax: 128000}, + Price: model.Price{ + InputPrice: 0.0003, + OutputPrice: 0.003, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 128001, InputTokenMax: 256000}, + Price: model.Price{ + InputPrice: 0.0006, + OutputPrice: 0.006, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-vl-flash-2026-01-22", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0006, + OutputPrice: 0.006, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{InputTokenMax: 32000}, + Price: model.Price{ + InputPrice: 0.00015, + OutputPrice: 0.0015, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 32001, InputTokenMax: 128000}, + Price: model.Price{ + InputPrice: 0.0003, + OutputPrice: 0.003, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 128001, InputTokenMax: 256000}, + Price: model.Price{ + InputPrice: 0.0006, + OutputPrice: 0.006, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-vl-flash-2025-10-15", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0006, + OutputPrice: 0.006, + ConditionalPrices: []model.ConditionalPrice{ + { + Condition: model.PriceCondition{InputTokenMax: 32000}, + Price: model.Price{ + InputPrice: 0.00015, + OutputPrice: 0.0015, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 32001, InputTokenMax: 128000}, + Price: model.Price{ + InputPrice: 0.0003, + OutputPrice: 0.003, + }, + }, + { + Condition: model.PriceCondition{InputTokenMin: 128001, InputTokenMax: 256000}, + Price: model.Price{ + InputPrice: 0.0006, + OutputPrice: 0.006, + }, + }, + }, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-vl-235b-a22b-thinking", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.002, + OutputPrice: 0.02, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-vl-235b-a22b-instruct", Type: mode.ChatCompletions, Owner: model.ModelOwnerAlibaba, Price: model.Price{ - InputPrice: 0.02, - OutputPrice: 0.06, + InputPrice: 0.002, + OutputPrice: 0.008, }, RPM: 1200, Config: model.NewModelConfig( - model.WithModelConfigMaxContextTokens(32768), - model.WithModelConfigMaxInputTokens(30720), - model.WithModelConfigMaxOutputTokens(8192), + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), model.WithModelConfigToolChoice(true), ), }, { - Model: "qwen-max-latest", + Model: "qwen3-vl-32b-thinking", Type: mode.ChatCompletions, Owner: model.ModelOwnerAlibaba, Price: model.Price{ - InputPrice: 0.02, - OutputPrice: 0.06, + InputPrice: 0.002, + OutputPrice: 0.02, }, RPM: 1200, Config: model.NewModelConfig( - model.WithModelConfigMaxContextTokens(32768), - model.WithModelConfigMaxInputTokens(30720), - model.WithModelConfigMaxOutputTokens(8192), + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), model.WithModelConfigToolChoice(true), ), }, - - // 通义千问-Plus { - Model: "qwen-plus", + Model: "qwen3-vl-32b-instruct", Type: mode.ChatCompletions, Owner: model.ModelOwnerAlibaba, Price: model.Price{ - InputPrice: 0.0008, - OutputPrice: 0.002, + InputPrice: 0.002, + OutputPrice: 0.008, }, RPM: 1200, Config: model.NewModelConfig( - model.WithModelConfigMaxContextTokens(131072), - model.WithModelConfigMaxInputTokens(129024), - model.WithModelConfigMaxOutputTokens(8192), + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), model.WithModelConfigToolChoice(true), ), }, { - Model: "qwen-plus-latest", + Model: "qwen3-vl-30b-a3b-thinking", Type: mode.ChatCompletions, Owner: model.ModelOwnerAlibaba, Price: model.Price{ - InputPrice: 0.0008, - OutputPrice: 0.002, + InputPrice: 0.00075, + OutputPrice: 0.0075, }, RPM: 1200, Config: model.NewModelConfig( - model.WithModelConfigMaxContextTokens(32000), - model.WithModelConfigMaxInputTokens(30000), - model.WithModelConfigMaxOutputTokens(8000), + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), model.WithModelConfigToolChoice(true), ), }, - - // 通义千问-Turbo { - Model: "qwen-turbo", + Model: "qwen3-vl-30b-a3b-instruct", Type: mode.ChatCompletions, Owner: model.ModelOwnerAlibaba, Price: model.Price{ - InputPrice: 0.0003, - OutputPrice: 0.0006, + InputPrice: 0.00075, + OutputPrice: 0.003, }, RPM: 1200, Config: model.NewModelConfig( - model.WithModelConfigMaxContextTokens(131072), - model.WithModelConfigMaxInputTokens(129024), - model.WithModelConfigMaxOutputTokens(8192), + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), model.WithModelConfigToolChoice(true), ), }, { - Model: "qwen-turbo-latest", + Model: "qwen3-vl-8b-thinking", Type: mode.ChatCompletions, Owner: model.ModelOwnerAlibaba, Price: model.Price{ - InputPrice: 0.0003, - OutputPrice: 0.0006, + InputPrice: 0.0005, + OutputPrice: 0.005, }, RPM: 1200, Config: model.NewModelConfig( - model.WithModelConfigMaxContextTokens(1000000), - model.WithModelConfigMaxInputTokens(1000000), - model.WithModelConfigMaxOutputTokens(8192), + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), model.WithModelConfigToolChoice(true), ), }, - - // Qwen-Long { - Model: "qwen-long", + Model: "qwen3-vl-8b-instruct", Type: mode.ChatCompletions, Owner: model.ModelOwnerAlibaba, Price: model.Price{ @@ -121,15 +1779,246 @@ var ModelList = []model.ModelConfig{ OutputPrice: 0.002, }, RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigVision(true), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-next-80b-a3b-thinking", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.001, + OutputPrice: 0.01, + }, + RPM: 1200, Config: model.NewModelConfig( model.WithModelConfigMaxContextTokens(1000000), model.WithModelConfigMaxInputTokens(1000000), - model.WithModelConfigMaxOutputTokens(6000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-next-80b-a3b-instruct", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.001, + OutputPrice: 0.004, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(1000000), + model.WithModelConfigMaxInputTokens(1000000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-235b-a22b-thinking-2507", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.002, + OutputPrice: 0.02, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-235b-a22b-instruct-2507", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.002, + OutputPrice: 0.008, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-30b-a3b-thinking-2507", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.00075, + OutputPrice: 0.0075, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-30b-a3b-instruct-2507", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.00075, + OutputPrice: 0.003, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-235b-a22b", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.002, + OutputPrice: 0.008, + ThinkingModeOutputPrice: 0.02, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-32b", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.002, + OutputPrice: 0.008, + ThinkingModeOutputPrice: 0.02, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-30b-a3b", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.00075, + OutputPrice: 0.003, + ThinkingModeOutputPrice: 0.0075, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-14b", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.001, + OutputPrice: 0.004, + ThinkingModeOutputPrice: 0.01, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-8b", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0005, + OutputPrice: 0.002, + ThinkingModeOutputPrice: 0.005, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-4b", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0003, + OutputPrice: 0.0012, + ThinkingModeOutputPrice: 0.003, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-1.7b", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0003, + OutputPrice: 0.0012, + ThinkingModeOutputPrice: 0.003, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), + model.WithModelConfigToolChoice(true), + ), + }, + { + Model: "qwen3-0.6b", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0003, + OutputPrice: 0.0012, + ThinkingModeOutputPrice: 0.003, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(256000), + model.WithModelConfigMaxInputTokens(256000), + model.WithModelConfigMaxOutputTokens(65536), model.WithModelConfigToolChoice(true), ), }, - - // 通义千问VL { Model: "qwen-vl-max", Type: mode.ChatCompletions, @@ -449,6 +2338,23 @@ var ModelList = []model.ModelConfig{ model.WithModelConfigToolChoice(true), ), }, + { + Model: "qwen2.5-vl-32b-instruct", + Type: mode.ChatCompletions, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.008, + OutputPrice: 0.024, + }, + RPM: 1200, + Config: model.NewModelConfig( + model.WithModelConfigMaxContextTokens(131072), + model.WithModelConfigMaxInputTokens(129024), + model.WithModelConfigMaxOutputTokens(8192), + model.WithModelConfigVision(true), + model.WithModelConfigToolChoice(true), + ), + }, { Model: "qwen2.5-vl-7b-instruct", Type: mode.ChatCompletions, @@ -1514,7 +3420,10 @@ var ModelList = []model.ModelConfig{ Model: "gte-rerank-v2", Type: mode.Rerank, Owner: model.ModelOwnerAlibaba, - RPM: 300, + Price: model.Price{ + InputPrice: 0.0008, + }, + RPM: 300, Config: model.NewModelConfig( model.WithModelConfigMaxContextTokens(8000), model.WithModelConfigMaxInputTokens(8000), @@ -1524,7 +3433,12 @@ var ModelList = []model.ModelConfig{ Model: "qwen3-vl-rerank", Type: mode.Rerank, Owner: model.ModelOwnerAlibaba, - RPM: 300, + Price: model.Price{ + InputPrice: 0.0005, + ImageInputPrice: 0.0005, + VideoInputPrice: 0.0005, + }, + RPM: 300, Config: model.NewModelConfig( model.WithModelConfigMaxContextTokens(32000), model.WithModelConfigMaxInputTokens(32000), @@ -1560,11 +3474,38 @@ var ModelList = []model.ModelConfig{ Type: mode.Embeddings, Owner: model.ModelOwnerAlibaba, Price: model.Price{ - InputPrice: 0.0007, + InputPrice: 0.0005, + }, + RPM: 1800, + Config: model.NewModelConfig( + model.WithModelConfigMaxInputTokens(8192), + ), + }, + { + Model: "text-embedding-v4", + Type: mode.Embeddings, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0005, + }, + RPM: 1800, + Config: model.NewModelConfig( + model.WithModelConfigMaxInputTokens(8192), + ), + }, + { + Model: "qwen3-vl-embedding", + Type: mode.Embeddings, + Owner: model.ModelOwnerAlibaba, + Price: model.Price{ + InputPrice: 0.0007, + ImageInputPrice: 0.0018, + VideoInputPrice: 0.0018, }, RPM: 1800, Config: model.NewModelConfig( model.WithModelConfigMaxInputTokens(8192), + model.WithModelConfigVision(true), ), }, } diff --git a/core/relay/adaptor/ali/constants_test.go b/core/relay/adaptor/ali/constants_test.go index 4826ba7c..a9c1d361 100644 --- a/core/relay/adaptor/ali/constants_test.go +++ b/core/relay/adaptor/ali/constants_test.go @@ -4,6 +4,7 @@ package ali import ( "testing" + "github.com/bytedance/sonic" "github.com/labring/aiproxy/core/common/consume" "github.com/labring/aiproxy/core/model" ) @@ -22,6 +23,20 @@ func aliModelPriceForTest(t *testing.T, modelName string) model.Price { return model.Price{} } +func TestAliModelListPricesAreValid(t *testing.T) { + t.Parallel() + + for _, mc := range ModelList { + t.Run(mc.Model, func(t *testing.T) { + t.Parallel() + + if err := mc.Price.ValidateConditionalPrices(); err != nil { + t.Fatalf("invalid conditional prices: %v", err) + } + }) + } +} + func TestAliImagePriceUsesSuccessfulImageCount(t *testing.T) { t.Parallel() @@ -99,3 +114,131 @@ func TestAliVideoEditPriceUsesInputAndOutputSeconds(t *testing.T) { t.Fatalf("expected 11.2 video edit amount, got %#v", amount) } } + +func TestAliQwenOmniAudioOutputOnlyChargesAudioOutput(t *testing.T) { + t.Parallel() + + usage := model.Usage{ + InputTokens: 1000, + AudioInputTokens: 250, + OutputTokens: 1000, + AudioOutputTokens: 800, + TotalTokens: 2000, + } + + amount := consume.CalculateAmountDetail( + 200, + usage, + aliChatUsageContext(usage), + aliModelPriceForTest(t, "qwen3-omni-flash"), + ) + + if amount.OutputAmount != 0 { + t.Fatalf("expected no text output amount for audio output, got %#v", amount) + } + + if amount.AudioOutputAmount != 0.05008 { + t.Fatalf("expected audio output amount 0.05008, got %#v", amount) + } +} + +func TestAliQwenOmniTextOutputUsesInputMediaContext(t *testing.T) { + t.Parallel() + + textUsage := model.Usage{ + InputTokens: 1000, + OutputTokens: 1000, + TotalTokens: 2000, + } + textAmount := consume.CalculateAmountDetail( + 200, + textUsage, + aliChatUsageContextWithDefaults(aliChatUsageContext(textUsage)), + aliModelPriceForTest(t, "qwen-omni-turbo"), + ) + + if textAmount.OutputAmount != 0.0016 { + t.Fatalf("expected pure text output amount 0.0016, got %#v", textAmount) + } + + imageUsage := model.Usage{ + InputTokens: 1000, + ImageInputTokens: 300, + OutputTokens: 1000, + TotalTokens: 2000, + } + imageAmount := consume.CalculateAmountDetail( + 200, + imageUsage, + aliChatUsageContext(imageUsage), + aliModelPriceForTest(t, "qwen-omni-turbo"), + ) + + if imageAmount.OutputAmount != 0.0045 { + t.Fatalf("expected multimodal output amount 0.0045, got %#v", imageAmount) + } +} + +func TestAliChatRequestUsageContextDetectsMediaAndAudioOutput(t *testing.T) { + t.Parallel() + + imageContext := aliChatRequestUsageContextForTest(t, `{ + "messages": [ + { + "role": "user", + "content": [ + {"type": "image_url", "image_url": {"url": "https://example.com/a.png"}}, + {"type": "text", "text": "describe"} + ] + } + ] + }`) + + if imageContext.InputMedia == nil || !*imageContext.InputMedia { + t.Fatalf("expected image request to set input media, got %#v", imageContext) + } + + if imageContext.InputVideo != nil && *imageContext.InputVideo { + t.Fatalf("expected image request not to set input video, got %#v", imageContext) + } + + videoContext := aliChatRequestUsageContextForTest(t, `{ + "messages": [ + { + "role": "user", + "content": [ + {"type": "video_url", "video_url": {"url": "https://example.com/a.mp4"}} + ] + } + ] + }`) + + if videoContext.InputMedia == nil || !*videoContext.InputMedia { + t.Fatalf("expected video request to set input media, got %#v", videoContext) + } + + if videoContext.InputVideo == nil || !*videoContext.InputVideo { + t.Fatalf("expected video request to set input video, got %#v", videoContext) + } + + audioOutputContext := aliChatRequestUsageContextForTest(t, `{ + "messages": [{"role": "user", "content": "say hello"}], + "modalities": ["text", "audio"], + "audio": {"voice": "Cherry", "format": "wav"} + }`) + + if audioOutputContext.OutputAudio == nil || !*audioOutputContext.OutputAudio { + t.Fatalf("expected audio output request to set output audio, got %#v", audioOutputContext) + } +} + +func aliChatRequestUsageContextForTest(t *testing.T, body string) model.UsageContext { + t.Helper() + + node, err := sonic.GetFromString(body) + if err != nil { + t.Fatalf("parse request body: %v", err) + } + + return aliChatRequestUsageContext(&node) +} diff --git a/web/public/locales/en/translation.json b/web/public/locales/en/translation.json index afe6494e..2cf41887 100644 --- a/web/public/locales/en/translation.json +++ b/web/public/locales/en/translation.json @@ -395,6 +395,9 @@ "selectVisible": "Select visible models", "noAvailableModels": "No builtin models available to import", "createFromSelected": "Import From This Model", + "editFromThis": "Edit From This", + "createFromThis": "Add From This", + "add": "Add", "importSelected": "Import {{count}} Models", "importing": "Importing...", "importSuccess": "{{count}} builtin models imported successfully", @@ -745,6 +748,7 @@ "resolution": "Resolution", "nativeResolution": "Native Resolution", "quality": "Quality", + "inputMedia": "Input Has Media", "inputVideo": "Input Has Video", "outputAudio": "Output Has Audio", "metadata": "Metadata", @@ -1206,6 +1210,7 @@ "multiValueHint": "Enter one value per line. Commas are also supported.", "serviceTier": "Service Tier", "serviceTierAny": "Any", + "inputMedia": "Input Has Media", "inputVideo": "Input Has Video", "outputAudio": "Output Has Audio", "booleanAny": "Any", diff --git a/web/public/locales/zh/translation.json b/web/public/locales/zh/translation.json index 1a29d5a8..93156dbc 100644 --- a/web/public/locales/zh/translation.json +++ b/web/public/locales/zh/translation.json @@ -384,6 +384,9 @@ "selectVisible": "选择当前筛选结果", "noAvailableModels": "没有可导入的内置模型", "createFromSelected": "从此模型导入", + "editFromThis": "由此编辑", + "createFromThis": "由此添加", + "add": "添加", "importSelected": "导入 {{count}} 个模型", "importing": "导入中...", "importSuccess": "成功导入 {{count}} 个内置模型", @@ -733,6 +736,7 @@ "resolution": "分辨率", "nativeResolution": "模型原生分辨率", "quality": "质量", + "inputMedia": "输入是否含媒体", "inputVideo": "输入是否含视频", "outputAudio": "输出是否有声音", "metadata": "元数据", @@ -1194,6 +1198,7 @@ "multiValueHint": "每行输入一个值,也支持用逗号分隔。", "serviceTier": "服务层级", "serviceTierAny": "任意", + "inputMedia": "输入是否含媒体", "inputVideo": "输入是否含视频", "outputAudio": "输出是否有声音", "booleanAny": "任意", diff --git a/web/src/components/price/PriceDisplay.tsx b/web/src/components/price/PriceDisplay.tsx index b94f0938..eb2d7a62 100644 --- a/web/src/components/price/PriceDisplay.tsx +++ b/web/src/components/price/PriceDisplay.tsx @@ -71,6 +71,10 @@ export function PriceDisplay({ price }: PriceDisplayProps) { parts.push(`${t('group.price.serviceTier')}: ${SERVICE_TIER_LABELS[condition.service_tier]}`) } + if (condition.input_media !== undefined) { + parts.push(`${t('group.price.inputMedia')}: ${condition.input_media ? t('common.yes') : t('common.no')}`) + } + if (condition.input_video !== undefined) { parts.push(`${t('group.price.inputVideo')}: ${condition.input_video ? t('common.yes') : t('common.no')}`) } diff --git a/web/src/components/price/PriceFormFields.tsx b/web/src/components/price/PriceFormFields.tsx index e2f09f86..45da3df1 100644 --- a/web/src/components/price/PriceFormFields.tsx +++ b/web/src/components/price/PriceFormFields.tsx @@ -152,6 +152,25 @@ function ConditionFields({ condition, onChange }: { +
+ + +