feat: support cloudflare now
This commit is contained in:
parent
c317872097
commit
9026ec7510
@ -85,6 +85,7 @@ _✨ 通过标准的 OpenAI API 格式访问所有的大模型,开箱即用
|
|||||||
+ [x] [Coze](https://www.coze.com/)
|
+ [x] [Coze](https://www.coze.com/)
|
||||||
+ [x] [Cohere](https://cohere.com/)
|
+ [x] [Cohere](https://cohere.com/)
|
||||||
+ [x] [DeepSeek](https://www.deepseek.com/)
|
+ [x] [DeepSeek](https://www.deepseek.com/)
|
||||||
|
+ [x] [Cloudflare Workers AI](https://developers.cloudflare.com/workers-ai/)
|
||||||
2. 支持配置镜像以及众多[第三方代理服务](https://iamazing.cn/page/openai-api-third-party-services)。
|
2. 支持配置镜像以及众多[第三方代理服务](https://iamazing.cn/page/openai-api-third-party-services)。
|
||||||
3. 支持通过**负载均衡**的方式访问多个渠道。
|
3. 支持通过**负载均衡**的方式访问多个渠道。
|
||||||
4. 支持 **stream 模式**,可以通过流式传输实现打字机效果。
|
4. 支持 **stream 模式**,可以通过流式传输实现打字机效果。
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
package ctxkey
|
|
||||||
|
|
||||||
const (
|
|
||||||
ConfigPrefix = "cfg_"
|
|
||||||
|
|
||||||
ConfigAPIVersion = ConfigPrefix + "api_version"
|
|
||||||
ConfigLibraryID = ConfigPrefix + "library_id"
|
|
||||||
ConfigPlugin = ConfigPrefix + "plugin"
|
|
||||||
ConfigSK = ConfigPrefix + "sk"
|
|
||||||
ConfigAK = ConfigPrefix + "ak"
|
|
||||||
ConfigRegion = ConfigPrefix + "region"
|
|
||||||
ConfigUserID = ConfigPrefix + "user_id"
|
|
||||||
)
|
|
@ -1,6 +1,7 @@
|
|||||||
package ctxkey
|
package ctxkey
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
Config = "config"
|
||||||
Id = "id"
|
Id = "id"
|
||||||
Username = "username"
|
Username = "username"
|
||||||
Role = "role"
|
Role = "role"
|
||||||
|
@ -2,6 +2,7 @@ package helper
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/songquanpeng/one-api/common/random"
|
"github.com/songquanpeng/one-api/common/random"
|
||||||
"html/template"
|
"html/template"
|
||||||
"log"
|
"log"
|
||||||
@ -105,6 +106,11 @@ func GenRequestID() string {
|
|||||||
return GetTimeString() + random.GetRandomNumberString(8)
|
return GetTimeString() + random.GetRandomNumberString(8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetResponseID(c *gin.Context) string {
|
||||||
|
logID := c.GetString(RequestIdKey)
|
||||||
|
return fmt.Sprintf("chatcmpl-%s", logID)
|
||||||
|
}
|
||||||
|
|
||||||
func Max(a int, b int) int {
|
func Max(a int, b int) int {
|
||||||
if a >= b {
|
if a >= b {
|
||||||
return a
|
return a
|
||||||
|
5
common/helper/key.go
Normal file
5
common/helper/key.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package helper
|
||||||
|
|
||||||
|
const (
|
||||||
|
RequestIdKey = "X-Oneapi-Request-Id"
|
||||||
|
)
|
@ -1,7 +1,3 @@
|
|||||||
package logger
|
package logger
|
||||||
|
|
||||||
const (
|
|
||||||
RequestIdKey = "X-Oneapi-Request-Id"
|
|
||||||
)
|
|
||||||
|
|
||||||
var LogDir string
|
var LogDir string
|
||||||
|
@ -87,7 +87,7 @@ func logHelper(ctx context.Context, level string, msg string) {
|
|||||||
if level == loggerINFO {
|
if level == loggerINFO {
|
||||||
writer = gin.DefaultWriter
|
writer = gin.DefaultWriter
|
||||||
}
|
}
|
||||||
id := ctx.Value(RequestIdKey)
|
id := ctx.Value(helper.RequestIdKey)
|
||||||
if id == nil {
|
if id == nil {
|
||||||
id = helper.GenRequestID()
|
id = helper.GenRequestID()
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,8 @@ func testChannel(channel *model.Channel) (err error, openaiErr *relaymodel.Error
|
|||||||
c.Request.Header.Set("Content-Type", "application/json")
|
c.Request.Header.Set("Content-Type", "application/json")
|
||||||
c.Set(ctxkey.Channel, channel.Type)
|
c.Set(ctxkey.Channel, channel.Type)
|
||||||
c.Set(ctxkey.BaseURL, channel.GetBaseURL())
|
c.Set(ctxkey.BaseURL, channel.GetBaseURL())
|
||||||
|
cfg, _ := channel.LoadConfig()
|
||||||
|
c.Set(ctxkey.Config, cfg)
|
||||||
middleware.SetupContextForSelectedChannel(c, channel, "")
|
middleware.SetupContextForSelectedChannel(c, channel, "")
|
||||||
meta := meta.GetByContext(c)
|
meta := meta.GetByContext(c)
|
||||||
apiType := channeltype.ToAPIType(channel.Type)
|
apiType := channeltype.ToAPIType(channel.Type)
|
||||||
|
@ -57,7 +57,7 @@ func Relay(c *gin.Context) {
|
|||||||
group := c.GetString(ctxkey.Group)
|
group := c.GetString(ctxkey.Group)
|
||||||
originalModel := c.GetString(ctxkey.OriginalModel)
|
originalModel := c.GetString(ctxkey.OriginalModel)
|
||||||
go processChannelRelayError(ctx, channelId, channelName, bizErr)
|
go processChannelRelayError(ctx, channelId, channelName, bizErr)
|
||||||
requestId := c.GetString(logger.RequestIdKey)
|
requestId := c.GetString(helper.RequestIdKey)
|
||||||
retryTimes := config.RetryTimes
|
retryTimes := config.RetryTimes
|
||||||
if !shouldRetry(c, bizErr.StatusCode) {
|
if !shouldRetry(c, bizErr.StatusCode) {
|
||||||
logger.Errorf(ctx, "relay error happen, status code is %d, won't retry in this case", bizErr.StatusCode)
|
logger.Errorf(ctx, "relay error happen, status code is %d, won't retry in this case", bizErr.StatusCode)
|
||||||
|
@ -65,21 +65,29 @@ func SetupContextForSelectedChannel(c *gin.Context, channel *model.Channel, mode
|
|||||||
c.Set(ctxkey.OriginalModel, modelName) // for retry
|
c.Set(ctxkey.OriginalModel, modelName) // for retry
|
||||||
c.Request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", channel.Key))
|
c.Request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", channel.Key))
|
||||||
c.Set(ctxkey.BaseURL, channel.GetBaseURL())
|
c.Set(ctxkey.BaseURL, channel.GetBaseURL())
|
||||||
|
cfg, _ := channel.LoadConfig()
|
||||||
// this is for backward compatibility
|
// this is for backward compatibility
|
||||||
switch channel.Type {
|
switch channel.Type {
|
||||||
case channeltype.Azure:
|
case channeltype.Azure:
|
||||||
c.Set(ctxkey.ConfigAPIVersion, channel.Other)
|
if cfg.APIVersion == "" {
|
||||||
|
cfg.APIVersion = channel.Other
|
||||||
|
}
|
||||||
case channeltype.Xunfei:
|
case channeltype.Xunfei:
|
||||||
c.Set(ctxkey.ConfigAPIVersion, channel.Other)
|
if cfg.APIVersion == "" {
|
||||||
|
cfg.APIVersion = channel.Other
|
||||||
|
}
|
||||||
case channeltype.Gemini:
|
case channeltype.Gemini:
|
||||||
c.Set(ctxkey.ConfigAPIVersion, channel.Other)
|
if cfg.APIVersion == "" {
|
||||||
|
cfg.APIVersion = channel.Other
|
||||||
|
}
|
||||||
case channeltype.AIProxyLibrary:
|
case channeltype.AIProxyLibrary:
|
||||||
c.Set(ctxkey.ConfigLibraryID, channel.Other)
|
if cfg.LibraryID == "" {
|
||||||
|
cfg.LibraryID = channel.Other
|
||||||
|
}
|
||||||
case channeltype.Ali:
|
case channeltype.Ali:
|
||||||
c.Set(ctxkey.ConfigPlugin, channel.Other)
|
if cfg.Plugin == "" {
|
||||||
}
|
cfg.Plugin = channel.Other
|
||||||
cfg, _ := channel.LoadConfig()
|
}
|
||||||
for k, v := range cfg {
|
|
||||||
c.Set(ctxkey.ConfigPrefix+k, v)
|
|
||||||
}
|
}
|
||||||
|
c.Set(ctxkey.Config, cfg)
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,14 @@ package middleware
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/songquanpeng/one-api/common/logger"
|
"github.com/songquanpeng/one-api/common/helper"
|
||||||
)
|
)
|
||||||
|
|
||||||
func SetUpLogger(server *gin.Engine) {
|
func SetUpLogger(server *gin.Engine) {
|
||||||
server.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
|
server.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
|
||||||
var requestID string
|
var requestID string
|
||||||
if param.Keys != nil {
|
if param.Keys != nil {
|
||||||
requestID = param.Keys[logger.RequestIdKey].(string)
|
requestID = param.Keys[helper.RequestIdKey].(string)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("[GIN] %s | %s | %3d | %13v | %15s | %7s %s\n",
|
return fmt.Sprintf("[GIN] %s | %s | %3d | %13v | %15s | %7s %s\n",
|
||||||
param.TimeStamp.Format("2006/01/02 - 15:04:05"),
|
param.TimeStamp.Format("2006/01/02 - 15:04:05"),
|
||||||
|
@ -4,16 +4,15 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/songquanpeng/one-api/common/helper"
|
"github.com/songquanpeng/one-api/common/helper"
|
||||||
"github.com/songquanpeng/one-api/common/logger"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func RequestId() func(c *gin.Context) {
|
func RequestId() func(c *gin.Context) {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
id := helper.GenRequestID()
|
id := helper.GenRequestID()
|
||||||
c.Set(logger.RequestIdKey, id)
|
c.Set(helper.RequestIdKey, id)
|
||||||
ctx := context.WithValue(c.Request.Context(), logger.RequestIdKey, id)
|
ctx := context.WithValue(c.Request.Context(), helper.RequestIdKey, id)
|
||||||
c.Request = c.Request.WithContext(ctx)
|
c.Request = c.Request.WithContext(ctx)
|
||||||
c.Header(logger.RequestIdKey, id)
|
c.Header(helper.RequestIdKey, id)
|
||||||
c.Next()
|
c.Next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ import (
|
|||||||
func abortWithMessage(c *gin.Context, statusCode int, message string) {
|
func abortWithMessage(c *gin.Context, statusCode int, message string) {
|
||||||
c.JSON(statusCode, gin.H{
|
c.JSON(statusCode, gin.H{
|
||||||
"error": gin.H{
|
"error": gin.H{
|
||||||
"message": helper.MessageWithRequestId(message, c.GetString(logger.RequestIdKey)),
|
"message": helper.MessageWithRequestId(message, c.GetString(helper.RequestIdKey)),
|
||||||
"type": "one_api_error",
|
"type": "one_api_error",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -38,6 +38,16 @@ type Channel struct {
|
|||||||
Config string `json:"config"`
|
Config string `json:"config"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ChannelConfig struct {
|
||||||
|
Region string `json:"region,omitempty"`
|
||||||
|
SK string `json:"sk,omitempty"`
|
||||||
|
AK string `json:"ak,omitempty"`
|
||||||
|
UserID string `json:"user_id,omitempty"`
|
||||||
|
APIVersion string `json:"api_version,omitempty"`
|
||||||
|
LibraryID string `json:"library_id,omitempty"`
|
||||||
|
Plugin string `json:"plugin,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
func GetAllChannels(startIdx int, num int, scope string) ([]*Channel, error) {
|
func GetAllChannels(startIdx int, num int, scope string) ([]*Channel, error) {
|
||||||
var channels []*Channel
|
var channels []*Channel
|
||||||
var err error
|
var err error
|
||||||
@ -161,14 +171,14 @@ func (channel *Channel) Delete() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (channel *Channel) LoadConfig() (map[string]string, error) {
|
func (channel *Channel) LoadConfig() (ChannelConfig, error) {
|
||||||
|
var cfg ChannelConfig
|
||||||
if channel.Config == "" {
|
if channel.Config == "" {
|
||||||
return nil, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
cfg := make(map[string]string)
|
|
||||||
err := json.Unmarshal([]byte(channel.Config), &cfg)
|
err := json.Unmarshal([]byte(channel.Config), &cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return cfg, err
|
||||||
}
|
}
|
||||||
return cfg, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/songquanpeng/one-api/relay/adaptor/anthropic"
|
"github.com/songquanpeng/one-api/relay/adaptor/anthropic"
|
||||||
"github.com/songquanpeng/one-api/relay/adaptor/aws"
|
"github.com/songquanpeng/one-api/relay/adaptor/aws"
|
||||||
"github.com/songquanpeng/one-api/relay/adaptor/baidu"
|
"github.com/songquanpeng/one-api/relay/adaptor/baidu"
|
||||||
|
"github.com/songquanpeng/one-api/relay/adaptor/cloudflare"
|
||||||
"github.com/songquanpeng/one-api/relay/adaptor/cohere"
|
"github.com/songquanpeng/one-api/relay/adaptor/cohere"
|
||||||
"github.com/songquanpeng/one-api/relay/adaptor/coze"
|
"github.com/songquanpeng/one-api/relay/adaptor/coze"
|
||||||
"github.com/songquanpeng/one-api/relay/adaptor/gemini"
|
"github.com/songquanpeng/one-api/relay/adaptor/gemini"
|
||||||
@ -49,6 +50,8 @@ func GetAdaptor(apiType int) adaptor.Adaptor {
|
|||||||
return &coze.Adaptor{}
|
return &coze.Adaptor{}
|
||||||
case apitype.Cohere:
|
case apitype.Cohere:
|
||||||
return &cohere.Adaptor{}
|
return &cohere.Adaptor{}
|
||||||
|
case apitype.Cloudflare:
|
||||||
|
return &cloudflare.Adaptor{}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/songquanpeng/one-api/common/ctxkey"
|
|
||||||
"github.com/songquanpeng/one-api/relay/adaptor"
|
"github.com/songquanpeng/one-api/relay/adaptor"
|
||||||
"github.com/songquanpeng/one-api/relay/meta"
|
"github.com/songquanpeng/one-api/relay/meta"
|
||||||
"github.com/songquanpeng/one-api/relay/model"
|
"github.com/songquanpeng/one-api/relay/model"
|
||||||
@ -13,10 +12,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Adaptor struct {
|
type Adaptor struct {
|
||||||
|
meta *meta.Meta
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Adaptor) Init(meta *meta.Meta) {
|
func (a *Adaptor) Init(meta *meta.Meta) {
|
||||||
|
a.meta = meta
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
|
func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
|
||||||
@ -34,7 +34,7 @@ func (a *Adaptor) ConvertRequest(c *gin.Context, relayMode int, request *model.G
|
|||||||
return nil, errors.New("request is nil")
|
return nil, errors.New("request is nil")
|
||||||
}
|
}
|
||||||
aiProxyLibraryRequest := ConvertRequest(*request)
|
aiProxyLibraryRequest := ConvertRequest(*request)
|
||||||
aiProxyLibraryRequest.LibraryId = c.GetString(ctxkey.ConfigLibraryID)
|
aiProxyLibraryRequest.LibraryId = a.meta.Config.LibraryID
|
||||||
return aiProxyLibraryRequest, nil
|
return aiProxyLibraryRequest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/songquanpeng/one-api/common/ctxkey"
|
|
||||||
"github.com/songquanpeng/one-api/relay/adaptor"
|
"github.com/songquanpeng/one-api/relay/adaptor"
|
||||||
"github.com/songquanpeng/one-api/relay/meta"
|
"github.com/songquanpeng/one-api/relay/meta"
|
||||||
"github.com/songquanpeng/one-api/relay/model"
|
"github.com/songquanpeng/one-api/relay/model"
|
||||||
@ -16,10 +15,11 @@ import (
|
|||||||
// https://help.aliyun.com/zh/dashscope/developer-reference/api-details
|
// https://help.aliyun.com/zh/dashscope/developer-reference/api-details
|
||||||
|
|
||||||
type Adaptor struct {
|
type Adaptor struct {
|
||||||
|
meta *meta.Meta
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Adaptor) Init(meta *meta.Meta) {
|
func (a *Adaptor) Init(meta *meta.Meta) {
|
||||||
|
a.meta = meta
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
|
func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
|
||||||
@ -47,8 +47,8 @@ func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Request, meta *me
|
|||||||
if meta.Mode == relaymode.ImagesGenerations {
|
if meta.Mode == relaymode.ImagesGenerations {
|
||||||
req.Header.Set("X-DashScope-Async", "enable")
|
req.Header.Set("X-DashScope-Async", "enable")
|
||||||
}
|
}
|
||||||
if c.GetString(ctxkey.ConfigPlugin) != "" {
|
if a.meta.Config.Plugin != "" {
|
||||||
req.Header.Set("X-DashScope-Plugin", c.GetString(ctxkey.ConfigPlugin))
|
req.Header.Set("X-DashScope-Plugin", a.meta.Config.Plugin)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package aws
|
package aws
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/aws/aws-sdk-go-v2/aws"
|
||||||
|
"github.com/aws/aws-sdk-go-v2/credentials"
|
||||||
|
"github.com/aws/aws-sdk-go-v2/service/bedrockruntime"
|
||||||
"github.com/songquanpeng/one-api/common/ctxkey"
|
"github.com/songquanpeng/one-api/common/ctxkey"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -16,10 +19,16 @@ import (
|
|||||||
var _ adaptor.Adaptor = new(Adaptor)
|
var _ adaptor.Adaptor = new(Adaptor)
|
||||||
|
|
||||||
type Adaptor struct {
|
type Adaptor struct {
|
||||||
|
meta *meta.Meta
|
||||||
|
awsClient *bedrockruntime.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Adaptor) Init(meta *meta.Meta) {
|
func (a *Adaptor) Init(meta *meta.Meta) {
|
||||||
|
a.meta = meta
|
||||||
|
a.awsClient = bedrockruntime.New(bedrockruntime.Options{
|
||||||
|
Region: meta.Config.Region,
|
||||||
|
Credentials: aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider(meta.Config.AK, meta.Config.SK, "")),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
|
func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
|
||||||
@ -54,9 +63,9 @@ func (a *Adaptor) DoRequest(c *gin.Context, meta *meta.Meta, requestBody io.Read
|
|||||||
|
|
||||||
func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, meta *meta.Meta) (usage *model.Usage, err *model.ErrorWithStatusCode) {
|
func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, meta *meta.Meta) (usage *model.Usage, err *model.ErrorWithStatusCode) {
|
||||||
if meta.IsStream {
|
if meta.IsStream {
|
||||||
err, usage = StreamHandler(c, resp)
|
err, usage = StreamHandler(c, a.awsClient)
|
||||||
} else {
|
} else {
|
||||||
err, usage = Handler(c, resp, meta.PromptTokens, meta.ActualModelName)
|
err, usage = Handler(c, a.awsClient, meta.ActualModelName)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -65,7 +74,6 @@ func (a *Adaptor) GetModelList() (models []string) {
|
|||||||
for n := range awsModelIDMap {
|
for n := range awsModelIDMap {
|
||||||
models = append(models, n)
|
models = append(models, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go-v2/aws"
|
"github.com/aws/aws-sdk-go-v2/aws"
|
||||||
"github.com/aws/aws-sdk-go-v2/credentials"
|
|
||||||
"github.com/aws/aws-sdk-go-v2/service/bedrockruntime"
|
"github.com/aws/aws-sdk-go-v2/service/bedrockruntime"
|
||||||
"github.com/aws/aws-sdk-go-v2/service/bedrockruntime/types"
|
"github.com/aws/aws-sdk-go-v2/service/bedrockruntime/types"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@ -23,18 +22,6 @@ import (
|
|||||||
relaymodel "github.com/songquanpeng/one-api/relay/model"
|
relaymodel "github.com/songquanpeng/one-api/relay/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newAwsClient(c *gin.Context) (*bedrockruntime.Client, error) {
|
|
||||||
ak := c.GetString(ctxkey.ConfigAK)
|
|
||||||
sk := c.GetString(ctxkey.ConfigSK)
|
|
||||||
region := c.GetString(ctxkey.ConfigRegion)
|
|
||||||
client := bedrockruntime.New(bedrockruntime.Options{
|
|
||||||
Region: region,
|
|
||||||
Credentials: aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider(ak, sk, "")),
|
|
||||||
})
|
|
||||||
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func wrapErr(err error) *relaymodel.ErrorWithStatusCode {
|
func wrapErr(err error) *relaymodel.ErrorWithStatusCode {
|
||||||
return &relaymodel.ErrorWithStatusCode{
|
return &relaymodel.ErrorWithStatusCode{
|
||||||
StatusCode: http.StatusInternalServerError,
|
StatusCode: http.StatusInternalServerError,
|
||||||
@ -62,12 +49,7 @@ func awsModelID(requestModel string) (string, error) {
|
|||||||
return "", errors.Errorf("model %s not found", requestModel)
|
return "", errors.Errorf("model %s not found", requestModel)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Handler(c *gin.Context, resp *http.Response, promptTokens int, modelName string) (*relaymodel.ErrorWithStatusCode, *relaymodel.Usage) {
|
func Handler(c *gin.Context, awsCli *bedrockruntime.Client, modelName string) (*relaymodel.ErrorWithStatusCode, *relaymodel.Usage) {
|
||||||
awsCli, err := newAwsClient(c)
|
|
||||||
if err != nil {
|
|
||||||
return wrapErr(errors.Wrap(err, "newAwsClient")), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
awsModelId, err := awsModelID(c.GetString(ctxkey.RequestModel))
|
awsModelId, err := awsModelID(c.GetString(ctxkey.RequestModel))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return wrapErr(errors.Wrap(err, "awsModelID")), nil
|
return wrapErr(errors.Wrap(err, "awsModelID")), nil
|
||||||
@ -120,13 +102,8 @@ func Handler(c *gin.Context, resp *http.Response, promptTokens int, modelName st
|
|||||||
return nil, &usage
|
return nil, &usage
|
||||||
}
|
}
|
||||||
|
|
||||||
func StreamHandler(c *gin.Context, resp *http.Response) (*relaymodel.ErrorWithStatusCode, *relaymodel.Usage) {
|
func StreamHandler(c *gin.Context, awsCli *bedrockruntime.Client) (*relaymodel.ErrorWithStatusCode, *relaymodel.Usage) {
|
||||||
createdTime := helper.GetTimestamp()
|
createdTime := helper.GetTimestamp()
|
||||||
awsCli, err := newAwsClient(c)
|
|
||||||
if err != nil {
|
|
||||||
return wrapErr(errors.Wrap(err, "newAwsClient")), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
awsModelId, err := awsModelID(c.GetString(ctxkey.RequestModel))
|
awsModelId, err := awsModelID(c.GetString(ctxkey.RequestModel))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return wrapErr(errors.Wrap(err, "awsModelID")), nil
|
return wrapErr(errors.Wrap(err, "awsModelID")), nil
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
package azure
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"github.com/songquanpeng/one-api/common/ctxkey"
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetAPIVersion(c *gin.Context) string {
|
|
||||||
query := c.Request.URL.Query()
|
|
||||||
apiVersion := query.Get("api-version")
|
|
||||||
if apiVersion == "" {
|
|
||||||
apiVersion = c.GetString(ctxkey.ConfigAPIVersion)
|
|
||||||
}
|
|
||||||
return apiVersion
|
|
||||||
}
|
|
66
relay/adaptor/cloudflare/adaptor.go
Normal file
66
relay/adaptor/cloudflare/adaptor.go
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
package cloudflare
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/songquanpeng/one-api/relay/adaptor"
|
||||||
|
"github.com/songquanpeng/one-api/relay/meta"
|
||||||
|
"github.com/songquanpeng/one-api/relay/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Adaptor struct {
|
||||||
|
meta *meta.Meta
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConvertImageRequest implements adaptor.Adaptor.
|
||||||
|
func (*Adaptor) ConvertImageRequest(request *model.ImageRequest) (any, error) {
|
||||||
|
return nil, errors.New("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConvertImageRequest implements adaptor.Adaptor.
|
||||||
|
|
||||||
|
func (a *Adaptor) Init(meta *meta.Meta) {
|
||||||
|
a.meta = meta
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
|
||||||
|
return fmt.Sprintf("%s/client/v4/accounts/%s/ai/run/%s", meta.BaseURL, meta.Config.UserID, meta.ActualModelName), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Request, meta *meta.Meta) error {
|
||||||
|
adaptor.SetupCommonRequestHeader(c, req, meta)
|
||||||
|
req.Header.Set("Authorization", "Bearer "+meta.APIKey)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Adaptor) ConvertRequest(c *gin.Context, relayMode int, request *model.GeneralOpenAIRequest) (any, error) {
|
||||||
|
if request == nil {
|
||||||
|
return nil, errors.New("request is nil")
|
||||||
|
}
|
||||||
|
return ConvertRequest(*request), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Adaptor) DoRequest(c *gin.Context, meta *meta.Meta, requestBody io.Reader) (*http.Response, error) {
|
||||||
|
return adaptor.DoRequestHelper(a, c, meta, requestBody)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, meta *meta.Meta) (usage *model.Usage, err *model.ErrorWithStatusCode) {
|
||||||
|
if meta.IsStream {
|
||||||
|
err, usage = StreamHandler(c, resp, meta.PromptTokens, meta.ActualModelName)
|
||||||
|
} else {
|
||||||
|
err, usage = Handler(c, resp, meta.PromptTokens, meta.ActualModelName)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Adaptor) GetModelList() []string {
|
||||||
|
return ModelList
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Adaptor) GetChannelName() string {
|
||||||
|
return "cloudflare"
|
||||||
|
}
|
36
relay/adaptor/cloudflare/constant.go
Normal file
36
relay/adaptor/cloudflare/constant.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package cloudflare
|
||||||
|
|
||||||
|
var ModelList = []string{
|
||||||
|
"@cf/meta/llama-2-7b-chat-fp16",
|
||||||
|
"@cf/meta/llama-2-7b-chat-int8",
|
||||||
|
"@cf/mistral/mistral-7b-instruct-v0.1",
|
||||||
|
"@hf/thebloke/deepseek-coder-6.7b-base-awq",
|
||||||
|
"@hf/thebloke/deepseek-coder-6.7b-instruct-awq",
|
||||||
|
"@cf/deepseek-ai/deepseek-math-7b-base",
|
||||||
|
"@cf/deepseek-ai/deepseek-math-7b-instruct",
|
||||||
|
"@cf/thebloke/discolm-german-7b-v1-awq",
|
||||||
|
"@cf/tiiuae/falcon-7b-instruct",
|
||||||
|
"@cf/google/gemma-2b-it-lora",
|
||||||
|
"@hf/google/gemma-7b-it",
|
||||||
|
"@cf/google/gemma-7b-it-lora",
|
||||||
|
"@hf/nousresearch/hermes-2-pro-mistral-7b",
|
||||||
|
"@hf/thebloke/llama-2-13b-chat-awq",
|
||||||
|
"@cf/meta-llama/llama-2-7b-chat-hf-lora",
|
||||||
|
"@cf/meta/llama-3-8b-instruct",
|
||||||
|
"@hf/thebloke/llamaguard-7b-awq",
|
||||||
|
"@hf/thebloke/mistral-7b-instruct-v0.1-awq",
|
||||||
|
"@hf/mistralai/mistral-7b-instruct-v0.2",
|
||||||
|
"@cf/mistral/mistral-7b-instruct-v0.2-lora",
|
||||||
|
"@hf/thebloke/neural-chat-7b-v3-1-awq",
|
||||||
|
"@cf/openchat/openchat-3.5-0106",
|
||||||
|
"@hf/thebloke/openhermes-2.5-mistral-7b-awq",
|
||||||
|
"@cf/microsoft/phi-2",
|
||||||
|
"@cf/qwen/qwen1.5-0.5b-chat",
|
||||||
|
"@cf/qwen/qwen1.5-1.8b-chat",
|
||||||
|
"@cf/qwen/qwen1.5-14b-chat-awq",
|
||||||
|
"@cf/qwen/qwen1.5-7b-chat-awq",
|
||||||
|
"@cf/defog/sqlcoder-7b-2",
|
||||||
|
"@hf/nexusflow/starling-lm-7b-beta",
|
||||||
|
"@cf/tinyllama/tinyllama-1.1b-chat-v1.0",
|
||||||
|
"@hf/thebloke/zephyr-7b-beta-awq",
|
||||||
|
}
|
152
relay/adaptor/cloudflare/main.go
Normal file
152
relay/adaptor/cloudflare/main.go
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
package cloudflare
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/songquanpeng/one-api/common"
|
||||||
|
"github.com/songquanpeng/one-api/common/helper"
|
||||||
|
"github.com/songquanpeng/one-api/common/logger"
|
||||||
|
"github.com/songquanpeng/one-api/relay/adaptor/openai"
|
||||||
|
"github.com/songquanpeng/one-api/relay/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ConvertRequest(textRequest model.GeneralOpenAIRequest) *Request {
|
||||||
|
lastMessage := textRequest.Messages[len(textRequest.Messages)-1]
|
||||||
|
return &Request{
|
||||||
|
MaxTokens: textRequest.MaxTokens,
|
||||||
|
Prompt: lastMessage.StringContent(),
|
||||||
|
Stream: textRequest.Stream,
|
||||||
|
Temperature: textRequest.Temperature,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ResponseCloudflare2OpenAI(cloudflareResponse *Response) *openai.TextResponse {
|
||||||
|
choice := openai.TextResponseChoice{
|
||||||
|
Index: 0,
|
||||||
|
Message: model.Message{
|
||||||
|
Role: "assistant",
|
||||||
|
Content: cloudflareResponse.Result.Response,
|
||||||
|
},
|
||||||
|
FinishReason: "stop",
|
||||||
|
}
|
||||||
|
fullTextResponse := openai.TextResponse{
|
||||||
|
Object: "chat.completion",
|
||||||
|
Created: helper.GetTimestamp(),
|
||||||
|
Choices: []openai.TextResponseChoice{choice},
|
||||||
|
}
|
||||||
|
return &fullTextResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
func StreamResponseCloudflare2OpenAI(cloudflareResponse *StreamResponse) *openai.ChatCompletionsStreamResponse {
|
||||||
|
var choice openai.ChatCompletionsStreamResponseChoice
|
||||||
|
choice.Delta.Content = cloudflareResponse.Response
|
||||||
|
choice.Delta.Role = "assistant"
|
||||||
|
openaiResponse := openai.ChatCompletionsStreamResponse{
|
||||||
|
Object: "chat.completion.chunk",
|
||||||
|
Choices: []openai.ChatCompletionsStreamResponseChoice{choice},
|
||||||
|
Created: helper.GetTimestamp(),
|
||||||
|
}
|
||||||
|
return &openaiResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
func StreamHandler(c *gin.Context, resp *http.Response, promptTokens int, modelName string) (*model.ErrorWithStatusCode, *model.Usage) {
|
||||||
|
scanner := bufio.NewScanner(resp.Body)
|
||||||
|
scanner.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
||||||
|
if atEOF && len(data) == 0 {
|
||||||
|
return 0, nil, nil
|
||||||
|
}
|
||||||
|
if i := bytes.IndexByte(data, '\n'); i >= 0 {
|
||||||
|
return i + 1, data[0:i], nil
|
||||||
|
}
|
||||||
|
if atEOF {
|
||||||
|
return len(data), data, nil
|
||||||
|
}
|
||||||
|
return 0, nil, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
dataChan := make(chan string)
|
||||||
|
stopChan := make(chan bool)
|
||||||
|
go func() {
|
||||||
|
for scanner.Scan() {
|
||||||
|
data := scanner.Text()
|
||||||
|
if len(data) < len("data: ") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
data = strings.TrimPrefix(data, "data: ")
|
||||||
|
dataChan <- data
|
||||||
|
}
|
||||||
|
stopChan <- true
|
||||||
|
}()
|
||||||
|
common.SetEventStreamHeaders(c)
|
||||||
|
id := helper.GetResponseID(c)
|
||||||
|
responseModel := c.GetString("original_model")
|
||||||
|
var responseText string
|
||||||
|
c.Stream(func(w io.Writer) bool {
|
||||||
|
select {
|
||||||
|
case data := <-dataChan:
|
||||||
|
// some implementations may add \r at the end of data
|
||||||
|
data = strings.TrimSuffix(data, "\r")
|
||||||
|
var cloudflareResponse StreamResponse
|
||||||
|
err := json.Unmarshal([]byte(data), &cloudflareResponse)
|
||||||
|
if err != nil {
|
||||||
|
logger.SysError("error unmarshalling stream response: " + err.Error())
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
response := StreamResponseCloudflare2OpenAI(&cloudflareResponse)
|
||||||
|
if response == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
responseText += cloudflareResponse.Response
|
||||||
|
response.Id = id
|
||||||
|
response.Model = responseModel
|
||||||
|
jsonStr, err := json.Marshal(response)
|
||||||
|
if err != nil {
|
||||||
|
logger.SysError("error marshalling stream response: " + err.Error())
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
c.Render(-1, common.CustomEvent{Data: "data: " + string(jsonStr)})
|
||||||
|
return true
|
||||||
|
case <-stopChan:
|
||||||
|
c.Render(-1, common.CustomEvent{Data: "data: [DONE]"})
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
_ = resp.Body.Close()
|
||||||
|
usage := openai.ResponseText2Usage(responseText, responseModel, promptTokens)
|
||||||
|
return nil, usage
|
||||||
|
}
|
||||||
|
|
||||||
|
func Handler(c *gin.Context, resp *http.Response, promptTokens int, modelName string) (*model.ErrorWithStatusCode, *model.Usage) {
|
||||||
|
responseBody, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return openai.ErrorWrapper(err, "read_response_body_failed", http.StatusInternalServerError), nil
|
||||||
|
}
|
||||||
|
err = resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return openai.ErrorWrapper(err, "close_response_body_failed", http.StatusInternalServerError), nil
|
||||||
|
}
|
||||||
|
var cloudflareResponse Response
|
||||||
|
err = json.Unmarshal(responseBody, &cloudflareResponse)
|
||||||
|
if err != nil {
|
||||||
|
return openai.ErrorWrapper(err, "unmarshal_response_body_failed", http.StatusInternalServerError), nil
|
||||||
|
}
|
||||||
|
fullTextResponse := ResponseCloudflare2OpenAI(&cloudflareResponse)
|
||||||
|
fullTextResponse.Model = modelName
|
||||||
|
usage := openai.ResponseText2Usage(cloudflareResponse.Result.Response, modelName, promptTokens)
|
||||||
|
fullTextResponse.Usage = *usage
|
||||||
|
fullTextResponse.Id = helper.GetResponseID(c)
|
||||||
|
jsonResponse, err := json.Marshal(fullTextResponse)
|
||||||
|
if err != nil {
|
||||||
|
return openai.ErrorWrapper(err, "marshal_response_body_failed", http.StatusInternalServerError), nil
|
||||||
|
}
|
||||||
|
c.Writer.Header().Set("Content-Type", "application/json")
|
||||||
|
c.Writer.WriteHeader(resp.StatusCode)
|
||||||
|
_, err = c.Writer.Write(jsonResponse)
|
||||||
|
return nil, usage
|
||||||
|
}
|
25
relay/adaptor/cloudflare/model.go
Normal file
25
relay/adaptor/cloudflare/model.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package cloudflare
|
||||||
|
|
||||||
|
type Request struct {
|
||||||
|
Lora string `json:"lora,omitempty"`
|
||||||
|
MaxTokens int `json:"max_tokens,omitempty"`
|
||||||
|
Prompt string `json:"prompt,omitempty"`
|
||||||
|
Raw bool `json:"raw,omitempty"`
|
||||||
|
Stream bool `json:"stream,omitempty"`
|
||||||
|
Temperature float64 `json:"temperature,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Result struct {
|
||||||
|
Response string `json:"response"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Response struct {
|
||||||
|
Result Result `json:"result"`
|
||||||
|
Success bool `json:"success"`
|
||||||
|
Errors []string `json:"errors"`
|
||||||
|
Messages []string `json:"messages"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type StreamResponse struct {
|
||||||
|
Response string `json:"response"`
|
||||||
|
}
|
@ -4,7 +4,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/songquanpeng/one-api/common/ctxkey"
|
|
||||||
"github.com/songquanpeng/one-api/relay/adaptor"
|
"github.com/songquanpeng/one-api/relay/adaptor"
|
||||||
"github.com/songquanpeng/one-api/relay/adaptor/openai"
|
"github.com/songquanpeng/one-api/relay/adaptor/openai"
|
||||||
"github.com/songquanpeng/one-api/relay/meta"
|
"github.com/songquanpeng/one-api/relay/meta"
|
||||||
@ -14,10 +13,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Adaptor struct {
|
type Adaptor struct {
|
||||||
|
meta *meta.Meta
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Adaptor) Init(meta *meta.Meta) {
|
func (a *Adaptor) Init(meta *meta.Meta) {
|
||||||
|
a.meta = meta
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
|
func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
|
||||||
@ -34,7 +34,7 @@ func (a *Adaptor) ConvertRequest(c *gin.Context, relayMode int, request *model.G
|
|||||||
if request == nil {
|
if request == nil {
|
||||||
return nil, errors.New("request is nil")
|
return nil, errors.New("request is nil")
|
||||||
}
|
}
|
||||||
request.User = c.GetString(ctxkey.ConfigUserID)
|
request.User = a.meta.Config.UserID
|
||||||
return ConvertRequest(*request), nil
|
return ConvertRequest(*request), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ func (a *Adaptor) Init(meta *meta.Meta) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
|
func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
|
||||||
version := helper.AssignOrDefault(meta.APIVersion, config.GeminiVersion)
|
version := helper.AssignOrDefault(meta.Config.APIVersion, config.GeminiVersion)
|
||||||
action := "generateContent"
|
action := "generateContent"
|
||||||
if meta.IsStream {
|
if meta.IsStream {
|
||||||
action = "streamGenerateContent"
|
action = "streamGenerateContent"
|
||||||
|
@ -29,13 +29,13 @@ func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
|
|||||||
if meta.Mode == relaymode.ImagesGenerations {
|
if meta.Mode == relaymode.ImagesGenerations {
|
||||||
// https://learn.microsoft.com/en-us/azure/ai-services/openai/dall-e-quickstart?tabs=dalle3%2Ccommand-line&pivots=rest-api
|
// https://learn.microsoft.com/en-us/azure/ai-services/openai/dall-e-quickstart?tabs=dalle3%2Ccommand-line&pivots=rest-api
|
||||||
// https://{resource_name}.openai.azure.com/openai/deployments/dall-e-3/images/generations?api-version=2024-03-01-preview
|
// https://{resource_name}.openai.azure.com/openai/deployments/dall-e-3/images/generations?api-version=2024-03-01-preview
|
||||||
fullRequestURL := fmt.Sprintf("%s/openai/deployments/%s/images/generations?api-version=%s", meta.BaseURL, meta.ActualModelName, meta.APIVersion)
|
fullRequestURL := fmt.Sprintf("%s/openai/deployments/%s/images/generations?api-version=%s", meta.BaseURL, meta.ActualModelName, meta.Config.APIVersion)
|
||||||
return fullRequestURL, nil
|
return fullRequestURL, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://learn.microsoft.com/en-us/azure/cognitive-services/openai/chatgpt-quickstart?pivots=rest-api&tabs=command-line#rest-api
|
// https://learn.microsoft.com/en-us/azure/cognitive-services/openai/chatgpt-quickstart?pivots=rest-api&tabs=command-line#rest-api
|
||||||
requestURL := strings.Split(meta.RequestURLPath, "?")[0]
|
requestURL := strings.Split(meta.RequestURLPath, "?")[0]
|
||||||
requestURL = fmt.Sprintf("%s?api-version=%s", requestURL, meta.APIVersion)
|
requestURL = fmt.Sprintf("%s?api-version=%s", requestURL, meta.Config.APIVersion)
|
||||||
task := strings.TrimPrefix(requestURL, "/v1/")
|
task := strings.TrimPrefix(requestURL, "/v1/")
|
||||||
model_ := meta.ActualModelName
|
model_ := meta.ActualModelName
|
||||||
model_ = strings.Replace(model_, ".", "", -1)
|
model_ = strings.Replace(model_, ".", "", -1)
|
||||||
|
@ -134,7 +134,7 @@ type ChatCompletionsStreamResponse struct {
|
|||||||
Created int64 `json:"created"`
|
Created int64 `json:"created"`
|
||||||
Model string `json:"model"`
|
Model string `json:"model"`
|
||||||
Choices []ChatCompletionsStreamResponseChoice `json:"choices"`
|
Choices []ChatCompletionsStreamResponseChoice `json:"choices"`
|
||||||
Usage *model.Usage `json:"usage"`
|
Usage *model.Usage `json:"usage,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CompletionsStreamResponse struct {
|
type CompletionsStreamResponse struct {
|
||||||
|
@ -14,10 +14,11 @@ import (
|
|||||||
|
|
||||||
type Adaptor struct {
|
type Adaptor struct {
|
||||||
request *model.GeneralOpenAIRequest
|
request *model.GeneralOpenAIRequest
|
||||||
|
meta *meta.Meta
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Adaptor) Init(meta *meta.Meta) {
|
func (a *Adaptor) Init(meta *meta.Meta) {
|
||||||
|
a.meta = meta
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
|
func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
|
||||||
@ -26,6 +27,14 @@ func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
|
|||||||
|
|
||||||
func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Request, meta *meta.Meta) error {
|
func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Request, meta *meta.Meta) error {
|
||||||
adaptor.SetupCommonRequestHeader(c, req, meta)
|
adaptor.SetupCommonRequestHeader(c, req, meta)
|
||||||
|
version := parseAPIVersionByModelName(meta.ActualModelName)
|
||||||
|
if version == "" {
|
||||||
|
version = a.meta.Config.APIVersion
|
||||||
|
}
|
||||||
|
if version == "" {
|
||||||
|
version = "v1.1"
|
||||||
|
}
|
||||||
|
a.meta.Config.APIVersion = version
|
||||||
// check DoResponse for auth part
|
// check DoResponse for auth part
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -61,9 +70,9 @@ func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, meta *meta.Met
|
|||||||
return nil, openai.ErrorWrapper(errors.New("request is nil"), "request_is_nil", http.StatusBadRequest)
|
return nil, openai.ErrorWrapper(errors.New("request is nil"), "request_is_nil", http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
if meta.IsStream {
|
if meta.IsStream {
|
||||||
err, usage = StreamHandler(c, *a.request, splits[0], splits[1], splits[2])
|
err, usage = StreamHandler(c, meta, *a.request, splits[0], splits[1], splits[2])
|
||||||
} else {
|
} else {
|
||||||
err, usage = Handler(c, *a.request, splits[0], splits[1], splits[2])
|
err, usage = Handler(c, meta, *a.request, splits[0], splits[1], splits[2])
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -9,12 +9,12 @@ import (
|
|||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/songquanpeng/one-api/common"
|
"github.com/songquanpeng/one-api/common"
|
||||||
"github.com/songquanpeng/one-api/common/ctxkey"
|
|
||||||
"github.com/songquanpeng/one-api/common/helper"
|
"github.com/songquanpeng/one-api/common/helper"
|
||||||
"github.com/songquanpeng/one-api/common/logger"
|
"github.com/songquanpeng/one-api/common/logger"
|
||||||
"github.com/songquanpeng/one-api/common/random"
|
"github.com/songquanpeng/one-api/common/random"
|
||||||
"github.com/songquanpeng/one-api/relay/adaptor/openai"
|
"github.com/songquanpeng/one-api/relay/adaptor/openai"
|
||||||
"github.com/songquanpeng/one-api/relay/constant"
|
"github.com/songquanpeng/one-api/relay/constant"
|
||||||
|
"github.com/songquanpeng/one-api/relay/meta"
|
||||||
"github.com/songquanpeng/one-api/relay/model"
|
"github.com/songquanpeng/one-api/relay/model"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -149,8 +149,8 @@ func buildXunfeiAuthUrl(hostUrl string, apiKey, apiSecret string) string {
|
|||||||
return callUrl
|
return callUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
func StreamHandler(c *gin.Context, textRequest model.GeneralOpenAIRequest, appId string, apiSecret string, apiKey string) (*model.ErrorWithStatusCode, *model.Usage) {
|
func StreamHandler(c *gin.Context, meta *meta.Meta, textRequest model.GeneralOpenAIRequest, appId string, apiSecret string, apiKey string) (*model.ErrorWithStatusCode, *model.Usage) {
|
||||||
domain, authUrl := getXunfeiAuthUrl(c, apiKey, apiSecret, textRequest.Model)
|
domain, authUrl := getXunfeiAuthUrl(meta.Config.APIVersion, apiKey, apiSecret)
|
||||||
dataChan, stopChan, err := xunfeiMakeRequest(textRequest, domain, authUrl, appId)
|
dataChan, stopChan, err := xunfeiMakeRequest(textRequest, domain, authUrl, appId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return openai.ErrorWrapper(err, "xunfei_request_failed", http.StatusInternalServerError), nil
|
return openai.ErrorWrapper(err, "xunfei_request_failed", http.StatusInternalServerError), nil
|
||||||
@ -179,8 +179,8 @@ func StreamHandler(c *gin.Context, textRequest model.GeneralOpenAIRequest, appId
|
|||||||
return nil, &usage
|
return nil, &usage
|
||||||
}
|
}
|
||||||
|
|
||||||
func Handler(c *gin.Context, textRequest model.GeneralOpenAIRequest, appId string, apiSecret string, apiKey string) (*model.ErrorWithStatusCode, *model.Usage) {
|
func Handler(c *gin.Context, meta *meta.Meta, textRequest model.GeneralOpenAIRequest, appId string, apiSecret string, apiKey string) (*model.ErrorWithStatusCode, *model.Usage) {
|
||||||
domain, authUrl := getXunfeiAuthUrl(c, apiKey, apiSecret, textRequest.Model)
|
domain, authUrl := getXunfeiAuthUrl(meta.Config.APIVersion, apiKey, apiSecret)
|
||||||
dataChan, stopChan, err := xunfeiMakeRequest(textRequest, domain, authUrl, appId)
|
dataChan, stopChan, err := xunfeiMakeRequest(textRequest, domain, authUrl, appId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return openai.ErrorWrapper(err, "xunfei_request_failed", http.StatusInternalServerError), nil
|
return openai.ErrorWrapper(err, "xunfei_request_failed", http.StatusInternalServerError), nil
|
||||||
@ -268,25 +268,12 @@ func xunfeiMakeRequest(textRequest model.GeneralOpenAIRequest, domain, authUrl,
|
|||||||
return dataChan, stopChan, nil
|
return dataChan, stopChan, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAPIVersion(c *gin.Context, modelName string) string {
|
func parseAPIVersionByModelName(modelName string) string {
|
||||||
query := c.Request.URL.Query()
|
|
||||||
apiVersion := query.Get("api-version")
|
|
||||||
if apiVersion != "" {
|
|
||||||
return apiVersion
|
|
||||||
}
|
|
||||||
parts := strings.Split(modelName, "-")
|
parts := strings.Split(modelName, "-")
|
||||||
if len(parts) == 2 {
|
if len(parts) == 2 {
|
||||||
apiVersion = parts[1]
|
return parts[1]
|
||||||
return apiVersion
|
|
||||||
|
|
||||||
}
|
}
|
||||||
apiVersion = c.GetString(ctxkey.ConfigAPIVersion)
|
return ""
|
||||||
if apiVersion != "" {
|
|
||||||
return apiVersion
|
|
||||||
}
|
|
||||||
apiVersion = "v1.1"
|
|
||||||
logger.SysLog("api_version not found, using default: " + apiVersion)
|
|
||||||
return apiVersion
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://www.xfyun.cn/doc/spark/Web.html#_1-%E6%8E%A5%E5%8F%A3%E8%AF%B4%E6%98%8E
|
// https://www.xfyun.cn/doc/spark/Web.html#_1-%E6%8E%A5%E5%8F%A3%E8%AF%B4%E6%98%8E
|
||||||
@ -304,8 +291,7 @@ func apiVersion2domain(apiVersion string) string {
|
|||||||
return "general" + apiVersion
|
return "general" + apiVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
func getXunfeiAuthUrl(c *gin.Context, apiKey string, apiSecret string, modelName string) (string, string) {
|
func getXunfeiAuthUrl(apiVersion string, apiKey string, apiSecret string) (string, string) {
|
||||||
apiVersion := getAPIVersion(c, modelName)
|
|
||||||
domain := apiVersion2domain(apiVersion)
|
domain := apiVersion2domain(apiVersion)
|
||||||
authUrl := buildXunfeiAuthUrl(fmt.Sprintf("wss://spark-api.xf-yun.com/%s/chat", apiVersion), apiKey, apiSecret)
|
authUrl := buildXunfeiAuthUrl(fmt.Sprintf("wss://spark-api.xf-yun.com/%s/chat", apiVersion), apiKey, apiSecret)
|
||||||
return domain, authUrl
|
return domain, authUrl
|
||||||
|
@ -15,6 +15,7 @@ const (
|
|||||||
AwsClaude
|
AwsClaude
|
||||||
Coze
|
Coze
|
||||||
Cohere
|
Cohere
|
||||||
|
Cloudflare
|
||||||
|
|
||||||
Dummy // this one is only for count, do not add any channel after this
|
Dummy // this one is only for count, do not add any channel after this
|
||||||
)
|
)
|
||||||
|
@ -38,6 +38,7 @@ const (
|
|||||||
Coze
|
Coze
|
||||||
Cohere
|
Cohere
|
||||||
DeepSeek
|
DeepSeek
|
||||||
|
Cloudflare
|
||||||
|
|
||||||
Dummy
|
Dummy
|
||||||
)
|
)
|
||||||
|
@ -31,6 +31,8 @@ func ToAPIType(channelType int) int {
|
|||||||
apiType = apitype.Coze
|
apiType = apitype.Coze
|
||||||
case Cohere:
|
case Cohere:
|
||||||
apiType = apitype.Cohere
|
apiType = apitype.Cohere
|
||||||
|
case Cloudflare:
|
||||||
|
apiType = apitype.Cloudflare
|
||||||
}
|
}
|
||||||
|
|
||||||
return apiType
|
return apiType
|
||||||
|
@ -38,6 +38,7 @@ var ChannelBaseURLs = []string{
|
|||||||
"https://api.coze.com", // 34
|
"https://api.coze.com", // 34
|
||||||
"https://api.cohere.ai", // 35
|
"https://api.cohere.ai", // 35
|
||||||
"https://api.deepseek.com", // 36
|
"https://api.deepseek.com", // 36
|
||||||
|
"https://api.cloudflare.com", // 37
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -13,12 +13,12 @@ import (
|
|||||||
"github.com/songquanpeng/one-api/common/ctxkey"
|
"github.com/songquanpeng/one-api/common/ctxkey"
|
||||||
"github.com/songquanpeng/one-api/common/logger"
|
"github.com/songquanpeng/one-api/common/logger"
|
||||||
"github.com/songquanpeng/one-api/model"
|
"github.com/songquanpeng/one-api/model"
|
||||||
"github.com/songquanpeng/one-api/relay/adaptor/azure"
|
|
||||||
"github.com/songquanpeng/one-api/relay/adaptor/openai"
|
"github.com/songquanpeng/one-api/relay/adaptor/openai"
|
||||||
"github.com/songquanpeng/one-api/relay/billing"
|
"github.com/songquanpeng/one-api/relay/billing"
|
||||||
billingratio "github.com/songquanpeng/one-api/relay/billing/ratio"
|
billingratio "github.com/songquanpeng/one-api/relay/billing/ratio"
|
||||||
"github.com/songquanpeng/one-api/relay/channeltype"
|
"github.com/songquanpeng/one-api/relay/channeltype"
|
||||||
"github.com/songquanpeng/one-api/relay/client"
|
"github.com/songquanpeng/one-api/relay/client"
|
||||||
|
"github.com/songquanpeng/one-api/relay/meta"
|
||||||
relaymodel "github.com/songquanpeng/one-api/relay/model"
|
relaymodel "github.com/songquanpeng/one-api/relay/model"
|
||||||
"github.com/songquanpeng/one-api/relay/relaymode"
|
"github.com/songquanpeng/one-api/relay/relaymode"
|
||||||
"io"
|
"io"
|
||||||
@ -28,6 +28,7 @@ import (
|
|||||||
|
|
||||||
func RelayAudioHelper(c *gin.Context, relayMode int) *relaymodel.ErrorWithStatusCode {
|
func RelayAudioHelper(c *gin.Context, relayMode int) *relaymodel.ErrorWithStatusCode {
|
||||||
ctx := c.Request.Context()
|
ctx := c.Request.Context()
|
||||||
|
meta := meta.GetByContext(c)
|
||||||
audioModel := "whisper-1"
|
audioModel := "whisper-1"
|
||||||
|
|
||||||
tokenId := c.GetInt(ctxkey.TokenId)
|
tokenId := c.GetInt(ctxkey.TokenId)
|
||||||
@ -128,7 +129,7 @@ func RelayAudioHelper(c *gin.Context, relayMode int) *relaymodel.ErrorWithStatus
|
|||||||
|
|
||||||
fullRequestURL := openai.GetFullRequestURL(baseURL, requestURL, channelType)
|
fullRequestURL := openai.GetFullRequestURL(baseURL, requestURL, channelType)
|
||||||
if channelType == channeltype.Azure {
|
if channelType == channeltype.Azure {
|
||||||
apiVersion := azure.GetAPIVersion(c)
|
apiVersion := meta.Config.APIVersion
|
||||||
if relayMode == relaymode.AudioTranscription {
|
if relayMode == relaymode.AudioTranscription {
|
||||||
// https://learn.microsoft.com/en-us/azure/ai-services/openai/whisper-quickstart?tabs=command-line#rest-api
|
// https://learn.microsoft.com/en-us/azure/ai-services/openai/whisper-quickstart?tabs=command-line#rest-api
|
||||||
fullRequestURL = fmt.Sprintf("%s/openai/deployments/%s/audio/transcriptions?api-version=%s", baseURL, audioModel, apiVersion)
|
fullRequestURL = fmt.Sprintf("%s/openai/deployments/%s/audio/transcriptions?api-version=%s", baseURL, audioModel, apiVersion)
|
||||||
|
@ -70,6 +70,7 @@ func RelayImageHelper(c *gin.Context, relayMode int) *relaymodel.ErrorWithStatus
|
|||||||
if adaptor == nil {
|
if adaptor == nil {
|
||||||
return openai.ErrorWrapper(fmt.Errorf("invalid api type: %d", meta.APIType), "invalid_api_type", http.StatusBadRequest)
|
return openai.ErrorWrapper(fmt.Errorf("invalid api type: %d", meta.APIType), "invalid_api_type", http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
adaptor.Init(meta)
|
||||||
|
|
||||||
switch meta.ChannelType {
|
switch meta.ChannelType {
|
||||||
case channeltype.Ali:
|
case channeltype.Ali:
|
||||||
|
@ -53,6 +53,7 @@ func RelayTextHelper(c *gin.Context) *model.ErrorWithStatusCode {
|
|||||||
if adaptor == nil {
|
if adaptor == nil {
|
||||||
return openai.ErrorWrapper(fmt.Errorf("invalid api type: %d", meta.APIType), "invalid_api_type", http.StatusBadRequest)
|
return openai.ErrorWrapper(fmt.Errorf("invalid api type: %d", meta.APIType), "invalid_api_type", http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
adaptor.Init(meta)
|
||||||
|
|
||||||
// get request body
|
// get request body
|
||||||
var requestBody io.Reader
|
var requestBody io.Reader
|
||||||
|
@ -3,7 +3,7 @@ package meta
|
|||||||
import (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/songquanpeng/one-api/common/ctxkey"
|
"github.com/songquanpeng/one-api/common/ctxkey"
|
||||||
"github.com/songquanpeng/one-api/relay/adaptor/azure"
|
"github.com/songquanpeng/one-api/model"
|
||||||
"github.com/songquanpeng/one-api/relay/channeltype"
|
"github.com/songquanpeng/one-api/relay/channeltype"
|
||||||
"github.com/songquanpeng/one-api/relay/relaymode"
|
"github.com/songquanpeng/one-api/relay/relaymode"
|
||||||
"strings"
|
"strings"
|
||||||
@ -19,10 +19,9 @@ type Meta struct {
|
|||||||
Group string
|
Group string
|
||||||
ModelMapping map[string]string
|
ModelMapping map[string]string
|
||||||
BaseURL string
|
BaseURL string
|
||||||
APIVersion string
|
|
||||||
APIKey string
|
APIKey string
|
||||||
APIType int
|
APIType int
|
||||||
Config map[string]string
|
Config model.ChannelConfig
|
||||||
IsStream bool
|
IsStream bool
|
||||||
OriginModelName string
|
OriginModelName string
|
||||||
ActualModelName string
|
ActualModelName string
|
||||||
@ -32,22 +31,22 @@ type Meta struct {
|
|||||||
|
|
||||||
func GetByContext(c *gin.Context) *Meta {
|
func GetByContext(c *gin.Context) *Meta {
|
||||||
meta := Meta{
|
meta := Meta{
|
||||||
Mode: relaymode.GetByPath(c.Request.URL.Path),
|
Mode: relaymode.GetByPath(c.Request.URL.Path),
|
||||||
ChannelType: c.GetInt(ctxkey.Channel),
|
ChannelType: c.GetInt(ctxkey.Channel),
|
||||||
ChannelId: c.GetInt(ctxkey.ChannelId),
|
ChannelId: c.GetInt(ctxkey.ChannelId),
|
||||||
TokenId: c.GetInt(ctxkey.TokenId),
|
TokenId: c.GetInt(ctxkey.TokenId),
|
||||||
TokenName: c.GetString(ctxkey.TokenName),
|
TokenName: c.GetString(ctxkey.TokenName),
|
||||||
UserId: c.GetInt(ctxkey.Id),
|
UserId: c.GetInt(ctxkey.Id),
|
||||||
Group: c.GetString(ctxkey.Group),
|
Group: c.GetString(ctxkey.Group),
|
||||||
ModelMapping: c.GetStringMapString(ctxkey.ModelMapping),
|
ModelMapping: c.GetStringMapString(ctxkey.ModelMapping),
|
||||||
BaseURL: c.GetString(ctxkey.BaseURL),
|
OriginModelName: c.GetString(ctxkey.RequestModel),
|
||||||
APIVersion: c.GetString(ctxkey.ConfigAPIVersion),
|
BaseURL: c.GetString(ctxkey.BaseURL),
|
||||||
APIKey: strings.TrimPrefix(c.Request.Header.Get("Authorization"), "Bearer "),
|
APIKey: strings.TrimPrefix(c.Request.Header.Get("Authorization"), "Bearer "),
|
||||||
Config: nil,
|
RequestURLPath: c.Request.URL.String(),
|
||||||
RequestURLPath: c.Request.URL.String(),
|
|
||||||
}
|
}
|
||||||
if meta.ChannelType == channeltype.Azure {
|
cfg, ok := c.Get(ctxkey.Config)
|
||||||
meta.APIVersion = azure.GetAPIVersion(c)
|
if ok {
|
||||||
|
meta.Config = cfg.(model.ChannelConfig)
|
||||||
}
|
}
|
||||||
if meta.BaseURL == "" {
|
if meta.BaseURL == "" {
|
||||||
meta.BaseURL = channeltype.ChannelBaseURLs[meta.ChannelType]
|
meta.BaseURL = channeltype.ChannelBaseURLs[meta.ChannelType]
|
||||||
|
@ -1,38 +1,39 @@
|
|||||||
export const CHANNEL_OPTIONS = [
|
export const CHANNEL_OPTIONS = [
|
||||||
{ key: 1, text: 'OpenAI', value: 1, color: 'green' },
|
{key: 1, text: 'OpenAI', value: 1, color: 'green'},
|
||||||
{ key: 14, text: 'Anthropic Claude', value: 14, color: 'black' },
|
{key: 14, text: 'Anthropic Claude', value: 14, color: 'black'},
|
||||||
{ key: 33, text: 'AWS Claude', value: 33, color: 'black' },
|
{key: 33, text: 'AWS Claude', value: 33, color: 'black'},
|
||||||
{ key: 3, text: 'Azure OpenAI', value: 3, color: 'olive' },
|
{key: 3, text: 'Azure OpenAI', value: 3, color: 'olive'},
|
||||||
{ key: 11, text: 'Google PaLM2', value: 11, color: 'orange' },
|
{key: 11, text: 'Google PaLM2', value: 11, color: 'orange'},
|
||||||
{ key: 24, text: 'Google Gemini', value: 24, color: 'orange' },
|
{key: 24, text: 'Google Gemini', value: 24, color: 'orange'},
|
||||||
{ key: 28, text: 'Mistral AI', value: 28, color: 'orange' },
|
{key: 28, text: 'Mistral AI', value: 28, color: 'orange'},
|
||||||
{ key: 15, text: '百度文心千帆', value: 15, color: 'blue' },
|
{key: 15, text: '百度文心千帆', value: 15, color: 'blue'},
|
||||||
{ key: 17, text: '阿里通义千问', value: 17, color: 'orange' },
|
{key: 17, text: '阿里通义千问', value: 17, color: 'orange'},
|
||||||
{ key: 18, text: '讯飞星火认知', value: 18, color: 'blue' },
|
{key: 18, text: '讯飞星火认知', value: 18, color: 'blue'},
|
||||||
{ key: 16, text: '智谱 ChatGLM', value: 16, color: 'violet' },
|
{key: 16, text: '智谱 ChatGLM', value: 16, color: 'violet'},
|
||||||
{ key: 19, text: '360 智脑', value: 19, color: 'blue' },
|
{key: 19, text: '360 智脑', value: 19, color: 'blue'},
|
||||||
{ key: 25, text: 'Moonshot AI', value: 25, color: 'black' },
|
{key: 25, text: 'Moonshot AI', value: 25, color: 'black'},
|
||||||
{ key: 23, text: '腾讯混元', value: 23, color: 'teal' },
|
{key: 23, text: '腾讯混元', value: 23, color: 'teal'},
|
||||||
{ key: 26, text: '百川大模型', value: 26, color: 'orange' },
|
{key: 26, text: '百川大模型', value: 26, color: 'orange'},
|
||||||
{ key: 27, text: 'MiniMax', value: 27, color: 'red' },
|
{key: 27, text: 'MiniMax', value: 27, color: 'red'},
|
||||||
{ key: 29, text: 'Groq', value: 29, color: 'orange' },
|
{key: 29, text: 'Groq', value: 29, color: 'orange'},
|
||||||
{ key: 30, text: 'Ollama', value: 30, color: 'black' },
|
{key: 30, text: 'Ollama', value: 30, color: 'black'},
|
||||||
{ key: 31, text: '零一万物', value: 31, color: 'green' },
|
{key: 31, text: '零一万物', value: 31, color: 'green'},
|
||||||
{ key: 32, text: '阶跃星辰', value: 32, color: 'blue' },
|
{key: 32, text: '阶跃星辰', value: 32, color: 'blue'},
|
||||||
{ key: 34, text: 'Coze', value: 34, color: 'blue' },
|
{key: 34, text: 'Coze', value: 34, color: 'blue'},
|
||||||
{ key: 35, text: 'Cohere', value: 35, color: 'blue' },
|
{key: 35, text: 'Cohere', value: 35, color: 'blue'},
|
||||||
{ key: 36, text: 'DeepSeek', value: 36, color: 'black' },
|
{key: 36, text: 'DeepSeek', value: 36, color: 'black'},
|
||||||
{ key: 8, text: '自定义渠道', value: 8, color: 'pink' },
|
{key: 37, text: 'Cloudflare', value: 37, color: 'orange'},
|
||||||
{ key: 22, text: '知识库:FastGPT', value: 22, color: 'blue' },
|
{key: 8, text: '自定义渠道', value: 8, color: 'pink'},
|
||||||
{ key: 21, text: '知识库:AI Proxy', value: 21, color: 'purple' },
|
{key: 22, text: '知识库:FastGPT', value: 22, color: 'blue'},
|
||||||
{ key: 20, text: '代理:OpenRouter', value: 20, color: 'black' },
|
{key: 21, text: '知识库:AI Proxy', value: 21, color: 'purple'},
|
||||||
{ key: 2, text: '代理:API2D', value: 2, color: 'blue' },
|
{key: 20, text: '代理:OpenRouter', value: 20, color: 'black'},
|
||||||
{ key: 5, text: '代理:OpenAI-SB', value: 5, color: 'brown' },
|
{key: 2, text: '代理:API2D', value: 2, color: 'blue'},
|
||||||
{ key: 7, text: '代理:OhMyGPT', value: 7, color: 'purple' },
|
{key: 5, text: '代理:OpenAI-SB', value: 5, color: 'brown'},
|
||||||
{ key: 10, text: '代理:AI Proxy', value: 10, color: 'purple' },
|
{key: 7, text: '代理:OhMyGPT', value: 7, color: 'purple'},
|
||||||
{ key: 4, text: '代理:CloseAI', value: 4, color: 'teal' },
|
{key: 10, text: '代理:AI Proxy', value: 10, color: 'purple'},
|
||||||
{ key: 6, text: '代理:OpenAI Max', value: 6, color: 'violet' },
|
{key: 4, text: '代理:CloseAI', value: 4, color: 'teal'},
|
||||||
{ key: 9, text: '代理:AI.LS', value: 9, color: 'yellow' },
|
{key: 6, text: '代理:OpenAI Max', value: 6, color: 'violet'},
|
||||||
{ key: 12, text: '代理:API2GPT', value: 12, color: 'blue' },
|
{key: 9, text: '代理:AI.LS', value: 9, color: 'yellow'},
|
||||||
{ key: 13, text: '代理:AIGC2D', value: 13, color: 'purple' }
|
{key: 12, text: '代理:API2GPT', value: 12, color: 'blue'},
|
||||||
|
{key: 13, text: '代理:AIGC2D', value: 13, color: 'purple'}
|
||||||
];
|
];
|
||||||
|
@ -488,6 +488,21 @@ const EditChannel = () => {
|
|||||||
/>
|
/>
|
||||||
</Form.Field>)
|
</Form.Field>)
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
inputs.type === 37 && (
|
||||||
|
<Form.Field>
|
||||||
|
<Form.Input
|
||||||
|
label='Account ID'
|
||||||
|
name='user_id'
|
||||||
|
required
|
||||||
|
placeholder={'请输入 Account ID,例如:d8d7c61dbc334c32d3ced580e4bf42b4'}
|
||||||
|
onChange={handleConfigChange}
|
||||||
|
value={config.user_id}
|
||||||
|
autoComplete=''
|
||||||
|
/>
|
||||||
|
</Form.Field>
|
||||||
|
)
|
||||||
|
}
|
||||||
{
|
{
|
||||||
inputs.type !== 33 && !isEdit && (
|
inputs.type !== 33 && !isEdit && (
|
||||||
<Form.Checkbox
|
<Form.Checkbox
|
||||||
|
Loading…
Reference in New Issue
Block a user