瀏覽代碼

feat: expose model display pricing

master
fengsilin 1 周之前
父節點
當前提交
ced4d7f323
共有 4 個文件被更改,包括 99 次插入21 次删除
  1. +6
    -0
      controller/pricing.go
  2. +32
    -4
      controller/pricing_user_test.go
  3. +26
    -17
      model/pricing.go
  4. +35
    -0
      model/pricing_test.go

+ 6
- 0
controller/pricing.go 查看文件

@@ -138,6 +138,9 @@ func GetUserPricing(c *gin.Context) {
if pricingData.PricingConfig != nil {
result["pricing_config"] = pricingData.PricingConfig
}
if len(pricingData.DisplayPricing) > 0 {
result["display_pricing"] = pricingData.DisplayPricing
}

if pricingData.QuotaType == model.QuotaTypeByTokens {
if pricingData.PricingConfig != nil {
@@ -184,6 +187,9 @@ func respondOriginalPrice(c *gin.Context, pricingData *model.Pricing) {
}
result["original_price"] = pricingData.ModelPrice
}
if len(pricingData.DisplayPricing) > 0 {
result["display_pricing"] = pricingData.DisplayPricing
}
c.JSON(200, result)
}



+ 32
- 4
controller/pricing_user_test.go 查看文件

@@ -9,8 +9,9 @@ import (
"github.com/QuantumNous/new-api/common"
"github.com/QuantumNous/new-api/model"
"github.com/QuantumNous/new-api/setting/ratio_setting"
"github.com/glebarez/sqlite"
"github.com/QuantumNous/new-api/types"
"github.com/gin-gonic/gin"
"github.com/glebarez/sqlite"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gorm.io/gorm"
@@ -152,6 +153,36 @@ func TestGetUserPricing_NotLoggedIn_PerCall(t *testing.T) {
assert.Equal(t, float64(0.04), resp["original_price"])
}

func TestGetUserPricingIncludesDisplayPricingWithoutChangingComputedPrice(t *testing.T) {
setupPricingTestDB(t)
modelName := "display-pricing-user-model"
router := gin.New()
router.GET("/api/pricing/user/*model", GetUserPricing)

setPricingCache([]model.Pricing{
{
ModelName: modelName,
QuotaType: model.QuotaTypeByCall,
ModelPrice: 0.5,
EnableGroup: []string{"default"},
DisplayPricing: []types.ModelDisplayPricingItem{
{Specification: "768p-6s", Price: 0.33333, Unit: "second", SortOrder: 1, DiscountRate: 1},
},
},
})

w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/api/pricing/user/"+modelName, nil)
router.ServeHTTP(w, req)

var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
require.Equal(t, http.StatusOK, w.Code)
require.Contains(t, resp, "display_pricing")
require.Equal(t, float64(0.5), resp["original_price"])
require.NotEqual(t, float64(0.33333), resp["original_price"])
}

// TestGetUserPricing_LoggedIn_NoDiscount 已登录但无折扣(分组倍率=1,无个人倍率)
func TestGetUserPricing_LoggedIn_NoDiscount(t *testing.T) {
db := setupPricingTestDB(t)
@@ -226,8 +257,6 @@ func TestGetUserPricing_LoggedIn_GroupDiscount(t *testing.T) {
assert.Equal(t, "8折", resp["discount"])
}



// TestGetUserPricing_PerCall_WithDiscount 按次计费 + 折扣
func TestGetUserPricing_PerCall_WithDiscount(t *testing.T) {
db := setupPricingTestDB(t)
@@ -280,4 +309,3 @@ func TestFormatDiscount(t *testing.T) {
assert.Equal(t, tt.expected, result, "ratio=%.2f", tt.ratio)
}
}


+ 26
- 17
model/pricing.go 查看文件

@@ -14,23 +14,24 @@ import (
)

type Pricing struct {
ModelName string `json:"model_name"`
Description string `json:"description,omitempty"`
Icon string `json:"icon,omitempty"`
Tags string `json:"tags,omitempty"`
VendorID int `json:"vendor_id,omitempty"`
QuotaType int `json:"quota_type"`
ModelRatio float64 `json:"model_ratio"`
ModelPrice float64 `json:"model_price"`
OwnerBy string `json:"owner_by"`
CompletionRatio float64 `json:"completion_ratio"`
CacheRatio float64 `json:"cache_ratio"`
CacheCreationRatio float64 `json:"cache_creation_ratio"`
EnableGroup []string `json:"enable_groups"`
SupportedEndpointTypes []constant.EndpointType `json:"supported_endpoint_types"`
PricingVersion string `json:"pricing_version,omitempty"`
Type int `json:"type"`
PricingConfig *types.PricingConfig `json:"pricing_config,omitempty"`
ModelName string `json:"model_name"`
Description string `json:"description,omitempty"`
Icon string `json:"icon,omitempty"`
Tags string `json:"tags,omitempty"`
VendorID int `json:"vendor_id,omitempty"`
QuotaType int `json:"quota_type"`
ModelRatio float64 `json:"model_ratio"`
ModelPrice float64 `json:"model_price"`
OwnerBy string `json:"owner_by"`
CompletionRatio float64 `json:"completion_ratio"`
CacheRatio float64 `json:"cache_ratio"`
CacheCreationRatio float64 `json:"cache_creation_ratio"`
EnableGroup []string `json:"enable_groups"`
SupportedEndpointTypes []constant.EndpointType `json:"supported_endpoint_types"`
PricingVersion string `json:"pricing_version,omitempty"`
Type int `json:"type"`
PricingConfig *types.PricingConfig `json:"pricing_config,omitempty"`
DisplayPricing []types.ModelDisplayPricingItem `json:"display_pricing,omitempty"`
}

type PricingVendor struct {
@@ -340,6 +341,7 @@ func updatePricing() {
}

applyGlobalDefault(&pricing, model)
applyDisplayPricing(&pricing, model)
pricingMap = append(pricingMap, pricing)
}

@@ -426,6 +428,13 @@ func applyMatrixPricingConfig(pricing *Pricing, model string) bool {
return true
}

func applyDisplayPricing(pricing *Pricing, model string) {
items := ratio_setting.GetModelDisplayPricing(model)
if len(items) > 0 {
pricing.DisplayPricing = items
}
}

func minPricingConfigPrice(cfg *types.PricingConfig) float64 {
if cfg == nil || len(cfg.Table) == 0 {
return 0


+ 35
- 0
model/pricing_test.go 查看文件

@@ -189,6 +189,41 @@ func TestGetPricingByModel_IncludesMatrixPricingConfig(t *testing.T) {
require.Equal(t, []constant.EndpointType{constant.EndpointTypeDoubaoVideo}, pricing.SupportedEndpointTypes)
}

func TestGetPricingByModelIncludesDisplayPricing(t *testing.T) {
setupPricingTest(t)

const displayModel = "display-pricing-model"
require.NoError(t, ratio_setting.UpdateModelRatioByJSONString(`{"`+displayModel+`":10}`))
require.NoError(t, ratio_setting.SetModelDisplayPricing(displayModel, []types.ModelDisplayPricingItem{
{Specification: "768p-6s", Price: 0.33333, Unit: "second", SortOrder: 1},
}))

require.NoError(t, (&Model{
ModelName: displayModel,
Status: 1,
}).Insert())
require.NoError(t, (&Channel{
Id: 1,
Type: constant.ChannelTypeOpenAI,
Key: "k",
Name: "channel-a",
Status: common.ChannelStatusEnabled,
Models: displayModel,
Group: "default",
}).Insert())

RefreshPricing()
pricing := GetPricingByModel(displayModel)

require.NotNil(t, pricing)
require.Len(t, pricing.DisplayPricing, 1)
require.Equal(t, "768p-6s", pricing.DisplayPricing[0].Specification)
require.Equal(t, QuotaTypeByTokens, pricing.QuotaType)
require.Equal(t, 10.0, pricing.ModelRatio)
require.Equal(t, 0.0, pricing.ModelPrice)
require.Nil(t, pricing.PricingConfig)
}

func TestParseModelEndpointTypes_SupportsObjectAndArray(t *testing.T) {
objectEndpoints := parseModelEndpointTypes(`{
"anthropic": {"path": "/v1/messages", "method": "POST"},


Loading…
取消
儲存