Commit e88b2890 authored by erio's avatar erio
Browse files

refactor: unify interval filtering and eliminate redundant Resolve calls

- applyRequestTierOverrides now uses filterValidIntervals consistently
  with applyTokenOverrides (per_request/image modes were not filtering)
- CostInput accepts optional pre-resolved pricing via Resolved field,
  eliminating duplicate Resolver.Resolve() calls in gateway billing paths
parent 1b5ae71d
...@@ -422,6 +422,7 @@ type CostInput struct { ...@@ -422,6 +422,7 @@ type CostInput struct {
RateMultiplier float64 RateMultiplier float64
ServiceTier string // "priority","flex","" 等 ServiceTier string // "priority","flex","" 等
Resolver *ModelPricingResolver // 定价解析器 Resolver *ModelPricingResolver // 定价解析器
Resolved *ResolvedPricing // 可选:预解析的定价结果(避免重复 Resolve 调用)
} }
// CalculateCostUnified 统一计费入口,支持三种计费模式。 // CalculateCostUnified 统一计费入口,支持三种计费模式。
...@@ -432,10 +433,14 @@ func (s *BillingService) CalculateCostUnified(input CostInput) (*CostBreakdown, ...@@ -432,10 +433,14 @@ func (s *BillingService) CalculateCostUnified(input CostInput) (*CostBreakdown,
return s.calculateCostInternal(input.Model, input.Tokens, input.RateMultiplier, input.ServiceTier, nil) return s.calculateCostInternal(input.Model, input.Tokens, input.RateMultiplier, input.ServiceTier, nil)
} }
resolved := input.Resolver.Resolve(input.Ctx, PricingInput{ // 优先使用预解析结果,避免重复 Resolve 调用
resolved := input.Resolved
if resolved == nil {
resolved = input.Resolver.Resolve(input.Ctx, PricingInput{
Model: input.Model, Model: input.Model,
GroupID: input.GroupID, GroupID: input.GroupID,
}) })
}
if input.RateMultiplier <= 0 { if input.RateMultiplier <= 0 {
input.RateMultiplier = 1.0 input.RateMultiplier = 1.0
......
...@@ -8007,7 +8007,7 @@ func (s *GatewayService) calculateImageCost( ...@@ -8007,7 +8007,7 @@ func (s *GatewayService) calculateImageCost(
billingModel string, billingModel string,
multiplier float64, multiplier float64,
) *CostBreakdown { ) *CostBreakdown {
if s.resolveChannelPricing(ctx, billingModel, apiKey) != nil { if resolved := s.resolveChannelPricing(ctx, billingModel, apiKey); resolved != nil {
tokens := UsageTokens{ tokens := UsageTokens{
InputTokens: result.Usage.InputTokens, InputTokens: result.Usage.InputTokens,
OutputTokens: result.Usage.OutputTokens, OutputTokens: result.Usage.OutputTokens,
...@@ -8022,6 +8022,7 @@ func (s *GatewayService) calculateImageCost( ...@@ -8022,6 +8022,7 @@ func (s *GatewayService) calculateImageCost(
RequestCount: 1, RequestCount: 1,
RateMultiplier: multiplier, RateMultiplier: multiplier,
Resolver: s.resolver, Resolver: s.resolver,
Resolved: resolved,
}) })
if err != nil { if err != nil {
logger.LegacyPrintf("service.gateway", "Calculate image token cost failed: %v", err) logger.LegacyPrintf("service.gateway", "Calculate image token cost failed: %v", err)
...@@ -8064,7 +8065,7 @@ func (s *GatewayService) calculateTokenCost( ...@@ -8064,7 +8065,7 @@ func (s *GatewayService) calculateTokenCost(
var err error var err error
// 优先尝试渠道定价 → CalculateCostUnified // 优先尝试渠道定价 → CalculateCostUnified
if s.resolveChannelPricing(ctx, billingModel, apiKey) != nil { if resolved := s.resolveChannelPricing(ctx, billingModel, apiKey); resolved != nil {
gid := apiKey.Group.ID gid := apiKey.Group.ID
cost, err = s.billingService.CalculateCostUnified(CostInput{ cost, err = s.billingService.CalculateCostUnified(CostInput{
Ctx: ctx, Ctx: ctx,
...@@ -8074,6 +8075,7 @@ func (s *GatewayService) calculateTokenCost( ...@@ -8074,6 +8075,7 @@ func (s *GatewayService) calculateTokenCost(
RequestCount: 1, RequestCount: 1,
RateMultiplier: multiplier, RateMultiplier: multiplier,
Resolver: s.resolver, Resolver: s.resolver,
Resolved: resolved,
}) })
} else if opts.LongContextThreshold > 0 { } else if opts.LongContextThreshold > 0 {
// 长上下文双倍计费(如 Gemini 200K 阈值) // 长上下文双倍计费(如 Gemini 200K 阈值)
......
...@@ -151,7 +151,7 @@ func (r *ModelPricingResolver) applyTokenOverrides(chPricing *ChannelModelPricin ...@@ -151,7 +151,7 @@ func (r *ModelPricingResolver) applyTokenOverrides(chPricing *ChannelModelPricin
// applyRequestTierOverrides 应用按次/图片模式的渠道覆盖 // applyRequestTierOverrides 应用按次/图片模式的渠道覆盖
func (r *ModelPricingResolver) applyRequestTierOverrides(chPricing *ChannelModelPricing, resolved *ResolvedPricing) { func (r *ModelPricingResolver) applyRequestTierOverrides(chPricing *ChannelModelPricing, resolved *ResolvedPricing) {
resolved.RequestTiers = chPricing.Intervals resolved.RequestTiers = filterValidIntervals(chPricing.Intervals)
if chPricing.PerRequestPrice != nil { if chPricing.PerRequestPrice != nil {
resolved.DefaultPerRequestPrice = *chPricing.PerRequestPrice resolved.DefaultPerRequestPrice = *chPricing.PerRequestPrice
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment