mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-04-08 12:17:26 +00:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9b421478c1 | ||
|
|
569751f5db | ||
|
|
608c945ae6 | ||
|
|
05beade3ad | ||
|
|
81167c4322 | ||
|
|
6fa1837c24 | ||
|
|
ba0c5bb4d9 | ||
|
|
5482fff62d | ||
|
|
1cde58c089 | ||
|
|
a0c4e9f10e | ||
|
|
d6d91e4340 | ||
|
|
f19b11be8c |
@@ -34,8 +34,9 @@ var ModelRatio = map[string]float64{
|
||||
"gpt-3.5-turbo-16k-0613": 1.5,
|
||||
"gpt-3.5-turbo-instruct": 0.75, // $0.0015 / 1K tokens
|
||||
"gpt-3.5-turbo-1106": 0.5, // $0.001 / 1K tokens
|
||||
"babbage-002": 0.2, // $0.0004 / 1K tokens
|
||||
"davinci-002": 1, // $0.002 / 1K tokens
|
||||
"gpt-3.5-turbo-0125": 0.25,
|
||||
"babbage-002": 0.2, // $0.0004 / 1K tokens
|
||||
"davinci-002": 1, // $0.002 / 1K tokens
|
||||
"text-ada-001": 0.2,
|
||||
"text-babbage-001": 0.25,
|
||||
"text-curie-001": 1,
|
||||
@@ -148,6 +149,9 @@ func GetModelRatio(name string) float64 {
|
||||
|
||||
func GetCompletionRatio(name string) float64 {
|
||||
if strings.HasPrefix(name, "gpt-3.5") {
|
||||
if strings.HasSuffix(name, "0125") {
|
||||
return 3
|
||||
}
|
||||
if strings.HasSuffix(name, "1106") {
|
||||
return 2
|
||||
}
|
||||
|
||||
@@ -73,6 +73,35 @@ func RedisDel(key string) error {
|
||||
}
|
||||
|
||||
func RedisDecrease(key string, value int64) error {
|
||||
ctx := context.Background()
|
||||
return RDB.DecrBy(ctx, key, value).Err()
|
||||
|
||||
// 检查键的剩余生存时间
|
||||
ttlCmd := RDB.TTL(context.Background(), key)
|
||||
ttl, err := ttlCmd.Result()
|
||||
if err != nil {
|
||||
// 失败则尝试直接减少
|
||||
return RDB.DecrBy(context.Background(), key, value).Err()
|
||||
}
|
||||
|
||||
// 如果剩余生存时间大于0,则进行减少操作
|
||||
if ttl > 0 {
|
||||
ctx := context.Background()
|
||||
// 开始一个Redis事务
|
||||
txn := RDB.TxPipeline()
|
||||
|
||||
// 减少余额
|
||||
decrCmd := txn.DecrBy(ctx, key, value)
|
||||
if err := decrCmd.Err(); err != nil {
|
||||
return err // 如果减少失败,则直接返回错误
|
||||
}
|
||||
|
||||
// 重新设置过期时间,使用原来的过期时间
|
||||
txn.Expire(ctx, key, ttl)
|
||||
|
||||
// 执行事务
|
||||
_, err = txn.Exec(ctx)
|
||||
return err
|
||||
} else {
|
||||
_ = RedisDel(key)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
)
|
||||
|
||||
func testChannel(channel *model.Channel, request ChatRequest) (err error, openaiErr *OpenAIError) {
|
||||
common.SysLog(fmt.Sprintf("testing channel %d with model %s", channel.Id, request.Model))
|
||||
switch channel.Type {
|
||||
case common.ChannelTypePaLM:
|
||||
fallthrough
|
||||
@@ -47,7 +48,11 @@ func testChannel(channel *model.Channel, request ChatRequest) (err error, openai
|
||||
request.Model = "gpt-3.5-turbo"
|
||||
}
|
||||
}
|
||||
requestURL := getFullRequestURL(channel.GetBaseURL(), "/v1/chat/completions", channel.Type)
|
||||
baseUrl := common.ChannelBaseURLs[channel.Type]
|
||||
if channel.GetBaseURL() != "" {
|
||||
baseUrl = channel.GetBaseURL()
|
||||
}
|
||||
requestURL := getFullRequestURL(baseUrl, "/v1/chat/completions", channel.Type)
|
||||
|
||||
if channel.Type == common.ChannelTypeAzure {
|
||||
requestURL = getFullRequestURL(channel.GetBaseURL(), fmt.Sprintf("/openai/deployments/%s/chat/completions?api-version=2023-03-15-preview", request.Model), channel.Type)
|
||||
@@ -109,7 +114,7 @@ func TestChannel(c *gin.Context) {
|
||||
})
|
||||
return
|
||||
}
|
||||
testModel := c.Param("model")
|
||||
testModel := c.Query("model")
|
||||
channel, err := model.GetChannelById(id, true)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
|
||||
@@ -38,6 +38,7 @@ func GetStatus(c *gin.Context) {
|
||||
"enable_drawing": common.DrawingEnabled,
|
||||
"enable_data_export": common.DataExportEnabled,
|
||||
"data_export_default_time": common.DataExportDefaultTime,
|
||||
"enable_online_topup": common.PayAddress != "" && common.EpayId != "" && common.EpayKey != "",
|
||||
},
|
||||
})
|
||||
return
|
||||
|
||||
@@ -180,6 +180,15 @@ func init() {
|
||||
Root: "gpt-3.5-turbo-1106",
|
||||
Parent: nil,
|
||||
},
|
||||
{
|
||||
Id: "gpt-3.5-turbo-0125",
|
||||
Object: "model",
|
||||
Created: 1706232090,
|
||||
OwnedBy: "openai",
|
||||
Permission: permission,
|
||||
Root: "gpt-3.5-turbo-0125",
|
||||
Parent: nil,
|
||||
},
|
||||
{
|
||||
Id: "gpt-3.5-turbo-instruct",
|
||||
Object: "model",
|
||||
|
||||
@@ -88,17 +88,17 @@ func requestOpenAI2Ali(request GeneralOpenAIRequest) *AliChatRequest {
|
||||
message := request.Messages[i]
|
||||
if message.Role == "system" {
|
||||
messages = append(messages, AliMessage{
|
||||
User: string(message.Content),
|
||||
User: message.StringContent(),
|
||||
Bot: "Okay",
|
||||
})
|
||||
continue
|
||||
} else {
|
||||
if i == len(request.Messages)-1 {
|
||||
prompt = string(message.Content)
|
||||
prompt = message.StringContent()
|
||||
break
|
||||
}
|
||||
messages = append(messages, AliMessage{
|
||||
User: string(message.Content),
|
||||
User: message.StringContent(),
|
||||
Bot: string(request.Messages[i+1].Content),
|
||||
})
|
||||
i++
|
||||
|
||||
@@ -89,7 +89,7 @@ func requestOpenAI2Baidu(request GeneralOpenAIRequest) *BaiduChatRequest {
|
||||
if message.Role == "system" {
|
||||
messages = append(messages, BaiduMessage{
|
||||
Role: "user",
|
||||
Content: string(message.Content),
|
||||
Content: message.StringContent(),
|
||||
})
|
||||
messages = append(messages, BaiduMessage{
|
||||
Role: "assistant",
|
||||
@@ -98,7 +98,7 @@ func requestOpenAI2Baidu(request GeneralOpenAIRequest) *BaiduChatRequest {
|
||||
} else {
|
||||
messages = append(messages, BaiduMessage{
|
||||
Role: message.Role,
|
||||
Content: string(message.Content),
|
||||
Content: message.StringContent(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ func requestOpenAI2Gemini(textRequest GeneralOpenAIRequest) *GeminiChatRequest {
|
||||
Role: message.Role,
|
||||
Parts: []GeminiPart{
|
||||
{
|
||||
Text: string(message.Content),
|
||||
Text: message.StringContent(),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ func requestOpenAI2PaLM(textRequest GeneralOpenAIRequest) *PaLMChatRequest {
|
||||
}
|
||||
for _, message := range textRequest.Messages {
|
||||
palmMessage := PaLMChatMessage{
|
||||
Content: string(message.Content),
|
||||
Content: message.StringContent(),
|
||||
}
|
||||
if message.Role == "user" {
|
||||
palmMessage.Author = "0"
|
||||
|
||||
@@ -84,7 +84,7 @@ func requestOpenAI2Tencent(request GeneralOpenAIRequest) *TencentChatRequest {
|
||||
if message.Role == "system" {
|
||||
messages = append(messages, TencentMessage{
|
||||
Role: "user",
|
||||
Content: string(message.Content),
|
||||
Content: message.StringContent(),
|
||||
})
|
||||
messages = append(messages, TencentMessage{
|
||||
Role: "assistant",
|
||||
@@ -93,7 +93,7 @@ func requestOpenAI2Tencent(request GeneralOpenAIRequest) *TencentChatRequest {
|
||||
continue
|
||||
}
|
||||
messages = append(messages, TencentMessage{
|
||||
Content: string(message.Content),
|
||||
Content: message.StringContent(),
|
||||
Role: message.Role,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ func requestOpenAI2Xunfei(request GeneralOpenAIRequest, xunfeiAppId string, doma
|
||||
if message.Role == "system" {
|
||||
messages = append(messages, XunfeiMessage{
|
||||
Role: "user",
|
||||
Content: string(message.Content),
|
||||
Content: message.StringContent(),
|
||||
})
|
||||
messages = append(messages, XunfeiMessage{
|
||||
Role: "assistant",
|
||||
@@ -90,7 +90,7 @@ func requestOpenAI2Xunfei(request GeneralOpenAIRequest, xunfeiAppId string, doma
|
||||
} else {
|
||||
messages = append(messages, XunfeiMessage{
|
||||
Role: message.Role,
|
||||
Content: string(message.Content),
|
||||
Content: message.StringContent(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ func requestOpenAI2Zhipu(request GeneralOpenAIRequest) *ZhipuRequest {
|
||||
if message.Role == "system" {
|
||||
messages = append(messages, ZhipuMessage{
|
||||
Role: "system",
|
||||
Content: string(message.Content),
|
||||
Content: message.StringContent(),
|
||||
})
|
||||
messages = append(messages, ZhipuMessage{
|
||||
Role: "user",
|
||||
@@ -123,7 +123,7 @@ func requestOpenAI2Zhipu(request GeneralOpenAIRequest) *ZhipuRequest {
|
||||
} else {
|
||||
messages = append(messages, ZhipuMessage{
|
||||
Role: message.Role,
|
||||
Content: string(message.Content),
|
||||
Content: message.StringContent(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,14 @@ const (
|
||||
ContentTypeImageURL = "image_url"
|
||||
)
|
||||
|
||||
func (m Message) StringContent() string {
|
||||
var stringContent string
|
||||
if err := json.Unmarshal(m.Content, &stringContent); err == nil {
|
||||
return stringContent
|
||||
}
|
||||
return string(m.Content)
|
||||
}
|
||||
|
||||
func (m Message) ParseContent() []MediaMessage {
|
||||
var contentList []MediaMessage
|
||||
var stringContent string
|
||||
@@ -132,6 +140,8 @@ type GeneralOpenAIRequest struct {
|
||||
Tools any `json:"tools,omitempty"`
|
||||
ToolChoice any `json:"tool_choice,omitempty"`
|
||||
User string `json:"user,omitempty"`
|
||||
LogProbs bool `json:"logprobs,omitempty"`
|
||||
TopLogProbs int `json:"top_logprobs,omitempty"`
|
||||
}
|
||||
|
||||
func (r GeneralOpenAIRequest) ParseInput() []string {
|
||||
@@ -399,12 +409,13 @@ func RelayMidjourney(c *gin.Context) {
|
||||
if err.Code == 30 {
|
||||
err.Result = "当前分组负载已饱和,请稍后再试,或升级账户以提升服务质量。"
|
||||
}
|
||||
c.JSON(400, gin.H{
|
||||
"error": err.Description + " " + err.Result,
|
||||
c.JSON(429, gin.H{
|
||||
"error": fmt.Sprintf("%s %s", err.Description, err.Result),
|
||||
"type": "upstream_error",
|
||||
})
|
||||
}
|
||||
channelId := c.GetInt("channel_id")
|
||||
common.SysError(fmt.Sprintf("relay error (channel #%d): %s", channelId, err.Result))
|
||||
common.SysError(fmt.Sprintf("relay error (channel #%d): %s", channelId, fmt.Sprintf("%s %s", err.Description, err.Result)))
|
||||
//if shouldDisableChannel(&err.OpenAIError) {
|
||||
// channelId := c.GetInt("channel_id")
|
||||
// channelName := c.GetString("channel_name")
|
||||
|
||||
@@ -48,7 +48,7 @@ func Distribute() func(c *gin.Context) {
|
||||
err = common.UnmarshalBodyReusable(c, &modelRequest)
|
||||
}
|
||||
if err != nil {
|
||||
abortWithMessage(c, http.StatusBadRequest, "无效的请求: "+err.Error())
|
||||
abortWithMessage(c, http.StatusBadRequest, "无效的请求, "+err.Error())
|
||||
return
|
||||
}
|
||||
if strings.HasPrefix(c.Request.URL.Path, "/v1/moderations") {
|
||||
|
||||
@@ -47,7 +47,9 @@ func ValidateUserToken(key string) (token *Token, err error) {
|
||||
token, err = CacheGetTokenByKey(key)
|
||||
if err == nil {
|
||||
if token.Status == common.TokenStatusExhausted {
|
||||
return nil, errors.New("该令牌额度已用尽 token.Status == common.TokenStatusExhausted " + key)
|
||||
keyPrefix := key[:3]
|
||||
keySuffix := key[len(key)-3:]
|
||||
return nil, errors.New("该令牌额度已用尽 TokenStatusExhausted[sk-" + keyPrefix + "***" + keySuffix + "]")
|
||||
} else if token.Status == common.TokenStatusExpired {
|
||||
return nil, errors.New("该令牌已过期")
|
||||
}
|
||||
@@ -73,7 +75,9 @@ func ValidateUserToken(key string) (token *Token, err error) {
|
||||
common.SysError("failed to update token status" + err.Error())
|
||||
}
|
||||
}
|
||||
return nil, errors.New(fmt.Sprintf("%s 该令牌额度已用尽 !token.UnlimitedQuota && token.RemainQuota = %d", token.Key, token.RemainQuota))
|
||||
keyPrefix := key[:3]
|
||||
keySuffix := key[len(key)-3:]
|
||||
return nil, errors.New(fmt.Sprintf("[sk-%s***%s] 该令牌额度已用尽 !token.UnlimitedQuota && token.RemainQuota = %d", keyPrefix, keySuffix, token.RemainQuota))
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@douyinfe/semi-ui": "^2.46.1",
|
||||
"@douyinfe/semi-icons": "^2.46.1",
|
||||
"@visactor/vchart": "~1.8.8",
|
||||
"@visactor/react-vchart": "~1.8.8",
|
||||
"@visactor/vchart-semi-theme": "~1.8.8",
|
||||
|
||||
@@ -463,11 +463,8 @@ const ChannelsTable = () => {
|
||||
const res = await API.get(`/api/channel/test/${record.id}?model=${model}`);
|
||||
const {success, message, time} = res.data;
|
||||
if (success) {
|
||||
let newChannels = [...channels];
|
||||
record.response_time = time * 1000;
|
||||
record.test_time = Date.now() / 1000;
|
||||
|
||||
setChannelFormat(newChannels)
|
||||
showInfo(`通道 ${record.name} 测试成功,耗时 ${time.toFixed(2)} 秒。`);
|
||||
} else {
|
||||
showError(message);
|
||||
|
||||
@@ -43,7 +43,8 @@ const HeaderBar = () => {
|
||||
const logo = getLogo();
|
||||
var themeMode = localStorage.getItem('theme-mode');
|
||||
const currentDate = new Date();
|
||||
const isNewYear = currentDate.getMonth() === 0 && currentDate.getDate() === 1;
|
||||
// enable fireworks on new year(1.1 and 2.9-2.24)
|
||||
const isNewYear = (currentDate.getMonth() === 0 && currentDate.getDate() === 1) || (currentDate.getMonth() === 1 && currentDate.getDate() >= 9 && currentDate.getDate() <= 24);
|
||||
|
||||
async function logout() {
|
||||
setShowSidebar(false);
|
||||
|
||||
@@ -8,8 +8,10 @@ const TopUp = () => {
|
||||
const [redemptionCode, setRedemptionCode] = useState('');
|
||||
const [topUpCode, setTopUpCode] = useState('');
|
||||
const [topUpCount, setTopUpCount] = useState(10);
|
||||
const [minTopupCount, setMinTopUpCount] = useState(1);
|
||||
const [amount, setAmount] = useState(0.0);
|
||||
const [topUpLink, setTopUpLink] = useState('');
|
||||
const [enableOnlineTopUp, setEnableOnlineTopUp] = useState(false);
|
||||
const [userQuota, setUserQuota] = useState(0);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [open, setOpen] = useState(false);
|
||||
@@ -52,6 +54,10 @@ const TopUp = () => {
|
||||
};
|
||||
|
||||
const preTopUp = async (payment) => {
|
||||
if (!enableOnlineTopUp) {
|
||||
showError('管理员未开启在线充值!');
|
||||
return;
|
||||
}
|
||||
if (amount === 0) {
|
||||
await getAmount();
|
||||
}
|
||||
@@ -126,6 +132,9 @@ const TopUp = () => {
|
||||
if (status.top_up_link) {
|
||||
setTopUpLink(status.top_up_link);
|
||||
}
|
||||
if (status.enable_online_topup) {
|
||||
setEnableOnlineTopUp(status.enable_online_topup);
|
||||
}
|
||||
}
|
||||
getUserQuota().then();
|
||||
}, []);
|
||||
@@ -227,13 +236,23 @@ const TopUp = () => {
|
||||
</Divider>
|
||||
<Form>
|
||||
<Form.Input
|
||||
disabled={!enableOnlineTopUp}
|
||||
field={'redemptionCount'}
|
||||
label={'实付金额:' + renderAmount()}
|
||||
placeholder='充值数量'
|
||||
name='redemptionCount'
|
||||
type={'number'}
|
||||
value={topUpCount}
|
||||
suffix={'$'}
|
||||
min={1}
|
||||
max={100000}
|
||||
onChange={async (value) => {
|
||||
if (value < 1) {
|
||||
value = 1;
|
||||
}
|
||||
if (value > 100000) {
|
||||
value = 100000;
|
||||
}
|
||||
setTopUpCount(value);
|
||||
await getAmount(value);
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user