Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
new-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
91f8d223
authored
Jul 23, 2023
by
JustSong
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: support zhipu's ChatGLM (close #289)
parent
005b2c2d
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
404 additions
and
49 deletions
+404
-49
README.md
+1
-2
common/constants.go
+2
-0
common/model-ratio.go
+6
-2
controller/model.go
+27
-18
controller/relay-text.go
+59
-6
controller/relay-zhipu.go
+290
-0
go.mod
+1
-2
go.sum
+2
-5
web/src/constants/channel.constants.js
+16
-14
No files found.
README.md
View file @
91f8d223
...
@@ -64,6 +64,7 @@ _✨ All in one 的 OpenAI 接口,整合各种 API 访问方式,开箱即用
...
@@ -64,6 +64,7 @@ _✨ All in one 的 OpenAI 接口,整合各种 API 访问方式,开箱即用
+
[
x
]
[
Anthropic Claude 系列模型
]
(https://anthropic.com)
+
[
x
]
[
Anthropic Claude 系列模型
]
(https://anthropic.com)
+
[
x
]
[
Google PaLM2 系列模型
]
(https://developers.generativeai.google)
+
[
x
]
[
Google PaLM2 系列模型
]
(https://developers.generativeai.google)
+
[
x
]
[
百度文心一言系列模型
]
(https://cloud.baidu.com/doc/WENXINWORKSHOP/index.html)
+
[
x
]
[
百度文心一言系列模型
]
(https://cloud.baidu.com/doc/WENXINWORKSHOP/index.html)
+
[
x
]
[
智谱 ChatGLM 系列模型
]
(https://bigmodel.cn)
+
[
x
]
[
API Distribute
]
(https://api.gptjk.top/register?aff=QGxj)
+
[
x
]
[
API Distribute
]
(https://api.gptjk.top/register?aff=QGxj)
+
[
x
]
[
OpenAI-SB
]
(https://openai-sb.com)
+
[
x
]
[
OpenAI-SB
]
(https://openai-sb.com)
+
[
x
]
[
API2D
]
(https://api2d.com/r/197971)
+
[
x
]
[
API2D
]
(https://api2d.com/r/197971)
...
@@ -95,8 +96,6 @@ _✨ All in one 的 OpenAI 接口,整合各种 API 访问方式,开箱即用
...
@@ -95,8 +96,6 @@ _✨ All in one 的 OpenAI 接口,整合各种 API 访问方式,开箱即用
+
邮箱登录注册以及通过邮箱进行密码重置。
+
邮箱登录注册以及通过邮箱进行密码重置。
+
[
GitHub 开放授权
](
https://github.com/settings/applications/new
)
。
+
[
GitHub 开放授权
](
https://github.com/settings/applications/new
)
。
+
微信公众号授权(需要额外部署
[
WeChat Server
](
https://github.com/songquanpeng/wechat-server
)
)。
+
微信公众号授权(需要额外部署
[
WeChat Server
](
https://github.com/songquanpeng/wechat-server
)
)。
21.
支持
[
ChatGLM
](
https://github.com/THUDM/ChatGLM2-6B
)
。
22.
未来其他大模型开放 API 后,将第一时间支持,并将其封装成同样的 API 访问方式。
## 部署
## 部署
### 基于 Docker 进行部署
### 基于 Docker 进行部署
...
...
common/constants.go
View file @
91f8d223
...
@@ -153,6 +153,7 @@ const (
...
@@ -153,6 +153,7 @@ const (
ChannelTypeAIGC2D
=
13
ChannelTypeAIGC2D
=
13
ChannelTypeAnthropic
=
14
ChannelTypeAnthropic
=
14
ChannelTypeBaidu
=
15
ChannelTypeBaidu
=
15
ChannelTypeZhipu
=
16
)
)
var
ChannelBaseURLs
=
[]
string
{
var
ChannelBaseURLs
=
[]
string
{
...
@@ -172,4 +173,5 @@ var ChannelBaseURLs = []string{
...
@@ -172,4 +173,5 @@ var ChannelBaseURLs = []string{
"https://api.aigc2d.com"
,
// 13
"https://api.aigc2d.com"
,
// 13
"https://api.anthropic.com"
,
// 14
"https://api.anthropic.com"
,
// 14
"https://aip.baidubce.com"
,
// 15
"https://aip.baidubce.com"
,
// 15
"https://open.bigmodel.cn"
,
// 16
}
}
common/model-ratio.go
View file @
91f8d223
...
@@ -8,6 +8,7 @@ import "encoding/json"
...
@@ -8,6 +8,7 @@ import "encoding/json"
// https://openai.com/pricing
// https://openai.com/pricing
// TODO: when a new api is enabled, check the pricing here
// TODO: when a new api is enabled, check the pricing here
// 1 === $0.002 / 1K tokens
// 1 === $0.002 / 1K tokens
// 1 === ¥0.014 / 1k tokens
var
ModelRatio
=
map
[
string
]
float64
{
var
ModelRatio
=
map
[
string
]
float64
{
"gpt-4"
:
15
,
"gpt-4"
:
15
,
"gpt-4-0314"
:
15
,
"gpt-4-0314"
:
15
,
...
@@ -39,9 +40,12 @@ var ModelRatio = map[string]float64{
...
@@ -39,9 +40,12 @@ var ModelRatio = map[string]float64{
"dall-e"
:
8
,
"dall-e"
:
8
,
"claude-instant-1"
:
0.75
,
"claude-instant-1"
:
0.75
,
"claude-2"
:
30
,
"claude-2"
:
30
,
"ERNIE-Bot"
:
1
,
// 0.012元/千
tokens
"ERNIE-Bot"
:
0.8572
,
// ¥0.012 / 1k
tokens
"ERNIE-Bot-turbo"
:
0.
67
,
// 0.008元/千
tokens
"ERNIE-Bot-turbo"
:
0.
5715
,
// ¥0.008 / 1k
tokens
"PaLM-2"
:
1
,
"PaLM-2"
:
1
,
"chatglm_pro"
:
0.7143
,
// ¥0.01 / 1k tokens
"chatglm_std"
:
0.3572
,
// ¥0.005 / 1k tokens
"chatglm_lite"
:
0.1429
,
// ¥0.002 / 1k tokens
}
}
func
ModelRatio2JSONString
()
string
{
func
ModelRatio2JSONString
()
string
{
...
...
controller/model.go
View file @
91f8d223
...
@@ -253,24 +253,6 @@ func init() {
...
@@ -253,24 +253,6 @@ func init() {
Parent
:
nil
,
Parent
:
nil
,
},
},
{
{
Id
:
"ChatGLM"
,
Object
:
"model"
,
Created
:
1677649963
,
OwnedBy
:
"thudm"
,
Permission
:
permission
,
Root
:
"ChatGLM"
,
Parent
:
nil
,
},
{
Id
:
"ChatGLM2"
,
Object
:
"model"
,
Created
:
1677649963
,
OwnedBy
:
"thudm"
,
Permission
:
permission
,
Root
:
"ChatGLM2"
,
Parent
:
nil
,
},
{
Id
:
"claude-instant-1"
,
Id
:
"claude-instant-1"
,
Object
:
"model"
,
Object
:
"model"
,
Created
:
1677649963
,
Created
:
1677649963
,
...
@@ -315,6 +297,33 @@ func init() {
...
@@ -315,6 +297,33 @@ func init() {
Root
:
"PaLM-2"
,
Root
:
"PaLM-2"
,
Parent
:
nil
,
Parent
:
nil
,
},
},
{
Id
:
"chatglm_pro"
,
Object
:
"model"
,
Created
:
1677649963
,
OwnedBy
:
"zhipu"
,
Permission
:
permission
,
Root
:
"chatglm_pro"
,
Parent
:
nil
,
},
{
Id
:
"chatglm_std"
,
Object
:
"model"
,
Created
:
1677649963
,
OwnedBy
:
"zhipu"
,
Permission
:
permission
,
Root
:
"chatglm_std"
,
Parent
:
nil
,
},
{
Id
:
"chatglm_lite"
,
Object
:
"model"
,
Created
:
1677649963
,
OwnedBy
:
"zhipu"
,
Permission
:
permission
,
Root
:
"chatglm_lite"
,
Parent
:
nil
,
},
}
}
openAIModelsMap
=
make
(
map
[
string
]
OpenAIModels
)
openAIModelsMap
=
make
(
map
[
string
]
OpenAIModels
)
for
_
,
model
:=
range
openAIModels
{
for
_
,
model
:=
range
openAIModels
{
...
...
controller/relay-text.go
View file @
91f8d223
...
@@ -19,6 +19,7 @@ const (
...
@@ -19,6 +19,7 @@ const (
APITypeClaude
APITypeClaude
APITypePaLM
APITypePaLM
APITypeBaidu
APITypeBaidu
APITypeZhipu
)
)
func
relayTextHelper
(
c
*
gin
.
Context
,
relayMode
int
)
*
OpenAIErrorWithStatusCode
{
func
relayTextHelper
(
c
*
gin
.
Context
,
relayMode
int
)
*
OpenAIErrorWithStatusCode
{
...
@@ -84,6 +85,8 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
...
@@ -84,6 +85,8 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
apiType
=
APITypeBaidu
apiType
=
APITypeBaidu
}
else
if
strings
.
HasPrefix
(
textRequest
.
Model
,
"PaLM"
)
{
}
else
if
strings
.
HasPrefix
(
textRequest
.
Model
,
"PaLM"
)
{
apiType
=
APITypePaLM
apiType
=
APITypePaLM
}
else
if
strings
.
HasPrefix
(
textRequest
.
Model
,
"chatglm_"
)
{
apiType
=
APITypeZhipu
}
}
baseURL
:=
common
.
ChannelBaseURLs
[
channelType
]
baseURL
:=
common
.
ChannelBaseURLs
[
channelType
]
requestURL
:=
c
.
Request
.
URL
.
String
()
requestURL
:=
c
.
Request
.
URL
.
String
()
...
@@ -134,6 +137,12 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
...
@@ -134,6 +137,12 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
apiKey
:=
c
.
Request
.
Header
.
Get
(
"Authorization"
)
apiKey
:=
c
.
Request
.
Header
.
Get
(
"Authorization"
)
apiKey
=
strings
.
TrimPrefix
(
apiKey
,
"Bearer "
)
apiKey
=
strings
.
TrimPrefix
(
apiKey
,
"Bearer "
)
fullRequestURL
+=
"?key="
+
apiKey
fullRequestURL
+=
"?key="
+
apiKey
case
APITypeZhipu
:
method
:=
"invoke"
if
textRequest
.
Stream
{
method
=
"sse-invoke"
}
fullRequestURL
=
fmt
.
Sprintf
(
"https://open.bigmodel.cn/api/paas/v3/model-api/%s/%s"
,
textRequest
.
Model
,
method
)
}
}
var
promptTokens
int
var
promptTokens
int
var
completionTokens
int
var
completionTokens
int
...
@@ -200,6 +209,13 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
...
@@ -200,6 +209,13 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
return
errorWrapper
(
err
,
"marshal_text_request_failed"
,
http
.
StatusInternalServerError
)
return
errorWrapper
(
err
,
"marshal_text_request_failed"
,
http
.
StatusInternalServerError
)
}
}
requestBody
=
bytes
.
NewBuffer
(
jsonStr
)
requestBody
=
bytes
.
NewBuffer
(
jsonStr
)
case
APITypeZhipu
:
zhipuRequest
:=
requestOpenAI2Zhipu
(
textRequest
)
jsonStr
,
err
:=
json
.
Marshal
(
zhipuRequest
)
if
err
!=
nil
{
return
errorWrapper
(
err
,
"marshal_text_request_failed"
,
http
.
StatusInternalServerError
)
}
requestBody
=
bytes
.
NewBuffer
(
jsonStr
)
}
}
req
,
err
:=
http
.
NewRequest
(
c
.
Request
.
Method
,
fullRequestURL
,
requestBody
)
req
,
err
:=
http
.
NewRequest
(
c
.
Request
.
Method
,
fullRequestURL
,
requestBody
)
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -221,6 +237,9 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
...
@@ -221,6 +237,9 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
anthropicVersion
=
"2023-06-01"
anthropicVersion
=
"2023-06-01"
}
}
req
.
Header
.
Set
(
"anthropic-version"
,
anthropicVersion
)
req
.
Header
.
Set
(
"anthropic-version"
,
anthropicVersion
)
case
APITypeZhipu
:
token
:=
getZhipuToken
(
apiKey
)
req
.
Header
.
Set
(
"Authorization"
,
token
)
}
}
req
.
Header
.
Set
(
"Content-Type"
,
c
.
Request
.
Header
.
Get
(
"Content-Type"
))
req
.
Header
.
Set
(
"Content-Type"
,
c
.
Request
.
Header
.
Get
(
"Content-Type"
))
req
.
Header
.
Set
(
"Accept"
,
c
.
Request
.
Header
.
Get
(
"Accept"
))
req
.
Header
.
Set
(
"Accept"
,
c
.
Request
.
Header
.
Get
(
"Accept"
))
...
@@ -252,11 +271,15 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
...
@@ -252,11 +271,15 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
if
strings
.
HasPrefix
(
textRequest
.
Model
,
"gpt-4"
)
{
if
strings
.
HasPrefix
(
textRequest
.
Model
,
"gpt-4"
)
{
completionRatio
=
2
completionRatio
=
2
}
}
if
isStream
&&
apiType
!=
APITypeBaidu
{
if
isStream
&&
apiType
!=
APITypeBaidu
&&
apiType
!=
APITypeZhipu
{
completionTokens
=
countTokenText
(
streamResponseText
,
textRequest
.
Model
)
completionTokens
=
countTokenText
(
streamResponseText
,
textRequest
.
Model
)
}
else
{
}
else
{
promptTokens
=
textResponse
.
Usage
.
PromptTokens
promptTokens
=
textResponse
.
Usage
.
PromptTokens
completionTokens
=
textResponse
.
Usage
.
CompletionTokens
completionTokens
=
textResponse
.
Usage
.
CompletionTokens
if
apiType
==
APITypeZhipu
{
// zhipu's API does not return prompt tokens & completion tokens
promptTokens
=
textResponse
.
Usage
.
TotalTokens
}
}
}
quota
=
promptTokens
+
int
(
float64
(
completionTokens
)
*
completionRatio
)
quota
=
promptTokens
+
int
(
float64
(
completionTokens
)
*
completionRatio
)
quota
=
int
(
float64
(
quota
)
*
ratio
)
quota
=
int
(
float64
(
quota
)
*
ratio
)
...
@@ -302,7 +325,9 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
...
@@ -302,7 +325,9 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
textResponse
.
Usage
=
*
usage
if
usage
!=
nil
{
textResponse
.
Usage
=
*
usage
}
return
nil
return
nil
}
}
case
APITypeClaude
:
case
APITypeClaude
:
...
@@ -318,7 +343,9 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
...
@@ -318,7 +343,9 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
textResponse
.
Usage
=
*
usage
if
usage
!=
nil
{
textResponse
.
Usage
=
*
usage
}
return
nil
return
nil
}
}
case
APITypeBaidu
:
case
APITypeBaidu
:
...
@@ -327,14 +354,18 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
...
@@ -327,14 +354,18 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
textResponse
.
Usage
=
*
usage
if
usage
!=
nil
{
textResponse
.
Usage
=
*
usage
}
return
nil
return
nil
}
else
{
}
else
{
err
,
usage
:=
baiduHandler
(
c
,
resp
)
err
,
usage
:=
baiduHandler
(
c
,
resp
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
textResponse
.
Usage
=
*
usage
if
usage
!=
nil
{
textResponse
.
Usage
=
*
usage
}
return
nil
return
nil
}
}
case
APITypePaLM
:
case
APITypePaLM
:
...
@@ -350,7 +381,29 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
...
@@ -350,7 +381,29 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
textResponse
.
Usage
=
*
usage
if
usage
!=
nil
{
textResponse
.
Usage
=
*
usage
}
return
nil
}
case
APITypeZhipu
:
if
isStream
{
err
,
usage
:=
zhipuStreamHandler
(
c
,
resp
)
if
err
!=
nil
{
return
err
}
if
usage
!=
nil
{
textResponse
.
Usage
=
*
usage
}
return
nil
}
else
{
err
,
usage
:=
zhipuHandler
(
c
,
resp
)
if
err
!=
nil
{
return
err
}
if
usage
!=
nil
{
textResponse
.
Usage
=
*
usage
}
return
nil
return
nil
}
}
default
:
default
:
...
...
controller/relay-zhipu.go
0 → 100644
View file @
91f8d223
package
controller
import
(
"bufio"
"encoding/json"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt"
"io"
"net/http"
"one-api/common"
"strings"
"sync"
"time"
)
// https://open.bigmodel.cn/doc/api#chatglm_std
// chatglm_std, chatglm_lite
// https://open.bigmodel.cn/api/paas/v3/model-api/chatglm_std/invoke
// https://open.bigmodel.cn/api/paas/v3/model-api/chatglm_std/sse-invoke
type
ZhipuMessage
struct
{
Role
string
`json:"role"`
Content
string
`json:"content"`
}
type
ZhipuRequest
struct
{
Prompt
[]
ZhipuMessage
`json:"prompt"`
Temperature
float64
`json:"temperature,omitempty"`
TopP
float64
`json:"top_p,omitempty"`
RequestId
string
`json:"request_id,omitempty"`
Incremental
bool
`json:"incremental,omitempty"`
}
type
ZhipuResponseData
struct
{
TaskId
string
`json:"task_id"`
RequestId
string
`json:"request_id"`
TaskStatus
string
`json:"task_status"`
Choices
[]
ZhipuMessage
`json:"choices"`
Usage
`json:"usage"`
}
type
ZhipuResponse
struct
{
Code
int
`json:"code"`
Msg
string
`json:"msg"`
Success
bool
`json:"success"`
Data
ZhipuResponseData
`json:"data"`
}
type
ZhipuStreamMetaResponse
struct
{
RequestId
string
`json:"request_id"`
TaskId
string
`json:"task_id"`
TaskStatus
string
`json:"task_status"`
Usage
`json:"usage"`
}
type
zhipuTokenData
struct
{
Token
string
ExpiryTime
time
.
Time
}
var
zhipuTokens
sync
.
Map
var
expSeconds
int64
=
24
*
3600
func
getZhipuToken
(
apikey
string
)
string
{
data
,
ok
:=
zhipuTokens
.
Load
(
apikey
)
if
ok
{
tokenData
:=
data
.
(
zhipuTokenData
)
if
time
.
Now
()
.
Before
(
tokenData
.
ExpiryTime
)
{
return
tokenData
.
Token
}
}
split
:=
strings
.
Split
(
apikey
,
"."
)
if
len
(
split
)
!=
2
{
common
.
SysError
(
"invalid zhipu key: "
+
apikey
)
return
""
}
id
:=
split
[
0
]
secret
:=
split
[
1
]
expMillis
:=
time
.
Now
()
.
Add
(
time
.
Duration
(
expSeconds
)
*
time
.
Second
)
.
UnixNano
()
/
1e6
expiryTime
:=
time
.
Now
()
.
Add
(
time
.
Duration
(
expSeconds
)
*
time
.
Second
)
timestamp
:=
time
.
Now
()
.
UnixNano
()
/
1e6
payload
:=
jwt
.
MapClaims
{
"api_key"
:
id
,
"exp"
:
expMillis
,
"timestamp"
:
timestamp
,
}
token
:=
jwt
.
NewWithClaims
(
jwt
.
SigningMethodHS256
,
payload
)
token
.
Header
[
"alg"
]
=
"HS256"
token
.
Header
[
"sign_type"
]
=
"SIGN"
tokenString
,
err
:=
token
.
SignedString
([]
byte
(
secret
))
if
err
!=
nil
{
return
""
}
zhipuTokens
.
Store
(
apikey
,
zhipuTokenData
{
Token
:
tokenString
,
ExpiryTime
:
expiryTime
,
})
return
tokenString
}
func
requestOpenAI2Zhipu
(
request
GeneralOpenAIRequest
)
*
ZhipuRequest
{
messages
:=
make
([]
ZhipuMessage
,
0
,
len
(
request
.
Messages
))
for
_
,
message
:=
range
request
.
Messages
{
messages
=
append
(
messages
,
ZhipuMessage
{
Role
:
message
.
Role
,
Content
:
message
.
Content
,
})
}
return
&
ZhipuRequest
{
Prompt
:
messages
,
Temperature
:
request
.
Temperature
,
TopP
:
request
.
TopP
,
Incremental
:
false
,
}
}
func
responseZhipu2OpenAI
(
response
*
ZhipuResponse
)
*
OpenAITextResponse
{
fullTextResponse
:=
OpenAITextResponse
{
Id
:
response
.
Data
.
TaskId
,
Object
:
"chat.completion"
,
Created
:
common
.
GetTimestamp
(),
Choices
:
make
([]
OpenAITextResponseChoice
,
0
,
len
(
response
.
Data
.
Choices
)),
Usage
:
response
.
Data
.
Usage
,
}
for
i
,
choice
:=
range
response
.
Data
.
Choices
{
openaiChoice
:=
OpenAITextResponseChoice
{
Index
:
i
,
Message
:
Message
{
Role
:
choice
.
Role
,
Content
:
strings
.
Trim
(
choice
.
Content
,
"
\"
"
),
},
FinishReason
:
""
,
}
if
i
==
len
(
response
.
Data
.
Choices
)
-
1
{
openaiChoice
.
FinishReason
=
"stop"
}
fullTextResponse
.
Choices
=
append
(
fullTextResponse
.
Choices
,
openaiChoice
)
}
return
&
fullTextResponse
}
func
streamResponseZhipu2OpenAI
(
zhipuResponse
string
)
*
ChatCompletionsStreamResponse
{
var
choice
ChatCompletionsStreamResponseChoice
choice
.
Delta
.
Content
=
zhipuResponse
choice
.
FinishReason
=
""
response
:=
ChatCompletionsStreamResponse
{
Object
:
"chat.completion.chunk"
,
Created
:
common
.
GetTimestamp
(),
Model
:
"chatglm"
,
Choices
:
[]
ChatCompletionsStreamResponseChoice
{
choice
},
}
return
&
response
}
func
streamMetaResponseZhipu2OpenAI
(
zhipuResponse
*
ZhipuStreamMetaResponse
)
(
*
ChatCompletionsStreamResponse
,
*
Usage
)
{
var
choice
ChatCompletionsStreamResponseChoice
choice
.
Delta
.
Content
=
""
choice
.
FinishReason
=
"stop"
response
:=
ChatCompletionsStreamResponse
{
Id
:
zhipuResponse
.
RequestId
,
Object
:
"chat.completion.chunk"
,
Created
:
common
.
GetTimestamp
(),
Model
:
"chatglm"
,
Choices
:
[]
ChatCompletionsStreamResponseChoice
{
choice
},
}
return
&
response
,
&
zhipuResponse
.
Usage
}
func
zhipuStreamHandler
(
c
*
gin
.
Context
,
resp
*
http
.
Response
)
(
*
OpenAIErrorWithStatusCode
,
*
Usage
)
{
var
usage
*
Usage
scanner
:=
bufio
.
NewScanner
(
resp
.
Body
)
scanner
.
Split
(
func
(
data
[]
byte
,
atEOF
bool
)
(
advance
int
,
token
[]
byte
,
err
error
)
{
if
atEOF
&&
len
(
data
)
==
0
{
return
0
,
nil
,
nil
}
if
i
:=
strings
.
Index
(
string
(
data
),
"
\n
"
);
i
>=
0
{
return
i
+
1
,
data
[
0
:
i
],
nil
}
if
atEOF
{
return
len
(
data
),
data
,
nil
}
return
0
,
nil
,
nil
})
dataChan
:=
make
(
chan
string
)
metaChan
:=
make
(
chan
string
)
stopChan
:=
make
(
chan
bool
)
go
func
()
{
for
scanner
.
Scan
()
{
data
:=
scanner
.
Text
()
data
=
strings
.
Trim
(
data
,
"
\"
"
)
if
len
(
data
)
<
5
{
// ignore blank line or wrong format
continue
}
if
data
[
:
5
]
==
"data:"
{
dataChan
<-
data
[
5
:
]
}
else
if
data
[
:
5
]
==
"meta:"
{
metaChan
<-
data
[
5
:
]
}
}
stopChan
<-
true
}()
c
.
Writer
.
Header
()
.
Set
(
"Content-Type"
,
"text/event-stream"
)
c
.
Writer
.
Header
()
.
Set
(
"Cache-Control"
,
"no-cache"
)
c
.
Writer
.
Header
()
.
Set
(
"Connection"
,
"keep-alive"
)
c
.
Writer
.
Header
()
.
Set
(
"Transfer-Encoding"
,
"chunked"
)
c
.
Writer
.
Header
()
.
Set
(
"X-Accel-Buffering"
,
"no"
)
c
.
Stream
(
func
(
w
io
.
Writer
)
bool
{
select
{
case
data
:=
<-
dataChan
:
response
:=
streamResponseZhipu2OpenAI
(
data
)
jsonResponse
,
err
:=
json
.
Marshal
(
response
)
if
err
!=
nil
{
common
.
SysError
(
"error marshalling stream response: "
+
err
.
Error
())
return
true
}
c
.
Render
(
-
1
,
common
.
CustomEvent
{
Data
:
"data: "
+
string
(
jsonResponse
)})
return
true
case
data
:=
<-
metaChan
:
var
zhipuResponse
ZhipuStreamMetaResponse
err
:=
json
.
Unmarshal
([]
byte
(
data
),
&
zhipuResponse
)
if
err
!=
nil
{
common
.
SysError
(
"error unmarshalling stream response: "
+
err
.
Error
())
return
true
}
response
,
zhipuUsage
:=
streamMetaResponseZhipu2OpenAI
(
&
zhipuResponse
)
jsonResponse
,
err
:=
json
.
Marshal
(
response
)
if
err
!=
nil
{
common
.
SysError
(
"error marshalling stream response: "
+
err
.
Error
())
return
true
}
usage
=
zhipuUsage
c
.
Render
(
-
1
,
common
.
CustomEvent
{
Data
:
"data: "
+
string
(
jsonResponse
)})
return
true
case
<-
stopChan
:
c
.
Render
(
-
1
,
common
.
CustomEvent
{
Data
:
"data: [DONE]"
})
return
false
}
})
err
:=
resp
.
Body
.
Close
()
if
err
!=
nil
{
return
errorWrapper
(
err
,
"close_response_body_failed"
,
http
.
StatusInternalServerError
),
nil
}
return
nil
,
usage
}
func
zhipuHandler
(
c
*
gin
.
Context
,
resp
*
http
.
Response
)
(
*
OpenAIErrorWithStatusCode
,
*
Usage
)
{
var
zhipuResponse
ZhipuResponse
responseBody
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
if
err
!=
nil
{
return
errorWrapper
(
err
,
"read_response_body_failed"
,
http
.
StatusInternalServerError
),
nil
}
err
=
resp
.
Body
.
Close
()
if
err
!=
nil
{
return
errorWrapper
(
err
,
"close_response_body_failed"
,
http
.
StatusInternalServerError
),
nil
}
err
=
json
.
Unmarshal
(
responseBody
,
&
zhipuResponse
)
if
err
!=
nil
{
return
errorWrapper
(
err
,
"unmarshal_response_body_failed"
,
http
.
StatusInternalServerError
),
nil
}
if
!
zhipuResponse
.
Success
{
return
&
OpenAIErrorWithStatusCode
{
OpenAIError
:
OpenAIError
{
Message
:
zhipuResponse
.
Msg
,
Type
:
"zhipu_error"
,
Param
:
""
,
Code
:
zhipuResponse
.
Code
,
},
StatusCode
:
resp
.
StatusCode
,
},
nil
}
fullTextResponse
:=
responseZhipu2OpenAI
(
&
zhipuResponse
)
jsonResponse
,
err
:=
json
.
Marshal
(
fullTextResponse
)
if
err
!=
nil
{
return
errorWrapper
(
err
,
"marshal_response_body_failed"
,
http
.
StatusInternalServerError
),
nil
}
c
.
Writer
.
Header
()
.
Set
(
"Content-Type"
,
"application/json"
)
c
.
Writer
.
WriteHeader
(
resp
.
StatusCode
)
_
,
err
=
c
.
Writer
.
Write
(
jsonResponse
)
return
nil
,
&
fullTextResponse
.
Usage
}
go.mod
View file @
91f8d223
...
@@ -11,6 +11,7 @@ require (
...
@@ -11,6 +11,7 @@ require (
github.com/gin-gonic/gin v1.9.1
github.com/gin-gonic/gin v1.9.1
github.com/go-playground/validator/v10 v10.14.0
github.com/go-playground/validator/v10 v10.14.0
github.com/go-redis/redis/v8 v8.11.5
github.com/go-redis/redis/v8 v8.11.5
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/google/uuid v1.3.0
github.com/google/uuid v1.3.0
github.com/pkoukk/tiktoken-go v0.1.1
github.com/pkoukk/tiktoken-go v0.1.1
golang.org/x/crypto v0.9.0
golang.org/x/crypto v0.9.0
...
@@ -20,7 +21,6 @@ require (
...
@@ -20,7 +21,6 @@ require (
)
)
require (
require (
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff // indirect
github.com/bytedance/sonic v1.9.1 // indirect
github.com/bytedance/sonic v1.9.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
...
@@ -32,7 +32,6 @@ require (
...
@@ -32,7 +32,6 @@ require (
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/gomodule/redigo v2.0.0+incompatible // indirect
github.com/gorilla/context v1.1.1 // indirect
github.com/gorilla/context v1.1.1 // indirect
github.com/gorilla/securecookie v1.1.1 // indirect
github.com/gorilla/securecookie v1.1.1 // indirect
github.com/gorilla/sessions v1.2.1 // indirect
github.com/gorilla/sessions v1.2.1 // indirect
...
...
go.sum
View file @
91f8d223
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff h1:RmdPFa+slIr4SCBg4st/l/vZWVe9QJKMXGO60Bxbe04=
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P97fT2CiHkbFQwkK3mjsFAP6zCYV2aXtjw=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
...
@@ -54,10 +52,10 @@ github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB
...
@@ -54,10 +52,10 @@ github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
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/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
...
@@ -67,7 +65,6 @@ github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8
...
@@ -67,7 +65,6 @@ github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
...
...
web/src/constants/channel.constants.js
View file @
91f8d223
export
const
CHANNEL_OPTIONS
=
[
export
const
CHANNEL_OPTIONS
=
[
{
key
:
1
,
text
:
'OpenAI'
,
value
:
1
,
color
:
'green'
},
{
key
:
1
,
text
:
'OpenAI'
,
value
:
1
,
color
:
'green'
},
{
key
:
14
,
text
:
'Anthropic'
,
value
:
14
,
color
:
'black'
},
{
key
:
14
,
text
:
'Anthropic Claude'
,
value
:
14
,
color
:
'black'
},
{
key
:
8
,
text
:
'自定义'
,
value
:
8
,
color
:
'pink'
},
{
key
:
3
,
text
:
'Azure OpenAI'
,
value
:
3
,
color
:
'olive'
},
{
key
:
3
,
text
:
'Azure'
,
value
:
3
,
color
:
'olive'
},
{
key
:
11
,
text
:
'Google PaLM2'
,
value
:
11
,
color
:
'orange'
},
{
key
:
11
,
text
:
'PaLM'
,
value
:
11
,
color
:
'orange'
},
{
key
:
15
,
text
:
'百度文心千帆'
,
value
:
15
,
color
:
'blue'
},
{
key
:
15
,
text
:
'Baidu'
,
value
:
15
,
color
:
'blue'
},
{
key
:
16
,
text
:
'智谱 ChatGLM'
,
value
:
16
,
color
:
'violet'
},
{
key
:
2
,
text
:
'API2D'
,
value
:
2
,
color
:
'blue'
},
{
key
:
8
,
text
:
'自定义渠道'
,
value
:
8
,
color
:
'pink'
},
{
key
:
4
,
text
:
'CloseAI'
,
value
:
4
,
color
:
'teal'
},
{
key
:
2
,
text
:
'代理:API2D'
,
value
:
2
,
color
:
'blue'
},
{
key
:
5
,
text
:
'OpenAI-SB'
,
value
:
5
,
color
:
'brown'
},
{
key
:
5
,
text
:
'代理:OpenAI-SB'
,
value
:
5
,
color
:
'brown'
},
{
key
:
6
,
text
:
'OpenAI Max'
,
value
:
6
,
color
:
'violet'
},
{
key
:
7
,
text
:
'代理:OhMyGPT'
,
value
:
7
,
color
:
'purple'
},
{
key
:
7
,
text
:
'OhMyGPT'
,
value
:
7
,
color
:
'purple'
},
{
key
:
10
,
text
:
'代理:AI Proxy'
,
value
:
10
,
color
:
'purple'
},
{
key
:
9
,
text
:
'AI.LS'
,
value
:
9
,
color
:
'yellow'
},
{
key
:
4
,
text
:
'代理:CloseAI'
,
value
:
4
,
color
:
'teal'
},
{
key
:
10
,
text
:
'AI Proxy'
,
value
:
10
,
color
:
'purple'
},
{
key
:
6
,
text
:
'代理:OpenAI Max'
,
value
:
6
,
color
:
'violet'
},
{
key
:
12
,
text
:
'API2GPT'
,
value
:
12
,
color
:
'blue'
},
{
key
:
9
,
text
:
'代理:AI.LS'
,
value
:
9
,
color
:
'yellow'
},
{
key
:
13
,
text
:
'AIGC2D'
,
value
:
13
,
color
:
'purple'
}
{
key
:
12
,
text
:
'代理:API2GPT'
,
value
:
12
,
color
:
'blue'
},
{
key
:
13
,
text
:
'代理:AIGC2D'
,
value
:
13
,
color
:
'purple'
}
];
];
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment