From 65acb94f454e8d2f3acd16d218afb164a3997ef2 Mon Sep 17 00:00:00 2001
From: Ghostz <137054651+ye4293@users.noreply.github.com>
Date: Sat, 13 Jul 2024 14:57:08 +0800
Subject: [PATCH 01/13] fix: text filed check for 4v request (#1634)
---
relay/adaptor/openai/token.go | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/relay/adaptor/openai/token.go b/relay/adaptor/openai/token.go
index ddbfad86..8378b264 100644
--- a/relay/adaptor/openai/token.go
+++ b/relay/adaptor/openai/token.go
@@ -97,7 +97,11 @@ func CountTokenMessages(messages []model.Message, model string) int {
m := it.(map[string]any)
switch m["type"] {
case "text":
- tokenNum += getTokenNum(tokenEncoder, m["text"].(string))
+ if textValue, ok := m["text"]; ok {
+ if textString, ok := textValue.(string); ok {
+ tokenNum += getTokenNum(tokenEncoder, textString)
+ }
+ }
case "image_url":
imageUrl, ok := m["image_url"].(map[string]any)
if ok {
From cf9b5f0b92877ee16a05ee8fe366fe6bd614200f Mon Sep 17 00:00:00 2001
From: LiuVaayne <10231735+vaayne@users.noreply.github.com>
Date: Sat, 13 Jul 2024 14:59:28 +0800
Subject: [PATCH 02/13] feat: support claude and gemini in vertex ai (#1621)
* feat: support claude and gemini in vertex ai
* fix: do not show api key field in channel page when the type is VertexAI
* fix: update getToken function to include channelId in cache key
---
go.mod | 33 +++-
go.sum | 148 ++++++++++++++++--
model/channel.go | 17 +-
relay/adaptor.go | 3 +
relay/adaptor/vertexai/adaptor.go | 101 ++++++++++++
relay/adaptor/vertexai/claude/adapter.go | 54 +++++++
relay/adaptor/vertexai/claude/model.go | 19 +++
relay/adaptor/vertexai/gemini/adapter.go | 49 ++++++
relay/adaptor/vertexai/registry.go | 51 ++++++
relay/adaptor/vertexai/token.go | 63 ++++++++
relay/apitype/define.go | 1 +
relay/channeltype/define.go | 1 +
relay/channeltype/helper.go | 2 +
relay/channeltype/url.go | 1 +
web/berry/src/constants/ChannelConstants.js | 6 +
.../src/views/Channel/component/EditModal.js | 2 +
web/berry/src/views/Channel/type/Config.js | 21 ++-
.../src/constants/channel.constants.js | 1 +
web/default/src/pages/Channel/EditChannel.js | 41 ++++-
19 files changed, 590 insertions(+), 24 deletions(-)
create mode 100644 relay/adaptor/vertexai/adaptor.go
create mode 100644 relay/adaptor/vertexai/claude/adapter.go
create mode 100644 relay/adaptor/vertexai/claude/model.go
create mode 100644 relay/adaptor/vertexai/gemini/adapter.go
create mode 100644 relay/adaptor/vertexai/registry.go
create mode 100644 relay/adaptor/vertexai/token.go
diff --git a/go.mod b/go.mod
index 9d9ce35a..87e26303 100644
--- a/go.mod
+++ b/go.mod
@@ -4,6 +4,7 @@ module github.com/songquanpeng/one-api
go 1.20
require (
+ cloud.google.com/go/iam v1.1.10
github.com/aws/aws-sdk-go-v2 v1.27.0
github.com/aws/aws-sdk-go-v2/credentials v1.17.15
github.com/aws/aws-sdk-go-v2/service/bedrockruntime v1.8.3
@@ -19,12 +20,14 @@ require (
github.com/gorilla/websocket v1.5.1
github.com/jinzhu/copier v0.4.0
github.com/joho/godotenv v1.5.1
+ github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/pkg/errors v0.9.1
github.com/pkoukk/tiktoken-go v0.1.7
github.com/smartystreets/goconvey v1.8.1
github.com/stretchr/testify v1.9.0
- golang.org/x/crypto v0.23.0
+ golang.org/x/crypto v0.24.0
golang.org/x/image v0.18.0
+ google.golang.org/api v0.187.0
gorm.io/driver/mysql v1.5.6
gorm.io/driver/postgres v1.5.7
gorm.io/driver/sqlite v1.5.5
@@ -32,6 +35,9 @@ require (
)
require (
+ cloud.google.com/go/auth v0.6.1 // indirect
+ cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect
+ cloud.google.com/go/compute/metadata v0.3.0 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.7 // indirect
@@ -45,13 +51,21 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dlclark/regexp2 v1.11.0 // indirect
+ github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
+ github.com/go-logr/logr v1.4.1 // indirect
+ github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-sql-driver/mysql v1.8.1 // indirect
github.com/goccy/go-json v0.10.3 // indirect
+ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
+ github.com/golang/protobuf v1.5.4 // indirect
+ github.com/google/s2a-go v0.1.7 // indirect
+ github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
+ github.com/googleapis/gax-go/v2 v2.12.5 // indirect
github.com/gopherjs/gopherjs v1.17.2 // indirect
github.com/gorilla/context v1.1.2 // indirect
github.com/gorilla/securecookie v1.1.2 // indirect
@@ -76,11 +90,22 @@ require (
github.com/smarty/assertions v1.15.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
+ go.opencensus.io v0.24.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
+ go.opentelemetry.io/otel v1.24.0 // indirect
+ go.opentelemetry.io/otel/metric v1.24.0 // indirect
+ go.opentelemetry.io/otel/trace v1.24.0 // indirect
golang.org/x/arch v0.8.0 // indirect
- golang.org/x/net v0.25.0 // indirect
+ golang.org/x/net v0.26.0 // indirect
+ golang.org/x/oauth2 v0.21.0 // indirect
golang.org/x/sync v0.7.0 // indirect
- golang.org/x/sys v0.20.0 // indirect
+ golang.org/x/sys v0.21.0 // indirect
golang.org/x/text v0.16.0 // indirect
- google.golang.org/protobuf v1.34.1 // indirect
+ golang.org/x/time v0.5.0 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240624140628-dc46fd24d27d // indirect
+ google.golang.org/grpc v1.64.0 // indirect
+ google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/go.sum b/go.sum
index 11810f25..ef28b51f 100644
--- a/go.sum
+++ b/go.sum
@@ -1,5 +1,15 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go/auth v0.6.1 h1:T0Zw1XM5c1GlpN2HYr2s+m3vr1p2wy+8VN+Z1FKxW38=
+cloud.google.com/go/auth v0.6.1/go.mod h1:eFHG7zDzbXHKmjJddFG/rBlcGp6t25SwRUiEQSlO4x4=
+cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4=
+cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q=
+cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
+cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
+cloud.google.com/go/iam v1.1.10 h1:ZSAr64oEhQSClwBL670MsJAW5/RLiC6kfw3Bqmd5ZDI=
+cloud.google.com/go/iam v1.1.10/go.mod h1:iEgMq62sg8zx446GCaijmA2Miwg5o3UbO+nI47WHJps=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/aws/aws-sdk-go-v2 v1.27.0 h1:7bZWKoXhzI+mMR/HjdMx8ZCC5+6fY0lS5tr0bbgiLlo=
github.com/aws/aws-sdk-go-v2 v1.27.0/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 h1:x6xsQXGSmW6frevwDA+vi/wqhp1ct18mVXYN08/93to=
@@ -18,12 +28,15 @@ github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -32,6 +45,12 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
+github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
@@ -48,6 +67,11 @@ github.com/gin-contrib/static v1.1.2 h1:c3kT4bFkUJn2aoRU3s6XnMjJT8J6nNWJkR0Nglqm
github.com/gin-contrib/static v1.1.2/go.mod h1:Fw90ozjHCmZBWbgrsqrDvO28YbhKEKzKp8GixhR4yLw=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
+github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
@@ -64,11 +88,40 @@ github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
-github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
+github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
+github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
+github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
+github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
+github.com/googleapis/gax-go/v2 v2.12.5 h1:8gw9KZK8TiVKB6q3zHY3SBzLnrGp6HQjyfYBYGmXdxA=
+github.com/googleapis/gax-go/v2 v2.12.5/go.mod h1:BUDKcWo+RaKq5SC9vVYL0wLADa3VcfswbOMMRmB9H3E=
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
github.com/gorilla/context v1.1.2 h1:WRkNAv2uoa03QNIc1A6u4O7DAGMUVoopZhkiXWA2V1o=
@@ -120,6 +173,8 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
+github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
+github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -128,6 +183,7 @@ github.com/pkoukk/tiktoken-go v0.1.7 h1:qOBHXX4PHtvIvmOtyg1EeKlwFRiMKAcoMp4Q+bLQ
github.com/pkoukk/tiktoken-go v0.1.7/go.mod h1:9NiV+i9mJKGj1rYOT+njbv+ZwA/zJxYdewGl6qVatpg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY=
github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec=
@@ -149,26 +205,96 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
+go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
+go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
+go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
+go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
+go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
+go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
+go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
+go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
-golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
-golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
+golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ=
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
-golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
-golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
+golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
+golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
-golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
+golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
-google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
-google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
+golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/api v0.187.0 h1:Mxs7VATVC2v7CY+7Xwm4ndkX71hpElcvx0D1Ji/p1eo=
+google.golang.org/api v0.187.0/go.mod h1:KIHlTc4x7N7gKKuVsdmfBXN13yEEWXWFURWY6SBp2gk=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4 h1:MuYw1wJzT+ZkybKfaOXKp5hJiZDn2iHaXRw0mRYdHSc=
+google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4/go.mod h1:px9SlOOZBg1wM1zdnr8jEL4CNGUBZ+ZKYtNPApNQc4c=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240624140628-dc46fd24d27d h1:k3zyW3BYYR30e8v3x0bTDdE9vpYFjZHK+HcyqkrppWk=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240624140628-dc46fd24d27d/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
+google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
+google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
@@ -185,5 +311,7 @@ gorm.io/driver/sqlite v1.5.5/go.mod h1:6NgQ7sQWAIFsPrJJl1lSNSu2TABh0ZZ/zm5fosATa
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s=
gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
diff --git a/model/channel.go b/model/channel.go
index a92f402c..759dfd4f 100644
--- a/model/channel.go
+++ b/model/channel.go
@@ -3,6 +3,7 @@ package model
import (
"encoding/json"
"fmt"
+
"github.com/songquanpeng/one-api/common/config"
"github.com/songquanpeng/one-api/common/helper"
"github.com/songquanpeng/one-api/common/logger"
@@ -39,13 +40,15 @@ type Channel struct {
}
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"`
+ 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"`
+ VertexAIProjectID string `json:"vertex_ai_project_id,omitempty"`
+ VertexAIADC string `json:"vertex_ai_adc,omitempty"`
}
func GetAllChannels(startIdx int, num int, scope string) ([]*Channel, error) {
diff --git a/relay/adaptor.go b/relay/adaptor.go
index 794a84a6..7fc83651 100644
--- a/relay/adaptor.go
+++ b/relay/adaptor.go
@@ -16,6 +16,7 @@ import (
"github.com/songquanpeng/one-api/relay/adaptor/openai"
"github.com/songquanpeng/one-api/relay/adaptor/palm"
"github.com/songquanpeng/one-api/relay/adaptor/tencent"
+ "github.com/songquanpeng/one-api/relay/adaptor/vertexai"
"github.com/songquanpeng/one-api/relay/adaptor/xunfei"
"github.com/songquanpeng/one-api/relay/adaptor/zhipu"
"github.com/songquanpeng/one-api/relay/apitype"
@@ -55,6 +56,8 @@ func GetAdaptor(apiType int) adaptor.Adaptor {
return &cloudflare.Adaptor{}
case apitype.DeepL:
return &deepl.Adaptor{}
+ case apitype.VertexAI:
+ return &vertexai.Adaptor{}
}
return nil
}
diff --git a/relay/adaptor/vertexai/adaptor.go b/relay/adaptor/vertexai/adaptor.go
new file mode 100644
index 00000000..f1b68b70
--- /dev/null
+++ b/relay/adaptor/vertexai/adaptor.go
@@ -0,0 +1,101 @@
+package vertexai
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "strings"
+
+ "github.com/gin-gonic/gin"
+ "github.com/songquanpeng/one-api/relay/adaptor"
+ channelhelper "github.com/songquanpeng/one-api/relay/adaptor"
+ "github.com/songquanpeng/one-api/relay/meta"
+ "github.com/songquanpeng/one-api/relay/model"
+ relaymodel "github.com/songquanpeng/one-api/relay/model"
+)
+
+var _ adaptor.Adaptor = new(Adaptor)
+
+const channelName = "vertexai"
+
+type Adaptor struct {}
+
+func (a *Adaptor) Init(meta *meta.Meta) {
+}
+
+func (a *Adaptor) ConvertRequest(c *gin.Context, relayMode int, request *model.GeneralOpenAIRequest) (any, error) {
+ if request == nil {
+ return nil, errors.New("request is nil")
+ }
+
+ adaptor := GetAdaptor(request.Model)
+ if adaptor == nil {
+ return nil, errors.New("adaptor not found")
+ }
+
+ return adaptor.ConvertRequest(c, relayMode, request)
+}
+
+func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, meta *meta.Meta) (usage *model.Usage, err *model.ErrorWithStatusCode) {
+ adaptor := GetAdaptor(meta.OriginModelName)
+ if adaptor == nil {
+ return nil, &relaymodel.ErrorWithStatusCode{
+ StatusCode: http.StatusInternalServerError,
+ Error: relaymodel.Error{
+ Message: "adaptor not found",
+ },
+ }
+ }
+ return adaptor.DoResponse(c, resp, meta)
+}
+
+func (a *Adaptor) GetModelList() (models []string) {
+ models = modelList
+ return
+}
+
+func (a *Adaptor) GetChannelName() string {
+ return channelName
+}
+
+func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
+ suffix := ""
+ if strings.HasPrefix(meta.ActualModelName, "gemini") {
+ if meta.IsStream {
+ suffix = "streamGenerateContent"
+ } else {
+ suffix = "generateContent"
+ }
+ } else {
+ if meta.IsStream {
+ suffix = "streamRawPredict"
+ } else {
+ suffix = "rawPredict"
+ }
+ }
+
+ baseUrl := fmt.Sprintf("https://%s-aiplatform.googleapis.com/v1/projects/%s/locations/%s/publishers/google/models/%s:%s", meta.Config.Region, meta.Config.VertexAIProjectID, meta.Config.Region, meta.ActualModelName, suffix)
+ return baseUrl, nil
+}
+
+func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Request, meta *meta.Meta) error {
+ adaptor.SetupCommonRequestHeader(c, req, meta)
+ token, err := getToken(c, meta.ChannelId, meta.Config.VertexAIADC)
+ if err != nil {
+ return err
+ }
+ req.Header.Set("Authorization", "Bearer "+token)
+ return nil
+}
+
+func (a *Adaptor) ConvertImageRequest(request *model.ImageRequest) (any, error) {
+ if request == nil {
+ return nil, errors.New("request is nil")
+ }
+ return request, nil
+}
+
+func (a *Adaptor) DoRequest(c *gin.Context, meta *meta.Meta, requestBody io.Reader) (*http.Response, error) {
+ return channelhelper.DoRequestHelper(a, c, meta, requestBody)
+}
diff --git a/relay/adaptor/vertexai/claude/adapter.go b/relay/adaptor/vertexai/claude/adapter.go
new file mode 100644
index 00000000..1e37f0ff
--- /dev/null
+++ b/relay/adaptor/vertexai/claude/adapter.go
@@ -0,0 +1,54 @@
+package vertexai
+
+import (
+ "net/http"
+
+ "github.com/gin-gonic/gin"
+ "github.com/pkg/errors"
+ "github.com/songquanpeng/one-api/common/ctxkey"
+ "github.com/songquanpeng/one-api/relay/adaptor/anthropic"
+
+ "github.com/songquanpeng/one-api/relay/meta"
+ "github.com/songquanpeng/one-api/relay/model"
+)
+
+var ModelList = []string{
+ "claude-3-haiku@20240307", "claude-3-opus@20240229", "claude-3-5-sonnet@20240620", "claude-3-sonnet@20240229",
+}
+
+const anthropicVersion = "vertex-2023-10-16"
+
+type Adaptor struct {
+}
+
+func (a *Adaptor) ConvertRequest(c *gin.Context, relayMode int, request *model.GeneralOpenAIRequest) (any, error) {
+ if request == nil {
+ return nil, errors.New("request is nil")
+ }
+
+ claudeReq := anthropic.ConvertRequest(*request)
+ req := Request{
+ AnthropicVersion: anthropicVersion,
+ // Model: claudeReq.Model,
+ Messages: claudeReq.Messages,
+ MaxTokens: claudeReq.MaxTokens,
+ Temperature: claudeReq.Temperature,
+ TopP: claudeReq.TopP,
+ TopK: claudeReq.TopK,
+ Stream: claudeReq.Stream,
+ Tools: claudeReq.Tools,
+ }
+
+ c.Set(ctxkey.RequestModel, request.Model)
+ c.Set(ctxkey.ConvertedRequest, req)
+ return req, nil
+}
+
+func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, meta *meta.Meta) (usage *model.Usage, err *model.ErrorWithStatusCode) {
+ if meta.IsStream {
+ err, usage = anthropic.StreamHandler(c, resp)
+ } else {
+ err, usage = anthropic.Handler(c, resp, meta.PromptTokens, meta.ActualModelName)
+ }
+ return
+}
diff --git a/relay/adaptor/vertexai/claude/model.go b/relay/adaptor/vertexai/claude/model.go
new file mode 100644
index 00000000..2f13f598
--- /dev/null
+++ b/relay/adaptor/vertexai/claude/model.go
@@ -0,0 +1,19 @@
+package vertexai
+
+import "github.com/songquanpeng/one-api/relay/adaptor/anthropic"
+
+type Request struct {
+ // AnthropicVersion must be "vertex-2023-10-16"
+ AnthropicVersion string `json:"anthropic_version"`
+ // Model string `json:"model"`
+ Messages []anthropic.Message `json:"messages"`
+ System string `json:"system,omitempty"`
+ MaxTokens int `json:"max_tokens,omitempty"`
+ StopSequences []string `json:"stop_sequences,omitempty"`
+ Stream bool `json:"stream,omitempty"`
+ Temperature float64 `json:"temperature,omitempty"`
+ TopP float64 `json:"top_p,omitempty"`
+ TopK int `json:"top_k,omitempty"`
+ Tools []anthropic.Tool `json:"tools,omitempty"`
+ ToolChoice any `json:"tool_choice,omitempty"`
+}
diff --git a/relay/adaptor/vertexai/gemini/adapter.go b/relay/adaptor/vertexai/gemini/adapter.go
new file mode 100644
index 00000000..43e6cbcd
--- /dev/null
+++ b/relay/adaptor/vertexai/gemini/adapter.go
@@ -0,0 +1,49 @@
+package vertexai
+
+import (
+ "net/http"
+
+ "github.com/gin-gonic/gin"
+ "github.com/pkg/errors"
+ "github.com/songquanpeng/one-api/common/ctxkey"
+ "github.com/songquanpeng/one-api/relay/adaptor/gemini"
+ "github.com/songquanpeng/one-api/relay/adaptor/openai"
+ "github.com/songquanpeng/one-api/relay/relaymode"
+
+ "github.com/songquanpeng/one-api/relay/meta"
+ "github.com/songquanpeng/one-api/relay/model"
+)
+
+var ModelList = []string{
+ "gemini-1.5-pro-001", "gemini-1.5-flash-001", "gemini-pro", "gemini-pro-vision",
+}
+
+type Adaptor struct {
+}
+
+func (a *Adaptor) ConvertRequest(c *gin.Context, relayMode int, request *model.GeneralOpenAIRequest) (any, error) {
+ if request == nil {
+ return nil, errors.New("request is nil")
+ }
+
+ geminiRequest := gemini.ConvertRequest(*request)
+ c.Set(ctxkey.RequestModel, request.Model)
+ c.Set(ctxkey.ConvertedRequest, geminiRequest)
+ return geminiRequest, nil
+}
+
+func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, meta *meta.Meta) (usage *model.Usage, err *model.ErrorWithStatusCode) {
+ if meta.IsStream {
+ var responseText string
+ err, responseText = gemini.StreamHandler(c, resp)
+ usage = openai.ResponseText2Usage(responseText, meta.ActualModelName, meta.PromptTokens)
+ } else {
+ switch meta.Mode {
+ case relaymode.Embeddings:
+ err, usage = gemini.EmbeddingHandler(c, resp)
+ default:
+ err, usage = gemini.Handler(c, resp, meta.PromptTokens, meta.ActualModelName)
+ }
+ }
+ return
+}
diff --git a/relay/adaptor/vertexai/registry.go b/relay/adaptor/vertexai/registry.go
new file mode 100644
index 00000000..f9547ebf
--- /dev/null
+++ b/relay/adaptor/vertexai/registry.go
@@ -0,0 +1,51 @@
+package vertexai
+
+import (
+ "net/http"
+
+ "github.com/gin-gonic/gin"
+ claude "github.com/songquanpeng/one-api/relay/adaptor/vertexai/claude"
+ gemini "github.com/songquanpeng/one-api/relay/adaptor/vertexai/gemini"
+ "github.com/songquanpeng/one-api/relay/meta"
+ "github.com/songquanpeng/one-api/relay/model"
+)
+
+type VertexAIModelType int
+
+const (
+ VerterAIClaude VertexAIModelType = iota + 1
+ VerterAIGemini
+)
+
+var modelMapping = map[string]VertexAIModelType{}
+var modelList = []string{}
+
+func init() {
+ modelList = append(modelList, claude.ModelList...)
+ for _, model := range claude.ModelList {
+ modelMapping[model] = VerterAIClaude
+ }
+
+ modelList = append(modelList, gemini.ModelList...)
+ for _, model := range gemini.ModelList {
+ modelMapping[model] = VerterAIGemini
+ }
+}
+
+
+type innerAIAdapter interface {
+ ConvertRequest(c *gin.Context, relayMode int, request *model.GeneralOpenAIRequest) (any, error)
+ DoResponse(c *gin.Context, resp *http.Response, meta *meta.Meta) (usage *model.Usage, err *model.ErrorWithStatusCode)
+}
+
+func GetAdaptor(model string) innerAIAdapter {
+ adaptorType := modelMapping[model]
+ switch adaptorType {
+ case VerterAIClaude:
+ return &claude.Adaptor{}
+ case VerterAIGemini:
+ return &gemini.Adaptor{}
+ default:
+ return nil
+ }
+}
diff --git a/relay/adaptor/vertexai/token.go b/relay/adaptor/vertexai/token.go
new file mode 100644
index 00000000..e5fa7b48
--- /dev/null
+++ b/relay/adaptor/vertexai/token.go
@@ -0,0 +1,63 @@
+package vertexai
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "time"
+
+ credentials "cloud.google.com/go/iam/credentials/apiv1"
+ "cloud.google.com/go/iam/credentials/apiv1/credentialspb"
+ "github.com/patrickmn/go-cache"
+ "google.golang.org/api/option"
+)
+
+type ApplicationDefaultCredentials struct {
+ Type string `json:"type"`
+ ProjectID string `json:"project_id"`
+ PrivateKeyID string `json:"private_key_id"`
+ PrivateKey string `json:"private_key"`
+ ClientEmail string `json:"client_email"`
+ ClientID string `json:"client_id"`
+ AuthURI string `json:"auth_uri"`
+ TokenURI string `json:"token_uri"`
+ AuthProviderX509CertURL string `json:"auth_provider_x509_cert_url"`
+ ClientX509CertURL string `json:"client_x509_cert_url"`
+ UniverseDomain string `json:"universe_domain"`
+}
+
+
+var Cache = cache.New(50*time.Minute, 55*time.Minute)
+
+const defaultScope = "https://www.googleapis.com/auth/cloud-platform"
+
+func getToken(ctx context.Context, channelId int, adcJson string) (string, error) {
+ cacheKey := fmt.Sprintf("vertexai-token-%d", channelId)
+ if token, found := Cache.Get(cacheKey); found {
+ return token.(string), nil
+ }
+ adc := &ApplicationDefaultCredentials{}
+ if err := json.Unmarshal([]byte(adcJson), adc); err != nil {
+ return "", fmt.Errorf("Failed to decode credentials file: %w", err)
+ }
+
+ c, err := credentials.NewIamCredentialsClient(ctx, option.WithCredentialsJSON([]byte(adcJson)))
+ if err != nil {
+ return "", fmt.Errorf("Failed to create client: %w", err)
+ }
+ defer c.Close()
+
+ req := &credentialspb.GenerateAccessTokenRequest{
+ // See https://pkg.go.dev/cloud.google.com/go/iam/credentials/apiv1/credentialspb#GenerateAccessTokenRequest.
+ Name: fmt.Sprintf("projects/-/serviceAccounts/%s", adc.ClientEmail),
+ Scope: []string{defaultScope},
+ }
+ resp, err := c.GenerateAccessToken(ctx, req)
+ if err != nil {
+ return "", fmt.Errorf("Failed to generate access token: %w", err)
+ }
+ _ = resp
+
+ Cache.Set(cacheKey, resp.AccessToken, cache.DefaultExpiration)
+ return resp.AccessToken, nil
+}
diff --git a/relay/apitype/define.go b/relay/apitype/define.go
index cf1df694..212a1b6b 100644
--- a/relay/apitype/define.go
+++ b/relay/apitype/define.go
@@ -17,6 +17,7 @@ const (
Cohere
Cloudflare
DeepL
+ VertexAI
Dummy // this one is only for count, do not add any channel after this
)
diff --git a/relay/channeltype/define.go b/relay/channeltype/define.go
index d3891c16..d1e7fcef 100644
--- a/relay/channeltype/define.go
+++ b/relay/channeltype/define.go
@@ -43,5 +43,6 @@ const (
TogetherAI
Doubao
Novita
+ VertextAI
Dummy
)
diff --git a/relay/channeltype/helper.go b/relay/channeltype/helper.go
index 1bb71402..67270a67 100644
--- a/relay/channeltype/helper.go
+++ b/relay/channeltype/helper.go
@@ -35,6 +35,8 @@ func ToAPIType(channelType int) int {
apiType = apitype.Cloudflare
case DeepL:
apiType = apitype.DeepL
+ case VertextAI:
+ apiType = apitype.VertexAI
}
return apiType
diff --git a/relay/channeltype/url.go b/relay/channeltype/url.go
index 5177333b..47241063 100644
--- a/relay/channeltype/url.go
+++ b/relay/channeltype/url.go
@@ -43,6 +43,7 @@ var ChannelBaseURLs = []string{
"https://api.together.xyz", // 39
"https://ark.cn-beijing.volces.com", // 40
"https://api.novita.ai/v3/openai", // 41
+ "", // 42
}
func init() {
diff --git a/web/berry/src/constants/ChannelConstants.js b/web/berry/src/constants/ChannelConstants.js
index 881f66bd..ac2e73a6 100644
--- a/web/berry/src/constants/ChannelConstants.js
+++ b/web/berry/src/constants/ChannelConstants.js
@@ -161,6 +161,12 @@ export const CHANNEL_OPTIONS = {
value: 39,
color: 'primary'
},
+ 42: {
+ key: 42,
+ text: 'VertexAI',
+ value: 42,
+ color: 'primary'
+ },
41: {
key: 41,
text: 'Novita',
diff --git a/web/berry/src/views/Channel/component/EditModal.js b/web/berry/src/views/Channel/component/EditModal.js
index 29bd3de2..7a2fd3d9 100644
--- a/web/berry/src/views/Channel/component/EditModal.js
+++ b/web/berry/src/views/Channel/component/EditModal.js
@@ -165,6 +165,8 @@ const EditModal = ({ open, channelId, onCancel, onOk }) => {
if (values.key === '') {
if (values.config.ak && values.config.sk && values.config.region) {
values.key = `${values.config.ak}|${values.config.sk}|${values.config.region}`;
+ } else if (values.config.region && values.config.vertex_ai_project_id && values.config.vertex_ai_adc) {
+ values.key = `${values.config.region}|${values.config.vertex_ai_project_id}|${values.config.vertex_ai_adc}`;
}
}
diff --git a/web/berry/src/views/Channel/type/Config.js b/web/berry/src/views/Channel/type/Config.js
index 51b7c6c4..73b2dfe8 100644
--- a/web/berry/src/views/Channel/type/Config.js
+++ b/web/berry/src/views/Channel/type/Config.js
@@ -203,7 +203,26 @@ const typeConfig = {
}
},
modelGroup: 'Coze'
- }
+ },
+ 42: {
+ inputLabel: {
+ key: '',
+ config: {
+ region: 'Vertex AI Region',
+ vertex_ai_project_id: 'Vertex AI Project ID',
+ vertex_ai_adc: 'Google Cloud Application Default Credentials JSON'
+ }
+ },
+ prompt: {
+ key: '',
+ config: {
+ region: 'Vertex AI Region.g. us-east5',
+ vertex_ai_project_id: 'Vertex AI Project ID',
+ vertex_ai_adc: 'Google Cloud Application Default Credentials JSON: https://cloud.google.com/docs/authentication/application-default-credentials'
+ }
+ },
+ modelGroup: 'anthropic'
+ },
};
export { defaultConfig, typeConfig };
diff --git a/web/default/src/constants/channel.constants.js b/web/default/src/constants/channel.constants.js
index 1b4c1910..b17f56c0 100644
--- a/web/default/src/constants/channel.constants.js
+++ b/web/default/src/constants/channel.constants.js
@@ -27,6 +27,7 @@ export const CHANNEL_OPTIONS = [
{key: 37, text: 'Cloudflare', value: 37, color: 'orange'},
{key: 38, text: 'DeepL', value: 38, color: 'black'},
{key: 39, text: 'together.ai', value: 39, color: 'blue'},
+ {key: 42, text: 'VertexAI', value: 42, color: 'blue'},
{key: 8, text: '自定义渠道', value: 8, color: 'pink'},
{key: 22, text: '知识库:FastGPT', value: 22, color: 'blue'},
{key: 21, text: '知识库:AI Proxy', value: 21, color: 'purple'},
diff --git a/web/default/src/pages/Channel/EditChannel.js b/web/default/src/pages/Channel/EditChannel.js
index fb80a726..64ff22f5 100644
--- a/web/default/src/pages/Channel/EditChannel.js
+++ b/web/default/src/pages/Channel/EditChannel.js
@@ -58,7 +58,9 @@ const EditChannel = () => {
region: '',
sk: '',
ak: '',
- user_id: ''
+ user_id: '',
+ vertex_ai_project_id: '',
+ vertex_ai_adc: ''
});
const handleInputChange = (e, { name, value }) => {
setInputs((inputs) => ({ ...inputs, [name]: value }));
@@ -160,6 +162,8 @@ const EditChannel = () => {
if (inputs.key === '') {
if (config.ak !== '' && config.sk !== '' && config.region !== '') {
inputs.key = `${config.ak}|${config.sk}|${config.region}`;
+ } else if (config.region !== '' && config.vertex_ai_project_id !== '' && config.vertex_ai_adc !== '') {
+ inputs.key = `${config.region}|${config.vertex_ai_project_id}|${config.vertex_ai_adc}`;
}
}
if (!isEdit && (inputs.name === '' || inputs.key === '')) {
@@ -456,6 +460,39 @@ const EditChannel = () => {
)
}
+ {
+ inputs.type === 42 && (
+
+
+
+
+
+ )
+ }
{
inputs.type === 34 && (
{
/>)
}
{
- inputs.type !== 33 && (batch ?
+ inputs.type !== 33 && inputs.type !== 42 && (batch ?
Date: Sun, 14 Jul 2024 17:57:16 +0800
Subject: [PATCH 03/13] feat: add field stop in GeneralOpenAIRequest (#1637)
---
relay/model/general.go | 1 +
1 file changed, 1 insertion(+)
diff --git a/relay/model/general.go b/relay/model/general.go
index 30772894..229a61c1 100644
--- a/relay/model/general.go
+++ b/relay/model/general.go
@@ -13,6 +13,7 @@ type GeneralOpenAIRequest struct {
PresencePenalty float64 `json:"presence_penalty,omitempty"`
ResponseFormat *ResponseFormat `json:"response_format,omitempty"`
Seed float64 `json:"seed,omitempty"`
+ Stop any `json:"stop,omitempty"`
Stream bool `json:"stream,omitempty"`
Temperature float64 `json:"temperature,omitempty"`
TopP float64 `json:"top_p,omitempty"`
From b65bee46fbd03b5cc3be063b027b714be735ebb6 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sun, 14 Jul 2024 17:58:38 +0800
Subject: [PATCH 04/13] chore(deps): bump google.golang.org/grpc from 1.64.0 to
1.64.1 (#1641)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.64.0 to 1.64.1.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.64.0...v1.64.1)
---
updated-dependencies:
- dependency-name: google.golang.org/grpc
dependency-type: indirect
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
go.mod | 2 +-
go.sum | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/go.mod b/go.mod
index 87e26303..ada53bc3 100644
--- a/go.mod
+++ b/go.mod
@@ -105,7 +105,7 @@ require (
golang.org/x/time v0.5.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240624140628-dc46fd24d27d // indirect
- google.golang.org/grpc v1.64.0 // indirect
+ google.golang.org/grpc v1.64.1 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/go.sum b/go.sum
index ef28b51f..53db8df2 100644
--- a/go.sum
+++ b/go.sum
@@ -282,8 +282,8 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
-google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
-google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
+google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA=
+google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
From a3eefb7af0b624aa104e0cf8550c8737e6ea694f Mon Sep 17 00:00:00 2001
From: zijiren <84728412+zijiren233@users.noreply.github.com>
Date: Sun, 14 Jul 2024 18:03:23 +0800
Subject: [PATCH 05/13] fix: rate limit can be zero (#1643)
---
middleware/rate-limit.go | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/middleware/rate-limit.go b/middleware/rate-limit.go
index 0f300f2b..c1be92f3 100644
--- a/middleware/rate-limit.go
+++ b/middleware/rate-limit.go
@@ -3,11 +3,12 @@ package middleware
import (
"context"
"fmt"
+ "net/http"
+ "time"
+
"github.com/gin-gonic/gin"
"github.com/songquanpeng/one-api/common"
"github.com/songquanpeng/one-api/common/config"
- "net/http"
- "time"
)
var timeFormat = "2006-01-02T15:04:05.000Z"
@@ -70,6 +71,11 @@ func memoryRateLimiter(c *gin.Context, maxRequestNum int, duration int64, mark s
}
func rateLimitFactory(maxRequestNum int, duration int64, mark string) func(c *gin.Context) {
+ if maxRequestNum == 0 {
+ return func(c *gin.Context) {
+ c.Next()
+ }
+ }
if common.RedisEnabled {
return func(c *gin.Context) {
redisRateLimiter(c, maxRequestNum, duration, mark)
From 1c44d7e1cdd45f3ebf7dbd4378a5b2ead7ade8f5 Mon Sep 17 00:00:00 2001
From: zijiren <84728412+zijiren233@users.noreply.github.com>
Date: Sun, 14 Jul 2024 18:06:11 +0800
Subject: [PATCH 06/13] feat: fast build linux/arm64 frontend (#1645)
---
.github/workflows/docker-image-arm64.yml | 69 -------------------
...image-amd64-en.yml => docker-image-en.yml} | 3 +-
...ocker-image-amd64.yml => docker-image.yml} | 3 +-
Dockerfile | 2 +-
4 files changed, 5 insertions(+), 72 deletions(-)
delete mode 100644 .github/workflows/docker-image-arm64.yml
rename .github/workflows/{docker-image-amd64-en.yml => docker-image-en.yml} (94%)
rename .github/workflows/{docker-image-amd64.yml => docker-image.yml} (95%)
diff --git a/.github/workflows/docker-image-arm64.yml b/.github/workflows/docker-image-arm64.yml
deleted file mode 100644
index dc2b4b97..00000000
--- a/.github/workflows/docker-image-arm64.yml
+++ /dev/null
@@ -1,69 +0,0 @@
-name: Publish Docker image (arm64)
-
-on:
- push:
- tags:
- - 'v*.*.*'
- - '!*-alpha*'
- workflow_dispatch:
- inputs:
- name:
- description: 'reason'
- required: false
-jobs:
- push_to_registries:
- name: Push Docker image to multiple registries
- runs-on: ubuntu-latest
- permissions:
- packages: write
- contents: read
- steps:
- - name: Check out the repo
- uses: actions/checkout@v3
-
- - name: Check repository URL
- run: |
- REPO_URL=$(git config --get remote.origin.url)
- if [[ $REPO_URL == *"pro" ]]; then
- exit 1
- fi
-
- - name: Save version info
- run: |
- git describe --tags > VERSION
-
- - name: Set up QEMU
- uses: docker/setup-qemu-action@v2
-
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v2
-
- - name: Log in to Docker Hub
- uses: docker/login-action@v2
- with:
- username: ${{ secrets.DOCKERHUB_USERNAME }}
- password: ${{ secrets.DOCKERHUB_TOKEN }}
-
- - name: Log in to the Container registry
- uses: docker/login-action@v2
- with:
- registry: ghcr.io
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Extract metadata (tags, labels) for Docker
- id: meta
- uses: docker/metadata-action@v4
- with:
- images: |
- justsong/one-api
- ghcr.io/${{ github.repository }}
-
- - name: Build and push Docker images
- uses: docker/build-push-action@v3
- with:
- context: .
- platforms: linux/amd64,linux/arm64
- push: true
- tags: ${{ steps.meta.outputs.tags }}
- labels: ${{ steps.meta.outputs.labels }}
\ No newline at end of file
diff --git a/.github/workflows/docker-image-amd64-en.yml b/.github/workflows/docker-image-en.yml
similarity index 94%
rename from .github/workflows/docker-image-amd64-en.yml
rename to .github/workflows/docker-image-en.yml
index 31c01e80..e894448f 100644
--- a/.github/workflows/docker-image-amd64-en.yml
+++ b/.github/workflows/docker-image-en.yml
@@ -1,4 +1,4 @@
-name: Publish Docker image (amd64, English)
+name: Publish Docker image (English)
on:
push:
@@ -51,6 +51,7 @@ jobs:
uses: docker/build-push-action@v3
with:
context: .
+ platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
\ No newline at end of file
diff --git a/.github/workflows/docker-image-amd64.yml b/.github/workflows/docker-image.yml
similarity index 95%
rename from .github/workflows/docker-image-amd64.yml
rename to .github/workflows/docker-image.yml
index 1b9983c6..57224135 100644
--- a/.github/workflows/docker-image-amd64.yml
+++ b/.github/workflows/docker-image.yml
@@ -1,4 +1,4 @@
-name: Publish Docker image (amd64)
+name: Publish Docker image
on:
push:
@@ -56,6 +56,7 @@ jobs:
uses: docker/build-push-action@v3
with:
context: .
+ platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index 29b4ca71..8154e4dc 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM node:16 as builder
+FROM --platform=$BUILDPLATFORM node:16 as builder
WORKDIR /web
COPY ./VERSION .
From 6209ff9ea9ecc93be4eb874cb16010b441aec269 Mon Sep 17 00:00:00 2001
From: zijiren <84728412+zijiren233@users.noreply.github.com>
Date: Tue, 16 Jul 2024 01:02:06 +0800
Subject: [PATCH 07/13] feat: vertexai support proxy url(example: cloudflare ai
gateway) and fix some vertexai bug (#1642)
* feat: vertexai support proxy url(example: cloudflare ai gateway)
* fix: do resp model mapping
* fix: missing system
* fix: stream need query alt=sse
---
relay/adaptor/vertexai/adaptor.go | 28 +++++++++++++++++++-----
relay/adaptor/vertexai/claude/adapter.go | 15 +++++++------
2 files changed, 30 insertions(+), 13 deletions(-)
diff --git a/relay/adaptor/vertexai/adaptor.go b/relay/adaptor/vertexai/adaptor.go
index f1b68b70..3fab4a45 100644
--- a/relay/adaptor/vertexai/adaptor.go
+++ b/relay/adaptor/vertexai/adaptor.go
@@ -19,7 +19,7 @@ var _ adaptor.Adaptor = new(Adaptor)
const channelName = "vertexai"
-type Adaptor struct {}
+type Adaptor struct{}
func (a *Adaptor) Init(meta *meta.Meta) {
}
@@ -38,7 +38,7 @@ func (a *Adaptor) ConvertRequest(c *gin.Context, relayMode int, request *model.G
}
func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, meta *meta.Meta) (usage *model.Usage, err *model.ErrorWithStatusCode) {
- adaptor := GetAdaptor(meta.OriginModelName)
+ adaptor := GetAdaptor(meta.ActualModelName)
if adaptor == nil {
return nil, &relaymodel.ErrorWithStatusCode{
StatusCode: http.StatusInternalServerError,
@@ -63,20 +63,36 @@ func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
suffix := ""
if strings.HasPrefix(meta.ActualModelName, "gemini") {
if meta.IsStream {
- suffix = "streamGenerateContent"
+ suffix = "streamGenerateContent?alt=sse"
} else {
suffix = "generateContent"
}
} else {
if meta.IsStream {
- suffix = "streamRawPredict"
+ suffix = "streamRawPredict?alt=sse"
} else {
suffix = "rawPredict"
}
}
- baseUrl := fmt.Sprintf("https://%s-aiplatform.googleapis.com/v1/projects/%s/locations/%s/publishers/google/models/%s:%s", meta.Config.Region, meta.Config.VertexAIProjectID, meta.Config.Region, meta.ActualModelName, suffix)
- return baseUrl, nil
+ if meta.BaseURL != "" {
+ return fmt.Sprintf(
+ "%s/v1/projects/%s/locations/%s/publishers/google/models/%s:%s",
+ meta.BaseURL,
+ meta.Config.VertexAIProjectID,
+ meta.Config.Region,
+ meta.ActualModelName,
+ suffix,
+ ), nil
+ }
+ return fmt.Sprintf(
+ "https://%s-aiplatform.googleapis.com/v1/projects/%s/locations/%s/publishers/google/models/%s:%s",
+ meta.Config.Region,
+ meta.Config.VertexAIProjectID,
+ meta.Config.Region,
+ meta.ActualModelName,
+ suffix,
+ ), nil
}
func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Request, meta *meta.Meta) error {
diff --git a/relay/adaptor/vertexai/claude/adapter.go b/relay/adaptor/vertexai/claude/adapter.go
index 1e37f0ff..b39e2dda 100644
--- a/relay/adaptor/vertexai/claude/adapter.go
+++ b/relay/adaptor/vertexai/claude/adapter.go
@@ -30,13 +30,14 @@ func (a *Adaptor) ConvertRequest(c *gin.Context, relayMode int, request *model.G
req := Request{
AnthropicVersion: anthropicVersion,
// Model: claudeReq.Model,
- Messages: claudeReq.Messages,
- MaxTokens: claudeReq.MaxTokens,
- Temperature: claudeReq.Temperature,
- TopP: claudeReq.TopP,
- TopK: claudeReq.TopK,
- Stream: claudeReq.Stream,
- Tools: claudeReq.Tools,
+ Messages: claudeReq.Messages,
+ System: claudeReq.System,
+ MaxTokens: claudeReq.MaxTokens,
+ Temperature: claudeReq.Temperature,
+ TopP: claudeReq.TopP,
+ TopK: claudeReq.TopK,
+ Stream: claudeReq.Stream,
+ Tools: claudeReq.Tools,
}
c.Set(ctxkey.RequestModel, request.Model)
From adba54acd34784bbf33a55259e10ebab51aa4263 Mon Sep 17 00:00:00 2001
From: "Laisky.Cai"
Date: Tue, 16 Jul 2024 23:48:54 +0800
Subject: [PATCH 08/13] fix: implement improved headers for anthropic to
support 8k outputs (#1654)
---
common/config/config.go | 1 -
relay/adaptor/anthropic/adaptor.go | 13 ++++++++++--
relay/adaptor/vertexai/claude/model.go | 22 ++++++++++----------
relay/adaptor/vertexai/registry.go | 1 -
relay/adaptor/vertexai/token.go | 1 -
relay/channeltype/url.go | 2 +-
relay/meta/relay_meta.go | 28 ++++++++++++++------------
7 files changed, 38 insertions(+), 30 deletions(-)
diff --git a/common/config/config.go b/common/config/config.go
index 9b55e413..11da0b96 100644
--- a/common/config/config.go
+++ b/common/config/config.go
@@ -147,7 +147,6 @@ var InitialRootAccessToken = os.Getenv("INITIAL_ROOT_ACCESS_TOKEN")
var GeminiVersion = env.String("GEMINI_VERSION", "v1")
-
var OnlyOneLogFile = env.Bool("ONLY_ONE_LOG_FILE", false)
var RelayProxy = env.String("RELAY_PROXY", "")
diff --git a/relay/adaptor/anthropic/adaptor.go b/relay/adaptor/anthropic/adaptor.go
index b1136e84..bd0949be 100644
--- a/relay/adaptor/anthropic/adaptor.go
+++ b/relay/adaptor/anthropic/adaptor.go
@@ -3,12 +3,14 @@ package anthropic
import (
"errors"
"fmt"
+ "io"
+ "net/http"
+ "strings"
+
"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"
- "io"
- "net/http"
)
type Adaptor struct {
@@ -31,6 +33,13 @@ func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Request, meta *me
}
req.Header.Set("anthropic-version", anthropicVersion)
req.Header.Set("anthropic-beta", "messages-2023-12-15")
+
+ // https://x.com/alexalbert__/status/1812921642143900036
+ // claude-3-5-sonnet can support 8k context
+ if strings.HasPrefix(meta.ActualModelName, "claude-3-5-sonnet") {
+ req.Header.Set("anthropic-beta", "max-tokens-3-5-sonnet-2024-07-15")
+ }
+
return nil
}
diff --git a/relay/adaptor/vertexai/claude/model.go b/relay/adaptor/vertexai/claude/model.go
index 2f13f598..e1bd5dd4 100644
--- a/relay/adaptor/vertexai/claude/model.go
+++ b/relay/adaptor/vertexai/claude/model.go
@@ -4,16 +4,16 @@ import "github.com/songquanpeng/one-api/relay/adaptor/anthropic"
type Request struct {
// AnthropicVersion must be "vertex-2023-10-16"
- AnthropicVersion string `json:"anthropic_version"`
+ AnthropicVersion string `json:"anthropic_version"`
// Model string `json:"model"`
- Messages []anthropic.Message `json:"messages"`
- System string `json:"system,omitempty"`
- MaxTokens int `json:"max_tokens,omitempty"`
- StopSequences []string `json:"stop_sequences,omitempty"`
- Stream bool `json:"stream,omitempty"`
- Temperature float64 `json:"temperature,omitempty"`
- TopP float64 `json:"top_p,omitempty"`
- TopK int `json:"top_k,omitempty"`
- Tools []anthropic.Tool `json:"tools,omitempty"`
- ToolChoice any `json:"tool_choice,omitempty"`
+ Messages []anthropic.Message `json:"messages"`
+ System string `json:"system,omitempty"`
+ MaxTokens int `json:"max_tokens,omitempty"`
+ StopSequences []string `json:"stop_sequences,omitempty"`
+ Stream bool `json:"stream,omitempty"`
+ Temperature float64 `json:"temperature,omitempty"`
+ TopP float64 `json:"top_p,omitempty"`
+ TopK int `json:"top_k,omitempty"`
+ Tools []anthropic.Tool `json:"tools,omitempty"`
+ ToolChoice any `json:"tool_choice,omitempty"`
}
diff --git a/relay/adaptor/vertexai/registry.go b/relay/adaptor/vertexai/registry.go
index f9547ebf..41099f02 100644
--- a/relay/adaptor/vertexai/registry.go
+++ b/relay/adaptor/vertexai/registry.go
@@ -32,7 +32,6 @@ func init() {
}
}
-
type innerAIAdapter interface {
ConvertRequest(c *gin.Context, relayMode int, request *model.GeneralOpenAIRequest) (any, error)
DoResponse(c *gin.Context, resp *http.Response, meta *meta.Meta) (usage *model.Usage, err *model.ErrorWithStatusCode)
diff --git a/relay/adaptor/vertexai/token.go b/relay/adaptor/vertexai/token.go
index e5fa7b48..0a5e0aad 100644
--- a/relay/adaptor/vertexai/token.go
+++ b/relay/adaptor/vertexai/token.go
@@ -26,7 +26,6 @@ type ApplicationDefaultCredentials struct {
UniverseDomain string `json:"universe_domain"`
}
-
var Cache = cache.New(50*time.Minute, 55*time.Minute)
const defaultScope = "https://www.googleapis.com/auth/cloud-platform"
diff --git a/relay/channeltype/url.go b/relay/channeltype/url.go
index 47241063..20a24ab0 100644
--- a/relay/channeltype/url.go
+++ b/relay/channeltype/url.go
@@ -43,7 +43,7 @@ var ChannelBaseURLs = []string{
"https://api.together.xyz", // 39
"https://ark.cn-beijing.volces.com", // 40
"https://api.novita.ai/v3/openai", // 41
- "", // 42
+ "", // 42
}
func init() {
diff --git a/relay/meta/relay_meta.go b/relay/meta/relay_meta.go
index 9714ebb5..04977db5 100644
--- a/relay/meta/relay_meta.go
+++ b/relay/meta/relay_meta.go
@@ -10,20 +10,22 @@ import (
)
type Meta struct {
- Mode int
- ChannelType int
- ChannelId int
- TokenId int
- TokenName string
- UserId int
- Group string
- ModelMapping map[string]string
- BaseURL string
- APIKey string
- APIType int
- Config model.ChannelConfig
- IsStream bool
+ Mode int
+ ChannelType int
+ ChannelId int
+ TokenId int
+ TokenName string
+ UserId int
+ Group string
+ ModelMapping map[string]string
+ BaseURL string
+ APIKey string
+ APIType int
+ Config model.ChannelConfig
+ IsStream bool
+ // OriginModelName is the model name from the raw user request
OriginModelName string
+ // ActualModelName is the model name after mapping
ActualModelName string
RequestURLPath string
PromptTokens int // only for DoResponse
From 2a892c193702be2a42f1079f3832244928674575 Mon Sep 17 00:00:00 2001
From: JustSong
Date: Wed, 17 Jul 2024 22:50:52 +0800
Subject: [PATCH 09/13] revert: feat: fast build linux/arm64 frontend (#1645)
This reverts commit 1c44d7e1cdd45f3ebf7dbd4378a5b2ead7ade8f5.
---
...image-en.yml => docker-image-amd64-en.yml} | 3 +-
...ocker-image.yml => docker-image-amd64.yml} | 3 +-
.github/workflows/docker-image-arm64.yml | 69 +++++++++++++++++++
Dockerfile | 2 +-
4 files changed, 72 insertions(+), 5 deletions(-)
rename .github/workflows/{docker-image-en.yml => docker-image-amd64-en.yml} (94%)
rename .github/workflows/{docker-image.yml => docker-image-amd64.yml} (95%)
create mode 100644 .github/workflows/docker-image-arm64.yml
diff --git a/.github/workflows/docker-image-en.yml b/.github/workflows/docker-image-amd64-en.yml
similarity index 94%
rename from .github/workflows/docker-image-en.yml
rename to .github/workflows/docker-image-amd64-en.yml
index e894448f..31c01e80 100644
--- a/.github/workflows/docker-image-en.yml
+++ b/.github/workflows/docker-image-amd64-en.yml
@@ -1,4 +1,4 @@
-name: Publish Docker image (English)
+name: Publish Docker image (amd64, English)
on:
push:
@@ -51,7 +51,6 @@ jobs:
uses: docker/build-push-action@v3
with:
context: .
- platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
\ No newline at end of file
diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image-amd64.yml
similarity index 95%
rename from .github/workflows/docker-image.yml
rename to .github/workflows/docker-image-amd64.yml
index 57224135..1b9983c6 100644
--- a/.github/workflows/docker-image.yml
+++ b/.github/workflows/docker-image-amd64.yml
@@ -1,4 +1,4 @@
-name: Publish Docker image
+name: Publish Docker image (amd64)
on:
push:
@@ -56,7 +56,6 @@ jobs:
uses: docker/build-push-action@v3
with:
context: .
- platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
\ No newline at end of file
diff --git a/.github/workflows/docker-image-arm64.yml b/.github/workflows/docker-image-arm64.yml
new file mode 100644
index 00000000..dc2b4b97
--- /dev/null
+++ b/.github/workflows/docker-image-arm64.yml
@@ -0,0 +1,69 @@
+name: Publish Docker image (arm64)
+
+on:
+ push:
+ tags:
+ - 'v*.*.*'
+ - '!*-alpha*'
+ workflow_dispatch:
+ inputs:
+ name:
+ description: 'reason'
+ required: false
+jobs:
+ push_to_registries:
+ name: Push Docker image to multiple registries
+ runs-on: ubuntu-latest
+ permissions:
+ packages: write
+ contents: read
+ steps:
+ - name: Check out the repo
+ uses: actions/checkout@v3
+
+ - name: Check repository URL
+ run: |
+ REPO_URL=$(git config --get remote.origin.url)
+ if [[ $REPO_URL == *"pro" ]]; then
+ exit 1
+ fi
+
+ - name: Save version info
+ run: |
+ git describe --tags > VERSION
+
+ - name: Set up QEMU
+ uses: docker/setup-qemu-action@v2
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v2
+
+ - name: Log in to Docker Hub
+ uses: docker/login-action@v2
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+ - name: Log in to the Container registry
+ uses: docker/login-action@v2
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Extract metadata (tags, labels) for Docker
+ id: meta
+ uses: docker/metadata-action@v4
+ with:
+ images: |
+ justsong/one-api
+ ghcr.io/${{ github.repository }}
+
+ - name: Build and push Docker images
+ uses: docker/build-push-action@v3
+ with:
+ context: .
+ platforms: linux/amd64,linux/arm64
+ push: true
+ tags: ${{ steps.meta.outputs.tags }}
+ labels: ${{ steps.meta.outputs.labels }}
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index 8154e4dc..29b4ca71 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM --platform=$BUILDPLATFORM node:16 as builder
+FROM node:16 as builder
WORKDIR /web
COPY ./VERSION .
From 39383e553280f4987fa62824c5090c8d85acc392 Mon Sep 17 00:00:00 2001
From: igophper <34326532+igophper@users.noreply.github.com>
Date: Mon, 22 Jul 2024 22:38:50 +0800
Subject: [PATCH 10/13] fix: support embedding models for doubao (#1662)
Fixes #1594
---
relay/adaptor/doubao/main.go | 6 +++-
relay/controller/text.go | 54 +++++++++++++++++++-----------------
2 files changed, 33 insertions(+), 27 deletions(-)
diff --git a/relay/adaptor/doubao/main.go b/relay/adaptor/doubao/main.go
index ea26e6ba..dd43d06c 100644
--- a/relay/adaptor/doubao/main.go
+++ b/relay/adaptor/doubao/main.go
@@ -7,8 +7,12 @@ import (
)
func GetRequestURL(meta *meta.Meta) (string, error) {
- if meta.Mode == relaymode.ChatCompletions {
+ switch meta.Mode {
+ case relaymode.ChatCompletions:
return fmt.Sprintf("%s/api/v3/chat/completions", meta.BaseURL), nil
+ case relaymode.Embeddings:
+ return fmt.Sprintf("%s/api/v3/embeddings", meta.BaseURL), nil
+ default:
}
return "", fmt.Errorf("unsupported relay mode %d for doubao", meta.Mode)
}
diff --git a/relay/controller/text.go b/relay/controller/text.go
index 0d3c56b0..52ee9949 100644
--- a/relay/controller/text.go
+++ b/relay/controller/text.go
@@ -10,6 +10,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/songquanpeng/one-api/common/logger"
"github.com/songquanpeng/one-api/relay"
+ "github.com/songquanpeng/one-api/relay/adaptor"
"github.com/songquanpeng/one-api/relay/adaptor/openai"
"github.com/songquanpeng/one-api/relay/apitype"
"github.com/songquanpeng/one-api/relay/billing"
@@ -31,9 +32,8 @@ func RelayTextHelper(c *gin.Context) *model.ErrorWithStatusCode {
meta.IsStream = textRequest.Stream
// map model name
- var isModelMapped bool
meta.OriginModelName = textRequest.Model
- textRequest.Model, isModelMapped = getMappedModelName(textRequest.Model, meta.ModelMapping)
+ textRequest.Model, _ = getMappedModelName(textRequest.Model, meta.ModelMapping)
meta.ActualModelName = textRequest.Model
// get model ratio & group ratio
modelRatio := billingratio.GetModelRatio(textRequest.Model, meta.ChannelType)
@@ -55,30 +55,9 @@ func RelayTextHelper(c *gin.Context) *model.ErrorWithStatusCode {
adaptor.Init(meta)
// get request body
- var requestBody io.Reader
- if meta.APIType == apitype.OpenAI {
- // no need to convert request for openai
- shouldResetRequestBody := isModelMapped || meta.ChannelType == channeltype.Baichuan // frequency_penalty 0 is not acceptable for baichuan
- if shouldResetRequestBody {
- jsonStr, err := json.Marshal(textRequest)
- if err != nil {
- return openai.ErrorWrapper(err, "json_marshal_failed", http.StatusInternalServerError)
- }
- requestBody = bytes.NewBuffer(jsonStr)
- } else {
- requestBody = c.Request.Body
- }
- } else {
- convertedRequest, err := adaptor.ConvertRequest(c, meta.Mode, textRequest)
- if err != nil {
- return openai.ErrorWrapper(err, "convert_request_failed", http.StatusInternalServerError)
- }
- jsonData, err := json.Marshal(convertedRequest)
- if err != nil {
- return openai.ErrorWrapper(err, "json_marshal_failed", http.StatusInternalServerError)
- }
- logger.Debugf(ctx, "converted request: \n%s", string(jsonData))
- requestBody = bytes.NewBuffer(jsonData)
+ requestBody, err := getRequestBody(c, meta, textRequest, adaptor)
+ if err != nil {
+ return openai.ErrorWrapper(err, "convert_request_failed", http.StatusInternalServerError)
}
// do request
@@ -103,3 +82,26 @@ func RelayTextHelper(c *gin.Context) *model.ErrorWithStatusCode {
go postConsumeQuota(ctx, usage, meta, textRequest, ratio, preConsumedQuota, modelRatio, groupRatio)
return nil
}
+
+func getRequestBody(c *gin.Context, meta *meta.Meta, textRequest *model.GeneralOpenAIRequest, adaptor adaptor.Adaptor) (io.Reader, error) {
+ if meta.APIType == apitype.OpenAI && meta.OriginModelName == meta.ActualModelName && meta.ChannelType != channeltype.Baichuan {
+ // no need to convert request for openai
+ return c.Request.Body, nil
+ }
+
+ // get request body
+ var requestBody io.Reader
+ convertedRequest, err := adaptor.ConvertRequest(c, meta.Mode, textRequest)
+ if err != nil {
+ logger.Debugf(c.Request.Context(), "converted request failed: %s\n", err.Error())
+ return nil, err
+ }
+ jsonData, err := json.Marshal(convertedRequest)
+ if err != nil {
+ logger.Debugf(c.Request.Context(), "converted request json_marshal_failed: %s\n", err.Error())
+ return nil, err
+ }
+ logger.Debugf(c.Request.Context(), "converted request: \n%s", string(jsonData))
+ requestBody = bytes.NewBuffer(jsonData)
+ return requestBody, nil
+}
From 5f03c856b486a9216371cc25957aa25cc9e337e9 Mon Sep 17 00:00:00 2001
From: zijiren <84728412+zijiren233@users.noreply.github.com>
Date: Mon, 22 Jul 2024 22:39:22 +0800
Subject: [PATCH 11/13] feat: fast build linux/arm64 frontend (#1663)
* feat: fast build linux/arm64 frontend
* fix: dockerfile as replace to AS
* fix: trim space
---
.github/workflows/docker-image-amd64.yml | 61 -------------------
...image-amd64-en.yml => docker-image-en.yml} | 10 ++-
...ocker-image-arm64.yml => docker-image.yml} | 3 +-
Dockerfile | 2 +-
4 files changed, 11 insertions(+), 65 deletions(-)
delete mode 100644 .github/workflows/docker-image-amd64.yml
rename .github/workflows/{docker-image-amd64-en.yml => docker-image-en.yml} (85%)
rename .github/workflows/{docker-image-arm64.yml => docker-image.yml} (96%)
diff --git a/.github/workflows/docker-image-amd64.yml b/.github/workflows/docker-image-amd64.yml
deleted file mode 100644
index 1b9983c6..00000000
--- a/.github/workflows/docker-image-amd64.yml
+++ /dev/null
@@ -1,61 +0,0 @@
-name: Publish Docker image (amd64)
-
-on:
- push:
- tags:
- - 'v*.*.*'
- workflow_dispatch:
- inputs:
- name:
- description: 'reason'
- required: false
-jobs:
- push_to_registries:
- name: Push Docker image to multiple registries
- runs-on: ubuntu-latest
- permissions:
- packages: write
- contents: read
- steps:
- - name: Check out the repo
- uses: actions/checkout@v3
-
- - name: Check repository URL
- run: |
- REPO_URL=$(git config --get remote.origin.url)
- if [[ $REPO_URL == *"pro" ]]; then
- exit 1
- fi
-
- - name: Save version info
- run: |
- git describe --tags > VERSION
-
- - name: Log in to Docker Hub
- uses: docker/login-action@v2
- with:
- username: ${{ secrets.DOCKERHUB_USERNAME }}
- password: ${{ secrets.DOCKERHUB_TOKEN }}
-
- - name: Log in to the Container registry
- uses: docker/login-action@v2
- with:
- registry: ghcr.io
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Extract metadata (tags, labels) for Docker
- id: meta
- uses: docker/metadata-action@v4
- with:
- images: |
- justsong/one-api
- ghcr.io/${{ github.repository }}
-
- - name: Build and push Docker images
- uses: docker/build-push-action@v3
- with:
- context: .
- push: true
- tags: ${{ steps.meta.outputs.tags }}
- labels: ${{ steps.meta.outputs.labels }}
\ No newline at end of file
diff --git a/.github/workflows/docker-image-amd64-en.yml b/.github/workflows/docker-image-en.yml
similarity index 85%
rename from .github/workflows/docker-image-amd64-en.yml
rename to .github/workflows/docker-image-en.yml
index 31c01e80..30cd0e38 100644
--- a/.github/workflows/docker-image-amd64-en.yml
+++ b/.github/workflows/docker-image-en.yml
@@ -1,4 +1,4 @@
-name: Publish Docker image (amd64, English)
+name: Publish Docker image (English)
on:
push:
@@ -34,6 +34,13 @@ jobs:
- name: Translate
run: |
python ./i18n/translate.py --repository_path . --json_file_path ./i18n/en.json
+
+ - name: Set up QEMU
+ uses: docker/setup-qemu-action@v2
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v2
+
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
@@ -51,6 +58,7 @@ jobs:
uses: docker/build-push-action@v3
with:
context: .
+ platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
\ No newline at end of file
diff --git a/.github/workflows/docker-image-arm64.yml b/.github/workflows/docker-image.yml
similarity index 96%
rename from .github/workflows/docker-image-arm64.yml
rename to .github/workflows/docker-image.yml
index dc2b4b97..56f1d6ad 100644
--- a/.github/workflows/docker-image-arm64.yml
+++ b/.github/workflows/docker-image.yml
@@ -1,10 +1,9 @@
-name: Publish Docker image (arm64)
+name: Publish Docker image
on:
push:
tags:
- 'v*.*.*'
- - '!*-alpha*'
workflow_dispatch:
inputs:
name:
diff --git a/Dockerfile b/Dockerfile
index 29b4ca71..ade561e4 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM node:16 as builder
+FROM --platform=$BUILDPLATFORM node:16 AS builder
WORKDIR /web
COPY ./VERSION .
From 296ab013b8877ff44cb13c53ae6f3a7ab3e905d8 Mon Sep 17 00:00:00 2001
From: TAKO <20227709+HynoR@users.noreply.github.com>
Date: Mon, 22 Jul 2024 22:44:08 +0800
Subject: [PATCH 12/13] feat: support gpt-4o mini (#1665)
* feat: support gpt-4o mini
* feat: fix gpt-4o mini image price
---
relay/adaptor/openai/constants.go | 1 +
relay/adaptor/openai/token.go | 14 ++++++++++++--
relay/billing/ratio/model.go | 23 ++++++++++++++---------
3 files changed, 27 insertions(+), 11 deletions(-)
diff --git a/relay/adaptor/openai/constants.go b/relay/adaptor/openai/constants.go
index 924f4b2a..156a50e7 100644
--- a/relay/adaptor/openai/constants.go
+++ b/relay/adaptor/openai/constants.go
@@ -8,6 +8,7 @@ var ModelList = []string{
"gpt-4-32k", "gpt-4-32k-0314", "gpt-4-32k-0613",
"gpt-4-turbo-preview", "gpt-4-turbo", "gpt-4-turbo-2024-04-09",
"gpt-4o", "gpt-4o-2024-05-13",
+ "gpt-4o-mini", "gpt-4o-mini-2024-07-18",
"gpt-4-vision-preview",
"text-embedding-ada-002", "text-embedding-3-small", "text-embedding-3-large",
"text-curie-001", "text-babbage-001", "text-ada-001", "text-davinci-002", "text-davinci-003",
diff --git a/relay/adaptor/openai/token.go b/relay/adaptor/openai/token.go
index 8378b264..7c8468b9 100644
--- a/relay/adaptor/openai/token.go
+++ b/relay/adaptor/openai/token.go
@@ -110,7 +110,7 @@ func CountTokenMessages(messages []model.Message, model string) int {
if imageUrl["detail"] != nil {
detail = imageUrl["detail"].(string)
}
- imageTokens, err := countImageTokens(url, detail)
+ imageTokens, err := countImageTokens(url, detail, model)
if err != nil {
logger.SysError("error counting image tokens: " + err.Error())
} else {
@@ -134,11 +134,15 @@ const (
lowDetailCost = 85
highDetailCostPerTile = 170
additionalCost = 85
+ // gpt-4o-mini cost higher than other model
+ gpt4oMiniLowDetailCost = 2833
+ gpt4oMiniHighDetailCost = 5667
+ gpt4oMiniAdditionalCost = 2833
)
// https://platform.openai.com/docs/guides/vision/calculating-costs
// https://github.com/openai/openai-cookbook/blob/05e3f9be4c7a2ae7ecf029a7c32065b024730ebe/examples/How_to_count_tokens_with_tiktoken.ipynb
-func countImageTokens(url string, detail string) (_ int, err error) {
+func countImageTokens(url string, detail string, model string) (_ int, err error) {
var fetchSize = true
var width, height int
// Reference: https://platform.openai.com/docs/guides/vision/low-or-high-fidelity-image-understanding
@@ -172,6 +176,9 @@ func countImageTokens(url string, detail string) (_ int, err error) {
}
switch detail {
case "low":
+ if strings.HasPrefix(model, "gpt-4o-mini") {
+ return gpt4oMiniLowDetailCost, nil
+ }
return lowDetailCost, nil
case "high":
if fetchSize {
@@ -191,6 +198,9 @@ func countImageTokens(url string, detail string) (_ int, err error) {
height = int(float64(height) * ratio)
}
numSquares := int(math.Ceil(float64(width)/512) * math.Ceil(float64(height)/512))
+ if strings.HasPrefix(model, "gpt-4o-mini") {
+ return numSquares*gpt4oMiniHighDetailCost + gpt4oMiniAdditionalCost, nil
+ }
result := numSquares*highDetailCostPerTile + additionalCost
return result, nil
default:
diff --git a/relay/billing/ratio/model.go b/relay/billing/ratio/model.go
index 8a7d5743..799fa90f 100644
--- a/relay/billing/ratio/model.go
+++ b/relay/billing/ratio/model.go
@@ -28,15 +28,17 @@ var ModelRatio = map[string]float64{
"gpt-4-32k": 30,
"gpt-4-32k-0314": 30,
"gpt-4-32k-0613": 30,
- "gpt-4-1106-preview": 5, // $0.01 / 1K tokens
- "gpt-4-0125-preview": 5, // $0.01 / 1K tokens
- "gpt-4-turbo-preview": 5, // $0.01 / 1K tokens
- "gpt-4-turbo": 5, // $0.01 / 1K tokens
- "gpt-4-turbo-2024-04-09": 5, // $0.01 / 1K tokens
- "gpt-4o": 2.5, // $0.005 / 1K tokens
- "gpt-4o-2024-05-13": 2.5, // $0.005 / 1K tokens
- "gpt-4-vision-preview": 5, // $0.01 / 1K tokens
- "gpt-3.5-turbo": 0.25, // $0.0005 / 1K tokens
+ "gpt-4-1106-preview": 5, // $0.01 / 1K tokens
+ "gpt-4-0125-preview": 5, // $0.01 / 1K tokens
+ "gpt-4-turbo-preview": 5, // $0.01 / 1K tokens
+ "gpt-4-turbo": 5, // $0.01 / 1K tokens
+ "gpt-4-turbo-2024-04-09": 5, // $0.01 / 1K tokens
+ "gpt-4o": 2.5, // $0.005 / 1K tokens
+ "gpt-4o-2024-05-13": 2.5, // $0.005 / 1K tokens
+ "gpt-4o-mini": 0.075, // $0.00015 / 1K tokens
+ "gpt-4o-mini-2024-07-18": 0.075, // $0.00015 / 1K tokens
+ "gpt-4-vision-preview": 5, // $0.01 / 1K tokens
+ "gpt-3.5-turbo": 0.25, // $0.0005 / 1K tokens
"gpt-3.5-turbo-0301": 0.75,
"gpt-3.5-turbo-0613": 0.75,
"gpt-3.5-turbo-16k": 1.5, // $0.003 / 1K tokens
@@ -308,6 +310,9 @@ func GetCompletionRatio(name string, channelType int) float64 {
return 4.0 / 3.0
}
if strings.HasPrefix(name, "gpt-4") {
+ if strings.HasPrefix(name, "gpt-4o-mini") {
+ return 4
+ }
if strings.HasPrefix(name, "gpt-4-turbo") ||
strings.HasPrefix(name, "gpt-4o") ||
strings.HasSuffix(name, "preview") {
From c936198ac8cf3c51bb839d11efea0bfd06fedc57 Mon Sep 17 00:00:00 2001
From: "Laisky.Cai"
Date: Mon, 22 Jul 2024 22:51:19 +0800
Subject: [PATCH 13/13] feat: add Proxy channel type and relay mode (#1678)
Add the Proxy channel type and relay mode to support proxying requests to custom upstream services.
---
controller/relay.go | 5 +
middleware/auth.go | 6 +
relay/adaptor.go | 3 +
relay/adaptor/proxy/adaptor.go | 89 ++++++++++++
relay/apitype/define.go | 1 +
relay/channeltype/define.go | 1 +
relay/channeltype/helper.go | 2 +
relay/channeltype/url.go | 1 +
relay/controller/proxy.go | 41 ++++++
relay/meta/relay_meta.go | 11 +-
relay/relaymode/define.go | 2 +
relay/relaymode/helper.go | 2 +
router/relay.go | 1 +
web/air/src/constants/channel.constants.js | 14 +-
web/berry/src/constants/ChannelConstants.js | 6 +
.../src/constants/channel.constants.js | 85 ++++++------
web/default/src/pages/Channel/EditChannel.js | 128 ++++++++++--------
17 files changed, 292 insertions(+), 106 deletions(-)
create mode 100644 relay/adaptor/proxy/adaptor.go
create mode 100644 relay/controller/proxy.go
diff --git a/controller/relay.go b/controller/relay.go
index 932e023b..49358e25 100644
--- a/controller/relay.go
+++ b/controller/relay.go
@@ -34,6 +34,8 @@ func relayHelper(c *gin.Context, relayMode int) *model.ErrorWithStatusCode {
fallthrough
case relaymode.AudioTranscription:
err = controller.RelayAudioHelper(c, relayMode)
+ case relaymode.Proxy:
+ err = controller.RelayProxyHelper(c, relayMode)
default:
err = controller.RelayTextHelper(c)
}
@@ -85,12 +87,15 @@ func Relay(c *gin.Context) {
channelId := c.GetInt(ctxkey.ChannelId)
lastFailedChannelId = channelId
channelName := c.GetString(ctxkey.ChannelName)
+ // BUG: bizErr is in race condition
go processChannelRelayError(ctx, userId, channelId, channelName, bizErr)
}
if bizErr != nil {
if bizErr.StatusCode == http.StatusTooManyRequests {
bizErr.Error.Message = "当前分组上游负载已饱和,请稍后再试"
}
+
+ // BUG: bizErr is in race condition
bizErr.Error.Message = helper.MessageWithRequestId(bizErr.Error.Message, requestId)
c.JSON(bizErr.StatusCode, gin.H{
"error": bizErr.Error,
diff --git a/middleware/auth.go b/middleware/auth.go
index 5cba490a..e0019838 100644
--- a/middleware/auth.go
+++ b/middleware/auth.go
@@ -140,6 +140,12 @@ func TokenAuth() func(c *gin.Context) {
return
}
}
+
+ // set channel id for proxy relay
+ if channelId := c.Param("channelid"); channelId != "" {
+ c.Set(ctxkey.SpecificChannelId, channelId)
+ }
+
c.Next()
}
}
diff --git a/relay/adaptor.go b/relay/adaptor.go
index 7fc83651..711e63bd 100644
--- a/relay/adaptor.go
+++ b/relay/adaptor.go
@@ -15,6 +15,7 @@ import (
"github.com/songquanpeng/one-api/relay/adaptor/ollama"
"github.com/songquanpeng/one-api/relay/adaptor/openai"
"github.com/songquanpeng/one-api/relay/adaptor/palm"
+ "github.com/songquanpeng/one-api/relay/adaptor/proxy"
"github.com/songquanpeng/one-api/relay/adaptor/tencent"
"github.com/songquanpeng/one-api/relay/adaptor/vertexai"
"github.com/songquanpeng/one-api/relay/adaptor/xunfei"
@@ -58,6 +59,8 @@ func GetAdaptor(apiType int) adaptor.Adaptor {
return &deepl.Adaptor{}
case apitype.VertexAI:
return &vertexai.Adaptor{}
+ case apitype.Proxy:
+ return &proxy.Adaptor{}
}
return nil
}
diff --git a/relay/adaptor/proxy/adaptor.go b/relay/adaptor/proxy/adaptor.go
new file mode 100644
index 00000000..670c7628
--- /dev/null
+++ b/relay/adaptor/proxy/adaptor.go
@@ -0,0 +1,89 @@
+package proxy
+
+import (
+ "fmt"
+ "io"
+ "net/http"
+ "strings"
+
+ "github.com/gin-gonic/gin"
+ "github.com/pkg/errors"
+ "github.com/songquanpeng/one-api/relay/adaptor"
+ channelhelper "github.com/songquanpeng/one-api/relay/adaptor"
+ "github.com/songquanpeng/one-api/relay/meta"
+ "github.com/songquanpeng/one-api/relay/model"
+ relaymodel "github.com/songquanpeng/one-api/relay/model"
+)
+
+var _ adaptor.Adaptor = new(Adaptor)
+
+const channelName = "proxy"
+
+type Adaptor struct{}
+
+func (a *Adaptor) Init(meta *meta.Meta) {
+}
+
+func (a *Adaptor) ConvertRequest(c *gin.Context, relayMode int, request *model.GeneralOpenAIRequest) (any, error) {
+ return nil, errors.New("notimplement")
+}
+
+func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, meta *meta.Meta) (usage *model.Usage, err *model.ErrorWithStatusCode) {
+ for k, v := range resp.Header {
+ for _, vv := range v {
+ c.Writer.Header().Set(k, vv)
+ }
+ }
+
+ c.Writer.WriteHeader(resp.StatusCode)
+ if _, gerr := io.Copy(c.Writer, resp.Body); gerr != nil {
+ return nil, &relaymodel.ErrorWithStatusCode{
+ StatusCode: http.StatusInternalServerError,
+ Error: relaymodel.Error{
+ Message: gerr.Error(),
+ },
+ }
+ }
+
+ return nil, nil
+}
+
+func (a *Adaptor) GetModelList() (models []string) {
+ return nil
+}
+
+func (a *Adaptor) GetChannelName() string {
+ return channelName
+}
+
+// GetRequestURL remove static prefix, and return the real request url to the upstream service
+func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
+ prefix := fmt.Sprintf("/v1/oneapi/proxy/%d", meta.ChannelId)
+ return meta.BaseURL + strings.TrimPrefix(meta.RequestURLPath, prefix), nil
+
+}
+
+func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Request, meta *meta.Meta) error {
+ for k, v := range c.Request.Header {
+ req.Header.Set(k, v[0])
+ }
+
+ // remove unnecessary headers
+ req.Header.Del("Host")
+ req.Header.Del("Content-Length")
+ req.Header.Del("Accept-Encoding")
+ req.Header.Del("Connection")
+
+ // set authorization header
+ req.Header.Set("Authorization", meta.APIKey)
+
+ return nil
+}
+
+func (a *Adaptor) ConvertImageRequest(request *model.ImageRequest) (any, error) {
+ return nil, errors.Errorf("not implement")
+}
+
+func (a *Adaptor) DoRequest(c *gin.Context, meta *meta.Meta, requestBody io.Reader) (*http.Response, error) {
+ return channelhelper.DoRequestHelper(a, c, meta, requestBody)
+}
diff --git a/relay/apitype/define.go b/relay/apitype/define.go
index 212a1b6b..cf7b6a0d 100644
--- a/relay/apitype/define.go
+++ b/relay/apitype/define.go
@@ -18,6 +18,7 @@ const (
Cloudflare
DeepL
VertexAI
+ Proxy
Dummy // this one is only for count, do not add any channel after this
)
diff --git a/relay/channeltype/define.go b/relay/channeltype/define.go
index d1e7fcef..e3b0c98e 100644
--- a/relay/channeltype/define.go
+++ b/relay/channeltype/define.go
@@ -44,5 +44,6 @@ const (
Doubao
Novita
VertextAI
+ Proxy
Dummy
)
diff --git a/relay/channeltype/helper.go b/relay/channeltype/helper.go
index 67270a67..fae3357f 100644
--- a/relay/channeltype/helper.go
+++ b/relay/channeltype/helper.go
@@ -37,6 +37,8 @@ func ToAPIType(channelType int) int {
apiType = apitype.DeepL
case VertextAI:
apiType = apitype.VertexAI
+ case Proxy:
+ apiType = apitype.Proxy
}
return apiType
diff --git a/relay/channeltype/url.go b/relay/channeltype/url.go
index 20a24ab0..b5026713 100644
--- a/relay/channeltype/url.go
+++ b/relay/channeltype/url.go
@@ -44,6 +44,7 @@ var ChannelBaseURLs = []string{
"https://ark.cn-beijing.volces.com", // 40
"https://api.novita.ai/v3/openai", // 41
"", // 42
+ "", // 43
}
func init() {
diff --git a/relay/controller/proxy.go b/relay/controller/proxy.go
new file mode 100644
index 00000000..dcaf15a9
--- /dev/null
+++ b/relay/controller/proxy.go
@@ -0,0 +1,41 @@
+// Package controller is a package for handling the relay controller
+package controller
+
+import (
+ "fmt"
+ "net/http"
+
+ "github.com/gin-gonic/gin"
+ "github.com/songquanpeng/one-api/common/logger"
+ "github.com/songquanpeng/one-api/relay"
+ "github.com/songquanpeng/one-api/relay/adaptor/openai"
+ "github.com/songquanpeng/one-api/relay/meta"
+ relaymodel "github.com/songquanpeng/one-api/relay/model"
+)
+
+// RelayProxyHelper is a helper function to proxy the request to the upstream service
+func RelayProxyHelper(c *gin.Context, relayMode int) *relaymodel.ErrorWithStatusCode {
+ ctx := c.Request.Context()
+ meta := meta.GetByContext(c)
+
+ adaptor := relay.GetAdaptor(meta.APIType)
+ if adaptor == nil {
+ return openai.ErrorWrapper(fmt.Errorf("invalid api type: %d", meta.APIType), "invalid_api_type", http.StatusBadRequest)
+ }
+ adaptor.Init(meta)
+
+ resp, err := adaptor.DoRequest(c, meta, c.Request.Body)
+ if err != nil {
+ logger.Errorf(ctx, "DoRequest failed: %s", err.Error())
+ return openai.ErrorWrapper(err, "do_request_failed", http.StatusInternalServerError)
+ }
+
+ // do response
+ _, respErr := adaptor.DoResponse(c, resp, meta)
+ if respErr != nil {
+ logger.Errorf(ctx, "respErr is not nil: %+v", respErr)
+ return respErr
+ }
+
+ return nil
+}
diff --git a/relay/meta/relay_meta.go b/relay/meta/relay_meta.go
index 04977db5..b1761e9a 100644
--- a/relay/meta/relay_meta.go
+++ b/relay/meta/relay_meta.go
@@ -18,11 +18,12 @@ type Meta struct {
UserId int
Group string
ModelMapping map[string]string
- BaseURL string
- APIKey string
- APIType int
- Config model.ChannelConfig
- IsStream bool
+ // BaseURL is the proxy url set in the channel config
+ BaseURL string
+ APIKey string
+ APIType int
+ Config model.ChannelConfig
+ IsStream bool
// OriginModelName is the model name from the raw user request
OriginModelName string
// ActualModelName is the model name after mapping
diff --git a/relay/relaymode/define.go b/relay/relaymode/define.go
index 96d09438..aa771205 100644
--- a/relay/relaymode/define.go
+++ b/relay/relaymode/define.go
@@ -11,4 +11,6 @@ const (
AudioSpeech
AudioTranscription
AudioTranslation
+ // Proxy is a special relay mode for proxying requests to custom upstream
+ Proxy
)
diff --git a/relay/relaymode/helper.go b/relay/relaymode/helper.go
index 926dd42e..2cde5b85 100644
--- a/relay/relaymode/helper.go
+++ b/relay/relaymode/helper.go
@@ -24,6 +24,8 @@ func GetByPath(path string) int {
relayMode = AudioTranscription
} else if strings.HasPrefix(path, "/v1/audio/translations") {
relayMode = AudioTranslation
+ } else if strings.HasPrefix(path, "/v1/oneapi/proxy") {
+ relayMode = Proxy
}
return relayMode
}
diff --git a/router/relay.go b/router/relay.go
index 65072c86..094ea5fb 100644
--- a/router/relay.go
+++ b/router/relay.go
@@ -19,6 +19,7 @@ func SetRelayRouter(router *gin.Engine) {
relayV1Router := router.Group("/v1")
relayV1Router.Use(middleware.RelayPanicRecover(), middleware.TokenAuth(), middleware.Distribute())
{
+ relayV1Router.Any("/oneapi/proxy/:channelid/*target", controller.Relay)
relayV1Router.POST("/completions", controller.Relay)
relayV1Router.POST("/chat/completions", controller.Relay)
relayV1Router.POST("/edits", controller.Relay)
diff --git a/web/air/src/constants/channel.constants.js b/web/air/src/constants/channel.constants.js
index 4bf035f9..18293f5f 100644
--- a/web/air/src/constants/channel.constants.js
+++ b/web/air/src/constants/channel.constants.js
@@ -1,10 +1,13 @@
export const CHANNEL_OPTIONS = [
{ key: 1, text: 'OpenAI', value: 1, color: 'green' },
{ key: 14, text: 'Anthropic Claude', value: 14, color: 'black' },
+ { key: 33, text: 'AWS', value: 33, color: 'black' },
{ key: 3, text: 'Azure OpenAI', value: 3, color: 'olive' },
{ key: 11, text: 'Google PaLM2', value: 11, color: 'orange' },
{ key: 24, text: 'Google Gemini', value: 24, color: 'orange' },
{ key: 28, text: 'Mistral AI', value: 28, color: 'orange' },
+ { key: 41, text: 'Novita', value: 41, color: 'purple' },
+ { key: 40, text: '字节跳动豆包', value: 40, color: 'blue' },
{ key: 15, text: '百度文心千帆', value: 15, color: 'blue' },
{ key: 17, text: '阿里通义千问', value: 17, color: 'orange' },
{ key: 18, text: '讯飞星火认知', value: 18, color: 'blue' },
@@ -17,6 +20,15 @@ export const CHANNEL_OPTIONS = [
{ key: 29, text: 'Groq', value: 29, color: 'orange' },
{ key: 30, text: 'Ollama', value: 30, color: 'black' },
{ key: 31, text: '零一万物', value: 31, color: 'green' },
+ { key: 32, text: '阶跃星辰', value: 32, color: 'blue' },
+ { key: 34, text: 'Coze', value: 34, color: 'blue' },
+ { key: 35, text: 'Cohere', value: 35, color: 'blue' },
+ { key: 36, text: 'DeepSeek', value: 36, color: 'black' },
+ { key: 37, text: 'Cloudflare', value: 37, color: 'orange' },
+ { key: 38, text: 'DeepL', value: 38, color: 'black' },
+ { key: 39, text: 'together.ai', value: 39, color: 'blue' },
+ { key: 42, text: 'VertexAI', value: 42, color: 'blue' },
+ { key: 43, text: 'Proxy', value: 43, color: 'blue' },
{ key: 8, text: '自定义渠道', value: 8, color: 'pink' },
{ key: 22, text: '知识库:FastGPT', value: 22, color: 'blue' },
{ key: 21, text: '知识库:AI Proxy', value: 21, color: 'purple' },
@@ -34,4 +46,4 @@ export const CHANNEL_OPTIONS = [
for (let i = 0; i < CHANNEL_OPTIONS.length; i++) {
CHANNEL_OPTIONS[i].label = CHANNEL_OPTIONS[i].text;
-}
\ No newline at end of file
+}
diff --git a/web/berry/src/constants/ChannelConstants.js b/web/berry/src/constants/ChannelConstants.js
index ac2e73a6..acfda37b 100644
--- a/web/berry/src/constants/ChannelConstants.js
+++ b/web/berry/src/constants/ChannelConstants.js
@@ -167,6 +167,12 @@ export const CHANNEL_OPTIONS = {
value: 42,
color: 'primary'
},
+ 43: {
+ key: 43,
+ text: 'Proxy',
+ value: 43,
+ color: 'primary'
+ },
41: {
key: 41,
text: 'Novita',
diff --git a/web/default/src/constants/channel.constants.js b/web/default/src/constants/channel.constants.js
index b17f56c0..b2a71016 100644
--- a/web/default/src/constants/channel.constants.js
+++ b/web/default/src/constants/channel.constants.js
@@ -1,44 +1,45 @@
export const CHANNEL_OPTIONS = [
- {key: 1, text: 'OpenAI', value: 1, color: 'green'},
- {key: 14, text: 'Anthropic Claude', value: 14, color: 'black'},
- {key: 33, text: 'AWS', value: 33, color: 'black'},
- {key: 3, text: 'Azure OpenAI', value: 3, color: 'olive'},
- {key: 11, text: 'Google PaLM2', value: 11, color: 'orange'},
- {key: 24, text: 'Google Gemini', value: 24, color: 'orange'},
- {key: 28, text: 'Mistral AI', value: 28, color: 'orange'},
- {key: 41, text: 'Novita', value: 41, color: 'purple'},
- {key: 40, text: '字节跳动豆包', value: 40, color: 'blue'},
- {key: 15, text: '百度文心千帆', value: 15, color: 'blue'},
- {key: 17, text: '阿里通义千问', value: 17, color: 'orange'},
- {key: 18, text: '讯飞星火认知', value: 18, color: 'blue'},
- {key: 16, text: '智谱 ChatGLM', value: 16, color: 'violet'},
- {key: 19, text: '360 智脑', value: 19, color: 'blue'},
- {key: 25, text: 'Moonshot AI', value: 25, color: 'black'},
- {key: 23, text: '腾讯混元', value: 23, color: 'teal'},
- {key: 26, text: '百川大模型', value: 26, color: 'orange'},
- {key: 27, text: 'MiniMax', value: 27, color: 'red'},
- {key: 29, text: 'Groq', value: 29, color: 'orange'},
- {key: 30, text: 'Ollama', value: 30, color: 'black'},
- {key: 31, text: '零一万物', value: 31, color: 'green'},
- {key: 32, text: '阶跃星辰', value: 32, color: 'blue'},
- {key: 34, text: 'Coze', value: 34, color: 'blue'},
- {key: 35, text: 'Cohere', value: 35, color: 'blue'},
- {key: 36, text: 'DeepSeek', value: 36, color: 'black'},
- {key: 37, text: 'Cloudflare', value: 37, color: 'orange'},
- {key: 38, text: 'DeepL', value: 38, color: 'black'},
- {key: 39, text: 'together.ai', value: 39, color: 'blue'},
- {key: 42, text: 'VertexAI', value: 42, color: 'blue'},
- {key: 8, text: '自定义渠道', value: 8, color: 'pink'},
- {key: 22, text: '知识库:FastGPT', value: 22, color: 'blue'},
- {key: 21, text: '知识库:AI Proxy', value: 21, color: 'purple'},
- {key: 20, text: '代理:OpenRouter', value: 20, color: 'black'},
- {key: 2, text: '代理:API2D', value: 2, color: 'blue'},
- {key: 5, text: '代理:OpenAI-SB', value: 5, color: 'brown'},
- {key: 7, text: '代理:OhMyGPT', value: 7, color: 'purple'},
- {key: 10, text: '代理:AI Proxy', value: 10, color: 'purple'},
- {key: 4, text: '代理:CloseAI', value: 4, color: 'teal'},
- {key: 6, text: '代理:OpenAI Max', value: 6, color: 'violet'},
- {key: 9, text: '代理:AI.LS', value: 9, color: 'yellow'},
- {key: 12, text: '代理:API2GPT', value: 12, color: 'blue'},
- {key: 13, text: '代理:AIGC2D', value: 13, color: 'purple'}
+ { key: 1, text: 'OpenAI', value: 1, color: 'green' },
+ { key: 14, text: 'Anthropic Claude', value: 14, color: 'black' },
+ { key: 33, text: 'AWS', value: 33, color: 'black' },
+ { key: 3, text: 'Azure OpenAI', value: 3, color: 'olive' },
+ { key: 11, text: 'Google PaLM2', value: 11, color: 'orange' },
+ { key: 24, text: 'Google Gemini', value: 24, color: 'orange' },
+ { key: 28, text: 'Mistral AI', value: 28, color: 'orange' },
+ { key: 41, text: 'Novita', value: 41, color: 'purple' },
+ { key: 40, text: '字节跳动豆包', value: 40, color: 'blue' },
+ { key: 15, text: '百度文心千帆', value: 15, color: 'blue' },
+ { key: 17, text: '阿里通义千问', value: 17, color: 'orange' },
+ { key: 18, text: '讯飞星火认知', value: 18, color: 'blue' },
+ { key: 16, text: '智谱 ChatGLM', value: 16, color: 'violet' },
+ { key: 19, text: '360 智脑', value: 19, color: 'blue' },
+ { key: 25, text: 'Moonshot AI', value: 25, color: 'black' },
+ { key: 23, text: '腾讯混元', value: 23, color: 'teal' },
+ { key: 26, text: '百川大模型', value: 26, color: 'orange' },
+ { key: 27, text: 'MiniMax', value: 27, color: 'red' },
+ { key: 29, text: 'Groq', value: 29, color: 'orange' },
+ { key: 30, text: 'Ollama', value: 30, color: 'black' },
+ { key: 31, text: '零一万物', value: 31, color: 'green' },
+ { key: 32, text: '阶跃星辰', value: 32, color: 'blue' },
+ { key: 34, text: 'Coze', value: 34, color: 'blue' },
+ { key: 35, text: 'Cohere', value: 35, color: 'blue' },
+ { key: 36, text: 'DeepSeek', value: 36, color: 'black' },
+ { key: 37, text: 'Cloudflare', value: 37, color: 'orange' },
+ { key: 38, text: 'DeepL', value: 38, color: 'black' },
+ { key: 39, text: 'together.ai', value: 39, color: 'blue' },
+ { key: 42, text: 'VertexAI', value: 42, color: 'blue' },
+ { key: 43, text: 'Proxy', value: 43, color: 'blue' },
+ { key: 8, text: '自定义渠道', value: 8, color: 'pink' },
+ { key: 22, text: '知识库:FastGPT', value: 22, color: 'blue' },
+ { key: 21, text: '知识库:AI Proxy', value: 21, color: 'purple' },
+ { key: 20, text: '代理:OpenRouter', value: 20, color: 'black' },
+ { key: 2, text: '代理:API2D', value: 2, color: 'blue' },
+ { key: 5, text: '代理:OpenAI-SB', value: 5, color: 'brown' },
+ { key: 7, text: '代理:OhMyGPT', value: 7, color: 'purple' },
+ { key: 10, text: '代理:AI Proxy', value: 10, color: 'purple' },
+ { key: 4, text: '代理:CloseAI', value: 4, color: 'teal' },
+ { key: 6, text: '代理:OpenAI Max', value: 6, color: 'violet' },
+ { key: 9, text: '代理:AI.LS', value: 9, color: 'yellow' },
+ { key: 12, text: '代理:API2GPT', value: 12, color: 'blue' },
+ { key: 13, text: '代理:AIGC2D', value: 13, color: 'purple' }
];
diff --git a/web/default/src/pages/Channel/EditChannel.js b/web/default/src/pages/Channel/EditChannel.js
index 64ff22f5..b967907e 100644
--- a/web/default/src/pages/Channel/EditChannel.js
+++ b/web/default/src/pages/Channel/EditChannel.js
@@ -170,7 +170,7 @@ const EditChannel = () => {
showInfo('请填写渠道名称和渠道密钥!');
return;
}
- if (inputs.models.length === 0) {
+ if (inputs.type !== 43 && inputs.models.length === 0) {
showInfo('请至少选择一个模型!');
return;
}
@@ -370,63 +370,75 @@ const EditChannel = () => {
)
}
-
- {
- copy(value).then();
- }}
- selection
- onChange={handleInputChange}
- value={inputs.models}
- autoComplete='new-password'
- options={modelOptions}
- />
-
-
-
-
-
- 填入
- }
- placeholder='输入自定义模型名称'
- value={customModel}
- onChange={(e, { value }) => {
- setCustomModel(value);
- }}
- onKeyDown={(e) => {
- if (e.key === 'Enter') {
- addCustomModel();
- e.preventDefault();
- }
- }}
- />
-
-
-
-
+ {
+ inputs.type !== 43 && (
+
+ {
+ copy(value).then();
+ }}
+ selection
+ onChange={handleInputChange}
+ value={inputs.models}
+ autoComplete='new-password'
+ options={modelOptions}
+ />
+
+ )
+ }
+ {
+ inputs.type !== 43 && (
+
+
+
+
+ 填入
+ }
+ placeholder='输入自定义模型名称'
+ value={customModel}
+ onChange={(e, { value }) => {
+ setCustomModel(value);
+ }}
+ onKeyDown={(e) => {
+ if (e.key === 'Enter') {
+ addCustomModel();
+ e.preventDefault();
+ }
+ }}
+ />
+
+ )
+ }
+ {
+ inputs.type !== 43 && (
+
+
+
+ )
+ }
{
inputs.type === 33 && (