Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion controller/playground.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"fmt"

"github.com/QuantumNous/new-api/i18n"
"github.com/QuantumNous/new-api/middleware"
"github.com/QuantumNous/new-api/model"
relaycommon "github.com/QuantumNous/new-api/relay/common"
Expand All @@ -25,7 +26,7 @@ func Playground(c *gin.Context) {

useAccessToken := c.GetBool("use_access_token")
if useAccessToken {
newAPIError = types.NewError(errors.New("暂不支持使用 access token"), types.ErrorCodeAccessDenied, types.ErrOptionWithSkipRetry())
newAPIError = types.NewError(errors.New(i18n.T(c, i18n.MsgPlaygroundAccessTokenUnsupported)), types.ErrorCodeAccessDenied, types.ErrOptionWithSkipRetry())
return
}

Expand Down
9 changes: 5 additions & 4 deletions controller/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/QuantumNous/new-api/common"
"github.com/QuantumNous/new-api/constant"
"github.com/QuantumNous/new-api/dto"
"github.com/QuantumNous/new-api/i18n"
"github.com/QuantumNous/new-api/logger"
"github.com/QuantumNous/new-api/middleware"
"github.com/QuantumNous/new-api/model"
Expand Down Expand Up @@ -308,10 +309,10 @@ func getChannel(c *gin.Context, info *relaycommon.RelayInfo, retryParam *service
info.PriceData.GroupRatioInfo = helper.HandleGroupRatio(c, info)

if err != nil {
return nil, types.NewError(fmt.Errorf("获取分组 %s 下模型 %s 的可用渠道失败(retry): %s", selectGroup, info.OriginModelName, err.Error()), types.ErrorCodeGetChannelFailed, types.ErrOptionWithSkipRetry())
return nil, types.NewError(errors.New(i18n.T(c, i18n.MsgChannelGetAvailableRetryFailed, map[string]any{"Group": selectGroup, "Model": info.OriginModelName, "Error": err.Error()})), types.ErrorCodeGetChannelFailed, types.ErrOptionWithSkipRetry())
}
if channel == nil {
return nil, types.NewError(fmt.Errorf("分组 %s 下模型 %s 的可用渠道不存在(retry)", selectGroup, info.OriginModelName), types.ErrorCodeGetChannelFailed, types.ErrOptionWithSkipRetry())
return nil, types.NewError(errors.New(i18n.T(c, i18n.MsgChannelNoAvailableRetry, map[string]any{"Group": selectGroup, "Model": info.OriginModelName})), types.ErrorCodeGetChannelFailed, types.ErrOptionWithSkipRetry())
}

newAPIError := middleware.SetupContextForSelectedChannel(c, channel, info.OriginModelName)
Expand Down Expand Up @@ -430,7 +431,7 @@ func RelayMidjourney(c *gin.Context) {
if mjErr != nil {
statusCode := http.StatusBadRequest
if mjErr.Code == 30 {
mjErr.Result = "当前分组负载已饱和,请稍后再试,或升级账户以提升服务质量。"
mjErr.Result = i18n.T(c, i18n.MsgChannelUpstreamSaturatedUpgrade)
statusCode = http.StatusTooManyRequests
}
c.JSON(statusCode, gin.H{
Expand Down Expand Up @@ -605,7 +606,7 @@ func RelayTask(c *gin.Context) {
// respondTaskError 统一输出 Task 错误响应(含 429 限流提示改写)
func respondTaskError(c *gin.Context, taskErr *dto.TaskError) {
if taskErr.StatusCode == http.StatusTooManyRequests {
taskErr.Message = "当前分组上游负载已饱和,请稍后再试"
taskErr.Message = i18n.T(c, i18n.MsgChannelUpstreamSaturated)
}
c.JSON(taskErr.StatusCode, taskErr)
}
Expand Down
40 changes: 29 additions & 11 deletions i18n/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ const (
MsgAuthUserIdMismatch = "auth.user_id_mismatch"
MsgAuthUserBanned = "auth.user_banned"
MsgAuthInsufficientPrivilege = "auth.insufficient_privilege"
MsgAuthClientIpParseFailed = "auth.client_ip_parse_failed"
MsgAuthIpNotAllowed = "auth.ip_not_allowed"
MsgAuthGroupAccessDenied = "auth.group_access_denied"
MsgAuthGroupDeprecated = "auth.group_deprecated"
MsgAuthSpecificChannelDenied = "auth.specific_channel_denied"
)

// Token related messages
Expand Down Expand Up @@ -166,17 +171,30 @@ const (

// Channel related messages
const (
MsgChannelNotExists = "channel.not_exists"
MsgChannelIdFormatError = "channel.id_format_error"
MsgChannelNoAvailableKey = "channel.no_available_key"
MsgChannelGetListFailed = "channel.get_list_failed"
MsgChannelGetTagsFailed = "channel.get_tags_failed"
MsgChannelGetKeyFailed = "channel.get_key_failed"
MsgChannelGetOllamaFailed = "channel.get_ollama_failed"
MsgChannelQueryFailed = "channel.query_failed"
MsgChannelNoValidUpstream = "channel.no_valid_upstream"
MsgChannelUpstreamSaturated = "channel.upstream_saturated"
MsgChannelGetAvailableFailed = "channel.get_available_failed"
MsgChannelNotExists = "channel.not_exists"
MsgChannelIdFormatError = "channel.id_format_error"
MsgChannelNoAvailableKey = "channel.no_available_key"
MsgChannelGetListFailed = "channel.get_list_failed"
MsgChannelGetTagsFailed = "channel.get_tags_failed"
MsgChannelGetKeyFailed = "channel.get_key_failed"
MsgChannelGetOllamaFailed = "channel.get_ollama_failed"
MsgChannelQueryFailed = "channel.query_failed"
MsgChannelNoValidUpstream = "channel.no_valid_upstream"
MsgChannelUpstreamSaturated = "channel.upstream_saturated"
MsgChannelUpstreamSaturatedUpgrade = "channel.upstream_saturated_upgrade"
MsgChannelGetAvailableFailed = "channel.get_available_failed"
MsgChannelGetAvailableRetryFailed = "channel.get_available_retry_failed"
MsgChannelNoAvailableRetry = "channel.no_available_retry"
)

// Playground related messages
const (
MsgPlaygroundAccessTokenUnsupported = "playground.access_token_unsupported"
)

// Task related messages
const (
MsgTaskFileTooLarge = "task.file_too_large"
)

// Model related messages
Expand Down
14 changes: 14 additions & 0 deletions i18n/locales/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ auth.user_id_format_error: "Unauthorized, New-Api-User header format error"
auth.user_id_mismatch: "Unauthorized, New-Api-User does not match logged in user"
auth.user_banned: "User has been banned"
auth.insufficient_privilege: "Unauthorized, insufficient privileges"
auth.client_ip_parse_failed: "Failed to parse client IP address"
auth.ip_not_allowed: "Your IP is not in this token's allowed IP list"
auth.group_access_denied: "You do not have permission to access group {{.Group}}"
auth.group_deprecated: "Group {{.Group}} has been deprecated"
auth.specific_channel_denied: "Regular users cannot specify a channel"

# Token messages
token.name_too_long: "Token name is too long"
Expand Down Expand Up @@ -154,7 +159,16 @@ channel.get_ollama_failed: "Failed to get Ollama models"
channel.query_failed: "Failed to query channel"
channel.no_valid_upstream: "No valid upstream channel"
channel.upstream_saturated: "Current group upstream load is saturated, please try again later"
channel.upstream_saturated_upgrade: "Current group upstream load is saturated, please try again later or upgrade your account for better service quality"
channel.get_available_failed: "Failed to get available channels for model {{.Model}} under group {{.Group}}"
channel.get_available_retry_failed: "Failed to get available channels for model {{.Model}} under group {{.Group}} (retry): {{.Error}}"
channel.no_available_retry: "No available channel for model {{.Model}} under group {{.Group}} (retry)"

# Playground messages
playground.access_token_unsupported: "Access tokens are not supported here"

# Task messages
task.file_too_large: "File {{.File}} exceeds the size limit. Maximum allowed is {{.MaxMB}} MB"

# Model messages
model.name_empty: "Model name cannot be empty"
Expand Down
14 changes: 14 additions & 0 deletions i18n/locales/zh-CN.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ auth.user_id_format_error: "无权进行此操作,New-Api-User 格式错误"
auth.user_id_mismatch: "无权进行此操作,New-Api-User 与登录用户不匹配"
auth.user_banned: "用户已被封禁"
auth.insufficient_privilege: "无权进行此操作,权限不足"
auth.client_ip_parse_failed: "无法解析客户端 IP 地址"
auth.ip_not_allowed: "您的 IP 不在令牌允许访问的列表中"
auth.group_access_denied: "无权访问 {{.Group}} 分组"
auth.group_deprecated: "分组 {{.Group}} 已被弃用"
auth.specific_channel_denied: "普通用户不支持指定渠道"

# Token messages
token.name_too_long: "令牌名称过长"
Expand Down Expand Up @@ -155,7 +160,16 @@ channel.get_ollama_failed: "获取Ollama模型失败"
channel.query_failed: "查询渠道失败"
channel.no_valid_upstream: "无有效上游渠道"
channel.upstream_saturated: "当前分组上游负载已饱和,请稍后再试"
channel.upstream_saturated_upgrade: "当前分组负载已饱和,请稍后再试,或升级账户以提升服务质量"
channel.get_available_failed: "获取分组 {{.Group}} 下模型 {{.Model}} 的可用渠道失败"
channel.get_available_retry_failed: "获取分组 {{.Group}} 下模型 {{.Model}} 的可用渠道失败(retry):{{.Error}}"
channel.no_available_retry: "分组 {{.Group}} 下模型 {{.Model}} 的可用渠道不存在(retry)"

# Playground messages
playground.access_token_unsupported: "暂不支持使用 access token"

# Task messages
task.file_too_large: "文件 {{.File}} 大小超过限制,最大允许 {{.MaxMB}} MB"

# Model messages
model.name_empty: "模型名称不能为空"
Expand Down
14 changes: 14 additions & 0 deletions i18n/locales/zh-TW.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ auth.user_id_format_error: "無權進行此操作,New-Api-User 格式錯誤"
auth.user_id_mismatch: "無權進行此操作,New-Api-User 與登入使用者不匹配"
auth.user_banned: "使用者已被封禁"
auth.insufficient_privilege: "無權進行此操作,權限不足"
auth.client_ip_parse_failed: "無法解析客戶端 IP 位址"
auth.ip_not_allowed: "您的 IP 不在令牌允許存取的清單中"
auth.group_access_denied: "無權存取 {{.Group}} 分組"
auth.group_deprecated: "分組 {{.Group}} 已被棄用"
auth.specific_channel_denied: "普通使用者不支援指定管道"

# Token messages
token.name_too_long: "令牌名稱過長"
Expand Down Expand Up @@ -155,7 +160,16 @@ channel.get_ollama_failed: "獲取Ollama模型失敗"
channel.query_failed: "查詢管道失敗"
channel.no_valid_upstream: "無有效上游管道"
channel.upstream_saturated: "當前分組上游負載已飽和,請稍後再試"
channel.upstream_saturated_upgrade: "當前分組負載已飽和,請稍後再試,或升級帳戶以提升服務品質"
channel.get_available_failed: "獲取分組 {{.Group}} 下模型 {{.Model}} 的可用管道失敗"
channel.get_available_retry_failed: "獲取分組 {{.Group}} 下模型 {{.Model}} 的可用管道失敗(retry):{{.Error}}"
channel.no_available_retry: "分組 {{.Group}} 下模型 {{.Model}} 的可用管道不存在(retry)"

# Playground messages
playground.access_token_unsupported: "暫不支援使用 access token"

# Task messages
task.file_too_large: "檔案 {{.File}} 大小超過限制,最大允許 {{.MaxMB}} MB"

# Model messages
model.name_empty: "模型名稱不能為空"
Expand Down
13 changes: 7 additions & 6 deletions middleware/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -354,11 +354,11 @@ func TokenAuth() func(c *gin.Context) {
logger.LogDebug(c, "Token has IP restrictions, checking client IP %s", clientIp)
ip := net.ParseIP(clientIp)
if ip == nil {
abortWithOpenAiMessage(c, http.StatusForbidden, "无法解析客户端 IP 地址")
abortWithOpenAiMessage(c, http.StatusForbidden, common.TranslateMessage(c, i18n.MsgAuthClientIpParseFailed))
return
}
if common.IsIpInCIDRList(ip, allowIps) == false {
abortWithOpenAiMessage(c, http.StatusForbidden, "您的 IP 不在令牌允许访问的列表中", types.ErrorCodeAccessDenied)
abortWithOpenAiMessage(c, http.StatusForbidden, common.TranslateMessage(c, i18n.MsgAuthIpNotAllowed), types.ErrorCodeAccessDenied)
return
}
logger.LogDebug(c, "Client IP %s passed the token IP restrictions check", clientIp)
Expand All @@ -384,13 +384,13 @@ func TokenAuth() func(c *gin.Context) {
if tokenGroup != "" {
// check common.UserUsableGroups[userGroup]
if _, ok := service.GetUserUsableGroups(userGroup)[tokenGroup]; !ok {
abortWithOpenAiMessage(c, http.StatusForbidden, fmt.Sprintf("无权访问 %s 分组", tokenGroup))
abortWithOpenAiMessage(c, http.StatusForbidden, common.TranslateMessage(c, i18n.MsgAuthGroupAccessDenied, map[string]any{"Group": tokenGroup}))
return
}
// check group in common.GroupRatio
if !ratio_setting.ContainsGroupRatio(tokenGroup) {
if tokenGroup != "auto" {
abortWithOpenAiMessage(c, http.StatusForbidden, fmt.Sprintf("分组 %s 已被弃用", tokenGroup))
abortWithOpenAiMessage(c, http.StatusForbidden, common.TranslateMessage(c, i18n.MsgAuthGroupDeprecated, map[string]any{"Group": tokenGroup}))
return
}
}
Expand Down Expand Up @@ -431,8 +431,9 @@ func SetupContextForToken(c *gin.Context, token *model.Token, parts ...string) e
c.Set("specific_channel_id", parts[1])
} else {
c.Header("specific_channel_version", "701e3ae1dc3f7975556d354e0675168d004891c8")
abortWithOpenAiMessage(c, http.StatusForbidden, "普通用户不支持指定渠道")
return fmt.Errorf("普通用户不支持指定渠道")
msg := common.TranslateMessage(c, i18n.MsgAuthSpecificChannelDenied)
abortWithOpenAiMessage(c, http.StatusForbidden, msg)
return fmt.Errorf("%s", msg)
}
}
return nil
Expand Down
5 changes: 3 additions & 2 deletions middleware/model-rate-limit.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/QuantumNous/new-api/common"
"github.com/QuantumNous/new-api/common/limiter"
"github.com/QuantumNous/new-api/constant"
"github.com/QuantumNous/new-api/i18n"
"github.com/QuantumNous/new-api/setting"

"github.com/gin-gonic/gin"
Expand Down Expand Up @@ -90,7 +91,7 @@ func redisRateLimitHandler(duration int64, totalMaxCount, successMaxCount int) g
return
}
if !allowed {
abortWithOpenAiMessage(c, http.StatusTooManyRequests, fmt.Sprintf("您已达到请求数限制:%d分钟内最多请求%d次", setting.ModelRequestRateLimitDurationMinutes, successMaxCount))
abortWithOpenAiMessage(c, http.StatusTooManyRequests, i18n.T(c, i18n.MsgRateLimitReached, map[string]any{"Minutes": setting.ModelRequestRateLimitDurationMinutes, "Max": successMaxCount}))
return
}

Expand All @@ -114,7 +115,7 @@ func redisRateLimitHandler(duration int64, totalMaxCount, successMaxCount int) g
}

if !allowed {
abortWithOpenAiMessage(c, http.StatusTooManyRequests, fmt.Sprintf("您已达到总请求数限制:%d分钟内最多请求%d次,包括失败次数,请检查您的请求是否正确", setting.ModelRequestRateLimitDurationMinutes, totalMaxCount))
abortWithOpenAiMessage(c, http.StatusTooManyRequests, i18n.T(c, i18n.MsgRateLimitTotalReached, map[string]any{"Minutes": setting.ModelRequestRateLimitDurationMinutes, "Max": totalMaxCount}))
}
}

Expand Down
3 changes: 2 additions & 1 deletion relay/channel/task/jimeng/adaptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"time"

"github.com/QuantumNous/new-api/common"
"github.com/QuantumNous/new-api/i18n"
"github.com/QuantumNous/new-api/model"
"github.com/samber/lo"

Expand Down Expand Up @@ -145,7 +146,7 @@ func (a *TaskAdaptor) BuildRequestBody(c *gin.Context, info *relaycommon.RelayIn
for _, fileHeader := range files {
// 检查文件大小
if fileHeader.Size > MaxFileSize {
return nil, fmt.Errorf("文件 %s 大小超过限制,最大允许 %d MB", fileHeader.Filename, MaxFileSize/(1024*1024))
return nil, fmt.Errorf("%s", i18n.T(c, i18n.MsgTaskFileTooLarge, map[string]any{"File": fileHeader.Filename, "MaxMB": MaxFileSize / (1024 * 1024)}))
}

file, err := fileHeader.Open()
Expand Down