From 646f37dd4b87cf5dcbe5ecf21feb6b3d83e8d01f Mon Sep 17 00:00:00 2001 From: fengsilin Date: Fri, 17 Apr 2026 09:15:48 +0800 Subject: [PATCH] =?UTF-8?q?feat(channel-pricing):=20Controller=20=E6=89=A9?= =?UTF-8?q?=E5=B1=95=20API=20=E6=94=AF=E6=8C=81=E6=96=B0=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=20+=20=E8=BE=93=E5=85=A5=E6=A0=A1=E9=AA=8C=20+=20=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 --- controller/channel_pricing.go | 119 ++++++++++++++++++++++++++-------- 1 file changed, 91 insertions(+), 28 deletions(-) diff --git a/controller/channel_pricing.go b/controller/channel_pricing.go index f904205..5e9d456 100644 --- a/controller/channel_pricing.go +++ b/controller/channel_pricing.go @@ -1,6 +1,7 @@ package controller import ( + "fmt" "strconv" "strings" @@ -50,14 +51,19 @@ func GetChannelPricingByModel(c *gin.Context) { // CreateChannelPricingRequest 创建渠道定价请求 type CreateChannelPricingRequest struct { - Id int `json:"id"` - ModelName string `json:"model_name" binding:"required"` - ChannelId int `json:"channel_id" binding:"required"` - QuotaType int `json:"quota_type"` - ModelRatio float64 `json:"model_ratio"` - CompletionRatio float64 `json:"completion_ratio"` - ModelPrice float64 `json:"model_price"` - TagIds string `json:"tag_ids"` + Id int `json:"id"` + ModelName string `json:"model_name" binding:"required"` + ChannelId int `json:"channel_id" binding:"required"` + QuotaType int `json:"quota_type"` + ModelRatio float64 `json:"model_ratio"` + CompletionRatio float64 `json:"completion_ratio"` + ModelPrice float64 `json:"model_price"` + TagIds string `json:"tag_ids"` + CacheRatio float64 `json:"cache_ratio"` + CacheCreationRatio float64 `json:"cache_creation_ratio"` + ImageRatio float64 `json:"image_ratio"` + AudioRatio float64 `json:"audio_ratio"` + AudioCompletionRatio float64 `json:"audio_completion_ratio"` } // CreateChannelPricing 创建或更新渠道定价 @@ -68,6 +74,11 @@ func CreateChannelPricing(c *gin.Context) { return } + if req.CacheRatio < 0 || req.CacheCreationRatio < 0 || req.ImageRatio < 0 || req.AudioRatio < 0 || req.AudioCompletionRatio < 0 { + common.ApiErrorMsg(c, "ratio values must be >= 0") + return + } + // 检查是否已存在 existing, _ := model.GetChannelPricing(req.ModelName, req.ChannelId) if existing != nil { @@ -77,29 +88,43 @@ func CreateChannelPricing(c *gin.Context) { existing.CompletionRatio = req.CompletionRatio existing.ModelPrice = req.ModelPrice existing.TagIds = req.TagIds + existing.CacheRatio = req.CacheRatio + existing.CacheCreationRatio = req.CacheCreationRatio + existing.ImageRatio = req.ImageRatio + existing.AudioRatio = req.AudioRatio + existing.AudioCompletionRatio = req.AudioCompletionRatio if err := existing.Update(); err != nil { common.ApiError(c, err) return } + common.SysLog(fmt.Sprintf("[ChannelPricing] updated: id=%d model=%s channel=%d", existing.Id, existing.ModelName, existing.ChannelId)) common.ApiSuccess(c, existing) return } // 创建 cp := &model.ChannelPricing{ - ModelName: req.ModelName, - ChannelId: req.ChannelId, - QuotaType: req.QuotaType, - ModelRatio: req.ModelRatio, - CompletionRatio: req.CompletionRatio, - ModelPrice: req.ModelPrice, - TagIds: req.TagIds, + ModelName: req.ModelName, + ChannelId: req.ChannelId, + QuotaType: req.QuotaType, + ModelRatio: req.ModelRatio, + CompletionRatio: req.CompletionRatio, + ModelPrice: req.ModelPrice, + TagIds: req.TagIds, + CacheRatio: req.CacheRatio, + CacheCreationRatio: req.CacheCreationRatio, + ImageRatio: req.ImageRatio, + AudioRatio: req.AudioRatio, + AudioCompletionRatio: req.AudioCompletionRatio, } if err := cp.Insert(); err != nil { common.ApiError(c, err) return } + common.SysLog(fmt.Sprintf("[ChannelPricing] created: model=%s channel=%d quotaType=%d modelRatio=%.4f completionRatio=%.4f modelPrice=%.4f cacheRatio=%.4f cacheCreationRatio=%.4f imageRatio=%.4f audioRatio=%.4f audioCompletionRatio=%.4f", + req.ModelName, req.ChannelId, req.QuotaType, req.ModelRatio, req.CompletionRatio, req.ModelPrice, + req.CacheRatio, req.CacheCreationRatio, req.ImageRatio, req.AudioRatio, req.AudioCompletionRatio)) common.ApiSuccess(c, cp) } @@ -119,13 +144,18 @@ func BatchCreateChannelPricing(c *gin.Context) { pricings := make([]*model.ChannelPricing, 0, len(req.Items)) for _, item := range req.Items { pricings = append(pricings, &model.ChannelPricing{ - ModelName: item.ModelName, - ChannelId: item.ChannelId, - QuotaType: item.QuotaType, - ModelRatio: item.ModelRatio, - CompletionRatio: item.CompletionRatio, - ModelPrice: item.ModelPrice, - TagIds: item.TagIds, + ModelName: item.ModelName, + ChannelId: item.ChannelId, + QuotaType: item.QuotaType, + ModelRatio: item.ModelRatio, + CompletionRatio: item.CompletionRatio, + ModelPrice: item.ModelPrice, + TagIds: item.TagIds, + CacheRatio: item.CacheRatio, + CacheCreationRatio: item.CacheCreationRatio, + ImageRatio: item.ImageRatio, + AudioRatio: item.AudioRatio, + AudioCompletionRatio: item.AudioCompletionRatio, }) } @@ -138,6 +168,11 @@ func BatchCreateChannelPricing(c *gin.Context) { existing.CompletionRatio = cp.CompletionRatio existing.ModelPrice = cp.ModelPrice existing.TagIds = cp.TagIds + existing.CacheRatio = cp.CacheRatio + existing.CacheCreationRatio = cp.CacheCreationRatio + existing.ImageRatio = cp.ImageRatio + existing.AudioRatio = cp.AudioRatio + existing.AudioCompletionRatio = cp.AudioCompletionRatio if err := existing.Update(); err != nil { common.ApiError(c, err) return @@ -168,6 +203,7 @@ func DeleteChannelPricing(c *gin.Context) { return } + common.SysLog(fmt.Sprintf("[ChannelPricing] deleted: id=%d", id)) common.ApiSuccess(c, nil) } @@ -204,6 +240,22 @@ func CopyGlobalPricing(c *gin.Context) { continue } + // 获取全局扩展比率 + globalCacheRatio, hasCacheRatio := ratio_setting.GetCacheRatio(ability.Model) + if !hasCacheRatio { + globalCacheRatio = 0 + } + globalCacheCreationRatio, hasCacheCreationRatio := ratio_setting.GetCreateCacheRatio(ability.Model) + if !hasCacheCreationRatio { + globalCacheCreationRatio = 0 + } + globalImageRatio, hasImageRatio := ratio_setting.GetImageRatio(ability.Model) + if !hasImageRatio { + globalImageRatio = 0 + } + globalAudioRatio := ratio_setting.GetAudioRatio(ability.Model) + globalAudioCompletionRatio := ratio_setting.GetAudioCompletionRatio(ability.Model) + // 确定定价类型 var quotaType int var ratio, completionRatio, price float64 @@ -228,17 +280,27 @@ func CopyGlobalPricing(c *gin.Context) { existing.ModelRatio = ratio existing.CompletionRatio = completionRatio existing.ModelPrice = price + existing.CacheRatio = globalCacheRatio + existing.CacheCreationRatio = globalCacheCreationRatio + existing.ImageRatio = globalImageRatio + existing.AudioRatio = globalAudioRatio + existing.AudioCompletionRatio = globalAudioCompletionRatio if err := existing.Update(); err == nil { imported++ } } else { cp := &model.ChannelPricing{ - ModelName: ability.Model, - ChannelId: channelId, - QuotaType: quotaType, - ModelRatio: ratio, - CompletionRatio: completionRatio, - ModelPrice: price, + ModelName: ability.Model, + ChannelId: channelId, + QuotaType: quotaType, + ModelRatio: ratio, + CompletionRatio: completionRatio, + ModelPrice: price, + CacheRatio: globalCacheRatio, + CacheCreationRatio: globalCacheCreationRatio, + ImageRatio: globalImageRatio, + AudioRatio: globalAudioRatio, + AudioCompletionRatio: globalAudioCompletionRatio, } if err := cp.Insert(); err == nil { imported++ @@ -246,6 +308,7 @@ func CopyGlobalPricing(c *gin.Context) { } } + common.SysLog(fmt.Sprintf("[ChannelPricing] copyGlobalPricing: channel=%d imported=%d/%d", channelId, imported, len(abilities))) common.ApiSuccess(c, gin.H{ "total": len(abilities), "imported": imported,