mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-09-13 07:40:56 +00:00
feat(task): replace built-in task adaptors with a sandboxed JS plugin system (#7076)
This commit is contained in:
@@ -5,11 +5,36 @@ import (
|
||||
|
||||
"github.com/QuantumNous/new-api/common"
|
||||
"github.com/QuantumNous/new-api/constant"
|
||||
"github.com/QuantumNous/new-api/dto"
|
||||
"github.com/QuantumNous/new-api/logger"
|
||||
"github.com/QuantumNous/new-api/model"
|
||||
"github.com/QuantumNous/new-api/pkg/jsplugin"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func GetChannelConstraints(c *gin.Context) *dto.ChannelConstraints {
|
||||
if c == nil {
|
||||
return &dto.ChannelConstraints{}
|
||||
}
|
||||
if existing, ok := common.GetContextKeyType[*dto.ChannelConstraints](c, constant.ContextKeyChannelConstraints); ok && existing != nil {
|
||||
return existing
|
||||
}
|
||||
constraints := &dto.ChannelConstraints{}
|
||||
common.SetContextKey(c, constant.ContextKeyChannelConstraints, constraints)
|
||||
return constraints
|
||||
}
|
||||
|
||||
func AppendTaskPluginIdentityFilter(c *gin.Context, pluginKey string) {
|
||||
if c == nil {
|
||||
return
|
||||
}
|
||||
GetChannelConstraints(c).AddFilter(dto.ChannelFilter{
|
||||
Kind: dto.FilterTaskPluginIdentity,
|
||||
TaskPluginKey: pluginKey,
|
||||
TaskPluginChannelTypes: pinnedTaskPluginChannelTypes(c, pluginKey),
|
||||
})
|
||||
}
|
||||
|
||||
type RetryParam struct {
|
||||
Ctx *gin.Context
|
||||
TokenGroup string
|
||||
@@ -85,6 +110,7 @@ func CacheGetRandomSatisfiedChannel(param *RetryParam) (*model.Channel, string,
|
||||
var err error
|
||||
selectGroup := param.TokenGroup
|
||||
userGroup := common.GetContextKeyString(param.Ctx, constant.ContextKeyUserGroup)
|
||||
filters := GetChannelConstraints(param.Ctx).Filters
|
||||
|
||||
if param.TokenGroup == "auto" {
|
||||
autoGroups := GetRequestAutoGroups(param.Ctx, userGroup)
|
||||
@@ -115,7 +141,12 @@ func CacheGetRandomSatisfiedChannel(param *RetryParam) (*model.Channel, string,
|
||||
}
|
||||
logger.LogDebug(param.Ctx, "Auto selecting group: %s, priorityRetry: %d", autoGroup, priorityRetry)
|
||||
|
||||
channel, _ = model.GetRandomSatisfiedChannel(autoGroup, param.ModelName, priorityRetry, param.RequestPath)
|
||||
channel, _ = model.GetRandomSatisfiedChannel(
|
||||
autoGroup,
|
||||
param.ModelName,
|
||||
priorityRetry,
|
||||
filters,
|
||||
)
|
||||
if channel == nil {
|
||||
// Current group has no available channel for this model, try next group
|
||||
// 当前分组没有该模型的可用渠道,尝试下一个分组
|
||||
@@ -153,10 +184,68 @@ func CacheGetRandomSatisfiedChannel(param *RetryParam) (*model.Channel, string,
|
||||
break
|
||||
}
|
||||
} else {
|
||||
channel, err = model.GetRandomSatisfiedChannel(param.TokenGroup, param.ModelName, param.GetRetry(), param.RequestPath)
|
||||
channel, err = model.GetRandomSatisfiedChannel(
|
||||
param.TokenGroup,
|
||||
param.ModelName,
|
||||
param.GetRetry(),
|
||||
filters,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, param.TokenGroup, err
|
||||
}
|
||||
}
|
||||
return channel, selectGroup, nil
|
||||
}
|
||||
|
||||
func pinnedTaskPluginChannelTypes(c *gin.Context, expected string) []int {
|
||||
if c == nil || expected == "" {
|
||||
return nil
|
||||
}
|
||||
if value, exists := c.Get(jsplugin.ContextKeyPinnedEndpoint); exists {
|
||||
pinned, ok := value.(jsplugin.PinnedEndpoint)
|
||||
if ok && pinned.Generation != nil && len(pinned.Candidates) > 1 {
|
||||
expectedFound := false
|
||||
channelTypes := make([]int, 0, len(pinned.Candidates))
|
||||
seen := make(map[int]struct{}, len(pinned.Candidates))
|
||||
for _, candidate := range pinned.Candidates {
|
||||
if candidate.Plugin == nil {
|
||||
continue
|
||||
}
|
||||
if candidate.Plugin.Meta.Key == expected {
|
||||
expectedFound = true
|
||||
}
|
||||
for _, channelType := range candidate.Plugin.Meta.ChannelTypes {
|
||||
if channelType == 0 || channelType == constant.ChannelTypeTaskPlugin {
|
||||
continue
|
||||
}
|
||||
if _, duplicate := seen[channelType]; duplicate {
|
||||
continue
|
||||
}
|
||||
if plugin, indexed := pinned.Generation.GetByChannelType(channelType); indexed && plugin == candidate.Plugin {
|
||||
seen[channelType] = struct{}{}
|
||||
channelTypes = append(channelTypes, channelType)
|
||||
}
|
||||
}
|
||||
}
|
||||
if expectedFound {
|
||||
return channelTypes
|
||||
}
|
||||
}
|
||||
}
|
||||
value, exists := c.Get(jsplugin.ContextKeyPinnedPlugin)
|
||||
pinned, ok := value.(jsplugin.PinnedPlugin)
|
||||
if !exists || !ok || pinned.Generation == nil || pinned.Plugin == nil || pinned.Plugin.Meta.Key != expected {
|
||||
return nil
|
||||
}
|
||||
channelTypes := make([]int, 0, len(pinned.Plugin.Meta.ChannelTypes))
|
||||
for _, channelType := range pinned.Plugin.Meta.ChannelTypes {
|
||||
if channelType == 0 || channelType == constant.ChannelTypeTaskPlugin {
|
||||
continue
|
||||
}
|
||||
channelTypes = append(channelTypes, channelType)
|
||||
}
|
||||
if len(channelTypes) == 0 {
|
||||
return nil
|
||||
}
|
||||
return channelTypes
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user