feat: improve model catalog aggregation

This commit is contained in:
2026-05-11 17:44:57 +08:00
parent ec87816c95
commit 0431cb8157
41 changed files with 4745 additions and 550 deletions
+58 -2
View File
@@ -3,6 +3,7 @@ package store
import (
"context"
"encoding/json"
"strconv"
"strings"
"github.com/jackc/pgx/v5"
@@ -182,7 +183,7 @@ func (s *Store) PricingRuleSetBillingConfig(ctx context.Context, id string) (map
return nil, nil
}
rows, err := s.pool.Query(ctx, `
SELECT resource_type, base_price::float8, dynamic_weight
SELECT resource_type, base_price::float8, dynamic_weight, formula_config
FROM model_pricing_rules
WHERE rule_set_id = $1::uuid
AND status = 'active'
@@ -197,15 +198,31 @@ ORDER BY priority ASC, resource_type ASC`, id)
var resourceType string
var basePrice float64
var dynamicWeightBytes []byte
if err := rows.Scan(&resourceType, &basePrice, &dynamicWeightBytes); err != nil {
var formulaConfigBytes []byte
if err := rows.Scan(&resourceType, &basePrice, &dynamicWeightBytes, &formulaConfigBytes); err != nil {
return nil, err
}
dynamicWeight := decodeObject(dynamicWeightBytes)
formulaConfig := decodeObject(formulaConfigBytes)
switch resourceType {
case "text_input":
config["textInputPer1k"] = basePrice
case "text_output":
config["textOutputPer1k"] = basePrice
case "text_total":
inputPrice := basePrice
if value, ok := pricingRuleNumberFromKeys(formulaConfig, "inputTokenPrice", "input_token_price", "textInputPer1k", "text_input"); ok {
inputPrice = value
}
config["textInputPer1k"] = inputPrice
if outputPrice, ok := pricingRuleNumberFromKeys(formulaConfig, "outputTokenPrice", "output_token_price", "textOutputPer1k", "text_output"); ok {
config["textOutputPer1k"] = outputPrice
}
resourceConfig := pricingResourceConfig(basePrice, dynamicWeight)
if len(formulaConfig) > 0 {
resourceConfig["formulaConfig"] = formulaConfig
}
config["text_total"] = resourceConfig
case "image":
config["imageBase"] = basePrice
config["image"] = pricingResourceConfig(basePrice, dynamicWeight)
@@ -225,6 +242,45 @@ ORDER BY priority ASC, resource_type ASC`, id)
return config, nil
}
func pricingRuleNumberFromKeys(config map[string]any, keys ...string) (float64, bool) {
if len(config) == 0 {
return 0, false
}
for _, key := range keys {
if value, ok := pricingRuleNumberValue(config[key]); ok {
return value, true
}
}
return 0, false
}
func pricingRuleNumberValue(value any) (float64, bool) {
switch typed := value.(type) {
case float64:
return typed, true
case float32:
return float64(typed), true
case int:
return float64(typed), true
case int64:
return float64(typed), true
case int32:
return float64(typed), true
case json.Number:
number, err := typed.Float64()
return number, err == nil
case string:
trimmed := strings.TrimSpace(typed)
if trimmed == "" {
return 0, false
}
number, err := strconv.ParseFloat(trimmed, 64)
return number, err == nil
default:
return 0, false
}
}
func pricingResourceConfig(basePrice float64, dynamicWeight map[string]any) map[string]any {
config := map[string]any{"basePrice": basePrice}
if len(dynamicWeight) > 0 {