From 5e351bc02a8032c1da7a1496792f9a1a1bceb883 Mon Sep 17 00:00:00 2001 From: "Laisky.Cai" Date: Sun, 26 Jan 2025 08:02:55 +0000 Subject: [PATCH] fix: whisper model billing - Refactor model name handling across multiple controllers to improve clarity and maintainability. - Enhance error logging and handling for better debugging and request processing robustness. - Update pricing models in accordance with new calculations, ensuring accuracy in the billing logic. --- relay/adaptor/proxy/adaptor.go | 1 - relay/billing/ratio/model.go | 7 ++++--- relay/controller/helper.go | 11 ----------- relay/controller/image.go | 5 +++-- relay/controller/text.go | 8 ++++---- relay/meta/relay_meta.go | 17 +++++++++++++++++ 6 files changed, 28 insertions(+), 21 deletions(-) diff --git a/relay/adaptor/proxy/adaptor.go b/relay/adaptor/proxy/adaptor.go index 32984fc7..7f6b29be 100644 --- a/relay/adaptor/proxy/adaptor.go +++ b/relay/adaptor/proxy/adaptor.go @@ -60,7 +60,6 @@ func (a *Adaptor) GetChannelName() string { func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) { prefix := fmt.Sprintf("/v1/oneapi/proxy/%d", meta.ChannelId) return meta.BaseURL + strings.TrimPrefix(meta.RequestURLPath, prefix), nil - } func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Request, meta *meta.Meta) error { diff --git a/relay/billing/ratio/model.go b/relay/billing/ratio/model.go index c9394162..470bd336 100644 --- a/relay/billing/ratio/model.go +++ b/relay/billing/ratio/model.go @@ -71,7 +71,7 @@ var ModelRatio = map[string]float64{ "text-davinci-003": 10, "text-davinci-edit-001": 10, "code-davinci-edit-001": 10, - "whisper-1": 15, // $0.006 / minute -> $0.006 / 150 words -> $0.006 / 200 tokens -> $0.03 / 1k tokens + "whisper-1": 15, "tts-1": 7.5, // $0.015 / 1K characters "tts-1-1106": 7.5, "tts-1-hd": 15, // $0.030 / 1K characters @@ -385,8 +385,9 @@ func GetAudioCompletionRatio(actualModelName string) float64 { // AudioTokensPerSecond is the number of audio tokens per second for each model. var AudioPromptTokensPerSecond = map[string]float64{ - // $0.006 / minute -> $0.002 / 20 seconds -> $0.002 / 1K tokens - "whisper-1": 1000 / 20, + // whisper 的 API 价格是 $0.0001/sec。one-api 的历史倍率为 15,对应 $0.03/kilo_tokens。 + // 那么换算后可得,每秒的 tokens 应该为 0.0001/0.03*1000 = 3.3333 + "whisper-1": 0.0001 / 0.03 * 1000, // gpt-4o-audio series processes 10 tokens per second "gpt-4o-audio-preview": 10, "gpt-4o-audio-preview-2024-12-17": 10, diff --git a/relay/controller/helper.go b/relay/controller/helper.go index f9d4fd48..746453af 100644 --- a/relay/controller/helper.go +++ b/relay/controller/helper.go @@ -135,17 +135,6 @@ func postConsumeQuota(ctx context.Context, usage *relaymodel.Usage, meta *meta.M return quota } -func getMappedModelName(modelName string, mapping map[string]string) (string, bool) { - if mapping == nil { - return modelName, false - } - mappedModelName := mapping[modelName] - if mappedModelName != "" { - return mappedModelName, true - } - return modelName, false -} - func isErrorHappened(meta *meta.Meta, resp *http.Response) bool { if resp == nil { if meta.ChannelType == channeltype.AwsClaude { diff --git a/relay/controller/image.go b/relay/controller/image.go index a3ae3b76..4987f30d 100644 --- a/relay/controller/image.go +++ b/relay/controller/image.go @@ -116,7 +116,8 @@ func RelayImageHelper(c *gin.Context, relayMode int) *relaymodel.ErrorWithStatus // map model name var isModelMapped bool meta.OriginModelName = imageRequest.Model - imageRequest.Model, isModelMapped = getMappedModelName(imageRequest.Model, meta.ModelMapping) + imageRequest.Model = meta.ActualModelName + isModelMapped = meta.OriginModelName != meta.ActualModelName meta.ActualModelName = imageRequest.Model metalib.Set2Context(c, meta) @@ -133,7 +134,7 @@ func RelayImageHelper(c *gin.Context, relayMode int) *relaymodel.ErrorWithStatus imageModel := imageRequest.Model // Convert the original image model - imageRequest.Model, _ = getMappedModelName(imageRequest.Model, billingratio.ImageOriginModelName) + imageRequest.Model = metalib.GetMappedModelName(imageRequest.Model, billingratio.ImageOriginModelName) c.Set("response_format", imageRequest.ResponseFormat) var requestBody io.Reader diff --git a/relay/controller/text.go b/relay/controller/text.go index d7532eff..1ced44b5 100644 --- a/relay/controller/text.go +++ b/relay/controller/text.go @@ -21,13 +21,13 @@ import ( "github.com/songquanpeng/one-api/relay/billing" billingratio "github.com/songquanpeng/one-api/relay/billing/ratio" "github.com/songquanpeng/one-api/relay/channeltype" - "github.com/songquanpeng/one-api/relay/meta" + metalib "github.com/songquanpeng/one-api/relay/meta" relaymodel "github.com/songquanpeng/one-api/relay/model" ) func RelayTextHelper(c *gin.Context) *relaymodel.ErrorWithStatusCode { ctx := c.Request.Context() - meta := meta.GetByContext(c) + meta := metalib.GetByContext(c) // get & validate textRequest textRequest, err := getAndValidateTextRequest(c, meta.Mode) if err != nil { @@ -38,7 +38,7 @@ func RelayTextHelper(c *gin.Context) *relaymodel.ErrorWithStatusCode { // map model name meta.OriginModelName = textRequest.Model - textRequest.Model, _ = getMappedModelName(textRequest.Model, meta.ModelMapping) + textRequest.Model = meta.ActualModelName meta.ActualModelName = textRequest.Model // set system prompt if not empty systemPromptReset := setSystemPrompt(ctx, textRequest, meta.SystemPrompt) @@ -117,7 +117,7 @@ func RelayTextHelper(c *gin.Context) *relaymodel.ErrorWithStatusCode { return nil } -func getRequestBody(c *gin.Context, meta *meta.Meta, textRequest *relaymodel.GeneralOpenAIRequest, adaptor adaptor.Adaptor) (io.Reader, error) { +func getRequestBody(c *gin.Context, meta *metalib.Meta, textRequest *relaymodel.GeneralOpenAIRequest, adaptor adaptor.Adaptor) (io.Reader, error) { if !config.EnforceIncludeUsage && meta.APIType == apitype.OpenAI && meta.OriginModelName == meta.ActualModelName && diff --git a/relay/meta/relay_meta.go b/relay/meta/relay_meta.go index b4bcf687..9ec5ce9a 100644 --- a/relay/meta/relay_meta.go +++ b/relay/meta/relay_meta.go @@ -35,6 +35,20 @@ type Meta struct { SystemPrompt string } +// GetMappedModelName returns the mapped model name and a bool indicating if the model name is mapped +func GetMappedModelName(modelName string, mapping map[string]string) string { + if mapping == nil { + return modelName + } + + mappedModelName := mapping[modelName] + if mappedModelName != "" { + return mappedModelName + } + + return modelName +} + func GetByContext(c *gin.Context) *Meta { if v, ok := c.Get(ctxkey.Meta); ok { return v.(*Meta) @@ -50,6 +64,7 @@ func GetByContext(c *gin.Context) *Meta { Group: c.GetString(ctxkey.Group), ModelMapping: c.GetStringMapString(ctxkey.ModelMapping), OriginModelName: c.GetString(ctxkey.RequestModel), + ActualModelName: c.GetString(ctxkey.RequestModel), BaseURL: c.GetString(ctxkey.BaseURL), APIKey: strings.TrimPrefix(c.Request.Header.Get("Authorization"), "Bearer "), RequestURLPath: c.Request.URL.String(), @@ -65,6 +80,8 @@ func GetByContext(c *gin.Context) *Meta { } meta.APIType = channeltype.ToAPIType(meta.ChannelType) + meta.ActualModelName = GetMappedModelName(meta.OriginModelName, meta.ModelMapping) + Set2Context(c, &meta) return &meta }