| package service |
|
|
| import ( |
| "errors" |
|
|
| "github.com/QuantumNous/new-api/common" |
| "github.com/QuantumNous/new-api/constant" |
| "github.com/QuantumNous/new-api/logger" |
| "github.com/QuantumNous/new-api/model" |
| "github.com/QuantumNous/new-api/setting" |
| "github.com/gin-gonic/gin" |
| ) |
|
|
| type RetryParam struct { |
| Ctx *gin.Context |
| TokenGroup string |
| ModelName string |
| Retry *int |
| resetNextTry bool |
| } |
|
|
| func (p *RetryParam) GetRetry() int { |
| if p.Retry == nil { |
| return 0 |
| } |
| return *p.Retry |
| } |
|
|
| func (p *RetryParam) SetRetry(retry int) { |
| p.Retry = &retry |
| } |
|
|
| func (p *RetryParam) IncreaseRetry() { |
| if p.resetNextTry { |
| p.resetNextTry = false |
| return |
| } |
| if p.Retry == nil { |
| p.Retry = new(int) |
| } |
| *p.Retry++ |
| } |
|
|
| func (p *RetryParam) ResetRetryNextTry() { |
| p.resetNextTry = true |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| func CacheGetRandomSatisfiedChannel(param *RetryParam) (*model.Channel, string, error) { |
| var channel *model.Channel |
| var err error |
| selectGroup := param.TokenGroup |
| userGroup := common.GetContextKeyString(param.Ctx, constant.ContextKeyUserGroup) |
|
|
| if param.TokenGroup == "auto" { |
| if len(setting.GetAutoGroups()) == 0 { |
| return nil, selectGroup, errors.New("auto groups is not enabled") |
| } |
| autoGroups := GetUserAutoGroup(userGroup) |
|
|
| |
| |
| startGroupIndex := 0 |
| crossGroupRetry := common.GetContextKeyBool(param.Ctx, constant.ContextKeyTokenCrossGroupRetry) |
|
|
| if lastGroupIndex, exists := common.GetContextKey(param.Ctx, constant.ContextKeyAutoGroupIndex); exists { |
| if idx, ok := lastGroupIndex.(int); ok { |
| startGroupIndex = idx |
| } |
| } |
|
|
| for i := startGroupIndex; i < len(autoGroups); i++ { |
| autoGroup := autoGroups[i] |
| |
| |
| priorityRetry := param.GetRetry() |
| |
| |
| if i > startGroupIndex { |
| priorityRetry = 0 |
| } |
| logger.LogDebug(param.Ctx, "Auto selecting group: %s, priorityRetry: %d", autoGroup, priorityRetry) |
|
|
| channel, _ = model.GetRandomSatisfiedChannel(autoGroup, param.ModelName, priorityRetry) |
| if channel == nil { |
| |
| |
| logger.LogDebug(param.Ctx, "No available channel in group %s for model %s at priorityRetry %d, trying next group", autoGroup, param.ModelName, priorityRetry) |
| |
| common.SetContextKey(param.Ctx, constant.ContextKeyAutoGroupIndex, i+1) |
| common.SetContextKey(param.Ctx, constant.ContextKeyAutoGroupRetryIndex, 0) |
| |
| |
| param.SetRetry(0) |
| continue |
| } |
| common.SetContextKey(param.Ctx, constant.ContextKeyAutoGroup, autoGroup) |
| selectGroup = autoGroup |
| logger.LogDebug(param.Ctx, "Auto selected group: %s", autoGroup) |
|
|
| |
| |
| if crossGroupRetry && priorityRetry >= common.RetryTimes { |
| |
| |
| |
| |
| logger.LogDebug(param.Ctx, "Current group %s retries exhausted (priorityRetry=%d >= RetryTimes=%d), preparing switch to next group for next retry", autoGroup, priorityRetry, common.RetryTimes) |
| common.SetContextKey(param.Ctx, constant.ContextKeyAutoGroupIndex, i+1) |
| |
| |
| param.SetRetry(0) |
| param.ResetRetryNextTry() |
| } else { |
| |
| |
| common.SetContextKey(param.Ctx, constant.ContextKeyAutoGroupIndex, i) |
| } |
| break |
| } |
| } else { |
| channel, err = model.GetRandomSatisfiedChannel(param.TokenGroup, param.ModelName, param.GetRetry()) |
| if err != nil { |
| return nil, param.TokenGroup, err |
| } |
| } |
| return channel, selectGroup, nil |
| } |
|
|