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
Commit
2a0bf7f9
authored
Jun 11, 2025
by
creamlike1024
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 分组特殊倍率
parent
92de4d0d
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
323 additions
and
154 deletions
+323
-154
controller/channel-test.go
+1
-1
controller/pricing.go
+8
-1
model/option.go
+3
-0
relay/common/relay_info.go
+2
-0
relay/helper/price.go
+8
-1
relay/relay-text.go
+2
-1
service/log_info_generate.go
+8
-7
service/quota.go
+21
-6
setting/group_ratio.go
+36
-5
web/src/components/settings/OperationSetting.js
+2
-0
web/src/components/table/LogsTable.js
+89
-57
web/src/helpers/render.js
+121
-75
web/src/pages/Setting/Operation/GroupRatioSettings.js
+22
-0
No files found.
controller/channel-test.go
View file @
2a0bf7f9
...
...
@@ -166,7 +166,7 @@ func testChannel(channel *model.Channel, testModel string) (err error, openAIErr
milliseconds
:=
tok
.
Sub
(
tik
)
.
Milliseconds
()
consumedTime
:=
float64
(
milliseconds
)
/
1000.0
other
:=
service
.
GenerateTextOtherInfo
(
c
,
info
,
priceData
.
ModelRatio
,
priceData
.
GroupRatio
,
priceData
.
CompletionRatio
,
usage
.
PromptTokensDetails
.
CachedTokens
,
priceData
.
CacheRatio
,
priceData
.
ModelPrice
)
usage
.
PromptTokensDetails
.
CachedTokens
,
priceData
.
CacheRatio
,
priceData
.
ModelPrice
,
priceData
.
UserGroupRatio
)
model
.
RecordConsumeLog
(
c
,
1
,
channel
.
Id
,
usage
.
PromptTokens
,
usage
.
CompletionTokens
,
info
.
OriginModelName
,
"模型测试"
,
quota
,
"模型测试"
,
0
,
quota
,
int
(
consumedTime
),
false
,
info
.
Group
,
other
)
common
.
SysLog
(
fmt
.
Sprintf
(
"testing channel #%d, response:
\n
%s"
,
channel
.
Id
,
string
(
respBody
)))
...
...
controller/pricing.go
View file @
2a0bf7f9
package
controller
import
(
"github.com/gin-gonic/gin"
"one-api/model"
"one-api/setting"
"one-api/setting/operation_setting"
"github.com/gin-gonic/gin"
)
func
GetPricing
(
c
*
gin
.
Context
)
{
...
...
@@ -20,6 +21,12 @@ func GetPricing(c *gin.Context) {
user
,
err
:=
model
.
GetUserCache
(
userId
.
(
int
))
if
err
==
nil
{
group
=
user
.
Group
for
g
:=
range
groupRatio
{
ratio
,
ok
:=
setting
.
GetGroupGroupRatio
(
group
,
g
)
if
ok
{
groupRatio
[
g
]
=
ratio
}
}
}
}
...
...
model/option.go
View file @
2a0bf7f9
...
...
@@ -98,6 +98,7 @@ func InitOptionMap() {
common
.
OptionMap
[
"ModelPrice"
]
=
operation_setting
.
ModelPrice2JSONString
()
common
.
OptionMap
[
"CacheRatio"
]
=
operation_setting
.
CacheRatio2JSONString
()
common
.
OptionMap
[
"GroupRatio"
]
=
setting
.
GroupRatio2JSONString
()
common
.
OptionMap
[
"GroupGroupRatio"
]
=
setting
.
GroupGroupRatio2JSONString
()
common
.
OptionMap
[
"UserUsableGroups"
]
=
setting
.
UserUsableGroups2JSONString
()
common
.
OptionMap
[
"CompletionRatio"
]
=
operation_setting
.
CompletionRatio2JSONString
()
common
.
OptionMap
[
"TopUpLink"
]
=
common
.
TopUpLink
...
...
@@ -355,6 +356,8 @@ func updateOptionMap(key string, value string) (err error) {
err
=
operation_setting
.
UpdateModelRatioByJSONString
(
value
)
case
"GroupRatio"
:
err
=
setting
.
UpdateGroupRatioByJSONString
(
value
)
case
"GroupGroupRatio"
:
err
=
setting
.
UpdateGroupGroupRatioByJSONString
(
value
)
case
"UserUsableGroups"
:
err
=
setting
.
UpdateUserUsableGroupsByJSONString
(
value
)
case
"CompletionRatio"
:
...
...
relay/common/relay_info.go
View file @
2a0bf7f9
...
...
@@ -61,6 +61,7 @@ type RelayInfo struct {
TokenKey
string
UserId
int
Group
string
UserGroup
string
TokenUnlimited
bool
StartTime
time
.
Time
FirstResponseTime
time
.
Time
...
...
@@ -204,6 +205,7 @@ func GenRelayInfo(c *gin.Context) *RelayInfo {
TokenKey
:
tokenKey
,
UserId
:
userId
,
Group
:
group
,
UserGroup
:
c
.
GetString
(
constant
.
ContextKeyUserGroup
),
TokenUnlimited
:
tokenUnlimited
,
StartTime
:
startTime
,
FirstResponseTime
:
startTime
.
Add
(
-
time
.
Second
),
...
...
relay/helper/price.go
View file @
2a0bf7f9
...
...
@@ -2,12 +2,13 @@ package helper
import
(
"fmt"
"github.com/gin-gonic/gin"
"one-api/common"
constant2
"one-api/constant"
relaycommon
"one-api/relay/common"
"one-api/setting"
"one-api/setting/operation_setting"
"github.com/gin-gonic/gin"
)
type
PriceData
struct
{
...
...
@@ -18,6 +19,7 @@ type PriceData struct {
CacheCreationRatio
float64
ImageRatio
float64
GroupRatio
float64
UserGroupRatio
float64
UsePrice
bool
ShouldPreConsumedQuota
int
}
...
...
@@ -29,6 +31,10 @@ func (p PriceData) ToSetting() string {
func
ModelPriceHelper
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
,
promptTokens
int
,
maxTokens
int
)
(
PriceData
,
error
)
{
modelPrice
,
usePrice
:=
operation_setting
.
GetModelPrice
(
info
.
OriginModelName
,
false
)
groupRatio
:=
setting
.
GetGroupRatio
(
info
.
Group
)
userGroupRatio
,
ok
:=
setting
.
GetGroupGroupRatio
(
info
.
UserGroup
,
info
.
Group
)
if
ok
{
groupRatio
=
userGroupRatio
}
var
preConsumedQuota
int
var
modelRatio
float64
var
completionRatio
float64
...
...
@@ -69,6 +75,7 @@ func ModelPriceHelper(c *gin.Context, info *relaycommon.RelayInfo, promptTokens
ModelRatio
:
modelRatio
,
CompletionRatio
:
completionRatio
,
GroupRatio
:
groupRatio
,
UserGroupRatio
:
userGroupRatio
,
UsePrice
:
usePrice
,
CacheRatio
:
cacheRatio
,
ImageRatio
:
imageRatio
,
...
...
relay/relay-text.go
View file @
2a0bf7f9
...
...
@@ -363,6 +363,7 @@ func postConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo,
modelRatio
:=
priceData
.
ModelRatio
groupRatio
:=
priceData
.
GroupRatio
modelPrice
:=
priceData
.
ModelPrice
userGroupRatio
:=
priceData
.
UserGroupRatio
// Convert values to decimal for precise calculation
dPromptTokens
:=
decimal
.
NewFromInt
(
int64
(
promptTokens
))
...
...
@@ -510,7 +511,7 @@ func postConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo,
if
extraContent
!=
""
{
logContent
+=
", "
+
extraContent
}
other
:=
service
.
GenerateTextOtherInfo
(
ctx
,
relayInfo
,
modelRatio
,
groupRatio
,
completionRatio
,
cacheTokens
,
cacheRatio
,
modelPrice
)
other
:=
service
.
GenerateTextOtherInfo
(
ctx
,
relayInfo
,
modelRatio
,
groupRatio
,
completionRatio
,
cacheTokens
,
cacheRatio
,
modelPrice
,
userGroupRatio
)
if
imageTokens
!=
0
{
other
[
"image"
]
=
true
other
[
"image_ratio"
]
=
imageRatio
...
...
service/log_info_generate.go
View file @
2a0bf7f9
...
...
@@ -8,7 +8,7 @@ import (
)
func
GenerateTextOtherInfo
(
ctx
*
gin
.
Context
,
relayInfo
*
relaycommon
.
RelayInfo
,
modelRatio
,
groupRatio
,
completionRatio
float64
,
cacheTokens
int
,
cacheRatio
float64
,
modelPrice
float64
)
map
[
string
]
interface
{}
{
cacheTokens
int
,
cacheRatio
float64
,
modelPrice
float64
,
userGroupRatio
float64
)
map
[
string
]
interface
{}
{
other
:=
make
(
map
[
string
]
interface
{})
other
[
"model_ratio"
]
=
modelRatio
other
[
"group_ratio"
]
=
groupRatio
...
...
@@ -16,6 +16,7 @@ func GenerateTextOtherInfo(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, m
other
[
"cache_tokens"
]
=
cacheTokens
other
[
"cache_ratio"
]
=
cacheRatio
other
[
"model_price"
]
=
modelPrice
other
[
"user_group_ratio"
]
=
userGroupRatio
other
[
"frt"
]
=
float64
(
relayInfo
.
FirstResponseTime
.
UnixMilli
()
-
relayInfo
.
StartTime
.
UnixMilli
())
if
relayInfo
.
ReasoningEffort
!=
""
{
other
[
"reasoning_effort"
]
=
relayInfo
.
ReasoningEffort
...
...
@@ -30,8 +31,8 @@ func GenerateTextOtherInfo(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, m
return
other
}
func
GenerateWssOtherInfo
(
ctx
*
gin
.
Context
,
relayInfo
*
relaycommon
.
RelayInfo
,
usage
*
dto
.
RealtimeUsage
,
modelRatio
,
groupRatio
,
completionRatio
,
audioRatio
,
audioCompletionRatio
,
modelPrice
float64
)
map
[
string
]
interface
{}
{
info
:=
GenerateTextOtherInfo
(
ctx
,
relayInfo
,
modelRatio
,
groupRatio
,
completionRatio
,
0
,
0.0
,
modelPrice
)
func
GenerateWssOtherInfo
(
ctx
*
gin
.
Context
,
relayInfo
*
relaycommon
.
RelayInfo
,
usage
*
dto
.
RealtimeUsage
,
modelRatio
,
groupRatio
,
completionRatio
,
audioRatio
,
audioCompletionRatio
,
modelPrice
,
userGroupRatio
float64
)
map
[
string
]
interface
{}
{
info
:=
GenerateTextOtherInfo
(
ctx
,
relayInfo
,
modelRatio
,
groupRatio
,
completionRatio
,
0
,
0.0
,
modelPrice
,
userGroupRatio
)
info
[
"ws"
]
=
true
info
[
"audio_input"
]
=
usage
.
InputTokenDetails
.
AudioTokens
info
[
"audio_output"
]
=
usage
.
OutputTokenDetails
.
AudioTokens
...
...
@@ -42,8 +43,8 @@ func GenerateWssOtherInfo(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, us
return
info
}
func
GenerateAudioOtherInfo
(
ctx
*
gin
.
Context
,
relayInfo
*
relaycommon
.
RelayInfo
,
usage
*
dto
.
Usage
,
modelRatio
,
groupRatio
,
completionRatio
,
audioRatio
,
audioCompletionRatio
,
modelPrice
float64
)
map
[
string
]
interface
{}
{
info
:=
GenerateTextOtherInfo
(
ctx
,
relayInfo
,
modelRatio
,
groupRatio
,
completionRatio
,
0
,
0.0
,
modelPrice
)
func
GenerateAudioOtherInfo
(
ctx
*
gin
.
Context
,
relayInfo
*
relaycommon
.
RelayInfo
,
usage
*
dto
.
Usage
,
modelRatio
,
groupRatio
,
completionRatio
,
audioRatio
,
audioCompletionRatio
,
modelPrice
,
userGroupRatio
float64
)
map
[
string
]
interface
{}
{
info
:=
GenerateTextOtherInfo
(
ctx
,
relayInfo
,
modelRatio
,
groupRatio
,
completionRatio
,
0
,
0.0
,
modelPrice
,
userGroupRatio
)
info
[
"audio"
]
=
true
info
[
"audio_input"
]
=
usage
.
PromptTokensDetails
.
AudioTokens
info
[
"audio_output"
]
=
usage
.
CompletionTokenDetails
.
AudioTokens
...
...
@@ -55,8 +56,8 @@ func GenerateAudioOtherInfo(ctx *gin.Context, relayInfo *relaycommon.RelayInfo,
}
func
GenerateClaudeOtherInfo
(
ctx
*
gin
.
Context
,
relayInfo
*
relaycommon
.
RelayInfo
,
modelRatio
,
groupRatio
,
completionRatio
float64
,
cacheTokens
int
,
cacheRatio
float64
,
cacheCreationTokens
int
,
cacheCreationRatio
float64
,
modelPrice
float64
)
map
[
string
]
interface
{}
{
info
:=
GenerateTextOtherInfo
(
ctx
,
relayInfo
,
modelRatio
,
groupRatio
,
completionRatio
,
cacheTokens
,
cacheRatio
,
modelPrice
)
cacheTokens
int
,
cacheRatio
float64
,
cacheCreationTokens
int
,
cacheCreationRatio
float64
,
modelPrice
float64
,
userGroupRatio
float64
)
map
[
string
]
interface
{}
{
info
:=
GenerateTextOtherInfo
(
ctx
,
relayInfo
,
modelRatio
,
groupRatio
,
completionRatio
,
cacheTokens
,
cacheRatio
,
modelPrice
,
userGroupRatio
)
info
[
"claude"
]
=
true
info
[
"cache_creation_tokens"
]
=
cacheCreationTokens
info
[
"cache_creation_ratio"
]
=
cacheCreationRatio
...
...
service/quota.go
View file @
2a0bf7f9
...
...
@@ -94,6 +94,10 @@ func PreWssConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, usag
audioInputTokens
:=
usage
.
InputTokenDetails
.
AudioTokens
audioOutTokens
:=
usage
.
OutputTokenDetails
.
AudioTokens
groupRatio
:=
setting
.
GetGroupRatio
(
relayInfo
.
Group
)
userGroupRatio
,
ok
:=
setting
.
GetGroupGroupRatio
(
relayInfo
.
UserGroup
,
relayInfo
.
Group
)
if
ok
{
groupRatio
=
userGroupRatio
}
modelRatio
,
_
:=
operation_setting
.
GetModelRatio
(
modelName
)
quotaInfo
:=
QuotaInfo
{
...
...
@@ -145,6 +149,11 @@ func PostWssConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, mod
audioRatio
:=
decimal
.
NewFromFloat
(
operation_setting
.
GetAudioRatio
(
relayInfo
.
OriginModelName
))
audioCompletionRatio
:=
decimal
.
NewFromFloat
(
operation_setting
.
GetAudioCompletionRatio
(
modelName
))
actualGroupRatio
:=
groupRatio
userGroupRatio
,
ok
:=
setting
.
GetGroupGroupRatio
(
relayInfo
.
UserGroup
,
relayInfo
.
Group
)
if
ok
{
actualGroupRatio
=
userGroupRatio
}
quotaInfo
:=
QuotaInfo
{
InputDetails
:
TokenDetails
{
TextTokens
:
textInputTokens
,
...
...
@@ -157,7 +166,7 @@ func PostWssConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, mod
ModelName
:
modelName
,
UsePrice
:
usePrice
,
ModelRatio
:
modelRatio
,
GroupRatio
:
g
roupRatio
,
GroupRatio
:
actualG
roupRatio
,
}
quota
:=
calculateAudioQuota
(
quotaInfo
)
...
...
@@ -189,7 +198,7 @@ func PostWssConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, mod
logContent
+=
", "
+
extraContent
}
other
:=
GenerateWssOtherInfo
(
ctx
,
relayInfo
,
usage
,
modelRatio
,
groupRatio
,
completionRatio
.
InexactFloat64
(),
audioRatio
.
InexactFloat64
(),
audioCompletionRatio
.
InexactFloat64
(),
modelPrice
)
completionRatio
.
InexactFloat64
(),
audioRatio
.
InexactFloat64
(),
audioCompletionRatio
.
InexactFloat64
(),
modelPrice
,
userGroupRatio
)
model
.
RecordConsumeLog
(
ctx
,
relayInfo
.
UserId
,
relayInfo
.
ChannelId
,
usage
.
InputTokens
,
usage
.
OutputTokens
,
logModel
,
tokenName
,
quota
,
logContent
,
relayInfo
.
TokenId
,
userQuota
,
int
(
useTimeSeconds
),
relayInfo
.
IsStream
,
relayInfo
.
Group
,
other
)
}
...
...
@@ -207,7 +216,7 @@ func PostClaudeConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo,
modelRatio
:=
priceData
.
ModelRatio
groupRatio
:=
priceData
.
GroupRatio
modelPrice
:=
priceData
.
ModelPrice
userGroupRatio
:=
priceData
.
UserGroupRatio
cacheRatio
:=
priceData
.
CacheRatio
cacheTokens
:=
usage
.
PromptTokensDetails
.
CachedTokens
...
...
@@ -256,7 +265,7 @@ func PostClaudeConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo,
}
other
:=
GenerateClaudeOtherInfo
(
ctx
,
relayInfo
,
modelRatio
,
groupRatio
,
completionRatio
,
cacheTokens
,
cacheRatio
,
cacheCreationTokens
,
cacheCreationRatio
,
modelPrice
)
cacheTokens
,
cacheRatio
,
cacheCreationTokens
,
cacheCreationRatio
,
modelPrice
,
userGroupRatio
)
model
.
RecordConsumeLog
(
ctx
,
relayInfo
.
UserId
,
relayInfo
.
ChannelId
,
promptTokens
,
completionTokens
,
modelName
,
tokenName
,
quota
,
logContent
,
relayInfo
.
TokenId
,
userQuota
,
int
(
useTimeSeconds
),
relayInfo
.
IsStream
,
relayInfo
.
Group
,
other
)
}
...
...
@@ -281,6 +290,12 @@ func PostAudioConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo,
modelPrice
:=
priceData
.
ModelPrice
usePrice
:=
priceData
.
UsePrice
actualGroupRatio
:=
groupRatio
userGroupRatio
,
ok
:=
setting
.
GetGroupGroupRatio
(
relayInfo
.
UserGroup
,
relayInfo
.
Group
)
if
ok
{
actualGroupRatio
=
userGroupRatio
}
quotaInfo
:=
QuotaInfo
{
InputDetails
:
TokenDetails
{
TextTokens
:
textInputTokens
,
...
...
@@ -293,7 +308,7 @@ func PostAudioConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo,
ModelName
:
relayInfo
.
OriginModelName
,
UsePrice
:
usePrice
,
ModelRatio
:
modelRatio
,
GroupRatio
:
g
roupRatio
,
GroupRatio
:
actualG
roupRatio
,
}
quota
:=
calculateAudioQuota
(
quotaInfo
)
...
...
@@ -333,7 +348,7 @@ func PostAudioConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo,
logContent
+=
", "
+
extraContent
}
other
:=
GenerateAudioOtherInfo
(
ctx
,
relayInfo
,
usage
,
modelRatio
,
groupRatio
,
completionRatio
.
InexactFloat64
(),
audioRatio
.
InexactFloat64
(),
audioCompletionRatio
.
InexactFloat64
(),
modelPrice
)
completionRatio
.
InexactFloat64
(),
audioRatio
.
InexactFloat64
(),
audioCompletionRatio
.
InexactFloat64
(),
modelPrice
,
userGroupRatio
)
model
.
RecordConsumeLog
(
ctx
,
relayInfo
.
UserId
,
relayInfo
.
ChannelId
,
usage
.
PromptTokens
,
usage
.
CompletionTokens
,
logModel
,
tokenName
,
quota
,
logContent
,
relayInfo
.
TokenId
,
userQuota
,
int
(
useTimeSeconds
),
relayInfo
.
IsStream
,
relayInfo
.
Group
,
other
)
}
...
...
setting/group_ratio.go
View file @
2a0bf7f9
...
...
@@ -14,10 +14,16 @@ var groupRatio = map[string]float64{
}
var
groupRatioMutex
sync
.
RWMutex
var
GroupGroupRatio
=
map
[
string
]
map
[
string
]
float64
{
"vip"
:
{
"edit_this"
:
0.9
,
},
}
func
GetGroupRatioCopy
()
map
[
string
]
float64
{
groupRatioMutex
.
RLock
()
defer
groupRatioMutex
.
RUnlock
()
groupRatioCopy
:=
make
(
map
[
string
]
float64
)
for
k
,
v
:=
range
groupRatio
{
groupRatioCopy
[
k
]
=
v
...
...
@@ -28,7 +34,7 @@ func GetGroupRatioCopy() map[string]float64 {
func
ContainsGroupRatio
(
name
string
)
bool
{
groupRatioMutex
.
RLock
()
defer
groupRatioMutex
.
RUnlock
()
_
,
ok
:=
groupRatio
[
name
]
return
ok
}
...
...
@@ -36,7 +42,7 @@ func ContainsGroupRatio(name string) bool {
func
GroupRatio2JSONString
()
string
{
groupRatioMutex
.
RLock
()
defer
groupRatioMutex
.
RUnlock
()
jsonBytes
,
err
:=
json
.
Marshal
(
groupRatio
)
if
err
!=
nil
{
common
.
SysError
(
"error marshalling model ratio: "
+
err
.
Error
())
...
...
@@ -47,7 +53,7 @@ func GroupRatio2JSONString() string {
func
UpdateGroupRatioByJSONString
(
jsonStr
string
)
error
{
groupRatioMutex
.
Lock
()
defer
groupRatioMutex
.
Unlock
()
groupRatio
=
make
(
map
[
string
]
float64
)
return
json
.
Unmarshal
([]
byte
(
jsonStr
),
&
groupRatio
)
}
...
...
@@ -55,7 +61,7 @@ func UpdateGroupRatioByJSONString(jsonStr string) error {
func
GetGroupRatio
(
name
string
)
float64
{
groupRatioMutex
.
RLock
()
defer
groupRatioMutex
.
RUnlock
()
ratio
,
ok
:=
groupRatio
[
name
]
if
!
ok
{
common
.
SysError
(
"group ratio not found: "
+
name
)
...
...
@@ -64,6 +70,31 @@ func GetGroupRatio(name string) float64 {
return
ratio
}
func
GetGroupGroupRatio
(
group
,
name
string
)
(
float64
,
bool
)
{
gp
,
ok
:=
GroupGroupRatio
[
group
]
if
!
ok
{
return
-
1
,
false
}
ratio
,
ok
:=
gp
[
name
]
if
!
ok
{
return
-
1
,
false
}
return
ratio
,
true
}
func
GroupGroupRatio2JSONString
()
string
{
jsonBytes
,
err
:=
json
.
Marshal
(
GroupGroupRatio
)
if
err
!=
nil
{
common
.
SysError
(
"error marshalling group-group ratio: "
+
err
.
Error
())
}
return
string
(
jsonBytes
)
}
func
UpdateGroupGroupRatioByJSONString
(
jsonStr
string
)
error
{
GroupGroupRatio
=
make
(
map
[
string
]
map
[
string
]
float64
)
return
json
.
Unmarshal
([]
byte
(
jsonStr
),
&
GroupGroupRatio
)
}
func
CheckGroupRatio
(
jsonStr
string
)
error
{
checkGroupRatio
:=
make
(
map
[
string
]
float64
)
err
:=
json
.
Unmarshal
([]
byte
(
jsonStr
),
&
checkGroupRatio
)
...
...
web/src/components/settings/OperationSetting.js
View file @
2a0bf7f9
...
...
@@ -30,6 +30,7 @@ const OperationSetting = () => {
CompletionRatio
:
''
,
ModelPrice
:
''
,
GroupRatio
:
''
,
GroupGroupRatio
:
''
,
UserUsableGroups
:
''
,
TopUpLink
:
''
,
'general_setting.docs_link'
:
''
,
...
...
@@ -74,6 +75,7 @@ const OperationSetting = () => {
if
(
item
.
key
===
'ModelRatio'
||
item
.
key
===
'GroupRatio'
||
item
.
key
===
'GroupGroupRatio'
||
item
.
key
===
'UserUsableGroups'
||
item
.
key
===
'CompletionRatio'
||
item
.
key
===
'ModelPrice'
||
...
...
web/src/components/table/LogsTable.js
View file @
2a0bf7f9
...
...
@@ -20,7 +20,7 @@ import {
renderQuota
,
stringToColor
,
getLogOther
,
renderModelTag
renderModelTag
,
}
from
'../../helpers'
;
import
{
...
...
@@ -39,11 +39,11 @@ import {
Card
,
Typography
,
Divider
,
Form
Form
,
}
from
'@douyinfe/semi-ui'
;
import
{
IllustrationNoResult
,
IllustrationNoResultDark
IllustrationNoResultDark
,
}
from
'@douyinfe/semi-illustrations'
;
import
{
ITEMS_PER_PAGE
}
from
'../../constants'
;
import
Paragraph
from
'@douyinfe/semi-ui/lib/es/typography/paragraph'
;
...
...
@@ -192,7 +192,7 @@ const LogsTable = () => {
if
(
!
modelMapped
)
{
return
renderModelTag
(
record
.
model_name
,
{
onClick
:
(
event
)
=>
{
copyText
(
event
,
record
.
model_name
).
then
((
r
)
=>
{
});
copyText
(
event
,
record
.
model_name
).
then
((
r
)
=>
{});
},
});
}
else
{
...
...
@@ -209,7 +209,7 @@ const LogsTable = () => {
<
/Text
>
{
renderModelTag
(
record
.
model_name
,
{
onClick
:
(
event
)
=>
{
copyText
(
event
,
record
.
model_name
).
then
((
r
)
=>
{
});
copyText
(
event
,
record
.
model_name
).
then
((
r
)
=>
{});
},
})}
<
/div
>
...
...
@@ -220,7 +220,7 @@ const LogsTable = () => {
{
renderModelTag
(
other
.
upstream_model_name
,
{
onClick
:
(
event
)
=>
{
copyText
(
event
,
other
.
upstream_model_name
).
then
(
(
r
)
=>
{
},
(
r
)
=>
{},
);
},
})}
...
...
@@ -231,7 +231,7 @@ const LogsTable = () => {
>
{
renderModelTag
(
record
.
model_name
,
{
onClick
:
(
event
)
=>
{
copyText
(
event
,
record
.
model_name
).
then
((
r
)
=>
{
});
copyText
(
event
,
record
.
model_name
).
then
((
r
)
=>
{});
},
suffixIcon
:
(
<
Route
...
...
@@ -598,21 +598,23 @@ const LogsTable = () => {
}
let
content
=
other
?.
claude
?
renderClaudeModelPriceSimple
(
other
.
model_ratio
,
other
.
model_price
,
other
.
group_ratio
,
other
.
cache_tokens
||
0
,
other
.
cache_ratio
||
1.0
,
other
.
cache_creation_tokens
||
0
,
other
.
cache_creation_ratio
||
1.0
,
)
other
.
model_ratio
,
other
.
model_price
,
other
.
group_ratio
,
other
?.
user_group_ratio
,
other
.
cache_tokens
||
0
,
other
.
cache_ratio
||
1.0
,
other
.
cache_creation_tokens
||
0
,
other
.
cache_creation_ratio
||
1.0
,
)
:
renderModelPriceSimple
(
other
.
model_ratio
,
other
.
model_price
,
other
.
group_ratio
,
other
.
cache_tokens
||
0
,
other
.
cache_ratio
||
1.0
,
);
other
.
model_ratio
,
other
.
model_price
,
other
.
group_ratio
,
other
?.
user_group_ratio
,
other
.
cache_tokens
||
0
,
other
.
cache_ratio
||
1.0
,
);
return
(
<
Paragraph
ellipsis
=
{{
...
...
@@ -742,7 +744,7 @@ const LogsTable = () => {
group
:
''
,
dateRange
:
[
timestamp2string
(
getTodayStartTimestamp
()),
timestamp2string
(
now
.
getTime
()
/
1000
+
3600
)
timestamp2string
(
now
.
getTime
()
/
1000
+
3600
)
,
],
logType
:
'0'
,
};
...
...
@@ -763,7 +765,11 @@ const LogsTable = () => {
let
start_timestamp
=
timestamp2string
(
getTodayStartTimestamp
());
let
end_timestamp
=
timestamp2string
(
now
.
getTime
()
/
1000
+
3600
);
if
(
formValues
.
dateRange
&&
Array
.
isArray
(
formValues
.
dateRange
)
&&
formValues
.
dateRange
.
length
===
2
)
{
if
(
formValues
.
dateRange
&&
Array
.
isArray
(
formValues
.
dateRange
)
&&
formValues
.
dateRange
.
length
===
2
)
{
start_timestamp
=
formValues
.
dateRange
[
0
];
end_timestamp
=
formValues
.
dateRange
[
1
];
}
...
...
@@ -941,27 +947,28 @@ const LogsTable = () => {
key
:
t
(
'日志详情'
),
value
:
other
?.
claude
?
renderClaudeLogContent
(
other
?.
model_ratio
,
other
.
completion_ratio
,
other
.
model_price
,
other
.
group_ratio
,
other
.
cache_ratio
||
1.0
,
other
.
cache_creation_ratio
||
1.0
,
)
other
?.
model_ratio
,
other
.
completion_ratio
,
other
.
model_price
,
other
.
group_ratio
,
other
?.
user_group_ratio
,
other
.
cache_ratio
||
1.0
,
other
.
cache_creation_ratio
||
1.0
,
)
:
renderLogContent
(
other
?.
model_ratio
,
other
.
completion_ratio
,
other
.
model_price
,
other
.
group_ratio
,
other
?.
user_group_ratio
,
false
,
1.0
,
undefined
,
other
.
web_search
||
false
,
other
.
web_search_call_count
||
0
,
other
.
file_search
||
false
,
other
.
file_search_call_count
||
0
,
),
other
?.
model_ratio
,
other
.
completion_ratio
,
other
.
model_price
,
other
.
group_ratio
,
other
?.
user_group_ratio
,
false
,
1.0
,
undefined
,
other
.
web_search
||
false
,
other
.
web_search_call_count
||
0
,
other
.
file_search
||
false
,
other
.
file_search_call_count
||
0
,
),
});
}
if
(
logs
[
i
].
type
===
2
)
{
...
...
@@ -992,6 +999,7 @@ const LogsTable = () => {
other
?.
audio_ratio
,
other
?.
audio_completion_ratio
,
other
?.
group_ratio
,
other
?.
user_group_ratio
,
other
?.
cache_tokens
||
0
,
other
?.
cache_ratio
||
1.0
,
);
...
...
@@ -1003,6 +1011,7 @@ const LogsTable = () => {
other
.
model_price
,
other
.
completion_ratio
,
other
.
group_ratio
,
other
?.
user_group_ratio
,
other
.
cache_tokens
||
0
,
other
.
cache_ratio
||
1.0
,
other
.
cache_creation_tokens
||
0
,
...
...
@@ -1016,6 +1025,7 @@ const LogsTable = () => {
other
?.
model_price
,
other
?.
completion_ratio
,
other
?.
group_ratio
,
other
?.
user_group_ratio
,
other
?.
cache_tokens
||
0
,
other
?.
cache_ratio
||
1.0
,
other
?.
image
||
false
,
...
...
@@ -1066,7 +1076,12 @@ const LogsTable = () => {
}
=
getFormValues
();
// 使用传入的 logType 或者表单中的 logType 或者状态中的 logType
const
currentLogType
=
customLogType
!==
null
?
customLogType
:
formLogType
!==
undefined
?
formLogType
:
logType
;
const
currentLogType
=
customLogType
!==
null
?
customLogType
:
formLogType
!==
undefined
?
formLogType
:
logType
;
let
localStartTimestamp
=
Date
.
parse
(
start_timestamp
)
/
1000
;
let
localEndTimestamp
=
Date
.
parse
(
end_timestamp
)
/
1000
;
...
...
@@ -1093,7 +1108,7 @@ const LogsTable = () => {
const
handlePageChange
=
(
page
)
=>
{
setActivePage
(
page
);
loadLogs
(
page
,
pageSize
).
then
((
r
)
=>
{
});
// 不传入logType,让其从表单获取最新值
loadLogs
(
page
,
pageSize
).
then
((
r
)
=>
{});
// 不传入logType,让其从表单获取最新值
};
const
handlePageSizeChange
=
async
(
size
)
=>
{
...
...
@@ -1208,9 +1223,9 @@ const LogsTable = () => {
getFormApi
=
{(
api
)
=>
setFormApi
(
api
)}
onSubmit
=
{
refresh
}
allowEmpty
=
{
true
}
autoComplete
=
"off"
layout
=
"vertical"
trigger
=
"change"
autoComplete
=
'off'
layout
=
'vertical'
trigger
=
'change'
stopValidateWithError
=
{
false
}
>
<
div
className
=
'flex flex-col gap-4'
>
...
...
@@ -1294,12 +1309,24 @@ const LogsTable = () => {
},
0
);
}}
>
<
Form
.
Select
.
Option
value
=
'0'
>
{
t
(
'全部'
)}
<
/Form.Select.Option
>
<
Form
.
Select
.
Option
value
=
'1'
>
{
t
(
'充值'
)}
<
/Form.Select.Option
>
<
Form
.
Select
.
Option
value
=
'2'
>
{
t
(
'消费'
)}
<
/Form.Select.Option
>
<
Form
.
Select
.
Option
value
=
'3'
>
{
t
(
'管理'
)}
<
/Form.Select.Option
>
<
Form
.
Select
.
Option
value
=
'4'
>
{
t
(
'系统'
)}
<
/Form.Select.Option
>
<
Form
.
Select
.
Option
value
=
'5'
>
{
t
(
'错误'
)}
<
/Form.Select.Option
>
<
Form
.
Select
.
Option
value
=
'0'
>
{
t
(
'全部'
)}
<
/Form.Select.Option
>
<
Form
.
Select
.
Option
value
=
'1'
>
{
t
(
'充值'
)}
<
/Form.Select.Option
>
<
Form
.
Select
.
Option
value
=
'2'
>
{
t
(
'消费'
)}
<
/Form.Select.Option
>
<
Form
.
Select
.
Option
value
=
'3'
>
{
t
(
'管理'
)}
<
/Form.Select.Option
>
<
Form
.
Select
.
Option
value
=
'4'
>
{
t
(
'系统'
)}
<
/Form.Select.Option
>
<
Form
.
Select
.
Option
value
=
'5'
>
{
t
(
'错误'
)}
<
/Form.Select.Option
>
<
/Form.Select
>
<
/div
>
...
...
@@ -1351,7 +1378,8 @@ const LogsTable = () => {
{...(
hasExpandableRows
()
&&
{
expandedRowRender
:
expandRowRender
,
expandRowByClick
:
true
,
rowExpandable
:
(
record
)
=>
expandData
[
record
.
key
]
&&
expandData
[
record
.
key
].
length
>
0
rowExpandable
:
(
record
)
=>
expandData
[
record
.
key
]
&&
expandData
[
record
.
key
].
length
>
0
,
})}
dataSource
=
{
logs
}
rowKey
=
'key'
...
...
@@ -1361,8 +1389,12 @@ const LogsTable = () => {
size
=
'middle'
empty
=
{
<
Empty
image
=
{
<
IllustrationNoResult
style
=
{{
width
:
150
,
height
:
150
}}
/>
}
darkModeImage
=
{
<
IllustrationNoResultDark
style
=
{{
width
:
150
,
height
:
150
}}
/>
}
image
=
{
<
IllustrationNoResult
style
=
{{
width
:
150
,
height
:
150
}}
/
>
}
darkModeImage
=
{
<
IllustrationNoResultDark
style
=
{{
width
:
150
,
height
:
150
}}
/
>
}
description
=
{
t
(
'搜索无结果'
)}
style
=
{{
padding
:
30
}}
/
>
...
...
web/src/helpers/render.js
View file @
2a0bf7f9
...
...
@@ -30,7 +30,7 @@ import {
Dify
,
Coze
,
SiliconCloud
,
FastGPT
FastGPT
,
}
from
'@lobehub/icons'
;
import
{
...
...
@@ -46,7 +46,7 @@ import {
Gift
,
User
,
Settings
,
CircleUser
CircleUser
,
}
from
'lucide-react'
;
// 侧边栏图标颜色映射
...
...
@@ -315,7 +315,6 @@ export const getModelCategories = (() => {
};
})();
/**
* 根据渠道类型返回对应的厂商图标
* @param {number} channelType - 渠道类型值
...
...
@@ -868,6 +867,10 @@ export function renderQuota(quota, digits = 2) {
return
renderNumber
(
quota
);
}
function
isValidGroupRatio
(
ratio
)
{
return
ratio
!==
undefined
&&
ratio
!==
null
&&
ratio
!==
-
1
;
}
export
function
renderModelPrice
(
inputTokens
,
completionTokens
,
...
...
@@ -875,6 +878,7 @@ export function renderModelPrice(
modelPrice
=
-
1
,
completionRatio
,
groupRatio
,
user_group_ratio
,
cacheTokens
=
0
,
cacheRatio
=
1.0
,
image
=
false
,
...
...
@@ -890,13 +894,19 @@ export function renderModelPrice(
audioInputTokens
=
0
,
audioInputPrice
=
0
,
)
{
const
useUserGroupRatio
=
isValidGroupRatio
(
user_group_ratio
);
const
ratioLabel
=
useUserGroupRatio
?
i18next
.
t
(
'专属倍率'
)
:
i18next
.
t
(
'分组倍率'
);
groupRatio
=
useUserGroupRatio
?
user_group_ratio
:
groupRatio
;
if
(
modelPrice
!==
-
1
)
{
return
i18next
.
t
(
'模型价格:${{price}} *
分组倍率
:{{ratio}} = ${{total}}'
,
'模型价格:${{price}} *
{{ratioType}}
:{{ratio}} = ${{total}}'
,
{
price
:
modelPrice
,
ratio
:
groupRatio
,
total
:
modelPrice
*
groupRatio
,
ratioType
:
ratioLabel
,
},
);
}
else
{
...
...
@@ -1033,11 +1043,12 @@ export function renderModelPrice(
// 构建输出部分描述
const
outputDesc
=
i18next
.
t
(
'输出 {{completion}} tokens / 1M tokens * ${{compPrice}}) *
分组倍率
{{ratio}}'
,
'输出 {{completion}} tokens / 1M tokens * ${{compPrice}}) *
{{ratioType}}
{{ratio}}'
,
{
completion
:
completionTokens
,
compPrice
:
completionRatioPrice
,
ratio
:
groupRatio
,
ratioType
:
ratioLabel
,
},
);
...
...
@@ -1045,23 +1056,25 @@ export function renderModelPrice(
const
extraServices
=
[
webSearch
&&
webSearchCallCount
>
0
?
i18next
.
t
(
' + Web搜索 {{count}}次 / 1K 次 * ${{price}} * 分组倍率 {{ratio}}'
,
{
count
:
webSearchCallCount
,
price
:
webSearchPrice
,
ratio
:
groupRatio
,
},
)
' + Web搜索 {{count}}次 / 1K 次 * ${{price}} * {{ratioType}} {{ratio}}'
,
{
count
:
webSearchCallCount
,
price
:
webSearchPrice
,
ratio
:
groupRatio
,
ratioType
:
ratioLabel
,
},
)
:
''
,
fileSearch
&&
fileSearchCallCount
>
0
?
i18next
.
t
(
' + 文件搜索 {{count}}次 / 1K 次 * ${{price}} * 分组倍率 {{ratio}}'
,
{
count
:
fileSearchCallCount
,
price
:
fileSearchPrice
,
ratio
:
groupRatio
,
},
)
' + 文件搜索 {{count}}次 / 1K 次 * ${{price}} * {{ratioType}} {{ratio}}'
,
{
count
:
fileSearchCallCount
,
price
:
fileSearchPrice
,
ratio
:
groupRatio
,
ratioType
:
ratioLabel
,
},
)
:
''
,
].
join
(
''
);
...
...
@@ -1097,6 +1110,7 @@ export function renderLogContent(
fileSearch
=
false
,
fileSearchCallCount
=
0
,
)
{
useUserGroupRatio
=
isValidGroupRatio
(
user_group_ratio
);
const
ratioLabel
=
useUserGroupRatio
?
i18next
.
t
(
'专属倍率'
)
:
i18next
.
t
(
'分组倍率'
);
...
...
@@ -1149,14 +1163,21 @@ export function renderModelPriceSimple(
modelRatio
,
modelPrice
=
-
1
,
groupRatio
,
user_group_ratio
,
cacheTokens
=
0
,
cacheRatio
=
1.0
,
image
=
false
,
imageRatio
=
1.0
,
)
{
const
useUserGroupRatio
=
isValidGroupRatio
(
user_group_ratio
);
const
ratioLabel
=
useUserGroupRatio
?
i18next
.
t
(
'专属倍率'
)
:
i18next
.
t
(
'分组倍率'
);
groupRatio
=
useUserGroupRatio
?
user_group_ratio
:
groupRatio
;
if
(
modelPrice
!==
-
1
)
{
return
i18next
.
t
(
'价格:${{price}} *
分组
:{{ratio}}'
,
{
return
i18next
.
t
(
'价格:${{price}} *
{{ratioType}}
:{{ratio}}'
,
{
price
:
modelPrice
,
ratioType
:
ratioLabel
,
ratio
:
groupRatio
,
});
}
else
{
...
...
@@ -1191,8 +1212,9 @@ export function renderModelPriceSimple(
},
);
}
else
{
return
i18next
.
t
(
'模型: {{ratio}} *
分组:
{{groupRatio}}'
,
{
return
i18next
.
t
(
'模型: {{ratio}} *
{{ratioType}}:
{{groupRatio}}'
,
{
ratio
:
modelRatio
,
ratioType
:
ratioLabel
,
groupRatio
:
groupRatio
,
});
}
...
...
@@ -1210,17 +1232,24 @@ export function renderAudioModelPrice(
audioRatio
,
audioCompletionRatio
,
groupRatio
,
user_group_ratio
,
cacheTokens
=
0
,
cacheRatio
=
1.0
,
)
{
const
useUserGroupRatio
=
isValidGroupRatio
(
user_group_ratio
);
const
ratioLabel
=
useUserGroupRatio
?
i18next
.
t
(
'专属倍率'
)
:
i18next
.
t
(
'分组倍率'
);
groupRatio
=
useUserGroupRatio
?
user_group_ratio
:
groupRatio
;
// 1 ratio = $0.002 / 1K tokens
if
(
modelPrice
!==
-
1
)
{
return
i18next
.
t
(
'模型价格:${{price}} *
分组倍率
:{{ratio}} = ${{total}}'
,
'模型价格:${{price}} *
{{ratioType}}
:{{ratio}} = ${{total}}'
,
{
price
:
modelPrice
,
ratio
:
groupRatio
,
total
:
modelPrice
*
groupRatio
,
ratioType
:
ratioLabel
,
},
);
}
else
{
...
...
@@ -1245,10 +1274,10 @@ export function renderAudioModelPrice(
let
audioPrice
=
(
audioInputTokens
/
1000000
)
*
inputRatioPrice
*
audioRatio
*
groupRatio
+
(
audioCompletionTokens
/
1000000
)
*
inputRatioPrice
*
audioRatio
*
audioCompletionRatio
*
groupRatio
;
inputRatioPrice
*
audioRatio
*
audioCompletionRatio
*
groupRatio
;
let
price
=
textPrice
+
audioPrice
;
return
(
<>
...
...
@@ -1304,27 +1333,27 @@ export function renderAudioModelPrice(
<
p
>
{
cacheTokens
>
0
?
i18next
.
t
(
'文字提示 {{nonCacheInput}} tokens / 1M tokens * ${{price}} + 缓存 {{cacheInput}} tokens / 1M tokens * ${{cachePrice}} + 文字补全 {{completion}} tokens / 1M tokens * ${{compPrice}} = ${{total}}'
,
{
nonCacheInput
:
inputTokens
-
cacheTokens
,
cacheInput
:
cacheTokens
,
cachePrice
:
inputRatioPrice
*
cacheRatio
,
price
:
inputRatioPrice
,
completion
:
completionTokens
,
compPrice
:
completionRatioPrice
,
total
:
textPrice
.
toFixed
(
6
),
},
)
'文字提示 {{nonCacheInput}} tokens / 1M tokens * ${{price}} + 缓存 {{cacheInput}} tokens / 1M tokens * ${{cachePrice}} + 文字补全 {{completion}} tokens / 1M tokens * ${{compPrice}} = ${{total}}'
,
{
nonCacheInput
:
inputTokens
-
cacheTokens
,
cacheInput
:
cacheTokens
,
cachePrice
:
inputRatioPrice
*
cacheRatio
,
price
:
inputRatioPrice
,
completion
:
completionTokens
,
compPrice
:
completionRatioPrice
,
total
:
textPrice
.
toFixed
(
6
),
},
)
:
i18next
.
t
(
'文字提示 {{input}} tokens / 1M tokens * ${{price}} + 文字补全 {{completion}} tokens / 1M tokens * ${{compPrice}} = ${{total}}'
,
{
input
:
inputTokens
,
price
:
inputRatioPrice
,
completion
:
completionTokens
,
compPrice
:
completionRatioPrice
,
total
:
textPrice
.
toFixed
(
6
),
},
)}
'文字提示 {{input}} tokens / 1M tokens * ${{price}} + 文字补全 {{completion}} tokens / 1M tokens * ${{compPrice}} = ${{total}}'
,
{
input
:
inputTokens
,
price
:
inputRatioPrice
,
completion
:
completionTokens
,
compPrice
:
completionRatioPrice
,
total
:
textPrice
.
toFixed
(
6
),
},
)}
<
/p
>
<
p
>
{
i18next
.
t
(
...
...
@@ -1374,12 +1403,17 @@ export function renderClaudeModelPrice(
modelPrice
=
-
1
,
completionRatio
,
groupRatio
,
user_group_ratio
,
cacheTokens
=
0
,
cacheRatio
=
1.0
,
cacheCreationTokens
=
0
,
cacheCreationRatio
=
1.0
,
)
{
const
ratioLabel
=
false
?
i18next
.
t
(
'专属倍率'
)
:
i18next
.
t
(
'分组倍率'
);
const
useUserGroupRatio
=
isValidGroupRatio
(
user_group_ratio
);
const
ratioLabel
=
useUserGroupRatio
?
i18next
.
t
(
'专属倍率'
)
:
i18next
.
t
(
'分组倍率'
);
groupRatio
=
useUserGroupRatio
?
user_group_ratio
:
groupRatio
;
if
(
modelPrice
!==
-
1
)
{
return
i18next
.
t
(
...
...
@@ -1461,33 +1495,35 @@ export function renderClaudeModelPrice(
<
p
>
{
cacheTokens
>
0
||
cacheCreationTokens
>
0
?
i18next
.
t
(
'提示 {{nonCacheInput}} tokens / 1M tokens * ${{price}} + 缓存 {{cacheInput}} tokens / 1M tokens * ${{cachePrice}} + 缓存创建 {{cacheCreationInput}} tokens / 1M tokens * ${{cacheCreationPrice}} + 补全 {{completion}} tokens / 1M tokens * ${{compPrice}} * 分组 {{ratio}} = ${{total}}'
,
{
nonCacheInput
:
nonCachedTokens
,
cacheInput
:
cacheTokens
,
cacheRatio
:
cacheRatio
,
cacheCreationInput
:
cacheCreationTokens
,
cacheCreationRatio
:
cacheCreationRatio
,
cachePrice
:
cacheRatioPrice
,
cacheCreationPrice
:
cacheCreationRatioPrice
,
price
:
inputRatioPrice
,
completion
:
completionTokens
,
compPrice
:
completionRatioPrice
,
ratio
:
groupRatio
,
total
:
price
.
toFixed
(
6
),
},
)
'提示 {{nonCacheInput}} tokens / 1M tokens * ${{price}} + 缓存 {{cacheInput}} tokens / 1M tokens * ${{cachePrice}} + 缓存创建 {{cacheCreationInput}} tokens / 1M tokens * ${{cacheCreationPrice}} + 补全 {{completion}} tokens / 1M tokens * ${{compPrice}} * {{ratioType}} {{ratio}} = ${{total}}'
,
{
nonCacheInput
:
nonCachedTokens
,
cacheInput
:
cacheTokens
,
cacheRatio
:
cacheRatio
,
cacheCreationInput
:
cacheCreationTokens
,
cacheCreationRatio
:
cacheCreationRatio
,
cachePrice
:
cacheRatioPrice
,
cacheCreationPrice
:
cacheCreationRatioPrice
,
price
:
inputRatioPrice
,
completion
:
completionTokens
,
compPrice
:
completionRatioPrice
,
ratio
:
groupRatio
,
ratioType
:
ratioLabel
,
total
:
price
.
toFixed
(
6
),
},
)
:
i18next
.
t
(
'提示 {{input}} tokens / 1M tokens * ${{price}} + 补全 {{completion}} tokens / 1M tokens * ${{compPrice}} * 分组 {{ratio}} = ${{total}}'
,
{
input
:
inputTokens
,
price
:
inputRatioPrice
,
completion
:
completionTokens
,
compPrice
:
completionRatioPrice
,
ratio
:
groupRatio
,
total
:
price
.
toFixed
(
6
),
},
)}
'提示 {{input}} tokens / 1M tokens * ${{price}} + 补全 {{completion}} tokens / 1M tokens * ${{compPrice}} * {{ratioType}} {{ratio}} = ${{total}}'
,
{
input
:
inputTokens
,
price
:
inputRatioPrice
,
completion
:
completionTokens
,
compPrice
:
completionRatioPrice
,
ratio
:
groupRatio
,
ratioType
:
ratioLabel
,
total
:
price
.
toFixed
(
6
),
},
)}
<
/p
>
<
p
>
{
i18next
.
t
(
'仅供参考,以实际扣费为准'
)}
<
/p
>
<
/article
>
...
...
@@ -1501,10 +1537,15 @@ export function renderClaudeLogContent(
completionRatio
,
modelPrice
=
-
1
,
groupRatio
,
user_group_ratio
,
cacheRatio
=
1.0
,
cacheCreationRatio
=
1.0
,
)
{
const
ratioLabel
=
false
?
i18next
.
t
(
'专属倍率'
)
:
i18next
.
t
(
'分组倍率'
);
const
useUserGroupRatio
=
isValidGroupRatio
(
user_group_ratio
);
const
ratioLabel
=
useUserGroupRatio
?
i18next
.
t
(
'专属倍率'
)
:
i18next
.
t
(
'分组倍率'
);
groupRatio
=
useUserGroupRatio
?
user_group_ratio
:
groupRatio
;
if
(
modelPrice
!==
-
1
)
{
return
i18next
.
t
(
'模型价格 ${{price}},{{ratioType}} {{ratio}}'
,
{
...
...
@@ -1531,12 +1572,17 @@ export function renderClaudeModelPriceSimple(
modelRatio
,
modelPrice
=
-
1
,
groupRatio
,
user_group_ratio
,
cacheTokens
=
0
,
cacheRatio
=
1.0
,
cacheCreationTokens
=
0
,
cacheCreationRatio
=
1.0
,
)
{
const
ratioLabel
=
false
?
i18next
.
t
(
'专属倍率'
)
:
i18next
.
t
(
'分组'
);
const
useUserGroupRatio
=
isValidGroupRatio
(
user_group_ratio
);
const
ratioLabel
=
useUserGroupRatio
?
i18next
.
t
(
'专属倍率'
)
:
i18next
.
t
(
'分组倍率'
);
groupRatio
=
useUserGroupRatio
?
user_group_ratio
:
groupRatio
;
if
(
modelPrice
!==
-
1
)
{
return
i18next
.
t
(
'价格:${{price}} * {{ratioType}}:{{ratio}}'
,
{
...
...
web/src/pages/Setting/Operation/GroupRatioSettings.js
View file @
2a0bf7f9
...
...
@@ -16,6 +16,7 @@ export default function GroupRatioSettings(props) {
const
[
inputs
,
setInputs
]
=
useState
({
GroupRatio
:
''
,
UserUsableGroups
:
''
,
GroupGroupRatio
:
''
,
});
const
refForm
=
useRef
();
const
[
inputsRow
,
setInputsRow
]
=
useState
(
inputs
);
...
...
@@ -136,6 +137,27 @@ export default function GroupRatioSettings(props) {
/
>
<
/Col
>
<
/Row
>
<
Row
gutter
=
{
16
}
>
<
Col
xs
=
{
24
}
sm
=
{
16
}
>
<
Form
.
TextArea
label
=
{
t
(
'分组特殊倍率'
)}
placeholder
=
{
t
(
'为一个 JSON 文本'
)}
field
=
{
'GroupGroupRatio'
}
autosize
=
{{
minRows
:
6
,
maxRows
:
12
}}
trigger
=
'blur'
stopValidateWithError
rules
=
{[
{
validator
:
(
rule
,
value
)
=>
verifyJSON
(
value
),
message
:
t
(
'不是合法的 JSON 字符串'
),
},
]}
onChange
=
{(
value
)
=>
setInputs
({
...
inputs
,
GroupGroupRatio
:
value
})
}
/
>
<
/Col
>
<
/Row
>
<
/Form.Section
>
<
/Form
>
<
Button
onClick
=
{
onSubmit
}
>
{
t
(
'保存分组倍率设置'
)}
<
/Button
>
...
...
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