mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-09-10 22:20:25 +00:00
236 lines
8.9 KiB
Go
236 lines
8.9 KiB
Go
package relay
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
|
|
"github.com/QuantumNous/new-api/constant"
|
|
pluginruntime "github.com/QuantumNous/new-api/pkg/jsplugin"
|
|
_ "github.com/QuantumNous/new-api/plugins"
|
|
"github.com/QuantumNous/new-api/relay/channel"
|
|
"github.com/QuantumNous/new-api/relay/channel/advancedcustom"
|
|
"github.com/QuantumNous/new-api/relay/channel/ali"
|
|
"github.com/QuantumNous/new-api/relay/channel/aws"
|
|
"github.com/QuantumNous/new-api/relay/channel/baidu"
|
|
"github.com/QuantumNous/new-api/relay/channel/baidu_v2"
|
|
"github.com/QuantumNous/new-api/relay/channel/claude"
|
|
"github.com/QuantumNous/new-api/relay/channel/cloudflare"
|
|
"github.com/QuantumNous/new-api/relay/channel/codex"
|
|
"github.com/QuantumNous/new-api/relay/channel/cohere"
|
|
"github.com/QuantumNous/new-api/relay/channel/coze"
|
|
"github.com/QuantumNous/new-api/relay/channel/deepseek"
|
|
"github.com/QuantumNous/new-api/relay/channel/dify"
|
|
"github.com/QuantumNous/new-api/relay/channel/gemini"
|
|
"github.com/QuantumNous/new-api/relay/channel/jimeng"
|
|
"github.com/QuantumNous/new-api/relay/channel/jina"
|
|
"github.com/QuantumNous/new-api/relay/channel/minimax"
|
|
"github.com/QuantumNous/new-api/relay/channel/mistral"
|
|
"github.com/QuantumNous/new-api/relay/channel/mokaai"
|
|
"github.com/QuantumNous/new-api/relay/channel/moonshot"
|
|
"github.com/QuantumNous/new-api/relay/channel/newapi"
|
|
"github.com/QuantumNous/new-api/relay/channel/ollama"
|
|
"github.com/QuantumNous/new-api/relay/channel/openai"
|
|
"github.com/QuantumNous/new-api/relay/channel/palm"
|
|
"github.com/QuantumNous/new-api/relay/channel/perplexity"
|
|
"github.com/QuantumNous/new-api/relay/channel/replicate"
|
|
"github.com/QuantumNous/new-api/relay/channel/siliconflow"
|
|
"github.com/QuantumNous/new-api/relay/channel/sub2api"
|
|
"github.com/QuantumNous/new-api/relay/channel/submodel"
|
|
jspluginadaptor "github.com/QuantumNous/new-api/relay/channel/task/jsplugin"
|
|
"github.com/QuantumNous/new-api/relay/channel/tencent"
|
|
"github.com/QuantumNous/new-api/relay/channel/vertex"
|
|
"github.com/QuantumNous/new-api/relay/channel/volcengine"
|
|
"github.com/QuantumNous/new-api/relay/channel/xai"
|
|
"github.com/QuantumNous/new-api/relay/channel/xunfei"
|
|
"github.com/QuantumNous/new-api/relay/channel/zhipu"
|
|
"github.com/QuantumNous/new-api/relay/channel/zhipu_4v"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
func GetAdaptor(apiType int) channel.Adaptor {
|
|
switch apiType {
|
|
case constant.APITypeAli:
|
|
return &ali.Adaptor{}
|
|
case constant.APITypeAnthropic:
|
|
return &claude.Adaptor{}
|
|
case constant.APITypeBaidu:
|
|
return &baidu.Adaptor{}
|
|
case constant.APITypeGemini:
|
|
return &gemini.Adaptor{}
|
|
case constant.APITypeOpenAI:
|
|
return &openai.Adaptor{}
|
|
case constant.APITypePaLM:
|
|
return &palm.Adaptor{}
|
|
case constant.APITypeTencent:
|
|
return &tencent.DispatchAdaptor{}
|
|
case constant.APITypeXunfei:
|
|
return &xunfei.Adaptor{}
|
|
case constant.APITypeZhipu:
|
|
return &zhipu.Adaptor{}
|
|
case constant.APITypeZhipuV4:
|
|
return &zhipu_4v.Adaptor{}
|
|
case constant.APITypeOllama:
|
|
return &ollama.Adaptor{}
|
|
case constant.APITypePerplexity:
|
|
return &perplexity.Adaptor{}
|
|
case constant.APITypeAws:
|
|
return &aws.Adaptor{}
|
|
case constant.APITypeCohere:
|
|
return &cohere.Adaptor{}
|
|
case constant.APITypeDify:
|
|
return &dify.Adaptor{}
|
|
case constant.APITypeJina:
|
|
return &jina.Adaptor{}
|
|
case constant.APITypeCloudflare:
|
|
return &cloudflare.Adaptor{}
|
|
case constant.APITypeSiliconFlow:
|
|
return &siliconflow.Adaptor{}
|
|
case constant.APITypeVertexAi:
|
|
return &vertex.Adaptor{}
|
|
case constant.APITypeMistral:
|
|
return &mistral.Adaptor{}
|
|
case constant.APITypeDeepSeek:
|
|
return &deepseek.Adaptor{}
|
|
case constant.APITypeMokaAI:
|
|
return &mokaai.Adaptor{}
|
|
case constant.APITypeVolcEngine:
|
|
return &volcengine.Adaptor{}
|
|
case constant.APITypeBaiduV2:
|
|
return &baidu_v2.Adaptor{}
|
|
case constant.APITypeOpenRouter:
|
|
return &openai.Adaptor{}
|
|
case constant.APITypeXinference:
|
|
return &openai.Adaptor{}
|
|
case constant.APITypeXai:
|
|
return &xai.Adaptor{}
|
|
case constant.APITypeCoze:
|
|
return &coze.Adaptor{}
|
|
case constant.APITypeJimeng:
|
|
return &jimeng.Adaptor{}
|
|
case constant.APITypeMoonshot:
|
|
return &moonshot.Adaptor{} // Moonshot uses Claude API
|
|
case constant.APITypeSubmodel:
|
|
return &submodel.Adaptor{}
|
|
case constant.APITypeMiniMax:
|
|
return &minimax.Adaptor{}
|
|
case constant.APITypeReplicate:
|
|
return &replicate.Adaptor{}
|
|
case constant.APITypeCodex:
|
|
return &codex.Adaptor{}
|
|
case constant.APITypeAdvancedCustom:
|
|
return &advancedcustom.Adaptor{}
|
|
case constant.APITypeSub2API:
|
|
return &sub2api.Adaptor{}
|
|
case constant.APITypeNewAPI:
|
|
return &newapi.Adaptor{}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func GetTaskPlatform(c *gin.Context) constant.TaskPlatform {
|
|
if pluginKey := c.GetString("task_plugin_key"); pluginKey != "" {
|
|
return constant.TaskPlatform(pluginKey)
|
|
}
|
|
channelType := c.GetInt("channel_type")
|
|
if channelType > 0 {
|
|
return constant.TaskPlatform(strconv.Itoa(channelType))
|
|
}
|
|
return constant.TaskPlatform(c.GetString("platform"))
|
|
}
|
|
|
|
var taskPluginKeys = map[constant.TaskPlatform]string{
|
|
constant.TaskPlatformSuno: "sunoapi",
|
|
constant.TaskPlatform(strconv.Itoa(constant.ChannelTypeAli)): "alibaba",
|
|
constant.TaskPlatform(strconv.Itoa(constant.ChannelTypeKling)): "kling",
|
|
constant.TaskPlatform(strconv.Itoa(constant.ChannelTypeJimeng)): "jimeng",
|
|
constant.TaskPlatform(strconv.Itoa(constant.ChannelTypeVidu)): "vidu",
|
|
constant.TaskPlatform(strconv.Itoa(constant.ChannelTypeDoubaoVideo)): "doubao",
|
|
constant.TaskPlatform(strconv.Itoa(constant.ChannelTypeVolcEngine)): "doubao",
|
|
constant.TaskPlatform(strconv.Itoa(constant.ChannelTypeGemini)): "google",
|
|
constant.TaskPlatform(strconv.Itoa(constant.ChannelTypeMiniMax)): "hailuo",
|
|
constant.TaskPlatform(strconv.Itoa(constant.ChannelTypeSora)): "sora",
|
|
constant.TaskPlatform(strconv.Itoa(constant.ChannelTypeOpenAI)): "sora",
|
|
constant.TaskPlatform(strconv.Itoa(constant.ChannelTypeVertexAi)): "vertex-ai",
|
|
}
|
|
|
|
func ResolveTaskPluginForPlatform(generation *pluginruntime.RoutingGeneration, platform constant.TaskPlatform) (*pluginruntime.LoadedPlugin, bool) {
|
|
if generation == nil {
|
|
return nil, false
|
|
}
|
|
if key, ok := taskPluginKeys[platform]; ok {
|
|
if plugin, found := generation.Get(key); found {
|
|
return plugin, true
|
|
}
|
|
}
|
|
return generation.Get(string(platform))
|
|
}
|
|
|
|
// TaskPlatformUnavailableError explains why no adaptor serves the platform:
|
|
// the task-plugin system is switched off, the resolved plugin is disabled,
|
|
// or the platform simply names nothing. The distinction is user-actionable,
|
|
// so it must survive into the client-facing message.
|
|
func TaskPlatformUnavailableError(platform constant.TaskPlatform) (string, string) {
|
|
if !pluginruntime.DefaultRegistry.Enabled() {
|
|
return "task_plugin_system_disabled", "the task plugin system is disabled on this gateway"
|
|
}
|
|
key := string(platform)
|
|
if mapped, ok := taskPluginKeys[platform]; ok {
|
|
key = mapped
|
|
}
|
|
for _, meta := range pluginruntime.DefaultRegistry.Snapshot().Factory {
|
|
if meta.Key == key {
|
|
return "task_plugin_disabled", fmt.Sprintf("task plugin %q is disabled on this gateway", key)
|
|
}
|
|
}
|
|
return "invalid_api_platform", fmt.Sprintf("invalid api platform: %s", platform)
|
|
}
|
|
|
|
func GetTaskAdaptor(platform constant.TaskPlatform) channel.TaskAdaptor {
|
|
plugin, ok := ResolveTaskPluginForPlatform(pluginruntime.DefaultRegistry.Generation(), platform)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return jspluginadaptor.New(plugin)
|
|
}
|
|
|
|
// getTaskAdaptorForRequest preserves the exact plugin object pinned by the
|
|
// declarative or shared-endpoint router. Legacy task routes are pinned here
|
|
// from one registry generation before the adaptor is returned.
|
|
func getTaskAdaptorForRequest(c *gin.Context, platform constant.TaskPlatform) (constant.TaskPlatform, channel.TaskAdaptor) {
|
|
if c != nil {
|
|
if value, exists := c.Get(pluginruntime.ContextKeyPinnedPlugin); exists {
|
|
if pinned, ok := value.(pluginruntime.PinnedPlugin); ok && pinned.Plugin != nil {
|
|
platform = constant.TaskPlatform(pinned.Plugin.Meta.Key)
|
|
return platform, jspluginadaptor.New(pinned.Plugin)
|
|
}
|
|
return platform, nil
|
|
}
|
|
if value, exists := c.Get(pluginruntime.ContextKeyPinnedEndpoint); exists {
|
|
if pinned, ok := value.(pluginruntime.PinnedEndpoint); ok && pinned.Plugin != nil {
|
|
platform = constant.TaskPlatform(pinned.Plugin.Meta.Key)
|
|
return platform, jspluginadaptor.New(pinned.Plugin)
|
|
}
|
|
return platform, nil
|
|
}
|
|
if value, exists := c.Get(pluginruntime.ContextKeyPinnedRoute); exists {
|
|
if pinned, ok := value.(pluginruntime.PinnedRoute); ok && pinned.Plugin != nil {
|
|
platform = constant.TaskPlatform(pinned.Plugin.Meta.Key)
|
|
return platform, jspluginadaptor.New(pinned.Plugin)
|
|
}
|
|
return platform, nil
|
|
}
|
|
}
|
|
generation := pluginruntime.DefaultRegistry.Generation()
|
|
plugin, ok := ResolveTaskPluginForPlatform(generation, platform)
|
|
if !ok {
|
|
return platform, nil
|
|
}
|
|
if c != nil {
|
|
c.Set(pluginruntime.ContextKeyPinnedPlugin, pluginruntime.PinnedPlugin{
|
|
Generation: generation,
|
|
Plugin: plugin,
|
|
})
|
|
}
|
|
return platform, jspluginadaptor.New(plugin)
|
|
}
|