diff --git a/common/redis.go b/common/redis.go
index f3205567..55d4931c 100644
--- a/common/redis.go
+++ b/common/redis.go
@@ -2,13 +2,15 @@ package common
import (
"context"
+ "os"
+ "strings"
+ "time"
+
"github.com/go-redis/redis/v8"
"github.com/songquanpeng/one-api/common/logger"
- "os"
- "time"
)
-var RDB *redis.Client
+var RDB redis.Cmdable
var RedisEnabled = true
// InitRedisClient This function is called after init()
@@ -23,13 +25,23 @@ func InitRedisClient() (err error) {
logger.SysLog("SYNC_FREQUENCY not set, Redis is disabled")
return nil
}
- logger.SysLog("Redis is enabled")
- opt, err := redis.ParseURL(os.Getenv("REDIS_CONN_STRING"))
- if err != nil {
- logger.FatalLog("failed to parse Redis connection string: " + err.Error())
+ redisConnString := os.Getenv("REDIS_CONN_STRING")
+ if os.Getenv("REDIS_MASTER_NAME") == "" {
+ logger.SysLog("Redis is enabled")
+ opt, err := redis.ParseURL(redisConnString)
+ if err != nil {
+ logger.FatalLog("failed to parse Redis connection string: " + err.Error())
+ }
+ RDB = redis.NewClient(opt)
+ } else {
+ // cluster mode
+ logger.SysLog("Redis cluster mode enabled")
+ RDB = redis.NewUniversalClient(&redis.UniversalOptions{
+ Addrs: strings.Split(redisConnString, ","),
+ Password: os.Getenv("REDIS_PASSWORD"),
+ MasterName: os.Getenv("REDIS_MASTER_NAME"),
+ })
}
- RDB = redis.NewClient(opt)
-
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
diff --git a/controller/channel-billing.go b/controller/channel-billing.go
index 0bc905de..c7d2d240 100644
--- a/controller/channel-billing.go
+++ b/controller/channel-billing.go
@@ -101,6 +101,16 @@ type SiliconFlowUsageResponse struct {
} `json:"data"`
}
+type DeepSeekUsageResponse struct {
+ IsAvailable bool `json:"is_available"`
+ BalanceInfos []struct {
+ Currency string `json:"currency"`
+ TotalBalance string `json:"total_balance"`
+ GrantedBalance string `json:"granted_balance"`
+ ToppedUpBalance string `json:"topped_up_balance"`
+ } `json:"balance_infos"`
+}
+
// GetAuthHeader get auth header
func GetAuthHeader(token string) http.Header {
h := http.Header{}
@@ -237,7 +247,36 @@ func updateChannelSiliconFlowBalance(channel *model.Channel) (float64, error) {
if response.Code != 20000 {
return 0, fmt.Errorf("code: %d, message: %s", response.Code, response.Message)
}
- balance, err := strconv.ParseFloat(response.Data.Balance, 64)
+ balance, err := strconv.ParseFloat(response.Data.TotalBalance, 64)
+ if err != nil {
+ return 0, err
+ }
+ channel.UpdateBalance(balance)
+ return balance, nil
+}
+
+func updateChannelDeepSeekBalance(channel *model.Channel) (float64, error) {
+ url := "https://api.deepseek.com/user/balance"
+ body, err := GetResponseBody("GET", url, channel, GetAuthHeader(channel.Key))
+ if err != nil {
+ return 0, err
+ }
+ response := DeepSeekUsageResponse{}
+ err = json.Unmarshal(body, &response)
+ if err != nil {
+ return 0, err
+ }
+ index := -1
+ for i, balanceInfo := range response.BalanceInfos {
+ if balanceInfo.Currency == "CNY" {
+ index = i
+ break
+ }
+ }
+ if index == -1 {
+ return 0, errors.New("currency CNY not found")
+ }
+ balance, err := strconv.ParseFloat(response.BalanceInfos[index].TotalBalance, 64)
if err != nil {
return 0, err
}
@@ -271,6 +310,8 @@ func updateChannelBalance(channel *model.Channel) (float64, error) {
return updateChannelAIGC2DBalance(channel)
case channeltype.SiliconFlow:
return updateChannelSiliconFlowBalance(channel)
+ case channeltype.DeepSeek:
+ return updateChannelDeepSeekBalance(channel)
default:
return 0, errors.New("尚未实现")
}
diff --git a/relay/adaptor/ali/constants.go b/relay/adaptor/ali/constants.go
index 3f24ce2e..f3d99520 100644
--- a/relay/adaptor/ali/constants.go
+++ b/relay/adaptor/ali/constants.go
@@ -1,7 +1,23 @@
package ali
var ModelList = []string{
- "qwen-turbo", "qwen-plus", "qwen-max", "qwen-max-longcontext",
- "text-embedding-v1",
+ "qwen-turbo", "qwen-turbo-latest",
+ "qwen-plus", "qwen-plus-latest",
+ "qwen-max", "qwen-max-latest",
+ "qwen-max-longcontext",
+ "qwen-vl-max", "qwen-vl-max-latest", "qwen-vl-plus", "qwen-vl-plus-latest",
+ "qwen-vl-ocr", "qwen-vl-ocr-latest",
+ "qwen-audio-turbo",
+ "qwen-math-plus", "qwen-math-plus-latest", "qwen-math-turbo", "qwen-math-turbo-latest",
+ "qwen-coder-plus", "qwen-coder-plus-latest", "qwen-coder-turbo", "qwen-coder-turbo-latest",
+ "qwq-32b-preview", "qwen2.5-72b-instruct", "qwen2.5-32b-instruct", "qwen2.5-14b-instruct", "qwen2.5-7b-instruct", "qwen2.5-3b-instruct", "qwen2.5-1.5b-instruct", "qwen2.5-0.5b-instruct",
+ "qwen2-72b-instruct", "qwen2-57b-a14b-instruct", "qwen2-7b-instruct", "qwen2-1.5b-instruct", "qwen2-0.5b-instruct",
+ "qwen1.5-110b-chat", "qwen1.5-72b-chat", "qwen1.5-32b-chat", "qwen1.5-14b-chat", "qwen1.5-7b-chat", "qwen1.5-1.8b-chat", "qwen1.5-0.5b-chat",
+ "qwen-72b-chat", "qwen-14b-chat", "qwen-7b-chat", "qwen-1.8b-chat", "qwen-1.8b-longcontext-chat",
+ "qwen2-vl-7b-instruct", "qwen2-vl-2b-instruct", "qwen-vl-v1", "qwen-vl-chat-v1",
+ "qwen2-audio-instruct", "qwen-audio-chat",
+ "qwen2.5-math-72b-instruct", "qwen2.5-math-7b-instruct", "qwen2.5-math-1.5b-instruct", "qwen2-math-72b-instruct", "qwen2-math-7b-instruct", "qwen2-math-1.5b-instruct",
+ "qwen2.5-coder-32b-instruct", "qwen2.5-coder-14b-instruct", "qwen2.5-coder-7b-instruct", "qwen2.5-coder-3b-instruct", "qwen2.5-coder-1.5b-instruct", "qwen2.5-coder-0.5b-instruct",
+ "text-embedding-v1", "text-embedding-v3", "text-embedding-v2", "text-embedding-async-v2", "text-embedding-async-v1",
"ali-stable-diffusion-xl", "ali-stable-diffusion-v1.5", "wanx-v1",
}
diff --git a/relay/adaptor/anthropic/constants.go b/relay/adaptor/anthropic/constants.go
index cb574706..8ea7c4d8 100644
--- a/relay/adaptor/anthropic/constants.go
+++ b/relay/adaptor/anthropic/constants.go
@@ -9,5 +9,4 @@ var ModelList = []string{
"claude-3-5-sonnet-20240620",
"claude-3-5-sonnet-20241022",
"claude-3-5-sonnet-latest",
- "claude-3-5-haiku-20241022",
}
diff --git a/relay/adaptor/gemini/constants.go b/relay/adaptor/gemini/constants.go
index 57b14378..9d1cbc4a 100644
--- a/relay/adaptor/gemini/constants.go
+++ b/relay/adaptor/gemini/constants.go
@@ -6,5 +6,6 @@ var ModelList = []string{
"gemini-pro", "gemini-1.0-pro",
"gemini-1.5-flash", "gemini-1.5-pro",
"text-embedding-004", "aqa",
- "gemini-2.0-flash-exp", "gemini-2.0-flash-thinking-exp",
+ "gemini-2.0-flash-exp",
+ "gemini-2.0-flash-thinking-exp",
}
diff --git a/relay/billing/ratio/model.go b/relay/billing/ratio/model.go
index 712c710d..125dbb9a 100644
--- a/relay/billing/ratio/model.go
+++ b/relay/billing/ratio/model.go
@@ -130,29 +130,94 @@ var ModelRatio = map[string]float64{
"chatglm_lite": 0.1429, // ¥0.002 / 1k tokens
"cogview-3": 0.25 * RMB,
// https://help.aliyun.com/zh/dashscope/developer-reference/tongyi-thousand-questions-metering-and-billing
- "qwen-turbo": 0.5715, // ¥0.008 / 1k tokens
- "qwen-plus": 1.4286, // ¥0.02 / 1k tokens
- "qwen-max": 1.4286, // ¥0.02 / 1k tokens
- "qwen-max-longcontext": 1.4286, // ¥0.02 / 1k tokens
- "text-embedding-v1": 0.05, // ¥0.0007 / 1k tokens
- "ali-stable-diffusion-xl": 8,
- "ali-stable-diffusion-v1.5": 8,
- "wanx-v1": 8,
- "SparkDesk": 1.2858, // ¥0.018 / 1k tokens
- "SparkDesk-v1.1": 1.2858, // ¥0.018 / 1k tokens
- "SparkDesk-v2.1": 1.2858, // ¥0.018 / 1k tokens
- "SparkDesk-v3.1": 1.2858, // ¥0.018 / 1k tokens
- "SparkDesk-v3.1-128K": 1.2858, // ¥0.018 / 1k tokens
- "SparkDesk-v3.5": 1.2858, // ¥0.018 / 1k tokens
- "SparkDesk-v3.5-32K": 1.2858, // ¥0.018 / 1k tokens
- "SparkDesk-v4.0": 1.2858, // ¥0.018 / 1k tokens
- "360GPT_S2_V9": 0.8572, // ¥0.012 / 1k tokens
- "embedding-bert-512-v1": 0.0715, // ¥0.001 / 1k tokens
- "embedding_s1_v1": 0.0715, // ¥0.001 / 1k tokens
- "semantic_similarity_s1_v1": 0.0715, // ¥0.001 / 1k tokens
- "hunyuan": 7.143, // ¥0.1 / 1k tokens // https://cloud.tencent.com/document/product/1729/97731#e0e6be58-60c8-469f-bdeb-6c264ce3b4d0
- "ChatStd": 0.01 * RMB,
- "ChatPro": 0.1 * RMB,
+ "qwen-turbo": 1.4286, // ¥0.02 / 1k tokens
+ "qwen-turbo-latest": 1.4286,
+ "qwen-plus": 1.4286,
+ "qwen-plus-latest": 1.4286,
+ "qwen-max": 1.4286,
+ "qwen-max-latest": 1.4286,
+ "qwen-max-longcontext": 1.4286,
+ "qwen-vl-max": 1.4286,
+ "qwen-vl-max-latest": 1.4286,
+ "qwen-vl-plus": 1.4286,
+ "qwen-vl-plus-latest": 1.4286,
+ "qwen-vl-ocr": 1.4286,
+ "qwen-vl-ocr-latest": 1.4286,
+ "qwen-audio-turbo": 1.4286,
+ "qwen-math-plus": 1.4286,
+ "qwen-math-plus-latest": 1.4286,
+ "qwen-math-turbo": 1.4286,
+ "qwen-math-turbo-latest": 1.4286,
+ "qwen-coder-plus": 1.4286,
+ "qwen-coder-plus-latest": 1.4286,
+ "qwen-coder-turbo": 1.4286,
+ "qwen-coder-turbo-latest": 1.4286,
+ "qwq-32b-preview": 1.4286,
+ "qwen2.5-72b-instruct": 1.4286,
+ "qwen2.5-32b-instruct": 1.4286,
+ "qwen2.5-14b-instruct": 1.4286,
+ "qwen2.5-7b-instruct": 1.4286,
+ "qwen2.5-3b-instruct": 1.4286,
+ "qwen2.5-1.5b-instruct": 1.4286,
+ "qwen2.5-0.5b-instruct": 1.4286,
+ "qwen2-72b-instruct": 1.4286,
+ "qwen2-57b-a14b-instruct": 1.4286,
+ "qwen2-7b-instruct": 1.4286,
+ "qwen2-1.5b-instruct": 1.4286,
+ "qwen2-0.5b-instruct": 1.4286,
+ "qwen1.5-110b-chat": 1.4286,
+ "qwen1.5-72b-chat": 1.4286,
+ "qwen1.5-32b-chat": 1.4286,
+ "qwen1.5-14b-chat": 1.4286,
+ "qwen1.5-7b-chat": 1.4286,
+ "qwen1.5-1.8b-chat": 1.4286,
+ "qwen1.5-0.5b-chat": 1.4286,
+ "qwen-72b-chat": 1.4286,
+ "qwen-14b-chat": 1.4286,
+ "qwen-7b-chat": 1.4286,
+ "qwen-1.8b-chat": 1.4286,
+ "qwen-1.8b-longcontext-chat": 1.4286,
+ "qwen2-vl-7b-instruct": 1.4286,
+ "qwen2-vl-2b-instruct": 1.4286,
+ "qwen-vl-v1": 1.4286,
+ "qwen-vl-chat-v1": 1.4286,
+ "qwen2-audio-instruct": 1.4286,
+ "qwen-audio-chat": 1.4286,
+ "qwen2.5-math-72b-instruct": 1.4286,
+ "qwen2.5-math-7b-instruct": 1.4286,
+ "qwen2.5-math-1.5b-instruct": 1.4286,
+ "qwen2-math-72b-instruct": 1.4286,
+ "qwen2-math-7b-instruct": 1.4286,
+ "qwen2-math-1.5b-instruct": 1.4286,
+ "qwen2.5-coder-32b-instruct": 1.4286,
+ "qwen2.5-coder-14b-instruct": 1.4286,
+ "qwen2.5-coder-7b-instruct": 1.4286,
+ "qwen2.5-coder-3b-instruct": 1.4286,
+ "qwen2.5-coder-1.5b-instruct": 1.4286,
+ "qwen2.5-coder-0.5b-instruct": 1.4286,
+ "text-embedding-v1": 0.05, // ¥0.0007 / 1k tokens
+ "text-embedding-v3": 0.05,
+ "text-embedding-v2": 0.05,
+ "text-embedding-async-v2": 0.05,
+ "text-embedding-async-v1": 0.05,
+ "ali-stable-diffusion-xl": 8.00,
+ "ali-stable-diffusion-v1.5": 8.00,
+ "wanx-v1": 8.00,
+ "SparkDesk": 1.2858, // ¥0.018 / 1k tokens
+ "SparkDesk-v1.1": 1.2858, // ¥0.018 / 1k tokens
+ "SparkDesk-v2.1": 1.2858, // ¥0.018 / 1k tokens
+ "SparkDesk-v3.1": 1.2858, // ¥0.018 / 1k tokens
+ "SparkDesk-v3.1-128K": 1.2858, // ¥0.018 / 1k tokens
+ "SparkDesk-v3.5": 1.2858, // ¥0.018 / 1k tokens
+ "SparkDesk-v3.5-32K": 1.2858, // ¥0.018 / 1k tokens
+ "SparkDesk-v4.0": 1.2858, // ¥0.018 / 1k tokens
+ "360GPT_S2_V9": 0.8572, // ¥0.012 / 1k tokens
+ "embedding-bert-512-v1": 0.0715, // ¥0.001 / 1k tokens
+ "embedding_s1_v1": 0.0715, // ¥0.001 / 1k tokens
+ "semantic_similarity_s1_v1": 0.0715, // ¥0.001 / 1k tokens
+ "hunyuan": 7.143, // ¥0.1 / 1k tokens // https://cloud.tencent.com/document/product/1729/97731#e0e6be58-60c8-469f-bdeb-6c264ce3b4d0
+ "ChatStd": 0.01 * RMB,
+ "ChatPro": 0.1 * RMB,
// https://platform.moonshot.cn/pricing
"moonshot-v1-8k": 0.012 * RMB,
"moonshot-v1-32k": 0.024 * RMB,
@@ -390,11 +455,13 @@ func GetCompletionRatio(name string, channelType int) float64 {
return 4.0 / 3.0
}
if strings.HasPrefix(name, "gpt-4") {
- if strings.HasPrefix(name, "gpt-4o-mini") || name == "gpt-4o-2024-08-06" {
+ if strings.HasPrefix(name, "gpt-4o") {
+ if name == "gpt-4o-2024-05-13" {
+ return 3
+ }
return 4
}
if strings.HasPrefix(name, "gpt-4-turbo") ||
- strings.HasPrefix(name, "gpt-4o") ||
strings.HasSuffix(name, "preview") {
return 3
}
diff --git a/relay/controller/audio.go b/relay/controller/audio.go
index dafa5cc7..541ee1a5 100644
--- a/relay/controller/audio.go
+++ b/relay/controller/audio.go
@@ -111,16 +111,9 @@ func RelayAudioHelper(c *gin.Context, relayMode int) *relaymodel.ErrorWithStatus
}()
// map model name
- modelMapping := c.GetString(ctxkey.ModelMapping)
- if modelMapping != "" {
- modelMap := make(map[string]string)
- err := json.Unmarshal([]byte(modelMapping), &modelMap)
- if err != nil {
- return openai.ErrorWrapper(err, "unmarshal_model_mapping_failed", http.StatusInternalServerError)
- }
- if modelMap[audioModel] != "" {
- audioModel = modelMap[audioModel]
- }
+ modelMapping := c.GetStringMapString(ctxkey.ModelMapping)
+ if modelMapping != nil && modelMapping[audioModel] != "" {
+ audioModel = modelMapping[audioModel]
}
baseURL := channeltype.ChannelBaseURLs[channelType]
diff --git a/web/berry/src/constants/ChannelConstants.js b/web/berry/src/constants/ChannelConstants.js
index 375adcd9..b5a855a6 100644
--- a/web/berry/src/constants/ChannelConstants.js
+++ b/web/berry/src/constants/ChannelConstants.js
@@ -185,7 +185,7 @@ export const CHANNEL_OPTIONS = {
value: 45,
color: 'primary'
},
- 45: {
+ 46: {
key: 46,
text: 'Replicate',
value: 46,
diff --git a/web/berry/src/views/Channel/component/TableRow.js b/web/berry/src/views/Channel/component/TableRow.js
index 3114479d..525f9188 100644
--- a/web/berry/src/views/Channel/component/TableRow.js
+++ b/web/berry/src/views/Channel/component/TableRow.js
@@ -268,6 +268,8 @@ function renderBalance(type, balance) {
return ¥{balance.toFixed(2)};
case 13: // AIGC2D
return {renderNumber(balance)};
+ case 36: // DeepSeek
+ return ¥{balance.toFixed(2)};
case 44: // SiliconFlow
return ¥{balance.toFixed(2)};
default:
diff --git a/web/default/src/components/ChannelsTable.js b/web/default/src/components/ChannelsTable.js
index 6e0ec05d..e745814b 100644
--- a/web/default/src/components/ChannelsTable.js
+++ b/web/default/src/components/ChannelsTable.js
@@ -52,6 +52,8 @@ function renderBalance(type, balance) {
return ¥{balance.toFixed(2)};
case 13: // AIGC2D
return {renderNumber(balance)};
+ case 36: // DeepSeek
+ return ¥{balance.toFixed(2)};
case 44: // SiliconFlow
return ¥{balance.toFixed(2)};
default: