diff --git a/relay/relay-text.go b/relay/relay-text.go index 84d4e38b..1856a2a1 100644 --- a/relay/relay-text.go +++ b/relay/relay-text.go @@ -517,6 +517,9 @@ func postConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, common.LogError(ctx, fmt.Sprintf("total tokens is 0, cannot consume quota, userId %d, channelId %d, "+ "tokenId %d, model %s, pre-consumed quota %d", relayInfo.UserId, relayInfo.ChannelId, relayInfo.TokenId, modelName, preConsumedQuota)) } else { + if !ratio.IsZero() && quota == 0 { + quota = 1 + } model.UpdateUserUsedQuotaAndRequestCount(relayInfo.UserId, quota) model.UpdateChannelUsedQuota(relayInfo.ChannelId, quota) } diff --git a/setting/rate_limit.go b/setting/rate_limit.go index 53b53f88..d550b2c3 100644 --- a/setting/rate_limit.go +++ b/setting/rate_limit.go @@ -3,6 +3,7 @@ package setting import ( "encoding/json" "fmt" + "math" "one-api/common" "sync" ) @@ -58,6 +59,9 @@ func CheckModelRequestRateLimitGroup(jsonStr string) error { if limits[0] < 0 || limits[1] < 1 { return fmt.Errorf("group %s has negative rate limit values: [%d, %d]", group, limits[0], limits[1]) } + if limits[0] > math.MaxInt32 || limits[1] > math.MaxInt32 { + return fmt.Errorf("group %s [%d, %d] has max rate limits value 2147483647", group, limits[0], limits[1]) + } } return nil diff --git a/web/src/helpers/render.js b/web/src/helpers/render.js index bd0a8131..1178d5f9 100644 --- a/web/src/helpers/render.js +++ b/web/src/helpers/render.js @@ -883,12 +883,22 @@ export function renderQuotaWithAmount(amount) { } export function renderQuota(quota, digits = 2) { + let quotaPerUnit = localStorage.getItem('quota_per_unit'); let displayInCurrency = localStorage.getItem('display_in_currency'); quotaPerUnit = parseFloat(quotaPerUnit); displayInCurrency = displayInCurrency === 'true'; if (displayInCurrency) { - return '$' + (quota / quotaPerUnit).toFixed(digits); + const result = quota / quotaPerUnit; + const fixedResult = result.toFixed(digits); + + // 如果 toFixed 后结果为 0 但原始值不为 0,显示最小值 + if (parseFloat(fixedResult) === 0 && quota > 0 && result > 0) { + const minValue = Math.pow(10, -digits); + return '$' + minValue.toFixed(digits); + } + + return '$' + fixedResult; } return renderNumber(quota); } diff --git a/web/src/pages/Setting/RateLimit/SettingsRequestRateLimit.js b/web/src/pages/Setting/RateLimit/SettingsRequestRateLimit.js index efb355df..bbdd623e 100644 --- a/web/src/pages/Setting/RateLimit/SettingsRequestRateLimit.js +++ b/web/src/pages/Setting/RateLimit/SettingsRequestRateLimit.js @@ -147,6 +147,7 @@ export default function RequestRateLimit(props) { label={t('用户每周期最多请求次数')} step={1} min={0} + max={100000000} suffix={t('次')} extraText={t('包括失败请求的次数,0代表不限制')} field={'ModelRequestRateLimitCount'} @@ -163,6 +164,7 @@ export default function RequestRateLimit(props) { label={t('用户每周期最多请求完成次数')} step={1} min={1} + max={100000000} suffix={t('次')} extraText={t('只包括请求成功的次数')} field={'ModelRequestRateLimitSuccessCount'} @@ -199,6 +201,7 @@ export default function RequestRateLimit(props) {
  • {t('使用 JSON 对象格式,格式为:{"组名": [最多请求次数, 最多请求完成次数]}')}
  • {t('示例:{"default": [200, 100], "vip": [0, 1000]}。')}
  • {t('[最多请求次数]必须大于等于0,[最多请求完成次数]必须大于等于1。')}
  • +
  • {t('[最多请求次数]和[最多请求完成次数]的最大值为2147483647。')}
  • {t('分组速率配置优先级高于全局速率限制。')}
  • {t('限制周期统一使用上方配置的“限制周期”值。')}