diff --git a/common/api_type.go b/common/api_type.go index c198ffc0e03..5375c4518e3 100644 --- a/common/api_type.go +++ b/common/api_type.go @@ -77,6 +77,8 @@ func ChannelType2APIType(channelType int) (int, bool) { apiType = constant.APITypeCodex case constant.ChannelTypeAdvancedCustom: apiType = constant.APITypeAdvancedCustom + case constant.ChannelTypeAliTokenPlan: + apiType = constant.APITypeAliTokenPlan } if apiType == -1 { return constant.APITypeOpenAI, false diff --git a/constant/api_type.go b/constant/api_type.go index f3657a11679..894c67163bc 100644 --- a/constant/api_type.go +++ b/constant/api_type.go @@ -37,5 +37,6 @@ const ( APITypeReplicate APITypeCodex APITypeAdvancedCustom + APITypeAliTokenPlan APITypeDummy // this one is only for count, do not add any channel after this ) diff --git a/constant/channel.go b/constant/channel.go index 45ec9a44e49..5aae556c253 100644 --- a/constant/channel.go +++ b/constant/channel.go @@ -56,6 +56,7 @@ const ( ChannelTypeReplicate = 56 ChannelTypeCodex = 57 ChannelTypeAdvancedCustom = 58 + ChannelTypeAliTokenPlan = 59 ChannelTypeDummy // this one is only for count, do not add any channel after this ) @@ -120,6 +121,7 @@ var ChannelBaseURLs = []string{ "https://api.replicate.com", //56 "https://chatgpt.com", //57 "", //58 + "https://token-plan.cn-beijing.maas.aliyuncs.com", //59 } var ChannelTypeNames = map[int]string{ @@ -178,6 +180,7 @@ var ChannelTypeNames = map[int]string{ ChannelTypeReplicate: "Replicate", ChannelTypeCodex: "ChatGPT Subscription (Codex)", ChannelTypeAdvancedCustom: "Advanced Custom", + ChannelTypeAliTokenPlan: "阿里云百炼Token Plan", } func GetChannelTypeName(channelType int) string { diff --git a/relay/channel/ali_token_plan/adaptor.go b/relay/channel/ali_token_plan/adaptor.go new file mode 100644 index 00000000000..800a149e018 --- /dev/null +++ b/relay/channel/ali_token_plan/adaptor.go @@ -0,0 +1,64 @@ +package ali_token_plan + +import ( + "fmt" + "io" + "net/http" + + "github.com/QuantumNous/new-api/relay/channel" + "github.com/QuantumNous/new-api/relay/channel/ali" + relaycommon "github.com/QuantumNous/new-api/relay/common" + "github.com/QuantumNous/new-api/relay/constant" + "github.com/QuantumNous/new-api/types" + + "github.com/gin-gonic/gin" +) + +type Adaptor struct { + ali.Adaptor +} + +func (a *Adaptor) GetRequestURL(info *relaycommon.RelayInfo) (string, error) { + if info.RelayFormat == types.RelayFormatClaude { + return fmt.Sprintf("%s/compatible-mode/v1/chat/completions", info.ChannelBaseUrl), nil + } + + switch info.RelayMode { + case constant.RelayModeResponses: + return fmt.Sprintf("%s/compatible-mode/v1/responses", info.ChannelBaseUrl), nil + case constant.RelayModeEmbeddings: + return fmt.Sprintf("%s/compatible-mode/v1/embeddings", info.ChannelBaseUrl), nil + case constant.RelayModeCompletions: + return fmt.Sprintf("%s/compatible-mode/v1/completions", info.ChannelBaseUrl), nil + case constant.RelayModeImagesGenerations: + return a.Adaptor.GetRequestURL(info) + case constant.RelayModeImagesEdits: + return a.Adaptor.GetRequestURL(info) + case constant.RelayModeRerank: + return fmt.Sprintf("%s/compatible-mode/v1/rerank", info.ChannelBaseUrl), nil + default: + return a.Adaptor.GetRequestURL(info) + } +} + +// SetupRequestHeader 覆写父类方法,去掉 DashScope 专属头部(X-DashScope-SSE 等) +// Token Plan 的 compatible-mode API 使用标准 OpenAI 协议,不需要 DashScope 头 +func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Header, info *relaycommon.RelayInfo) error { + channel.SetupApiRequestHeader(info, c, req) + req.Set("Authorization", "Bearer "+info.ApiKey) + return nil +} + +// DoRequest 覆写父类方法,确保 DoApiRequest 接收的是 *ali_token_plan.Adaptor +// 而非内层的 *ali.Adaptor,这样 GetRequestURL 和 SetupRequestHeader 的覆写才能生效 +func (a *Adaptor) DoRequest(c *gin.Context, info *relaycommon.RelayInfo, requestBody io.Reader) (any, error) { + return channel.DoApiRequest(a, c, info, requestBody) +} + +func (a *Adaptor) GetModelList() []string { + return ali.ModelList +} + +func (a *Adaptor) GetChannelName() string { + return "ali_token_plan" +} diff --git a/relay/common/relay_info.go b/relay/common/relay_info.go index f97f335cb2e..8364ee79dba 100644 --- a/relay/common/relay_info.go +++ b/relay/common/relay_info.go @@ -337,6 +337,7 @@ var streamSupportedChannels = map[int]bool{ constant.ChannelTypeMiniMax: true, constant.ChannelTypeSiliconFlow: true, constant.ChannelTypeAdvancedCustom: true, + constant.ChannelTypeAliTokenPlan: true, } func GenRelayInfoWs(c *gin.Context, ws *websocket.Conn) *RelayInfo { diff --git a/relay/relay_adaptor.go b/relay/relay_adaptor.go index 2922744654e..138a1d716e5 100644 --- a/relay/relay_adaptor.go +++ b/relay/relay_adaptor.go @@ -7,6 +7,7 @@ import ( "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/ali_token_plan" "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" @@ -123,6 +124,8 @@ func GetAdaptor(apiType int) channel.Adaptor { return &codex.Adaptor{} case constant.APITypeAdvancedCustom: return &advancedcustom.Adaptor{} + case constant.APITypeAliTokenPlan: + return &ali_token_plan.Adaptor{} } return nil } diff --git a/web/classic/src/constants/channel.constants.js b/web/classic/src/constants/channel.constants.js index 278e756336b..3a643534710 100644 --- a/web/classic/src/constants/channel.constants.js +++ b/web/classic/src/constants/channel.constants.js @@ -189,11 +189,16 @@ export const CHANNEL_OPTIONS = [ color: 'blue', label: 'ChatGPT Subscription (Codex)', }, + { + value: 59, + color: 'orange', + label: '阿里云百炼Token Plan', + }, ]; // Channel types that support upstream model list fetching in UI. export const MODEL_FETCHABLE_CHANNEL_TYPES = new Set([ - 1, 4, 14, 34, 17, 26, 27, 24, 47, 25, 20, 23, 31, 40, 42, 48, 43, + 1, 4, 14, 34, 17, 26, 27, 24, 47, 25, 20, 23, 31, 40, 42, 48, 43, 59, ]); export const MODEL_TABLE_PAGE_SIZE = 10;