|
|
@@ -20,6 +20,7 @@ import (
|
|
|
"github.com/QuantumNous/new-api/dto"
|
|
|
"github.com/QuantumNous/new-api/middleware"
|
|
|
"github.com/QuantumNous/new-api/model"
|
|
|
+ "github.com/QuantumNous/new-api/pkg/billingexpr"
|
|
|
"github.com/QuantumNous/new-api/relay"
|
|
|
relaycommon "github.com/QuantumNous/new-api/relay/common"
|
|
|
relayconstant "github.com/QuantumNous/new-api/relay/constant"
|
|
|
@@ -232,6 +233,15 @@ func testChannel(channel *model.Channel, testModel string, endpointType string,
|
|
|
info.IsChannelTest = true
|
|
|
info.InitChannelMeta(c)
|
|
|
|
|
|
+ err = attachTestBillingRequestInput(info, request)
|
|
|
+ if err != nil {
|
|
|
+ return testResult{
|
|
|
+ context: c,
|
|
|
+ localErr: err,
|
|
|
+ newAPIError: types.NewError(err, types.ErrorCodeJsonMarshalFailed),
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
err = helper.ModelMappedHelper(c, info, request)
|
|
|
if err != nil {
|
|
|
return testResult{
|
|
|
@@ -468,21 +478,11 @@ func testChannel(channel *model.Channel, testModel string, endpointType string,
|
|
|
}
|
|
|
info.SetEstimatePromptTokens(usage.PromptTokens)
|
|
|
|
|
|
- quota := 0
|
|
|
- if !priceData.UsePrice {
|
|
|
- quota = usage.PromptTokens + int(math.Round(float64(usage.CompletionTokens)*priceData.CompletionRatio))
|
|
|
- quota = int(math.Round(float64(quota) * priceData.ModelRatio))
|
|
|
- if priceData.ModelRatio != 0 && quota <= 0 {
|
|
|
- quota = 1
|
|
|
- }
|
|
|
- } else {
|
|
|
- quota = int(priceData.ModelPrice * common.QuotaPerUnit)
|
|
|
- }
|
|
|
+ quota, tieredResult := settleTestQuota(info, priceData, usage)
|
|
|
tok := time.Now()
|
|
|
milliseconds := tok.Sub(tik).Milliseconds()
|
|
|
consumedTime := float64(milliseconds) / 1000.0
|
|
|
- other := service.GenerateTextOtherInfo(c, info, priceData.ModelRatio, priceData.GroupRatioInfo.GroupRatio, priceData.CompletionRatio,
|
|
|
- usage.PromptTokensDetails.CachedTokens, priceData.CacheRatio, priceData.ModelPrice, priceData.GroupRatioInfo.GroupSpecialRatio)
|
|
|
+ other := buildTestLogOther(c, info, priceData, usage, tieredResult)
|
|
|
model.RecordConsumeLog(c, 1, model.RecordConsumeLogParams{
|
|
|
ChannelId: channel.Id,
|
|
|
PromptTokens: usage.PromptTokens,
|
|
|
@@ -504,6 +504,50 @@ func testChannel(channel *model.Channel, testModel string, endpointType string,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+func attachTestBillingRequestInput(info *relaycommon.RelayInfo, request dto.Request) error {
|
|
|
+ if info == nil {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ input, err := helper.BuildBillingExprRequestInputFromRequest(request, info.RequestHeaders)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ info.BillingRequestInput = &input
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func settleTestQuota(info *relaycommon.RelayInfo, priceData types.PriceData, usage *dto.Usage) (int, *billingexpr.TieredResult) {
|
|
|
+ if usage != nil && info != nil && info.TieredBillingSnapshot != nil {
|
|
|
+ isClaudeUsageSemantic := usage.UsageSemantic == "anthropic" || info.GetFinalRequestRelayFormat() == types.RelayFormatClaude
|
|
|
+ usedVars := billingexpr.UsedVars(info.TieredBillingSnapshot.ExprString)
|
|
|
+ if ok, quota, result := service.TryTieredSettle(info, service.BuildTieredTokenParams(usage, isClaudeUsageSemantic, usedVars)); ok {
|
|
|
+ return quota, result
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ quota := 0
|
|
|
+ if !priceData.UsePrice {
|
|
|
+ quota = usage.PromptTokens + int(math.Round(float64(usage.CompletionTokens)*priceData.CompletionRatio))
|
|
|
+ quota = int(math.Round(float64(quota) * priceData.ModelRatio))
|
|
|
+ if priceData.ModelRatio != 0 && quota <= 0 {
|
|
|
+ quota = 1
|
|
|
+ }
|
|
|
+ return quota, nil
|
|
|
+ }
|
|
|
+
|
|
|
+ return int(priceData.ModelPrice * common.QuotaPerUnit), nil
|
|
|
+}
|
|
|
+
|
|
|
+func buildTestLogOther(c *gin.Context, info *relaycommon.RelayInfo, priceData types.PriceData, usage *dto.Usage, tieredResult *billingexpr.TieredResult) map[string]interface{} {
|
|
|
+ other := service.GenerateTextOtherInfo(c, info, priceData.ModelRatio, priceData.GroupRatioInfo.GroupRatio, priceData.CompletionRatio,
|
|
|
+ usage.PromptTokensDetails.CachedTokens, priceData.CacheRatio, priceData.ModelPrice, priceData.GroupRatioInfo.GroupSpecialRatio)
|
|
|
+ if tieredResult != nil {
|
|
|
+ service.InjectTieredBillingInfo(other, info, tieredResult)
|
|
|
+ }
|
|
|
+ return other
|
|
|
+}
|
|
|
+
|
|
|
func coerceTestUsage(usageAny any, isStream bool, estimatePromptTokens int) (*dto.Usage, error) {
|
|
|
switch u := usageAny.(type) {
|
|
|
case *dto.Usage:
|