feat(*): 模型计费与渠道目录 - 支持视频 Token 报价结算和稳定模型展示

This commit is contained in:
ddCat
2026-09-18 23:26:54 +08:00
parent 90add8c466
commit 1a79005d25
57 changed files with 2904 additions and 341 deletions

View File

@@ -0,0 +1,41 @@
package kernel
import (
"errors"
"math/big"
)
var (
ErrInvalidTokenBilling = errors.New("invalid token billing parameters")
ErrTokenBillingOverflow = errors.New("token billing amount overflows int64")
)
type TokenBillingTerm struct {
Tokens int64
PriceMicrocredits int64
}
// TokenBillingAmount 按每百万 Token 单价及万分比倍率汇总费用,只对最终微积分金额上取整。
func TokenBillingAmount(multiplierBPS int64, terms ...TokenBillingTerm) (int64, error) {
if multiplierBPS <= 0 {
return 0, ErrInvalidTokenBilling
}
var total, product big.Int
for _, term := range terms {
if term.Tokens < 0 || term.PriceMicrocredits < 0 {
return 0, ErrInvalidTokenBilling
}
product.Mul(big.NewInt(term.Tokens), big.NewInt(term.PriceMicrocredits))
total.Add(&total, &product)
}
total.Mul(&total, big.NewInt(multiplierBPS))
var remainder big.Int
total.QuoRem(&total, big.NewInt(10_000_000_000), &remainder)
if remainder.Sign() != 0 {
total.Add(&total, big.NewInt(1))
}
if !total.IsInt64() {
return 0, ErrTokenBillingOverflow
}
return total.Int64(), nil
}

View File

@@ -0,0 +1,90 @@
package kernel
import (
"errors"
"math"
"testing"
)
func TestTokenBillingAmount(t *testing.T) {
for _, test := range []struct {
name string
multiplier int64
terms []TokenBillingTerm
want int64
}{
{
name: "maximum configured price", multiplier: 10_000,
terms: []TokenBillingTerm{{Tokens: 10_000_000, PriceMicrocredits: 1_000_000_000_000}},
want: 10_000_000_000_000,
},
{
name: "maximum configured price with multiplier", multiplier: 12_500,
terms: []TokenBillingTerm{{Tokens: 10_000_000, PriceMicrocredits: 1_000_000_000_000}},
want: 12_500_000_000_000,
},
{
name: "round once after combining terms", multiplier: 10_000,
terms: []TokenBillingTerm{{Tokens: 1, PriceMicrocredits: 400_000}, {Tokens: 1, PriceMicrocredits: 400_000}, {Tokens: 1, PriceMicrocredits: 100_000}},
want: 1,
},
{
name: "apply multiplier before rounding", multiplier: 12_500,
terms: []TokenBillingTerm{{Tokens: 1, PriceMicrocredits: 400_000}, {Tokens: 1, PriceMicrocredits: 400_000}},
want: 1,
},
{
name: "fractional microcredit rounds up", multiplier: 1,
terms: []TokenBillingTerm{{Tokens: 1, PriceMicrocredits: 1}},
want: 1,
},
{
name: "maximum int64 result after overflowing intermediate sum", multiplier: 10_000,
terms: []TokenBillingTerm{{Tokens: math.MaxInt64, PriceMicrocredits: 500_000}, {Tokens: math.MaxInt64, PriceMicrocredits: 500_000}},
want: math.MaxInt64,
},
{
name: "free usage", multiplier: math.MaxInt64,
terms: []TokenBillingTerm{{Tokens: math.MaxInt64, PriceMicrocredits: 0}},
want: 0,
},
} {
t.Run(test.name, func(t *testing.T) {
amount, err := TokenBillingAmount(test.multiplier, test.terms...)
if err != nil || amount != test.want {
t.Fatalf("TokenBillingAmount() = %d, %v; want %d", amount, err, test.want)
}
})
}
}
func TestTokenBillingAmountRejectsInvalidParametersAndFinalOverflow(t *testing.T) {
for _, test := range []struct {
name string
multiplier int64
terms []TokenBillingTerm
wantErr error
}{
{name: "zero multiplier", terms: []TokenBillingTerm{{Tokens: 1, PriceMicrocredits: 1}}, wantErr: ErrInvalidTokenBilling},
{name: "negative multiplier", multiplier: -1, wantErr: ErrInvalidTokenBilling},
{name: "negative tokens", multiplier: 10_000, terms: []TokenBillingTerm{{Tokens: -1}}, wantErr: ErrInvalidTokenBilling},
{name: "negative price even with zero tokens", multiplier: 10_000, terms: []TokenBillingTerm{{PriceMicrocredits: -1}}, wantErr: ErrInvalidTokenBilling},
{
name: "final amount overflow", multiplier: 10_001,
terms: []TokenBillingTerm{{Tokens: math.MaxInt64, PriceMicrocredits: 1_000_000}},
wantErr: ErrTokenBillingOverflow,
},
{
name: "rounding causes final overflow", multiplier: 10_000,
terms: []TokenBillingTerm{{Tokens: math.MaxInt64, PriceMicrocredits: 1_000_000}, {Tokens: 1, PriceMicrocredits: 1}},
wantErr: ErrTokenBillingOverflow,
},
} {
t.Run(test.name, func(t *testing.T) {
amount, err := TokenBillingAmount(test.multiplier, test.terms...)
if amount != 0 || !errors.Is(err, test.wantErr) {
t.Fatalf("TokenBillingAmount() = %d, %v; want 0, %v", amount, err, test.wantErr)
}
})
}
}