Merge remote-tracking branch 'origin/alpha' into alpha
This commit is contained in:
@@ -52,6 +52,14 @@ func GetAllChannels(c *gin.Context) {
|
|||||||
channelData := make([]*model.Channel, 0)
|
channelData := make([]*model.Channel, 0)
|
||||||
idSort, _ := strconv.ParseBool(c.Query("id_sort"))
|
idSort, _ := strconv.ParseBool(c.Query("id_sort"))
|
||||||
enableTagMode, _ := strconv.ParseBool(c.Query("tag_mode"))
|
enableTagMode, _ := strconv.ParseBool(c.Query("tag_mode"))
|
||||||
|
// type filter
|
||||||
|
typeStr := c.Query("type")
|
||||||
|
typeFilter := -1
|
||||||
|
if typeStr != "" {
|
||||||
|
if t, err := strconv.Atoi(typeStr); err == nil {
|
||||||
|
typeFilter = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var total int64
|
var total int64
|
||||||
|
|
||||||
@@ -72,6 +80,14 @@ func GetAllChannels(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
// 计算 tag 总数用于分页
|
// 计算 tag 总数用于分页
|
||||||
total, _ = model.CountAllTags()
|
total, _ = model.CountAllTags()
|
||||||
|
} else if typeFilter >= 0 {
|
||||||
|
channels, err := model.GetChannelsByType((p-1)*pageSize, pageSize, idSort, typeFilter)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
channelData = channels
|
||||||
|
total, _ = model.CountChannelsByType(typeFilter)
|
||||||
} else {
|
} else {
|
||||||
channels, err := model.GetAllChannels((p-1)*pageSize, pageSize, false, idSort)
|
channels, err := model.GetAllChannels((p-1)*pageSize, pageSize, false, idSort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -82,14 +98,18 @@ func GetAllChannels(c *gin.Context) {
|
|||||||
total, _ = model.CountAllChannels()
|
total, _ = model.CountAllChannels()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// calculate type counts
|
||||||
|
typeCounts, _ := model.CountChannelsGroupByType()
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"success": true,
|
"success": true,
|
||||||
"message": "",
|
"message": "",
|
||||||
"data": gin.H{
|
"data": gin.H{
|
||||||
"items": channelData,
|
"items": channelData,
|
||||||
"total": total,
|
"total": total,
|
||||||
"page": p,
|
"page": p,
|
||||||
"page_size": pageSize,
|
"page_size": pageSize,
|
||||||
|
"type_counts": typeCounts,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -4,13 +4,14 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"one-api/model"
|
"one-api/model"
|
||||||
"one-api/setting"
|
"one-api/setting"
|
||||||
|
"one-api/setting/ratio_setting"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetGroups(c *gin.Context) {
|
func GetGroups(c *gin.Context) {
|
||||||
groupNames := make([]string, 0)
|
groupNames := make([]string, 0)
|
||||||
for groupName, _ := range setting.GetGroupRatioCopy() {
|
for groupName := range ratio_setting.GetGroupRatioCopy() {
|
||||||
groupNames = append(groupNames, groupName)
|
groupNames = append(groupNames, groupName)
|
||||||
}
|
}
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
@@ -25,7 +26,7 @@ func GetUserGroups(c *gin.Context) {
|
|||||||
userGroup := ""
|
userGroup := ""
|
||||||
userId := c.GetInt("id")
|
userId := c.GetInt("id")
|
||||||
userGroup, _ = model.GetUserGroup(userId, false)
|
userGroup, _ = model.GetUserGroup(userId, false)
|
||||||
for groupName, ratio := range setting.GetGroupRatioCopy() {
|
for groupName, ratio := range ratio_setting.GetGroupRatioCopy() {
|
||||||
// UserUsableGroups contains the groups that the user can use
|
// UserUsableGroups contains the groups that the user can use
|
||||||
userUsableGroups := setting.GetUserUsableGroups(userGroup)
|
userUsableGroups := setting.GetUserUsableGroups(userGroup)
|
||||||
if desc, ok := userUsableGroups[groupName]; ok {
|
if desc, ok := userUsableGroups[groupName]; ok {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"one-api/model"
|
"one-api/model"
|
||||||
"one-api/setting"
|
"one-api/setting"
|
||||||
"one-api/setting/console_setting"
|
"one-api/setting/console_setting"
|
||||||
|
"one-api/setting/ratio_setting"
|
||||||
"one-api/setting/system_setting"
|
"one-api/setting/system_setting"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -103,7 +104,7 @@ func UpdateOption(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
case "GroupRatio":
|
case "GroupRatio":
|
||||||
err = setting.CheckGroupRatio(option.Value)
|
err = ratio_setting.CheckGroupRatio(option.Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"success": false,
|
"success": false,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package controller
|
|||||||
import (
|
import (
|
||||||
"one-api/model"
|
"one-api/model"
|
||||||
"one-api/setting"
|
"one-api/setting"
|
||||||
"one-api/setting/operation_setting"
|
"one-api/setting/ratio_setting"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
@@ -13,7 +13,7 @@ func GetPricing(c *gin.Context) {
|
|||||||
userId, exists := c.Get("id")
|
userId, exists := c.Get("id")
|
||||||
usableGroup := map[string]string{}
|
usableGroup := map[string]string{}
|
||||||
groupRatio := map[string]float64{}
|
groupRatio := map[string]float64{}
|
||||||
for s, f := range setting.GetGroupRatioCopy() {
|
for s, f := range ratio_setting.GetGroupRatioCopy() {
|
||||||
groupRatio[s] = f
|
groupRatio[s] = f
|
||||||
}
|
}
|
||||||
var group string
|
var group string
|
||||||
@@ -22,7 +22,7 @@ func GetPricing(c *gin.Context) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
group = user.Group
|
group = user.Group
|
||||||
for g := range groupRatio {
|
for g := range groupRatio {
|
||||||
ratio, ok := setting.GetGroupGroupRatio(group, g)
|
ratio, ok := ratio_setting.GetGroupGroupRatio(group, g)
|
||||||
if ok {
|
if ok {
|
||||||
groupRatio[g] = ratio
|
groupRatio[g] = ratio
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,7 @@ func GetPricing(c *gin.Context) {
|
|||||||
|
|
||||||
usableGroup = setting.GetUserUsableGroups(group)
|
usableGroup = setting.GetUserUsableGroups(group)
|
||||||
// check groupRatio contains usableGroup
|
// check groupRatio contains usableGroup
|
||||||
for group := range setting.GetGroupRatioCopy() {
|
for group := range ratio_setting.GetGroupRatioCopy() {
|
||||||
if _, ok := usableGroup[group]; !ok {
|
if _, ok := usableGroup[group]; !ok {
|
||||||
delete(groupRatio, group)
|
delete(groupRatio, group)
|
||||||
}
|
}
|
||||||
@@ -47,7 +47,7 @@ func GetPricing(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ResetModelRatio(c *gin.Context) {
|
func ResetModelRatio(c *gin.Context) {
|
||||||
defaultStr := operation_setting.DefaultModelRatio2JSONString()
|
defaultStr := ratio_setting.DefaultModelRatio2JSONString()
|
||||||
err := model.UpdateOption("ModelRatio", defaultStr)
|
err := model.UpdateOption("ModelRatio", defaultStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(200, gin.H{
|
c.JSON(200, gin.H{
|
||||||
@@ -56,7 +56,7 @@ func ResetModelRatio(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = operation_setting.UpdateModelRatioByJSONString(defaultStr)
|
err = ratio_setting.UpdateModelRatioByJSONString(defaultStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(200, gin.H{
|
c.JSON(200, gin.H{
|
||||||
"success": false,
|
"success": false,
|
||||||
|
|||||||
4
main.go
4
main.go
@@ -12,7 +12,7 @@ import (
|
|||||||
"one-api/model"
|
"one-api/model"
|
||||||
"one-api/router"
|
"one-api/router"
|
||||||
"one-api/service"
|
"one-api/service"
|
||||||
"one-api/setting/operation_setting"
|
"one-api/setting/ratio_setting"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initialize model settings
|
// Initialize model settings
|
||||||
operation_setting.InitRatioSettings()
|
ratio_setting.InitRatioSettings()
|
||||||
// Initialize constants
|
// Initialize constants
|
||||||
constant.InitEnv()
|
constant.InitEnv()
|
||||||
// Initialize options
|
// Initialize options
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
relayconstant "one-api/relay/constant"
|
relayconstant "one-api/relay/constant"
|
||||||
"one-api/service"
|
"one-api/service"
|
||||||
"one-api/setting"
|
"one-api/setting"
|
||||||
|
"one-api/setting/ratio_setting"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -48,7 +49,7 @@ func Distribute() func(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// check group in common.GroupRatio
|
// check group in common.GroupRatio
|
||||||
if !setting.ContainsGroupRatio(tokenGroup) {
|
if !ratio_setting.ContainsGroupRatio(tokenGroup) {
|
||||||
if tokenGroup != "auto" {
|
if tokenGroup != "auto" {
|
||||||
abortWithOpenAiMessage(c, http.StatusForbidden, fmt.Sprintf("分组 %s 已被弃用", tokenGroup))
|
abortWithOpenAiMessage(c, http.StatusForbidden, fmt.Sprintf("分组 %s 已被弃用", tokenGroup))
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -597,3 +597,39 @@ func CountAllTags() (int64, error) {
|
|||||||
err := DB.Model(&Channel{}).Where("tag is not null AND tag != ''").Distinct("tag").Count(&total).Error
|
err := DB.Model(&Channel{}).Where("tag is not null AND tag != ''").Distinct("tag").Count(&total).Error
|
||||||
return total, err
|
return total, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get channels of specified type with pagination
|
||||||
|
func GetChannelsByType(startIdx int, num int, idSort bool, channelType int) ([]*Channel, error) {
|
||||||
|
var channels []*Channel
|
||||||
|
order := "priority desc"
|
||||||
|
if idSort {
|
||||||
|
order = "id desc"
|
||||||
|
}
|
||||||
|
err := DB.Where("type = ?", channelType).Order(order).Limit(num).Offset(startIdx).Omit("key").Find(&channels).Error
|
||||||
|
return channels, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count channels of specific type
|
||||||
|
func CountChannelsByType(channelType int) (int64, error) {
|
||||||
|
var count int64
|
||||||
|
err := DB.Model(&Channel{}).Where("type = ?", channelType).Count(&count).Error
|
||||||
|
return count, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return map[type]count for all channels
|
||||||
|
func CountChannelsGroupByType() (map[int64]int64, error) {
|
||||||
|
type result struct {
|
||||||
|
Type int64 `gorm:"column:type"`
|
||||||
|
Count int64 `gorm:"column:count"`
|
||||||
|
}
|
||||||
|
var results []result
|
||||||
|
err := DB.Model(&Channel{}).Select("type, count(*) as count").Group("type").Find(&results).Error
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
counts := make(map[int64]int64)
|
||||||
|
for _, r := range results {
|
||||||
|
counts[r.Type] = r.Count
|
||||||
|
}
|
||||||
|
return counts, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"one-api/setting"
|
"one-api/setting"
|
||||||
"one-api/setting/config"
|
"one-api/setting/config"
|
||||||
"one-api/setting/operation_setting"
|
"one-api/setting/operation_setting"
|
||||||
|
"one-api/setting/ratio_setting"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -96,13 +97,13 @@ func InitOptionMap() {
|
|||||||
common.OptionMap["ModelRequestRateLimitDurationMinutes"] = strconv.Itoa(setting.ModelRequestRateLimitDurationMinutes)
|
common.OptionMap["ModelRequestRateLimitDurationMinutes"] = strconv.Itoa(setting.ModelRequestRateLimitDurationMinutes)
|
||||||
common.OptionMap["ModelRequestRateLimitSuccessCount"] = strconv.Itoa(setting.ModelRequestRateLimitSuccessCount)
|
common.OptionMap["ModelRequestRateLimitSuccessCount"] = strconv.Itoa(setting.ModelRequestRateLimitSuccessCount)
|
||||||
common.OptionMap["ModelRequestRateLimitGroup"] = setting.ModelRequestRateLimitGroup2JSONString()
|
common.OptionMap["ModelRequestRateLimitGroup"] = setting.ModelRequestRateLimitGroup2JSONString()
|
||||||
common.OptionMap["ModelRatio"] = operation_setting.ModelRatio2JSONString()
|
common.OptionMap["ModelRatio"] = ratio_setting.ModelRatio2JSONString()
|
||||||
common.OptionMap["ModelPrice"] = operation_setting.ModelPrice2JSONString()
|
common.OptionMap["ModelPrice"] = ratio_setting.ModelPrice2JSONString()
|
||||||
common.OptionMap["CacheRatio"] = operation_setting.CacheRatio2JSONString()
|
common.OptionMap["CacheRatio"] = ratio_setting.CacheRatio2JSONString()
|
||||||
common.OptionMap["GroupRatio"] = setting.GroupRatio2JSONString()
|
common.OptionMap["GroupRatio"] = ratio_setting.GroupRatio2JSONString()
|
||||||
common.OptionMap["GroupGroupRatio"] = setting.GroupGroupRatio2JSONString()
|
common.OptionMap["GroupGroupRatio"] = ratio_setting.GroupGroupRatio2JSONString()
|
||||||
common.OptionMap["UserUsableGroups"] = setting.UserUsableGroups2JSONString()
|
common.OptionMap["UserUsableGroups"] = setting.UserUsableGroups2JSONString()
|
||||||
common.OptionMap["CompletionRatio"] = operation_setting.CompletionRatio2JSONString()
|
common.OptionMap["CompletionRatio"] = ratio_setting.CompletionRatio2JSONString()
|
||||||
common.OptionMap["TopUpLink"] = common.TopUpLink
|
common.OptionMap["TopUpLink"] = common.TopUpLink
|
||||||
//common.OptionMap["ChatLink"] = common.ChatLink
|
//common.OptionMap["ChatLink"] = common.ChatLink
|
||||||
//common.OptionMap["ChatLink2"] = common.ChatLink2
|
//common.OptionMap["ChatLink2"] = common.ChatLink2
|
||||||
@@ -358,19 +359,19 @@ func updateOptionMap(key string, value string) (err error) {
|
|||||||
case "DataExportDefaultTime":
|
case "DataExportDefaultTime":
|
||||||
common.DataExportDefaultTime = value
|
common.DataExportDefaultTime = value
|
||||||
case "ModelRatio":
|
case "ModelRatio":
|
||||||
err = operation_setting.UpdateModelRatioByJSONString(value)
|
err = ratio_setting.UpdateModelRatioByJSONString(value)
|
||||||
case "GroupRatio":
|
case "GroupRatio":
|
||||||
err = setting.UpdateGroupRatioByJSONString(value)
|
err = ratio_setting.UpdateGroupRatioByJSONString(value)
|
||||||
case "GroupGroupRatio":
|
case "GroupGroupRatio":
|
||||||
err = setting.UpdateGroupGroupRatioByJSONString(value)
|
err = ratio_setting.UpdateGroupGroupRatioByJSONString(value)
|
||||||
case "UserUsableGroups":
|
case "UserUsableGroups":
|
||||||
err = setting.UpdateUserUsableGroupsByJSONString(value)
|
err = setting.UpdateUserUsableGroupsByJSONString(value)
|
||||||
case "CompletionRatio":
|
case "CompletionRatio":
|
||||||
err = operation_setting.UpdateCompletionRatioByJSONString(value)
|
err = ratio_setting.UpdateCompletionRatioByJSONString(value)
|
||||||
case "ModelPrice":
|
case "ModelPrice":
|
||||||
err = operation_setting.UpdateModelPriceByJSONString(value)
|
err = ratio_setting.UpdateModelPriceByJSONString(value)
|
||||||
case "CacheRatio":
|
case "CacheRatio":
|
||||||
err = operation_setting.UpdateCacheRatioByJSONString(value)
|
err = ratio_setting.UpdateCacheRatioByJSONString(value)
|
||||||
case "TopUpLink":
|
case "TopUpLink":
|
||||||
common.TopUpLink = value
|
common.TopUpLink = value
|
||||||
//case "ChatLink":
|
//case "ChatLink":
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package model
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"one-api/common"
|
"one-api/common"
|
||||||
"one-api/setting/operation_setting"
|
"one-api/setting/ratio_setting"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -65,14 +65,14 @@ func updatePricing() {
|
|||||||
ModelName: model,
|
ModelName: model,
|
||||||
EnableGroup: groups,
|
EnableGroup: groups,
|
||||||
}
|
}
|
||||||
modelPrice, findPrice := operation_setting.GetModelPrice(model, false)
|
modelPrice, findPrice := ratio_setting.GetModelPrice(model, false)
|
||||||
if findPrice {
|
if findPrice {
|
||||||
pricing.ModelPrice = modelPrice
|
pricing.ModelPrice = modelPrice
|
||||||
pricing.QuotaType = 1
|
pricing.QuotaType = 1
|
||||||
} else {
|
} else {
|
||||||
modelRatio, _ := operation_setting.GetModelRatio(model)
|
modelRatio, _ := ratio_setting.GetModelRatio(model)
|
||||||
pricing.ModelRatio = modelRatio
|
pricing.ModelRatio = modelRatio
|
||||||
pricing.CompletionRatio = operation_setting.GetCompletionRatio(model)
|
pricing.CompletionRatio = ratio_setting.GetCompletionRatio(model)
|
||||||
pricing.QuotaType = 0
|
pricing.QuotaType = 0
|
||||||
}
|
}
|
||||||
pricingMap = append(pricingMap, pricing)
|
pricingMap = append(pricingMap, pricing)
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ import (
|
|||||||
"one-api/common"
|
"one-api/common"
|
||||||
constant2 "one-api/constant"
|
constant2 "one-api/constant"
|
||||||
relaycommon "one-api/relay/common"
|
relaycommon "one-api/relay/common"
|
||||||
"one-api/setting"
|
"one-api/setting/ratio_setting"
|
||||||
"one-api/setting/operation_setting"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
@@ -49,21 +48,21 @@ func HandleGroupRatio(ctx *gin.Context, relayInfo *relaycommon.RelayInfo) GroupR
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check user group special ratio
|
// check user group special ratio
|
||||||
userGroupRatio, ok := setting.GetGroupGroupRatio(relayInfo.UserGroup, relayInfo.Group)
|
userGroupRatio, ok := ratio_setting.GetGroupGroupRatio(relayInfo.UserGroup, relayInfo.Group)
|
||||||
if ok {
|
if ok {
|
||||||
// user group special ratio
|
// user group special ratio
|
||||||
groupRatioInfo.GroupSpecialRatio = userGroupRatio
|
groupRatioInfo.GroupSpecialRatio = userGroupRatio
|
||||||
groupRatioInfo.GroupRatio = userGroupRatio
|
groupRatioInfo.GroupRatio = userGroupRatio
|
||||||
} else {
|
} else {
|
||||||
// normal group ratio
|
// normal group ratio
|
||||||
groupRatioInfo.GroupRatio = setting.GetGroupRatio(relayInfo.Group)
|
groupRatioInfo.GroupRatio = ratio_setting.GetGroupRatio(relayInfo.Group)
|
||||||
}
|
}
|
||||||
|
|
||||||
return groupRatioInfo
|
return groupRatioInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func ModelPriceHelper(c *gin.Context, info *relaycommon.RelayInfo, promptTokens int, maxTokens int) (PriceData, error) {
|
func ModelPriceHelper(c *gin.Context, info *relaycommon.RelayInfo, promptTokens int, maxTokens int) (PriceData, error) {
|
||||||
modelPrice, usePrice := operation_setting.GetModelPrice(info.OriginModelName, false)
|
modelPrice, usePrice := ratio_setting.GetModelPrice(info.OriginModelName, false)
|
||||||
|
|
||||||
groupRatioInfo := HandleGroupRatio(c, info)
|
groupRatioInfo := HandleGroupRatio(c, info)
|
||||||
|
|
||||||
@@ -79,7 +78,7 @@ func ModelPriceHelper(c *gin.Context, info *relaycommon.RelayInfo, promptTokens
|
|||||||
preConsumedTokens = promptTokens + maxTokens
|
preConsumedTokens = promptTokens + maxTokens
|
||||||
}
|
}
|
||||||
var success bool
|
var success bool
|
||||||
modelRatio, success = operation_setting.GetModelRatio(info.OriginModelName)
|
modelRatio, success = ratio_setting.GetModelRatio(info.OriginModelName)
|
||||||
if !success {
|
if !success {
|
||||||
acceptUnsetRatio := false
|
acceptUnsetRatio := false
|
||||||
if accept, ok := info.UserSetting[constant2.UserAcceptUnsetRatioModel]; ok {
|
if accept, ok := info.UserSetting[constant2.UserAcceptUnsetRatioModel]; ok {
|
||||||
@@ -92,10 +91,10 @@ func ModelPriceHelper(c *gin.Context, info *relaycommon.RelayInfo, promptTokens
|
|||||||
return PriceData{}, fmt.Errorf("模型 %s 倍率或价格未配置,请联系管理员设置或开始自用模式;Model %s ratio or price not set, please set or start self-use mode", info.OriginModelName, info.OriginModelName)
|
return PriceData{}, fmt.Errorf("模型 %s 倍率或价格未配置,请联系管理员设置或开始自用模式;Model %s ratio or price not set, please set or start self-use mode", info.OriginModelName, info.OriginModelName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
completionRatio = operation_setting.GetCompletionRatio(info.OriginModelName)
|
completionRatio = ratio_setting.GetCompletionRatio(info.OriginModelName)
|
||||||
cacheRatio, _ = operation_setting.GetCacheRatio(info.OriginModelName)
|
cacheRatio, _ = ratio_setting.GetCacheRatio(info.OriginModelName)
|
||||||
cacheCreationRatio, _ = operation_setting.GetCreateCacheRatio(info.OriginModelName)
|
cacheCreationRatio, _ = ratio_setting.GetCreateCacheRatio(info.OriginModelName)
|
||||||
imageRatio, _ = operation_setting.GetImageRatio(info.OriginModelName)
|
imageRatio, _ = ratio_setting.GetImageRatio(info.OriginModelName)
|
||||||
ratio := modelRatio * groupRatioInfo.GroupRatio
|
ratio := modelRatio * groupRatioInfo.GroupRatio
|
||||||
preConsumedQuota = int(float64(preConsumedTokens) * ratio)
|
preConsumedQuota = int(float64(preConsumedTokens) * ratio)
|
||||||
} else {
|
} else {
|
||||||
@@ -122,11 +121,11 @@ func ModelPriceHelper(c *gin.Context, info *relaycommon.RelayInfo, promptTokens
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ContainPriceOrRatio(modelName string) bool {
|
func ContainPriceOrRatio(modelName string) bool {
|
||||||
_, ok := operation_setting.GetModelPrice(modelName, false)
|
_, ok := ratio_setting.GetModelPrice(modelName, false)
|
||||||
if ok {
|
if ok {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
_, ok = operation_setting.GetModelRatio(modelName)
|
_, ok = ratio_setting.GetModelRatio(modelName)
|
||||||
if ok {
|
if ok {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
relayconstant "one-api/relay/constant"
|
relayconstant "one-api/relay/constant"
|
||||||
"one-api/service"
|
"one-api/service"
|
||||||
"one-api/setting"
|
"one-api/setting"
|
||||||
"one-api/setting/operation_setting"
|
"one-api/setting/ratio_setting"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -174,17 +174,17 @@ func RelaySwapFace(c *gin.Context) *dto.MidjourneyResponse {
|
|||||||
return service.MidjourneyErrorWrapper(constant.MjRequestError, "sour_base64_and_target_base64_is_required")
|
return service.MidjourneyErrorWrapper(constant.MjRequestError, "sour_base64_and_target_base64_is_required")
|
||||||
}
|
}
|
||||||
modelName := service.CoverActionToModelName(constant.MjActionSwapFace)
|
modelName := service.CoverActionToModelName(constant.MjActionSwapFace)
|
||||||
modelPrice, success := operation_setting.GetModelPrice(modelName, true)
|
modelPrice, success := ratio_setting.GetModelPrice(modelName, true)
|
||||||
// 如果没有配置价格,则使用默认价格
|
// 如果没有配置价格,则使用默认价格
|
||||||
if !success {
|
if !success {
|
||||||
defaultPrice, ok := operation_setting.GetDefaultModelRatioMap()[modelName]
|
defaultPrice, ok := ratio_setting.GetDefaultModelRatioMap()[modelName]
|
||||||
if !ok {
|
if !ok {
|
||||||
modelPrice = 0.1
|
modelPrice = 0.1
|
||||||
} else {
|
} else {
|
||||||
modelPrice = defaultPrice
|
modelPrice = defaultPrice
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
groupRatio := setting.GetGroupRatio(group)
|
groupRatio := ratio_setting.GetGroupRatio(group)
|
||||||
ratio := modelPrice * groupRatio
|
ratio := modelPrice * groupRatio
|
||||||
userQuota, err := model.GetUserQuota(userId, false)
|
userQuota, err := model.GetUserQuota(userId, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -480,17 +480,17 @@ func RelayMidjourneySubmit(c *gin.Context, relayMode int) *dto.MidjourneyRespons
|
|||||||
fullRequestURL := fmt.Sprintf("%s%s", baseURL, requestURL)
|
fullRequestURL := fmt.Sprintf("%s%s", baseURL, requestURL)
|
||||||
|
|
||||||
modelName := service.CoverActionToModelName(midjRequest.Action)
|
modelName := service.CoverActionToModelName(midjRequest.Action)
|
||||||
modelPrice, success := operation_setting.GetModelPrice(modelName, true)
|
modelPrice, success := ratio_setting.GetModelPrice(modelName, true)
|
||||||
// 如果没有配置价格,则使用默认价格
|
// 如果没有配置价格,则使用默认价格
|
||||||
if !success {
|
if !success {
|
||||||
defaultPrice, ok := operation_setting.GetDefaultModelRatioMap()[modelName]
|
defaultPrice, ok := ratio_setting.GetDefaultModelRatioMap()[modelName]
|
||||||
if !ok {
|
if !ok {
|
||||||
modelPrice = 0.1
|
modelPrice = 0.1
|
||||||
} else {
|
} else {
|
||||||
modelPrice = defaultPrice
|
modelPrice = defaultPrice
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
groupRatio := setting.GetGroupRatio(group)
|
groupRatio := ratio_setting.GetGroupRatio(group)
|
||||||
ratio := modelPrice * groupRatio
|
ratio := modelPrice * groupRatio
|
||||||
userQuota, err := model.GetUserQuota(userId, false)
|
userQuota, err := model.GetUserQuota(userId, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -15,8 +15,7 @@ import (
|
|||||||
relaycommon "one-api/relay/common"
|
relaycommon "one-api/relay/common"
|
||||||
relayconstant "one-api/relay/constant"
|
relayconstant "one-api/relay/constant"
|
||||||
"one-api/service"
|
"one-api/service"
|
||||||
"one-api/setting"
|
"one-api/setting/ratio_setting"
|
||||||
"one-api/setting/operation_setting"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -38,9 +37,9 @@ func RelayTaskSubmit(c *gin.Context, relayMode int) (taskErr *dto.TaskError) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
modelName := service.CoverTaskActionToModelName(platform, relayInfo.Action)
|
modelName := service.CoverTaskActionToModelName(platform, relayInfo.Action)
|
||||||
modelPrice, success := operation_setting.GetModelPrice(modelName, true)
|
modelPrice, success := ratio_setting.GetModelPrice(modelName, true)
|
||||||
if !success {
|
if !success {
|
||||||
defaultPrice, ok := operation_setting.GetDefaultModelRatioMap()[modelName]
|
defaultPrice, ok := ratio_setting.GetDefaultModelRatioMap()[modelName]
|
||||||
if !ok {
|
if !ok {
|
||||||
modelPrice = 0.1
|
modelPrice = 0.1
|
||||||
} else {
|
} else {
|
||||||
@@ -49,7 +48,7 @@ func RelayTaskSubmit(c *gin.Context, relayMode int) (taskErr *dto.TaskError) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 预扣
|
// 预扣
|
||||||
groupRatio := setting.GetGroupRatio(relayInfo.Group)
|
groupRatio := ratio_setting.GetGroupRatio(relayInfo.Group)
|
||||||
ratio := modelPrice * groupRatio
|
ratio := modelPrice * groupRatio
|
||||||
userQuota, err := model.GetUserQuota(relayInfo.UserId, false)
|
userQuota, err := model.GetUserQuota(relayInfo.UserId, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
relaycommon "one-api/relay/common"
|
relaycommon "one-api/relay/common"
|
||||||
"one-api/relay/helper"
|
"one-api/relay/helper"
|
||||||
"one-api/setting"
|
"one-api/setting"
|
||||||
"one-api/setting/operation_setting"
|
"one-api/setting/ratio_setting"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -46,9 +46,9 @@ func calculateAudioQuota(info QuotaInfo) int {
|
|||||||
return int(quota.IntPart())
|
return int(quota.IntPart())
|
||||||
}
|
}
|
||||||
|
|
||||||
completionRatio := decimal.NewFromFloat(operation_setting.GetCompletionRatio(info.ModelName))
|
completionRatio := decimal.NewFromFloat(ratio_setting.GetCompletionRatio(info.ModelName))
|
||||||
audioRatio := decimal.NewFromFloat(operation_setting.GetAudioRatio(info.ModelName))
|
audioRatio := decimal.NewFromFloat(ratio_setting.GetAudioRatio(info.ModelName))
|
||||||
audioCompletionRatio := decimal.NewFromFloat(operation_setting.GetAudioCompletionRatio(info.ModelName))
|
audioCompletionRatio := decimal.NewFromFloat(ratio_setting.GetAudioCompletionRatio(info.ModelName))
|
||||||
|
|
||||||
groupRatio := decimal.NewFromFloat(info.GroupRatio)
|
groupRatio := decimal.NewFromFloat(info.GroupRatio)
|
||||||
modelRatio := decimal.NewFromFloat(info.ModelRatio)
|
modelRatio := decimal.NewFromFloat(info.ModelRatio)
|
||||||
@@ -94,18 +94,18 @@ func PreWssConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, usag
|
|||||||
textOutTokens := usage.OutputTokenDetails.TextTokens
|
textOutTokens := usage.OutputTokenDetails.TextTokens
|
||||||
audioInputTokens := usage.InputTokenDetails.AudioTokens
|
audioInputTokens := usage.InputTokenDetails.AudioTokens
|
||||||
audioOutTokens := usage.OutputTokenDetails.AudioTokens
|
audioOutTokens := usage.OutputTokenDetails.AudioTokens
|
||||||
groupRatio := setting.GetGroupRatio(relayInfo.Group)
|
groupRatio := ratio_setting.GetGroupRatio(relayInfo.Group)
|
||||||
modelRatio, _ := operation_setting.GetModelRatio(modelName)
|
modelRatio, _ := ratio_setting.GetModelRatio(modelName)
|
||||||
|
|
||||||
autoGroup, exists := ctx.Get("auto_group")
|
autoGroup, exists := ctx.Get("auto_group")
|
||||||
if exists {
|
if exists {
|
||||||
groupRatio = setting.GetGroupRatio(autoGroup.(string))
|
groupRatio = ratio_setting.GetGroupRatio(autoGroup.(string))
|
||||||
log.Printf("final group ratio: %f", groupRatio)
|
log.Printf("final group ratio: %f", groupRatio)
|
||||||
relayInfo.Group = autoGroup.(string)
|
relayInfo.Group = autoGroup.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
actualGroupRatio := groupRatio
|
actualGroupRatio := groupRatio
|
||||||
userGroupRatio, ok := setting.GetGroupGroupRatio(relayInfo.UserGroup, relayInfo.Group)
|
userGroupRatio, ok := ratio_setting.GetGroupGroupRatio(relayInfo.UserGroup, relayInfo.Group)
|
||||||
if ok {
|
if ok {
|
||||||
actualGroupRatio = userGroupRatio
|
actualGroupRatio = userGroupRatio
|
||||||
}
|
}
|
||||||
@@ -154,9 +154,9 @@ func PostWssConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, mod
|
|||||||
audioOutTokens := usage.OutputTokenDetails.AudioTokens
|
audioOutTokens := usage.OutputTokenDetails.AudioTokens
|
||||||
|
|
||||||
tokenName := ctx.GetString("token_name")
|
tokenName := ctx.GetString("token_name")
|
||||||
completionRatio := decimal.NewFromFloat(operation_setting.GetCompletionRatio(modelName))
|
completionRatio := decimal.NewFromFloat(ratio_setting.GetCompletionRatio(modelName))
|
||||||
audioRatio := decimal.NewFromFloat(operation_setting.GetAudioRatio(relayInfo.OriginModelName))
|
audioRatio := decimal.NewFromFloat(ratio_setting.GetAudioRatio(relayInfo.OriginModelName))
|
||||||
audioCompletionRatio := decimal.NewFromFloat(operation_setting.GetAudioCompletionRatio(modelName))
|
audioCompletionRatio := decimal.NewFromFloat(ratio_setting.GetAudioCompletionRatio(modelName))
|
||||||
|
|
||||||
modelRatio := priceData.ModelRatio
|
modelRatio := priceData.ModelRatio
|
||||||
groupRatio := priceData.GroupRatioInfo.GroupRatio
|
groupRatio := priceData.GroupRatioInfo.GroupRatio
|
||||||
@@ -289,9 +289,9 @@ func PostAudioConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo,
|
|||||||
audioOutTokens := usage.CompletionTokenDetails.AudioTokens
|
audioOutTokens := usage.CompletionTokenDetails.AudioTokens
|
||||||
|
|
||||||
tokenName := ctx.GetString("token_name")
|
tokenName := ctx.GetString("token_name")
|
||||||
completionRatio := decimal.NewFromFloat(operation_setting.GetCompletionRatio(relayInfo.OriginModelName))
|
completionRatio := decimal.NewFromFloat(ratio_setting.GetCompletionRatio(relayInfo.OriginModelName))
|
||||||
audioRatio := decimal.NewFromFloat(operation_setting.GetAudioRatio(relayInfo.OriginModelName))
|
audioRatio := decimal.NewFromFloat(ratio_setting.GetAudioRatio(relayInfo.OriginModelName))
|
||||||
audioCompletionRatio := decimal.NewFromFloat(operation_setting.GetAudioCompletionRatio(relayInfo.OriginModelName))
|
audioCompletionRatio := decimal.NewFromFloat(ratio_setting.GetAudioCompletionRatio(relayInfo.OriginModelName))
|
||||||
|
|
||||||
modelRatio := priceData.ModelRatio
|
modelRatio := priceData.ModelRatio
|
||||||
groupRatio := priceData.GroupRatioInfo.GroupRatio
|
groupRatio := priceData.GroupRatioInfo.GroupRatio
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package operation_setting
|
package ratio_setting
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package setting
|
package ratio_setting
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
package operation_setting
|
package ratio_setting
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"one-api/common"
|
"one-api/common"
|
||||||
|
"one-api/setting/operation_setting"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
@@ -366,7 +367,7 @@ func GetModelRatio(name string) (float64, bool) {
|
|||||||
}
|
}
|
||||||
ratio, ok := modelRatioMap[name]
|
ratio, ok := modelRatioMap[name]
|
||||||
if !ok {
|
if !ok {
|
||||||
return 37.5, SelfUseModeEnabled
|
return 37.5, operation_setting.SelfUseModeEnabled
|
||||||
}
|
}
|
||||||
return ratio, true
|
return ratio, true
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Card, Spin, Tabs } from '@douyinfe/semi-ui';
|
import { Card, Spin } from '@douyinfe/semi-ui';
|
||||||
import SettingsGeneral from '../../pages/Setting/Operation/SettingsGeneral.js';
|
import SettingsGeneral from '../../pages/Setting/Operation/SettingsGeneral.js';
|
||||||
import SettingsDrawing from '../../pages/Setting/Operation/SettingsDrawing.js';
|
import SettingsDrawing from '../../pages/Setting/Operation/SettingsDrawing.js';
|
||||||
import SettingsSensitiveWords from '../../pages/Setting/Operation/SettingsSensitiveWords.js';
|
import SettingsSensitiveWords from '../../pages/Setting/Operation/SettingsSensitiveWords.js';
|
||||||
@@ -7,63 +7,58 @@ import SettingsLog from '../../pages/Setting/Operation/SettingsLog.js';
|
|||||||
import SettingsDataDashboard from '../../pages/Setting/Operation/SettingsDataDashboard.js';
|
import SettingsDataDashboard from '../../pages/Setting/Operation/SettingsDataDashboard.js';
|
||||||
import SettingsMonitoring from '../../pages/Setting/Operation/SettingsMonitoring.js';
|
import SettingsMonitoring from '../../pages/Setting/Operation/SettingsMonitoring.js';
|
||||||
import SettingsCreditLimit from '../../pages/Setting/Operation/SettingsCreditLimit.js';
|
import SettingsCreditLimit from '../../pages/Setting/Operation/SettingsCreditLimit.js';
|
||||||
import ModelSettingsVisualEditor from '../../pages/Setting/Operation/ModelSettingsVisualEditor.js';
|
|
||||||
import GroupRatioSettings from '../../pages/Setting/Operation/GroupRatioSettings.js';
|
|
||||||
import ModelRatioSettings from '../../pages/Setting/Operation/ModelRatioSettings.js';
|
|
||||||
|
|
||||||
import { API, showError, showSuccess } from '../../helpers';
|
|
||||||
import SettingsChats from '../../pages/Setting/Operation/SettingsChats.js';
|
import SettingsChats from '../../pages/Setting/Operation/SettingsChats.js';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { API, showError } from '../../helpers';
|
||||||
import ModelRatioNotSetEditor from '../../pages/Setting/Operation/ModelRationNotSetEditor.js';
|
|
||||||
|
|
||||||
const OperationSetting = () => {
|
const OperationSetting = () => {
|
||||||
const { t } = useTranslation();
|
|
||||||
let [inputs, setInputs] = useState({
|
let [inputs, setInputs] = useState({
|
||||||
|
/* 额度相关 */
|
||||||
QuotaForNewUser: 0,
|
QuotaForNewUser: 0,
|
||||||
|
PreConsumedQuota: 0,
|
||||||
QuotaForInviter: 0,
|
QuotaForInviter: 0,
|
||||||
QuotaForInvitee: 0,
|
QuotaForInvitee: 0,
|
||||||
QuotaRemindThreshold: 0,
|
|
||||||
PreConsumedQuota: 0,
|
/* 通用设置 */
|
||||||
StreamCacheQueueLength: 0,
|
|
||||||
ModelRatio: '',
|
|
||||||
CacheRatio: '',
|
|
||||||
CompletionRatio: '',
|
|
||||||
ModelPrice: '',
|
|
||||||
GroupRatio: '',
|
|
||||||
GroupGroupRatio: '',
|
|
||||||
AutoGroups: '',
|
|
||||||
DefaultUseAutoGroup: false,
|
|
||||||
UserUsableGroups: '',
|
|
||||||
TopUpLink: '',
|
TopUpLink: '',
|
||||||
'general_setting.docs_link': '',
|
'general_setting.docs_link': '',
|
||||||
// ChatLink2: '', // 添加的新状态变量
|
|
||||||
QuotaPerUnit: 0,
|
QuotaPerUnit: 0,
|
||||||
AutomaticDisableChannelEnabled: false,
|
RetryTimes: 0,
|
||||||
AutomaticEnableChannelEnabled: false,
|
|
||||||
ChannelDisableThreshold: 0,
|
|
||||||
LogConsumeEnabled: false,
|
|
||||||
DisplayInCurrencyEnabled: false,
|
DisplayInCurrencyEnabled: false,
|
||||||
DisplayTokenStatEnabled: false,
|
DisplayTokenStatEnabled: false,
|
||||||
CheckSensitiveEnabled: false,
|
DefaultCollapseSidebar: false,
|
||||||
CheckSensitiveOnPromptEnabled: false,
|
DemoSiteEnabled: false,
|
||||||
CheckSensitiveOnCompletionEnabled: '',
|
SelfUseModeEnabled: false,
|
||||||
StopOnSensitiveEnabled: '',
|
|
||||||
SensitiveWords: '',
|
/* 绘图设置 */
|
||||||
|
DrawingEnabled: false,
|
||||||
MjNotifyEnabled: false,
|
MjNotifyEnabled: false,
|
||||||
MjAccountFilterEnabled: false,
|
MjAccountFilterEnabled: false,
|
||||||
MjModeClearEnabled: false,
|
|
||||||
MjForwardUrlEnabled: false,
|
MjForwardUrlEnabled: false,
|
||||||
|
MjModeClearEnabled: false,
|
||||||
MjActionCheckSuccessEnabled: false,
|
MjActionCheckSuccessEnabled: false,
|
||||||
DrawingEnabled: false,
|
|
||||||
|
/* 敏感词设置 */
|
||||||
|
CheckSensitiveEnabled: false,
|
||||||
|
CheckSensitiveOnPromptEnabled: false,
|
||||||
|
SensitiveWords: '',
|
||||||
|
|
||||||
|
/* 日志设置 */
|
||||||
|
LogConsumeEnabled: false,
|
||||||
|
|
||||||
|
/* 数据看板 */
|
||||||
DataExportEnabled: false,
|
DataExportEnabled: false,
|
||||||
DataExportDefaultTime: 'hour',
|
DataExportDefaultTime: 'hour',
|
||||||
DataExportInterval: 5,
|
DataExportInterval: 5,
|
||||||
DefaultCollapseSidebar: false, // 默认折叠侧边栏
|
|
||||||
RetryTimes: 0,
|
/* 监控设置 */
|
||||||
Chats: '[]',
|
ChannelDisableThreshold: 0,
|
||||||
DemoSiteEnabled: false,
|
QuotaRemindThreshold: 0,
|
||||||
SelfUseModeEnabled: false,
|
AutomaticDisableChannelEnabled: false,
|
||||||
|
AutomaticEnableChannelEnabled: false,
|
||||||
AutomaticDisableKeywords: '',
|
AutomaticDisableKeywords: '',
|
||||||
|
|
||||||
|
/* 聊天设置 */
|
||||||
|
Chats: '[]',
|
||||||
});
|
});
|
||||||
|
|
||||||
let [loading, setLoading] = useState(false);
|
let [loading, setLoading] = useState(false);
|
||||||
@@ -74,22 +69,9 @@ const OperationSetting = () => {
|
|||||||
if (success) {
|
if (success) {
|
||||||
let newInputs = {};
|
let newInputs = {};
|
||||||
data.forEach((item) => {
|
data.forEach((item) => {
|
||||||
if (
|
|
||||||
item.key === 'ModelRatio' ||
|
|
||||||
item.key === 'GroupRatio' ||
|
|
||||||
item.key === 'GroupGroupRatio' ||
|
|
||||||
item.key === 'AutoGroups' ||
|
|
||||||
item.key === 'UserUsableGroups' ||
|
|
||||||
item.key === 'CompletionRatio' ||
|
|
||||||
item.key === 'ModelPrice' ||
|
|
||||||
item.key === 'CacheRatio'
|
|
||||||
) {
|
|
||||||
item.value = JSON.stringify(JSON.parse(item.value), null, 2);
|
|
||||||
}
|
|
||||||
if (
|
if (
|
||||||
item.key.endsWith('Enabled') ||
|
item.key.endsWith('Enabled') ||
|
||||||
['DefaultCollapseSidebar'].includes(item.key) ||
|
['DefaultCollapseSidebar'].includes(item.key)
|
||||||
['DefaultUseAutoGroup'].includes(item.key)
|
|
||||||
) {
|
) {
|
||||||
newInputs[item.key] = item.value === 'true' ? true : false;
|
newInputs[item.key] = item.value === 'true' ? true : false;
|
||||||
} else {
|
} else {
|
||||||
@@ -153,24 +135,6 @@ const OperationSetting = () => {
|
|||||||
<Card style={{ marginTop: '10px' }}>
|
<Card style={{ marginTop: '10px' }}>
|
||||||
<SettingsChats options={inputs} refresh={onRefresh} />
|
<SettingsChats options={inputs} refresh={onRefresh} />
|
||||||
</Card>
|
</Card>
|
||||||
{/* 分组倍率设置 */}
|
|
||||||
<Card style={{ marginTop: '10px' }}>
|
|
||||||
<GroupRatioSettings options={inputs} refresh={onRefresh} />
|
|
||||||
</Card>
|
|
||||||
{/* 合并模型倍率设置和可视化倍率设置 */}
|
|
||||||
<Card style={{ marginTop: '10px' }}>
|
|
||||||
<Tabs type='line'>
|
|
||||||
<Tabs.TabPane tab={t('模型倍率设置')} itemKey='model'>
|
|
||||||
<ModelRatioSettings options={inputs} refresh={onRefresh} />
|
|
||||||
</Tabs.TabPane>
|
|
||||||
<Tabs.TabPane tab={t('可视化倍率设置')} itemKey='visual'>
|
|
||||||
<ModelSettingsVisualEditor options={inputs} refresh={onRefresh} />
|
|
||||||
</Tabs.TabPane>
|
|
||||||
<Tabs.TabPane tab={t('未设置倍率模型')} itemKey='unset_models'>
|
|
||||||
<ModelRatioNotSetEditor options={inputs} refresh={onRefresh} />
|
|
||||||
</Tabs.TabPane>
|
|
||||||
</Tabs>
|
|
||||||
</Card>
|
|
||||||
</Spin>
|
</Spin>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
109
web/src/components/settings/RatioSetting.js
Normal file
109
web/src/components/settings/RatioSetting.js
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { Card, Spin, Tabs } from '@douyinfe/semi-ui';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import GroupRatioSettings from '../../pages/Setting/Ratio/GroupRatioSettings.js';
|
||||||
|
import ModelRatioSettings from '../../pages/Setting/Ratio/ModelRatioSettings.js';
|
||||||
|
import ModelSettingsVisualEditor from '../../pages/Setting/Ratio/ModelSettingsVisualEditor.js';
|
||||||
|
import ModelRatioNotSetEditor from '../../pages/Setting/Ratio/ModelRationNotSetEditor.js';
|
||||||
|
|
||||||
|
import { API, showError } from '../../helpers';
|
||||||
|
|
||||||
|
const RatioSetting = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
let [inputs, setInputs] = useState({
|
||||||
|
ModelPrice: '',
|
||||||
|
ModelRatio: '',
|
||||||
|
CacheRatio: '',
|
||||||
|
CompletionRatio: '',
|
||||||
|
GroupRatio: '',
|
||||||
|
GroupGroupRatio: '',
|
||||||
|
AutoGroups: '',
|
||||||
|
DefaultUseAutoGroup: false,
|
||||||
|
UserUsableGroups: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
const getOptions = async () => {
|
||||||
|
const res = await API.get('/api/option/');
|
||||||
|
const { success, message, data } = res.data;
|
||||||
|
if (success) {
|
||||||
|
let newInputs = {};
|
||||||
|
data.forEach((item) => {
|
||||||
|
if (
|
||||||
|
item.key === 'ModelRatio' ||
|
||||||
|
item.key === 'GroupRatio' ||
|
||||||
|
item.key === 'GroupGroupRatio' ||
|
||||||
|
item.key === 'AutoGroups' ||
|
||||||
|
item.key === 'UserUsableGroups' ||
|
||||||
|
item.key === 'CompletionRatio' ||
|
||||||
|
item.key === 'ModelPrice' ||
|
||||||
|
item.key === 'CacheRatio'
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
item.value = JSON.stringify(JSON.parse(item.value), null, 2);
|
||||||
|
} catch (e) {
|
||||||
|
// 如果后端返回的不是合法 JSON,直接展示
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (['DefaultUseAutoGroup'].includes(item.key)) {
|
||||||
|
newInputs[item.key] = item.value === 'true' ? true : false;
|
||||||
|
} else {
|
||||||
|
newInputs[item.key] = item.value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setInputs(newInputs);
|
||||||
|
} else {
|
||||||
|
showError(message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onRefresh = async () => {
|
||||||
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
await getOptions();
|
||||||
|
} catch (error) {
|
||||||
|
showError('刷新失败');
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
onRefresh();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Spin spinning={loading} size='large'>
|
||||||
|
{/* 分组倍率设置 */}
|
||||||
|
<Card style={{ marginTop: '10px' }}>
|
||||||
|
<GroupRatioSettings options={inputs} refresh={onRefresh} />
|
||||||
|
</Card>
|
||||||
|
{/* 模型倍率设置以及可视化编辑器 */}
|
||||||
|
<Card style={{ marginTop: '10px' }}>
|
||||||
|
<Tabs type='line'>
|
||||||
|
<Tabs.TabPane tab={t('模型倍率设置')} itemKey='model'>
|
||||||
|
<ModelRatioSettings options={inputs} refresh={onRefresh} />
|
||||||
|
</Tabs.TabPane>
|
||||||
|
<Tabs.TabPane tab={t('可视化倍率设置')} itemKey='visual'>
|
||||||
|
<ModelSettingsVisualEditor
|
||||||
|
options={inputs}
|
||||||
|
refresh={onRefresh}
|
||||||
|
/>
|
||||||
|
</Tabs.TabPane>
|
||||||
|
<Tabs.TabPane tab={t('未设置倍率模型')} itemKey='unset_models'>
|
||||||
|
<ModelRatioNotSetEditor
|
||||||
|
options={inputs}
|
||||||
|
refresh={onRefresh}
|
||||||
|
/>
|
||||||
|
</Tabs.TabPane>
|
||||||
|
</Tabs>
|
||||||
|
</Card>
|
||||||
|
</Spin>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RatioSetting;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState, useMemo, useRef } from 'react';
|
||||||
import {
|
import {
|
||||||
API,
|
API,
|
||||||
showError,
|
showError,
|
||||||
@@ -16,11 +16,6 @@ import {
|
|||||||
XCircle,
|
XCircle,
|
||||||
AlertCircle,
|
AlertCircle,
|
||||||
HelpCircle,
|
HelpCircle,
|
||||||
TestTube,
|
|
||||||
Zap,
|
|
||||||
Timer,
|
|
||||||
Clock,
|
|
||||||
AlertTriangle,
|
|
||||||
Coins,
|
Coins,
|
||||||
Tags
|
Tags
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
@@ -43,7 +38,9 @@ import {
|
|||||||
Typography,
|
Typography,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
Card,
|
Card,
|
||||||
Form
|
Form,
|
||||||
|
Tabs,
|
||||||
|
TabPane
|
||||||
} from '@douyinfe/semi-ui';
|
} from '@douyinfe/semi-ui';
|
||||||
import {
|
import {
|
||||||
IllustrationNoResult,
|
IllustrationNoResult,
|
||||||
@@ -141,31 +138,31 @@ const ChannelsTable = () => {
|
|||||||
time = time.toFixed(2) + t(' 秒');
|
time = time.toFixed(2) + t(' 秒');
|
||||||
if (responseTime === 0) {
|
if (responseTime === 0) {
|
||||||
return (
|
return (
|
||||||
<Tag size='large' color='grey' shape='circle' prefixIcon={<TestTube size={14} />}>
|
<Tag size='large' color='grey' shape='circle'>
|
||||||
{t('未测试')}
|
{t('未测试')}
|
||||||
</Tag>
|
</Tag>
|
||||||
);
|
);
|
||||||
} else if (responseTime <= 1000) {
|
} else if (responseTime <= 1000) {
|
||||||
return (
|
return (
|
||||||
<Tag size='large' color='green' shape='circle' prefixIcon={<Zap size={14} />}>
|
<Tag size='large' color='green' shape='circle'>
|
||||||
{time}
|
{time}
|
||||||
</Tag>
|
</Tag>
|
||||||
);
|
);
|
||||||
} else if (responseTime <= 3000) {
|
} else if (responseTime <= 3000) {
|
||||||
return (
|
return (
|
||||||
<Tag size='large' color='lime' shape='circle' prefixIcon={<Timer size={14} />}>
|
<Tag size='large' color='lime' shape='circle'>
|
||||||
{time}
|
{time}
|
||||||
</Tag>
|
</Tag>
|
||||||
);
|
);
|
||||||
} else if (responseTime <= 5000) {
|
} else if (responseTime <= 5000) {
|
||||||
return (
|
return (
|
||||||
<Tag size='large' color='yellow' shape='circle' prefixIcon={<Clock size={14} />}>
|
<Tag size='large' color='yellow' shape='circle'>
|
||||||
{time}
|
{time}
|
||||||
</Tag>
|
</Tag>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<Tag size='large' color='red' shape='circle' prefixIcon={<AlertTriangle size={14} />}>
|
<Tag size='large' color='red' shape='circle'>
|
||||||
{time}
|
{time}
|
||||||
</Tag>
|
</Tag>
|
||||||
);
|
);
|
||||||
@@ -682,11 +679,10 @@ const ChannelsTable = () => {
|
|||||||
const [isBatchTesting, setIsBatchTesting] = useState(false);
|
const [isBatchTesting, setIsBatchTesting] = useState(false);
|
||||||
const [testQueue, setTestQueue] = useState([]);
|
const [testQueue, setTestQueue] = useState([]);
|
||||||
const [isProcessingQueue, setIsProcessingQueue] = useState(false);
|
const [isProcessingQueue, setIsProcessingQueue] = useState(false);
|
||||||
|
const [activeTypeKey, setActiveTypeKey] = useState('all');
|
||||||
// Form API 引用
|
const [typeCounts, setTypeCounts] = useState({});
|
||||||
|
const requestCounter = useRef(0);
|
||||||
const [formApi, setFormApi] = useState(null);
|
const [formApi, setFormApi] = useState(null);
|
||||||
|
|
||||||
// Form 初始值
|
|
||||||
const formInitValues = {
|
const formInitValues = {
|
||||||
searchKeyword: '',
|
searchKeyword: '',
|
||||||
searchGroup: '',
|
searchGroup: '',
|
||||||
@@ -868,17 +864,23 @@ const ChannelsTable = () => {
|
|||||||
setChannels(channelDates);
|
setChannels(channelDates);
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadChannels = async (page, pageSize, idSort, enableTagMode) => {
|
const loadChannels = async (page, pageSize, idSort, enableTagMode, typeKey = activeTypeKey) => {
|
||||||
|
const reqId = ++requestCounter.current; // 记录当前请求序号
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
const typeParam = (!enableTagMode && typeKey !== 'all') ? `&type=${typeKey}` : '';
|
||||||
const res = await API.get(
|
const res = await API.get(
|
||||||
`/api/channel/?p=${page}&page_size=${pageSize}&id_sort=${idSort}&tag_mode=${enableTagMode}`,
|
`/api/channel/?p=${page}&page_size=${pageSize}&id_sort=${idSort}&tag_mode=${enableTagMode}${typeParam}`,
|
||||||
);
|
);
|
||||||
if (res === undefined) {
|
if (res === undefined || reqId !== requestCounter.current) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { success, message, data } = res.data;
|
const { success, message, data } = res.data;
|
||||||
if (success) {
|
if (success) {
|
||||||
const { items, total } = data;
|
const { items, total, type_counts } = data;
|
||||||
|
if (type_counts) {
|
||||||
|
const sumAll = Object.values(type_counts).reduce((acc, v) => acc + v, 0);
|
||||||
|
setTypeCounts({ ...type_counts, all: sumAll });
|
||||||
|
}
|
||||||
setChannelFormat(items, enableTagMode);
|
setChannelFormat(items, enableTagMode);
|
||||||
setChannelCount(total);
|
setChannelCount(total);
|
||||||
} else {
|
} else {
|
||||||
@@ -1044,12 +1046,16 @@ const ChannelsTable = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const typeParam = (!enableTagMode && activeTypeKey !== 'all') ? `&type=${activeTypeKey}` : '';
|
||||||
const res = await API.get(
|
const res = await API.get(
|
||||||
`/api/channel/search?keyword=${searchKeyword}&group=${searchGroup}&model=${searchModel}&id_sort=${idSort}&tag_mode=${enableTagMode}`,
|
`/api/channel/search?keyword=${searchKeyword}&group=${searchGroup}&model=${searchModel}&id_sort=${idSort}&tag_mode=${enableTagMode}${typeParam}`,
|
||||||
);
|
);
|
||||||
const { success, message, data } = res.data;
|
const { success, message, data } = res.data;
|
||||||
if (success) {
|
if (success) {
|
||||||
setChannelFormat(data, enableTagMode);
|
const { items = [], type_counts = {} } = data;
|
||||||
|
const sumAll = Object.values(type_counts).reduce((acc, v) => acc + v, 0);
|
||||||
|
setTypeCounts({ ...type_counts, all: sumAll });
|
||||||
|
setChannelFormat(items, enableTagMode);
|
||||||
setActivePage(1);
|
setActivePage(1);
|
||||||
} else {
|
} else {
|
||||||
showError(message);
|
showError(message);
|
||||||
@@ -1179,7 +1185,94 @@ const ChannelsTable = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const channelTypeCounts = useMemo(() => {
|
||||||
|
if (Object.keys(typeCounts).length > 0) return typeCounts;
|
||||||
|
// fallback 本地计算
|
||||||
|
const counts = { all: channels.length };
|
||||||
|
channels.forEach((channel) => {
|
||||||
|
const collect = (ch) => {
|
||||||
|
const type = ch.type;
|
||||||
|
counts[type] = (counts[type] || 0) + 1;
|
||||||
|
};
|
||||||
|
if (channel.children !== undefined) {
|
||||||
|
channel.children.forEach(collect);
|
||||||
|
} else {
|
||||||
|
collect(channel);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return counts;
|
||||||
|
}, [typeCounts, channels]);
|
||||||
|
|
||||||
|
const availableTypeKeys = useMemo(() => {
|
||||||
|
const keys = ['all'];
|
||||||
|
Object.entries(channelTypeCounts).forEach(([k, v]) => {
|
||||||
|
if (k !== 'all' && v > 0) keys.push(String(k));
|
||||||
|
});
|
||||||
|
return keys;
|
||||||
|
}, [channelTypeCounts]);
|
||||||
|
|
||||||
|
const renderTypeTabs = () => {
|
||||||
|
if (enableTagMode) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tabs
|
||||||
|
activeKey={activeTypeKey}
|
||||||
|
type="card"
|
||||||
|
collapsible
|
||||||
|
onChange={(key) => {
|
||||||
|
setActiveTypeKey(key);
|
||||||
|
setActivePage(1);
|
||||||
|
loadChannels(1, pageSize, idSort, enableTagMode, key);
|
||||||
|
}}
|
||||||
|
className="mb-4"
|
||||||
|
>
|
||||||
|
<TabPane
|
||||||
|
itemKey="all"
|
||||||
|
tab={
|
||||||
|
<span className="flex items-center gap-2">
|
||||||
|
{t('全部')}
|
||||||
|
<Tag color={activeTypeKey === 'all' ? 'red' : 'grey'} size='small' shape='circle'>
|
||||||
|
{channelTypeCounts['all'] || 0}
|
||||||
|
</Tag>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{CHANNEL_OPTIONS.filter((opt) => availableTypeKeys.includes(String(opt.value))).map((option) => {
|
||||||
|
const key = String(option.value);
|
||||||
|
const count = channelTypeCounts[option.value] || 0;
|
||||||
|
return (
|
||||||
|
<TabPane
|
||||||
|
key={key}
|
||||||
|
itemKey={key}
|
||||||
|
tab={
|
||||||
|
<span className="flex items-center gap-2">
|
||||||
|
{getChannelIcon(option.value)}
|
||||||
|
{option.label}
|
||||||
|
<Tag color={activeTypeKey === key ? 'red' : 'grey'} size='small' shape='circle'>
|
||||||
|
{count}
|
||||||
|
</Tag>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Tabs>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
let pageData = channels;
|
let pageData = channels;
|
||||||
|
if (activeTypeKey !== 'all') {
|
||||||
|
const typeVal = parseInt(activeTypeKey);
|
||||||
|
if (!isNaN(typeVal)) {
|
||||||
|
pageData = pageData.filter((ch) => {
|
||||||
|
if (ch.children !== undefined) {
|
||||||
|
return ch.children.some((c) => c.type === typeVal);
|
||||||
|
}
|
||||||
|
return ch.type === typeVal;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handlePageChange = (page) => {
|
const handlePageChange = (page) => {
|
||||||
setActivePage(page);
|
setActivePage(page);
|
||||||
@@ -1371,6 +1464,7 @@ const ChannelsTable = () => {
|
|||||||
|
|
||||||
const renderHeader = () => (
|
const renderHeader = () => (
|
||||||
<div className="flex flex-col w-full">
|
<div className="flex flex-col w-full">
|
||||||
|
{renderTypeTabs()}
|
||||||
<div className="flex flex-col md:flex-row justify-between gap-4">
|
<div className="flex flex-col md:flex-row justify-between gap-4">
|
||||||
<div className="flex flex-wrap md:flex-nowrap items-center gap-2 w-full md:w-auto order-2 md:order-1">
|
<div className="flex flex-wrap md:flex-nowrap items-center gap-2 w-full md:w-auto order-2 md:order-1">
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -1588,7 +1588,7 @@
|
|||||||
"性能指标": "Performance Indicators",
|
"性能指标": "Performance Indicators",
|
||||||
"模型数据分析": "Model Data Analysis",
|
"模型数据分析": "Model Data Analysis",
|
||||||
"搜索无结果": "No results found",
|
"搜索无结果": "No results found",
|
||||||
"仪表盘配置": "Dashboard Configuration",
|
"仪表盘设置": "Dashboard Settings",
|
||||||
"API信息管理,可以配置多个API地址用于状态展示和负载均衡(最多50个)": "API information management, you can configure multiple API addresses for status display and load balancing (maximum 50)",
|
"API信息管理,可以配置多个API地址用于状态展示和负载均衡(最多50个)": "API information management, you can configure multiple API addresses for status display and load balancing (maximum 50)",
|
||||||
"线路描述": "Route description",
|
"线路描述": "Route description",
|
||||||
"颜色": "Color",
|
"颜色": "Color",
|
||||||
|
|||||||
@@ -530,7 +530,7 @@ const EditChannel = (props) => {
|
|||||||
handleInputChange('key', value);
|
handleInputChange('key', value);
|
||||||
}}
|
}}
|
||||||
value={inputs.key}
|
value={inputs.key}
|
||||||
style={{ minHeight: 150, fontFamily: 'JetBrains Mono, Consolas' }}
|
autosize={{ minRows: 6, maxRows: 6 }}
|
||||||
autoComplete='new-password'
|
autoComplete='new-password'
|
||||||
className="!rounded-lg"
|
className="!rounded-lg"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1112,6 +1112,7 @@ const Detail = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
<Tabs
|
<Tabs
|
||||||
type="button"
|
type="button"
|
||||||
|
preventScroll={true}
|
||||||
activeKey={activeChartTab}
|
activeKey={activeChartTab}
|
||||||
onChange={setActiveChartTab}
|
onChange={setActiveChartTab}
|
||||||
>
|
>
|
||||||
@@ -1388,6 +1389,7 @@ const Detail = (props) => {
|
|||||||
) : (
|
) : (
|
||||||
<Tabs
|
<Tabs
|
||||||
type="card"
|
type="card"
|
||||||
|
preventScroll={true}
|
||||||
collapsible
|
collapsible
|
||||||
activeKey={activeUptimeTab}
|
activeKey={activeUptimeTab}
|
||||||
onChange={setActiveUptimeTab}
|
onChange={setActiveUptimeTab}
|
||||||
|
|||||||
@@ -184,16 +184,16 @@ export default function GroupRatioSettings(props) {
|
|||||||
if (!value || value.trim() === '') {
|
if (!value || value.trim() === '') {
|
||||||
return true; // Allow empty values
|
return true; // Allow empty values
|
||||||
}
|
}
|
||||||
|
|
||||||
// First check if it's valid JSON
|
// First check if it's valid JSON
|
||||||
try {
|
try {
|
||||||
const parsed = JSON.parse(value);
|
const parsed = JSON.parse(value);
|
||||||
|
|
||||||
// Check if it's an array
|
// Check if it's an array
|
||||||
if (!Array.isArray(parsed)) {
|
if (!Array.isArray(parsed)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if every element is a string
|
// Check if every element is a string
|
||||||
return parsed.every(item => typeof item === 'string');
|
return parsed.every(item => typeof item === 'string');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -10,6 +10,7 @@ import OperationSetting from '../../components/settings/OperationSetting.js';
|
|||||||
import RateLimitSetting from '../../components/settings/RateLimitSetting.js';
|
import RateLimitSetting from '../../components/settings/RateLimitSetting.js';
|
||||||
import ModelSetting from '../../components/settings/ModelSetting.js';
|
import ModelSetting from '../../components/settings/ModelSetting.js';
|
||||||
import DashboardSetting from '../../components/settings/DashboardSetting.js';
|
import DashboardSetting from '../../components/settings/DashboardSetting.js';
|
||||||
|
import RatioSetting from '../../components/settings/RatioSetting.js';
|
||||||
|
|
||||||
const Setting = () => {
|
const Setting = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -24,6 +25,11 @@ const Setting = () => {
|
|||||||
content: <OperationSetting />,
|
content: <OperationSetting />,
|
||||||
itemKey: 'operation',
|
itemKey: 'operation',
|
||||||
});
|
});
|
||||||
|
panes.push({
|
||||||
|
tab: t('倍率设置'),
|
||||||
|
content: <RatioSetting />,
|
||||||
|
itemKey: 'ratio',
|
||||||
|
});
|
||||||
panes.push({
|
panes.push({
|
||||||
tab: t('速率限制设置'),
|
tab: t('速率限制设置'),
|
||||||
content: <RateLimitSetting />,
|
content: <RateLimitSetting />,
|
||||||
@@ -45,7 +51,7 @@ const Setting = () => {
|
|||||||
itemKey: 'other',
|
itemKey: 'other',
|
||||||
});
|
});
|
||||||
panes.push({
|
panes.push({
|
||||||
tab: t('仪表盘配置'),
|
tab: t('仪表盘设置'),
|
||||||
content: <DashboardSetting />,
|
content: <DashboardSetting />,
|
||||||
itemKey: 'dashboard',
|
itemKey: 'dashboard',
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user