diff --git a/relay/channel/task/doubao/adaptor.go b/relay/channel/task/doubao/adaptor.go index a6dabb5f..6c1fc17b 100644 --- a/relay/channel/task/doubao/adaptor.go +++ b/relay/channel/task/doubao/adaptor.go @@ -132,18 +132,19 @@ func (a *TaskAdaptor) BuildRequestHeader(_ *gin.Context, req *http.Request, _ *r return nil } -// EstimateBilling 检测请求 metadata 中是否包含视频输入,返回视频折扣 OtherRatio。 +// EstimateBilling 根据请求 metadata 中的输出分辨率与是否包含视频输入,返回相对基准价的计费 OtherRatio。 func (a *TaskAdaptor) EstimateBilling(c *gin.Context, info *relaycommon.RelayInfo) map[string]float64 { req, err := relaycommon.GetTaskRequest(c) if err != nil { return nil } - if hasVideoInMetadata(req.Metadata) { - if ratio, ok := GetVideoInputRatio(info.OriginModelName); ok { - return map[string]float64{"video_input": ratio} - } + hasVideo := hasVideoInMetadata(req.Metadata) + resolution, _ := req.Metadata["resolution"].(string) + ratio, ok := GetVideoInputRatio(info.OriginModelName, resolution, hasVideo) + if !ok || ratio == 1.0 { + return nil } - return nil + return map[string]float64{"video_input": ratio} } // hasVideoInMetadata 直接检查 metadata 的 content 数组是否包含 video_url 条目, diff --git a/relay/channel/task/doubao/constants.go b/relay/channel/task/doubao/constants.go index d65773d3..6cf86027 100644 --- a/relay/channel/task/doubao/constants.go +++ b/relay/channel/task/doubao/constants.go @@ -1,5 +1,7 @@ package doubao +import "strings" + var ModelList = []string{ "doubao-seedance-1-0-pro-250528", "doubao-seedance-1-0-lite-t2v", @@ -11,15 +13,40 @@ var ModelList = []string{ var ChannelName = "doubao-video" -// videoInputRatioMap 视频输入折扣比率(含视频单价 / 不含视频单价)。 -// 管理员应将 ModelRatio 设置为"不含视频"的较高费率, -// 系统在检测到视频输入时自动乘以此折扣。 -var videoInputRatioMap = map[string]float64{ - "doubao-seedance-2-0-260128": 28.0 / 46.0, // ~0.6087 - "doubao-seedance-2-0-fast-260128": 22.0 / 37.0, // ~0.5946 +// videoPriceKey 价格表的二维键:输出分辨率是否为 1080p、输入是否含视频。 +type videoPriceKey struct { + is1080p bool + hasVideo bool } -func GetVideoInputRatio(modelName string) (float64, bool) { - r, ok := videoInputRatioMap[modelName] - return r, ok +// videoPriceTable 各模型在不同 (输出分辨率档, 是否含视频输入) 下的单价(元/百万 token)。 +// 其中 {480p/720p, 不含视频}(零值键)为基准价,等于管理员应配置的 ModelRatio; +// 计费时取 实际单价/基准价 作为 OtherRatio,缺省分辨率按 480p/720p 档处理。 +var videoPriceTable = map[string]map[videoPriceKey]float64{ + "doubao-seedance-2-0-260128": { + {is1080p: false, hasVideo: false}: 46.0, + {is1080p: false, hasVideo: true}: 28.0, + {is1080p: true, hasVideo: false}: 51.0, + {is1080p: true, hasVideo: true}: 31.0, + }, + "doubao-seedance-2-0-fast-260128": { + {is1080p: false, hasVideo: false}: 37.0, + {is1080p: false, hasVideo: true}: 22.0, + }, +} + +// GetVideoInputRatio 返回指定模型在给定输出分辨率/是否含视频输入下,相对基准价的计费倍率。 +// 第二个返回值表示该模型是否配置了价格表;倍率为 1.0 时调用方可忽略该 OtherRatio。 +func GetVideoInputRatio(modelName, resolution string, hasVideo bool) (float64, bool) { + prices, ok := videoPriceTable[modelName] + base := prices[videoPriceKey{}] // 零值键 = {480p/720p, 不含视频} 基准价 + if !ok || base <= 0 { + return 0, false + } + price, ok := prices[videoPriceKey{is1080p: strings.EqualFold(resolution, "1080p"), hasVideo: hasVideo}] + if !ok { + // 未配置的组合(如 fast 无 1080p,上游会自行报错)按基准价计费即可。 + return 1.0, true + } + return price / base, true }