Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
new-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
fc1259f5
authored
Jul 07, 2026
by
CaIon
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactor(price): improve handling of other ratios in PriceData
parent
394b023d
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
255 additions
and
55 deletions
+255
-55
controller/relay.go
+1
-1
relay/chat_completions_via_responses_test.go
+45
-0
relay/image_handler.go
+1
-1
relay/relay_task.go
+15
-25
service/task_billing.go
+18
-10
service/task_billing_test.go
+99
-0
service/text_quota.go
+2
-11
types/price_data.go
+74
-7
No files found.
controller/relay.go
View file @
fc1259f5
...
@@ -588,7 +588,7 @@ func RelayTask(c *gin.Context) {
...
@@ -588,7 +588,7 @@ func RelayTask(c *gin.Context) {
ModelPrice
:
relayInfo
.
PriceData
.
ModelPrice
,
ModelPrice
:
relayInfo
.
PriceData
.
ModelPrice
,
GroupRatio
:
relayInfo
.
PriceData
.
GroupRatioInfo
.
GroupRatio
,
GroupRatio
:
relayInfo
.
PriceData
.
GroupRatioInfo
.
GroupRatio
,
ModelRatio
:
relayInfo
.
PriceData
.
ModelRatio
,
ModelRatio
:
relayInfo
.
PriceData
.
ModelRatio
,
OtherRatios
:
relayInfo
.
PriceData
.
OtherRatios
,
OtherRatios
:
relayInfo
.
PriceData
.
OtherRatios
()
,
OriginModelName
:
relayInfo
.
OriginModelName
,
OriginModelName
:
relayInfo
.
OriginModelName
,
PerCallBilling
:
common
.
StringsContains
(
constant
.
TaskPricePatches
,
relayInfo
.
OriginModelName
)
||
relayInfo
.
PriceData
.
UsePrice
,
PerCallBilling
:
common
.
StringsContains
(
constant
.
TaskPricePatches
,
relayInfo
.
OriginModelName
)
||
relayInfo
.
PriceData
.
UsePrice
,
}
}
...
...
relay/chat_completions_via_responses_test.go
View file @
fc1259f5
package
relay
package
relay
import
(
import
(
"math"
"testing"
"testing"
relaycommon
"github.com/QuantumNous/new-api/relay/common"
"github.com/QuantumNous/new-api/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
)
func
TestIsResponsesEventStreamContentType
(
t
*
testing
.
T
)
{
func
TestIsResponsesEventStreamContentType
(
t
*
testing
.
T
)
{
...
@@ -24,3 +28,44 @@ func TestIsResponsesEventStreamContentType(t *testing.T) {
...
@@ -24,3 +28,44 @@ func TestIsResponsesEventStreamContentType(t *testing.T) {
})
})
}
}
}
}
func
TestRecalcQuotaFromRatiosIgnoresInvalidMultipliers
(
t
*
testing
.
T
)
{
info
:=
&
relaycommon
.
RelayInfo
{
PriceData
:
types
.
PriceData
{
Quota
:
100
,
},
}
info
.
PriceData
.
AddOtherRatio
(
"duration"
,
2
)
quota
,
ok
:=
recalcQuotaFromRatios
(
info
,
map
[
string
]
float64
{
"duration"
:
3
,
"zero"
:
0
,
"negative"
:
-
1
,
"nan"
:
math
.
NaN
(),
"inf"
:
math
.
Inf
(
1
),
})
require
.
True
(
t
,
ok
)
assert
.
Equal
(
t
,
150
,
quota
)
assert
.
True
(
t
,
info
.
PriceData
.
HasOtherRatio
(
"duration"
))
}
func
TestRecalcQuotaFromRatiosRejectsAllInvalidAdjustedRatios
(
t
*
testing
.
T
)
{
info
:=
&
relaycommon
.
RelayInfo
{
PriceData
:
types
.
PriceData
{
Quota
:
100
,
},
}
info
.
PriceData
.
AddOtherRatio
(
"duration"
,
2
)
quota
,
ok
:=
recalcQuotaFromRatios
(
info
,
map
[
string
]
float64
{
"zero"
:
0
,
"negative"
:
-
1
,
"nan"
:
math
.
NaN
(),
"inf"
:
math
.
Inf
(
1
),
})
require
.
False
(
t
,
ok
)
assert
.
Equal
(
t
,
0
,
quota
)
assert
.
True
(
t
,
info
.
PriceData
.
HasOtherRatio
(
"duration"
))
}
relay/image_handler.go
View file @
fc1259f5
...
@@ -128,7 +128,7 @@ func ImageHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *type
...
@@ -128,7 +128,7 @@ func ImageHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *type
// Adaptors may have already set a more accurate count from the
// Adaptors may have already set a more accurate count from the
// upstream response; only set the default when they haven't.
// upstream response; only set the default when they haven't.
if
info
.
PriceData
.
UsePrice
{
// only price model use N ratio
if
info
.
PriceData
.
UsePrice
{
// only price model use N ratio
if
_
,
hasN
:=
info
.
PriceData
.
OtherRatios
[
"n"
];
!
hasN
{
if
!
info
.
PriceData
.
HasOtherRatio
(
"n"
)
{
info
.
PriceData
.
AddOtherRatio
(
"n"
,
float64
(
imageN
))
info
.
PriceData
.
AddOtherRatio
(
"n"
,
float64
(
imageN
))
}
}
}
}
...
...
relay/relay_task.go
View file @
fc1259f5
...
@@ -196,12 +196,7 @@ func RelayTaskSubmit(c *gin.Context, info *relaycommon.RelayInfo) (*TaskSubmitRe
...
@@ -196,12 +196,7 @@ func RelayTaskSubmit(c *gin.Context, info *relaycommon.RelayInfo) (*TaskSubmitRe
// 6. 将 OtherRatios 应用到基础额度(饱和转换,防止溢出成负数)
// 6. 将 OtherRatios 应用到基础额度(饱和转换,防止溢出成负数)
if
!
common
.
StringsContains
(
constant
.
TaskPricePatches
,
modelName
)
{
if
!
common
.
StringsContains
(
constant
.
TaskPricePatches
,
modelName
)
{
quotaWithRatios
:=
float64
(
info
.
PriceData
.
Quota
)
quotaWithRatios
:=
info
.
PriceData
.
ApplyOtherRatiosToFloat
(
float64
(
info
.
PriceData
.
Quota
))
for
_
,
ra
:=
range
info
.
PriceData
.
OtherRatios
{
if
ra
!=
1.0
{
quotaWithRatios
*=
ra
}
}
quota
,
clamp
:=
common
.
QuotaFromFloatChecked
(
quotaWithRatios
)
quota
,
clamp
:=
common
.
QuotaFromFloatChecked
(
quotaWithRatios
)
info
.
PriceData
.
Quota
=
quota
info
.
PriceData
.
Quota
=
quota
noteTaskQuotaClamp
(
info
,
clamp
)
noteTaskQuotaClamp
(
info
,
clamp
)
...
@@ -232,7 +227,7 @@ func RelayTaskSubmit(c *gin.Context, info *relaycommon.RelayInfo) (*TaskSubmitRe
...
@@ -232,7 +227,7 @@ func RelayTaskSubmit(c *gin.Context, info *relaycommon.RelayInfo) (*TaskSubmitRe
}
}
// 10. 返回 OtherRatios 给下游(header 必须在 DoResponse 写 body 之前设置)
// 10. 返回 OtherRatios 给下游(header 必须在 DoResponse 写 body 之前设置)
otherRatios
:=
info
.
PriceData
.
OtherRatios
otherRatios
:=
info
.
PriceData
.
OtherRatios
()
if
otherRatios
==
nil
{
if
otherRatios
==
nil
{
otherRatios
=
map
[
string
]
float64
{}
otherRatios
=
map
[
string
]
float64
{}
}
}
...
@@ -248,10 +243,12 @@ func RelayTaskSubmit(c *gin.Context, info *relaycommon.RelayInfo) (*TaskSubmitRe
...
@@ -248,10 +243,12 @@ func RelayTaskSubmit(c *gin.Context, info *relaycommon.RelayInfo) (*TaskSubmitRe
// 11. 提交后计费调整:让适配器根据上游实际返回调整 OtherRatios
// 11. 提交后计费调整:让适配器根据上游实际返回调整 OtherRatios
finalQuota
:=
info
.
PriceData
.
Quota
finalQuota
:=
info
.
PriceData
.
Quota
if
adjustedRatios
:=
adaptor
.
AdjustBillingOnSubmit
(
info
,
taskData
);
len
(
adjustedRatios
)
>
0
{
if
adjustedRatios
:=
adaptor
.
AdjustBillingOnSubmit
(
info
,
taskData
);
len
(
adjustedRatios
)
>
0
{
// 基于调整后的 ratios 重新计算 quota
if
adjustedQuota
,
ok
:=
recalcQuotaFromRatios
(
info
,
adjustedRatios
);
ok
{
finalQuota
=
recalcQuotaFromRatios
(
info
,
adjustedRatios
)
// 基于调整后的 ratios 重新计算 quota
info
.
PriceData
.
OtherRatios
=
adjustedRatios
finalQuota
=
adjustedQuota
info
.
PriceData
.
Quota
=
finalQuota
info
.
PriceData
.
ReplaceOtherRatios
(
adjustedRatios
)
info
.
PriceData
.
Quota
=
finalQuota
}
}
}
return
&
TaskSubmitResult
{
return
&
TaskSubmitResult
{
...
@@ -264,25 +261,18 @@ func RelayTaskSubmit(c *gin.Context, info *relaycommon.RelayInfo) (*TaskSubmitRe
...
@@ -264,25 +261,18 @@ func RelayTaskSubmit(c *gin.Context, info *relaycommon.RelayInfo) (*TaskSubmitRe
// recalcQuotaFromRatios 根据 adjustedRatios 重新计算 quota。
// recalcQuotaFromRatios 根据 adjustedRatios 重新计算 quota。
// 公式: baseQuota × ∏(ratio) — 其中 baseQuota 是不含 OtherRatios 的基础额度。
// 公式: baseQuota × ∏(ratio) — 其中 baseQuota 是不含 OtherRatios 的基础额度。
func
recalcQuotaFromRatios
(
info
*
relaycommon
.
RelayInfo
,
ratios
map
[
string
]
float64
)
int
{
func
recalcQuotaFromRatios
(
info
*
relaycommon
.
RelayInfo
,
ratios
map
[
string
]
float64
)
(
int
,
bool
)
{
// 从 PriceData 获取不含 OtherRatios 的基础价格
// 从 PriceData 获取不含 OtherRatios 的基础价格
baseQuota
:=
float64
(
info
.
PriceData
.
Quota
)
baseQuota
:=
info
.
PriceData
.
RemoveOtherRatiosFromFloat
(
float64
(
info
.
PriceData
.
Quota
))
// 先除掉原有的 OtherRatios 恢复基础额度
priceData
:=
info
.
PriceData
for
_
,
ra
:=
range
info
.
PriceData
.
OtherRatios
{
if
!
priceData
.
ReplaceOtherRatios
(
ratios
)
{
if
ra
!=
1.0
&&
ra
>
0
{
return
0
,
false
baseQuota
/=
ra
}
}
}
// 应用新的 ratios
// 应用新的 ratios
result
:=
baseQuota
result
:=
priceData
.
ApplyOtherRatiosToFloat
(
baseQuota
)
for
_
,
ra
:=
range
ratios
{
if
ra
!=
1.0
{
result
*=
ra
}
}
quota
,
clamp
:=
common
.
QuotaFromFloatChecked
(
result
)
quota
,
clamp
:=
common
.
QuotaFromFloatChecked
(
result
)
noteTaskQuotaClamp
(
info
,
clamp
)
noteTaskQuotaClamp
(
info
,
clamp
)
return
quota
return
quota
,
true
}
}
// noteTaskQuotaClamp records the first quota saturation event onto the task's
// noteTaskQuotaClamp records the first quota saturation event onto the task's
...
...
service/task_billing.go
View file @
fc1259f5
...
@@ -11,6 +11,7 @@ import (
...
@@ -11,6 +11,7 @@ import (
"github.com/QuantumNous/new-api/model"
"github.com/QuantumNous/new-api/model"
relaycommon
"github.com/QuantumNous/new-api/relay/common"
relaycommon
"github.com/QuantumNous/new-api/relay/common"
"github.com/QuantumNous/new-api/setting/ratio_setting"
"github.com/QuantumNous/new-api/setting/ratio_setting"
"github.com/QuantumNous/new-api/types"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin"
)
)
...
@@ -23,9 +24,9 @@ func LogTaskConsumption(c *gin.Context, info *relaycommon.RelayInfo) {
...
@@ -23,9 +24,9 @@ func LogTaskConsumption(c *gin.Context, info *relaycommon.RelayInfo) {
if
common
.
StringsContains
(
constant
.
TaskPricePatches
,
info
.
OriginModelName
)
{
if
common
.
StringsContains
(
constant
.
TaskPricePatches
,
info
.
OriginModelName
)
{
logContent
=
fmt
.
Sprintf
(
"%s,按次计费"
,
logContent
)
logContent
=
fmt
.
Sprintf
(
"%s,按次计费"
,
logContent
)
}
else
{
}
else
{
if
len
(
info
.
PriceData
.
O
therRatios
)
>
0
{
if
otherRatios
:=
info
.
PriceData
.
OtherRatios
();
len
(
o
therRatios
)
>
0
{
var
contents
[]
string
var
contents
[]
string
for
key
,
ra
:=
range
info
.
PriceData
.
O
therRatios
{
for
key
,
ra
:=
range
o
therRatios
{
if
1.0
!=
ra
{
if
1.0
!=
ra
{
contents
=
append
(
contents
,
fmt
.
Sprintf
(
"%s: %.2f"
,
key
,
ra
))
contents
=
append
(
contents
,
fmt
.
Sprintf
(
"%s: %.2f"
,
key
,
ra
))
}
}
...
@@ -126,8 +127,8 @@ func taskBillingOther(task *model.Task) map[string]interface{} {
...
@@ -126,8 +127,8 @@ func taskBillingOther(task *model.Task) map[string]interface{} {
other
[
"model_ratio"
]
=
bc
.
ModelRatio
other
[
"model_ratio"
]
=
bc
.
ModelRatio
}
}
other
[
"group_ratio"
]
=
bc
.
GroupRatio
other
[
"group_ratio"
]
=
bc
.
GroupRatio
if
len
(
bc
.
OtherRatios
)
>
0
{
if
priceData
:=
taskBillingContextPriceData
(
bc
);
priceData
!=
nil
{
for
k
,
v
:=
range
bc
.
OtherRatios
{
for
k
,
v
:=
range
priceData
.
OtherRatios
()
{
other
[
k
]
=
v
other
[
k
]
=
v
}
}
}
}
...
@@ -140,6 +141,17 @@ func taskBillingOther(task *model.Task) map[string]interface{} {
...
@@ -140,6 +141,17 @@ func taskBillingOther(task *model.Task) map[string]interface{} {
return
other
return
other
}
}
func
taskBillingContextPriceData
(
bc
*
model
.
TaskBillingContext
)
*
types
.
PriceData
{
if
bc
==
nil
||
len
(
bc
.
OtherRatios
)
==
0
{
return
nil
}
priceData
:=
&
types
.
PriceData
{}
if
!
priceData
.
ReplaceOtherRatios
(
bc
.
OtherRatios
)
{
return
nil
}
return
priceData
}
// taskModelName 从 BillingContext 或 Properties 中获取模型名称。
// taskModelName 从 BillingContext 或 Properties 中获取模型名称。
func
taskModelName
(
task
*
model
.
Task
)
string
{
func
taskModelName
(
task
*
model
.
Task
)
string
{
if
bc
:=
task
.
PrivateData
.
BillingContext
;
bc
!=
nil
&&
bc
.
OriginModelName
!=
""
{
if
bc
:=
task
.
PrivateData
.
BillingContext
;
bc
!=
nil
&&
bc
.
OriginModelName
!=
""
{
...
@@ -294,12 +306,8 @@ func RecalculateTaskQuotaByTokens(ctx context.Context, task *model.Task, totalTo
...
@@ -294,12 +306,8 @@ func RecalculateTaskQuotaByTokens(ctx context.Context, task *model.Task, totalTo
// 计算 OtherRatios 乘积(视频折扣、时长等)
// 计算 OtherRatios 乘积(视频折扣、时长等)
otherMultiplier
:=
1.0
otherMultiplier
:=
1.0
if
bc
:=
task
.
PrivateData
.
BillingContext
;
bc
!=
nil
{
if
priceData
:=
taskBillingContextPriceData
(
task
.
PrivateData
.
BillingContext
);
priceData
!=
nil
{
for
_
,
r
:=
range
bc
.
OtherRatios
{
otherMultiplier
=
priceData
.
OtherRatioMultiplier
()
if
r
!=
1.0
&&
r
>
0
{
otherMultiplier
*=
r
}
}
}
}
// 计算实际应扣费额度: totalTokens * modelRatio * groupRatio * otherMultiplier(饱和转换,防止溢出成负数)
// 计算实际应扣费额度: totalTokens * modelRatio * groupRatio * otherMultiplier(饱和转换,防止溢出成负数)
...
...
service/task_billing_test.go
View file @
fc1259f5
...
@@ -3,6 +3,7 @@ package service
...
@@ -3,6 +3,7 @@ package service
import
(
import
(
"context"
"context"
"encoding/json"
"encoding/json"
"math"
"net/http"
"net/http"
"os"
"os"
"testing"
"testing"
...
@@ -11,7 +12,9 @@ import (
...
@@ -11,7 +12,9 @@ import (
"github.com/QuantumNous/new-api/common"
"github.com/QuantumNous/new-api/common"
"github.com/QuantumNous/new-api/model"
"github.com/QuantumNous/new-api/model"
relaycommon
"github.com/QuantumNous/new-api/relay/common"
relaycommon
"github.com/QuantumNous/new-api/relay/common"
"github.com/QuantumNous/new-api/types"
"github.com/glebarez/sqlite"
"github.com/glebarez/sqlite"
"github.com/shopspring/decimal"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/require"
"gorm.io/gorm"
"gorm.io/gorm"
...
@@ -139,6 +142,102 @@ func makeTask(userId, channelId, quota, tokenId int, billingSource string, subsc
...
@@ -139,6 +142,102 @@ func makeTask(userId, channelId, quota, tokenId int, billingSource string, subsc
}
}
}
}
func
TestPriceDataOtherRatiosFilterAndSnapshot
(
t
*
testing
.
T
)
{
priceData
:=
types
.
PriceData
{}
priceData
.
AddOtherRatio
(
"zero"
,
0
)
priceData
.
AddOtherRatio
(
"negative"
,
-
0.5
)
priceData
.
AddOtherRatio
(
"nan"
,
math
.
NaN
())
priceData
.
AddOtherRatio
(
"inf"
,
math
.
Inf
(
1
))
priceData
.
AddOtherRatio
(
"one"
,
1
)
priceData
.
AddOtherRatio
(
"positive"
,
2.5
)
ratios
:=
priceData
.
OtherRatios
()
require
.
Len
(
t
,
ratios
,
2
)
assert
.
Equal
(
t
,
1.0
,
ratios
[
"one"
])
assert
.
Equal
(
t
,
2.5
,
ratios
[
"positive"
])
assert
.
True
(
t
,
priceData
.
HasOtherRatio
(
"one"
))
assert
.
False
(
t
,
priceData
.
HasOtherRatio
(
"zero"
))
ratios
[
"positive"
]
=
99
ratios
[
"new"
]
=
3
nextSnapshot
:=
priceData
.
OtherRatios
()
assert
.
Equal
(
t
,
2.5
,
nextSnapshot
[
"positive"
])
assert
.
NotContains
(
t
,
nextSnapshot
,
"new"
)
}
func
TestPriceDataReplaceAndApplyOtherRatios
(
t
*
testing
.
T
)
{
priceData
:=
types
.
PriceData
{}
replaced
:=
priceData
.
ReplaceOtherRatios
(
map
[
string
]
float64
{
"zero"
:
0
,
"negative"
:
-
3
,
"nan"
:
math
.
NaN
(),
"inf"
:
math
.
Inf
(
1
),
"one"
:
1
,
"duration"
:
2
,
"size"
:
1.5
,
})
require
.
True
(
t
,
replaced
)
assert
.
Equal
(
t
,
3.0
,
priceData
.
OtherRatioMultiplier
())
assert
.
Equal
(
t
,
30.0
,
priceData
.
ApplyOtherRatiosToFloat
(
10
))
assert
.
Equal
(
t
,
10.0
,
priceData
.
RemoveOtherRatiosFromFloat
(
30
))
assert
.
True
(
t
,
decimal
.
NewFromInt
(
30
)
.
Equal
(
priceData
.
ApplyOtherRatiosToDecimal
(
decimal
.
NewFromInt
(
10
))))
replaced
=
priceData
.
ReplaceOtherRatios
(
map
[
string
]
float64
{
"zero"
:
0
,
"nan"
:
math
.
NaN
(),
})
require
.
False
(
t
,
replaced
)
assert
.
Nil
(
t
,
priceData
.
OtherRatios
())
assert
.
Equal
(
t
,
1.0
,
priceData
.
OtherRatioMultiplier
())
}
func
TestTaskBillingOtherFiltersHistoricalOtherRatios
(
t
*
testing
.
T
)
{
task
:=
makeTask
(
1
,
1
,
100
,
0
,
BillingSourceWallet
,
0
)
task
.
PrivateData
.
BillingContext
.
OtherRatios
=
map
[
string
]
float64
{
"seconds"
:
2
,
"identity"
:
1
,
"zero"
:
0
,
"negative"
:
-
1
,
"nan"
:
math
.
NaN
(),
"inf"
:
math
.
Inf
(
1
),
}
other
:=
taskBillingOther
(
task
)
assert
.
Equal
(
t
,
2.0
,
other
[
"seconds"
])
assert
.
Equal
(
t
,
1.0
,
other
[
"identity"
])
assert
.
NotContains
(
t
,
other
,
"zero"
)
assert
.
NotContains
(
t
,
other
,
"negative"
)
assert
.
NotContains
(
t
,
other
,
"nan"
)
assert
.
NotContains
(
t
,
other
,
"inf"
)
}
func
TestTaskBillingContextPriceDataFiltersMultiplier
(
t
*
testing
.
T
)
{
priceData
:=
taskBillingContextPriceData
(
&
model
.
TaskBillingContext
{
OtherRatios
:
map
[
string
]
float64
{
"seconds"
:
2
,
"size"
:
3
,
"identity"
:
1
,
"zero"
:
0
,
"negative"
:
-
1
,
"nan"
:
math
.
NaN
(),
"inf"
:
math
.
Inf
(
1
),
},
})
require
.
NotNil
(
t
,
priceData
)
assert
.
Equal
(
t
,
6.0
,
priceData
.
OtherRatioMultiplier
())
assert
.
Equal
(
t
,
map
[
string
]
float64
{
"seconds"
:
2
,
"size"
:
3
,
"identity"
:
1
,
},
priceData
.
OtherRatios
())
}
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// Read-back helpers
// Read-back helpers
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
...
...
service/text_quota.go
View file @
fc1259f5
...
@@ -296,12 +296,7 @@ func calculateTextQuotaSummary(ctx *gin.Context, relayInfo *relaycommon.RelayInf
...
@@ -296,12 +296,7 @@ func calculateTextQuotaSummary(ctx *gin.Context, relayInfo *relaycommon.RelayInf
quotaCalculateDecimal
:=
promptQuota
.
Add
(
completionQuota
)
.
Mul
(
ratio
)
quotaCalculateDecimal
:=
promptQuota
.
Add
(
completionQuota
)
.
Mul
(
ratio
)
quotaCalculateDecimal
=
quotaCalculateDecimal
.
Add
(
summary
.
ToolCallSurchargeQuota
)
quotaCalculateDecimal
=
quotaCalculateDecimal
.
Add
(
summary
.
ToolCallSurchargeQuota
)
quotaCalculateDecimal
=
quotaCalculateDecimal
.
Add
(
audioInputQuota
)
quotaCalculateDecimal
=
quotaCalculateDecimal
.
Add
(
audioInputQuota
)
quotaCalculateDecimal
=
relayInfo
.
PriceData
.
ApplyOtherRatiosToDecimal
(
quotaCalculateDecimal
)
if
len
(
relayInfo
.
PriceData
.
OtherRatios
)
>
0
{
for
_
,
otherRatio
:=
range
relayInfo
.
PriceData
.
OtherRatios
{
quotaCalculateDecimal
=
quotaCalculateDecimal
.
Mul
(
decimal
.
NewFromFloat
(
otherRatio
))
}
}
if
!
ratio
.
IsZero
()
&&
quotaCalculateDecimal
.
LessThanOrEqual
(
decimal
.
Zero
)
{
if
!
ratio
.
IsZero
()
&&
quotaCalculateDecimal
.
LessThanOrEqual
(
decimal
.
Zero
)
{
quotaCalculateDecimal
=
decimal
.
NewFromInt
(
1
)
quotaCalculateDecimal
=
decimal
.
NewFromInt
(
1
)
...
@@ -313,11 +308,7 @@ func calculateTextQuotaSummary(ctx *gin.Context, relayInfo *relaycommon.RelayInf
...
@@ -313,11 +308,7 @@ func calculateTextQuotaSummary(ctx *gin.Context, relayInfo *relaycommon.RelayInf
quotaCalculateDecimal
:=
dModelPrice
.
Mul
(
dQuotaPerUnit
)
.
Mul
(
dGroupRatio
)
quotaCalculateDecimal
:=
dModelPrice
.
Mul
(
dQuotaPerUnit
)
.
Mul
(
dGroupRatio
)
quotaCalculateDecimal
=
quotaCalculateDecimal
.
Add
(
summary
.
ToolCallSurchargeQuota
)
quotaCalculateDecimal
=
quotaCalculateDecimal
.
Add
(
summary
.
ToolCallSurchargeQuota
)
quotaCalculateDecimal
=
quotaCalculateDecimal
.
Add
(
audioInputQuota
)
quotaCalculateDecimal
=
quotaCalculateDecimal
.
Add
(
audioInputQuota
)
if
len
(
relayInfo
.
PriceData
.
OtherRatios
)
>
0
{
quotaCalculateDecimal
=
relayInfo
.
PriceData
.
ApplyOtherRatiosToDecimal
(
quotaCalculateDecimal
)
for
_
,
otherRatio
:=
range
relayInfo
.
PriceData
.
OtherRatios
{
quotaCalculateDecimal
=
quotaCalculateDecimal
.
Mul
(
decimal
.
NewFromFloat
(
otherRatio
))
}
}
quota
,
clamp
:=
common
.
QuotaFromDecimalChecked
(
quotaCalculateDecimal
)
quota
,
clamp
:=
common
.
QuotaFromDecimalChecked
(
quotaCalculateDecimal
)
summary
.
Quota
=
quota
summary
.
Quota
=
quota
noteQuotaClamp
(
relayInfo
,
clamp
)
noteQuotaClamp
(
relayInfo
,
clamp
)
...
...
types/price_data.go
View file @
fc1259f5
...
@@ -3,6 +3,8 @@ package types
...
@@ -3,6 +3,8 @@ package types
import
(
import
(
"fmt"
"fmt"
"math"
"math"
"github.com/shopspring/decimal"
)
)
type
GroupRatioInfo
struct
{
type
GroupRatioInfo
struct
{
...
@@ -23,7 +25,7 @@ type PriceData struct {
...
@@ -23,7 +25,7 @@ type PriceData struct {
ImageRatio
float64
ImageRatio
float64
AudioRatio
float64
AudioRatio
float64
AudioCompletionRatio
float64
AudioCompletionRatio
float64
O
therRatios
map
[
string
]
float64
o
therRatios
map
[
string
]
float64
UsePrice
bool
UsePrice
bool
Quota
int
// 按次计费的最终额度(MJ / Task)
Quota
int
// 按次计费的最终额度(MJ / Task)
QuotaToPreConsume
int
// 按量计费的预消耗额度
QuotaToPreConsume
int
// 按量计费的预消耗额度
...
@@ -31,15 +33,80 @@ type PriceData struct {
...
@@ -31,15 +33,80 @@ type PriceData struct {
}
}
func
(
p
*
PriceData
)
AddOtherRatio
(
key
string
,
ratio
float64
)
{
func
(
p
*
PriceData
)
AddOtherRatio
(
key
string
,
ratio
float64
)
{
if
p
.
OtherRatios
==
nil
{
if
!
isValidOtherRatio
(
ratio
)
{
p
.
OtherRatios
=
make
(
map
[
string
]
float64
)
return
}
if
p
.
otherRatios
==
nil
{
p
.
otherRatios
=
make
(
map
[
string
]
float64
)
}
p
.
otherRatios
[
key
]
=
ratio
}
func
(
p
*
PriceData
)
ReplaceOtherRatios
(
ratios
map
[
string
]
float64
)
bool
{
p
.
otherRatios
=
nil
for
key
,
ratio
:=
range
ratios
{
p
.
AddOtherRatio
(
key
,
ratio
)
}
return
len
(
p
.
otherRatios
)
>
0
}
func
(
p
*
PriceData
)
HasOtherRatio
(
key
string
)
bool
{
ratio
,
ok
:=
p
.
otherRatios
[
key
]
return
ok
&&
isValidOtherRatio
(
ratio
)
}
func
(
p
*
PriceData
)
OtherRatios
()
map
[
string
]
float64
{
if
len
(
p
.
otherRatios
)
==
0
{
return
nil
}
ratios
:=
make
(
map
[
string
]
float64
,
len
(
p
.
otherRatios
))
for
key
,
ratio
:=
range
p
.
otherRatios
{
if
isValidOtherRatio
(
ratio
)
{
ratios
[
key
]
=
ratio
}
}
if
len
(
ratios
)
==
0
{
return
nil
}
return
ratios
}
func
(
p
*
PriceData
)
OtherRatioMultiplier
()
float64
{
multiplier
:=
1.0
for
_
,
ratio
:=
range
p
.
otherRatios
{
if
isValidOtherRatio
(
ratio
)
&&
ratio
!=
1.0
{
multiplier
*=
ratio
}
}
return
multiplier
}
func
(
p
*
PriceData
)
ApplyOtherRatiosToFloat
(
value
float64
)
float64
{
return
value
*
p
.
OtherRatioMultiplier
()
}
func
(
p
*
PriceData
)
ApplyOtherRatiosToDecimal
(
value
decimal
.
Decimal
)
decimal
.
Decimal
{
for
_
,
ratio
:=
range
p
.
otherRatios
{
if
isValidOtherRatio
(
ratio
)
&&
ratio
!=
1.0
{
value
=
value
.
Mul
(
decimal
.
NewFromFloat
(
ratio
))
}
}
}
return
value
}
func
(
p
*
PriceData
)
RemoveOtherRatiosFromFloat
(
value
float64
)
float64
{
for
_
,
ratio
:=
range
p
.
otherRatios
{
if
isValidOtherRatio
(
ratio
)
&&
ratio
!=
1.0
{
value
/=
ratio
}
}
return
value
}
func
isValidOtherRatio
(
ratio
float64
)
bool
{
// NaN/Inf would poison every downstream quota multiplication
// NaN/Inf would poison every downstream quota multiplication
// (int(NaN * quota) wraps to a negative charge).
// (int(NaN * quota) wraps to a negative charge).
if
!
(
ratio
>
0
)
||
math
.
IsInf
(
ratio
,
1
)
{
return
ratio
>
0
&&
!
math
.
IsInf
(
ratio
,
1
)
return
}
p
.
OtherRatios
[
key
]
=
ratio
}
}
func
(
p
*
PriceData
)
ToSetting
()
string
{
func
(
p
*
PriceData
)
ToSetting
()
string
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment