⚡️ feat: channel support plugin settings (#89)
This commit is contained in:
parent
41134576f2
commit
d8d880bf85
@ -110,13 +110,7 @@ func init() {
|
|||||||
"gemini-pro-vision": {[]float64{1, 1}, ChannelTypeGemini},
|
"gemini-pro-vision": {[]float64{1, 1}, ChannelTypeGemini},
|
||||||
|
|
||||||
// ¥0.005 / 1k tokens
|
// ¥0.005 / 1k tokens
|
||||||
"chatglm_turbo": {[]float64{0.3572, 0.3572}, ChannelTypeZhipu},
|
|
||||||
"chatglm_std": {[]float64{0.3572, 0.3572}, ChannelTypeZhipu},
|
|
||||||
"glm-3-turbo": {[]float64{0.3572, 0.3572}, ChannelTypeZhipu},
|
"glm-3-turbo": {[]float64{0.3572, 0.3572}, ChannelTypeZhipu},
|
||||||
// ¥0.01 / 1k tokens
|
|
||||||
"chatglm_pro": {[]float64{0.7143, 0.7143}, ChannelTypeZhipu},
|
|
||||||
// ¥0.002 / 1k tokens
|
|
||||||
"chatglm_lite": {[]float64{0.1429, 0.1429}, ChannelTypeZhipu},
|
|
||||||
// ¥0.1 / 1k tokens
|
// ¥0.1 / 1k tokens
|
||||||
"glm-4": {[]float64{7.143, 7.143}, ChannelTypeZhipu},
|
"glm-4": {[]float64{7.143, 7.143}, ChannelTypeZhipu},
|
||||||
"glm-4v": {[]float64{7.143, 7.143}, ChannelTypeZhipu},
|
"glm-4v": {[]float64{7.143, 7.143}, ChannelTypeZhipu},
|
||||||
|
@ -55,6 +55,9 @@ func init() {
|
|||||||
common.ChannelType360: "360",
|
common.ChannelType360: "360",
|
||||||
common.ChannelTypeTencent: "Tencent",
|
common.ChannelTypeTencent: "Tencent",
|
||||||
common.ChannelTypeBaichuan: "Baichuan",
|
common.ChannelTypeBaichuan: "Baichuan",
|
||||||
|
common.ChannelTypeMiniMax: "MiniMax",
|
||||||
|
common.ChannelTypeDeepseek: "Deepseek",
|
||||||
|
common.ChannelTypeMoonshot: "Moonshot",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
5
go.mod
5
go.mod
@ -18,7 +18,7 @@ require (
|
|||||||
github.com/stretchr/testify v1.8.3
|
github.com/stretchr/testify v1.8.3
|
||||||
golang.org/x/crypto v0.17.0
|
golang.org/x/crypto v0.17.0
|
||||||
golang.org/x/image v0.14.0
|
golang.org/x/image v0.14.0
|
||||||
gorm.io/driver/mysql v1.4.3
|
gorm.io/driver/mysql v1.4.7
|
||||||
gorm.io/driver/postgres v1.5.2
|
gorm.io/driver/postgres v1.5.2
|
||||||
gorm.io/driver/sqlite v1.4.3
|
gorm.io/driver/sqlite v1.4.3
|
||||||
gorm.io/gorm v1.25.0
|
gorm.io/gorm v1.25.0
|
||||||
@ -36,7 +36,7 @@ require (
|
|||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
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.7.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.2 // indirect
|
github.com/goccy/go-json v0.10.2 // 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
|
||||||
@ -64,4 +64,5 @@ require (
|
|||||||
golang.org/x/text v0.14.0 // indirect
|
golang.org/x/text v0.14.0 // indirect
|
||||||
google.golang.org/protobuf v1.30.0 // indirect
|
google.golang.org/protobuf v1.30.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
gorm.io/datatypes v1.2.0
|
||||||
)
|
)
|
||||||
|
6
go.sum
6
go.sum
@ -51,6 +51,8 @@ github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC
|
|||||||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
|
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
|
||||||
|
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||||
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=
|
||||||
@ -199,8 +201,12 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
|
|||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gorm.io/datatypes v1.2.0 h1:5YT+eokWdIxhJgWHdrb2zYUimyk0+TaFth+7a0ybzco=
|
||||||
|
gorm.io/datatypes v1.2.0/go.mod h1:o1dh0ZvjIjhH/bngTpypG6lVRJ5chTBxE09FH/71k04=
|
||||||
gorm.io/driver/mysql v1.4.3 h1:/JhWJhO2v17d8hjApTltKNADm7K7YI2ogkR7avJUL3k=
|
gorm.io/driver/mysql v1.4.3 h1:/JhWJhO2v17d8hjApTltKNADm7K7YI2ogkR7avJUL3k=
|
||||||
gorm.io/driver/mysql v1.4.3/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c=
|
gorm.io/driver/mysql v1.4.3/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c=
|
||||||
|
gorm.io/driver/mysql v1.4.7 h1:rY46lkCspzGHn7+IYsNpSfEv9tA+SU4SkkB+GFX125Y=
|
||||||
|
gorm.io/driver/mysql v1.4.7/go.mod h1:SxzItlnT1cb6e1e4ZRpgJN2VYtcqJgqnHxWr4wsP8oc=
|
||||||
gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0=
|
gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0=
|
||||||
gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8=
|
gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8=
|
||||||
gorm.io/driver/sqlite v1.4.3 h1:HBBcZSDnWi5BW3B3rwvVTc510KGkBkexlOg0QrmLUuU=
|
gorm.io/driver/sqlite v1.4.3 h1:HBBcZSDnWi5BW3B3rwvVTc510KGkBkexlOg0QrmLUuU=
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"one-api/common"
|
"one-api/common"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"gorm.io/datatypes"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -28,8 +29,12 @@ type Channel struct {
|
|||||||
Priority *int64 `json:"priority" gorm:"bigint;default:0"`
|
Priority *int64 `json:"priority" gorm:"bigint;default:0"`
|
||||||
Proxy *string `json:"proxy" gorm:"type:varchar(255);default:''"`
|
Proxy *string `json:"proxy" gorm:"type:varchar(255);default:''"`
|
||||||
TestModel string `json:"test_model" form:"test_model" gorm:"type:varchar(50);default:''"`
|
TestModel string `json:"test_model" form:"test_model" gorm:"type:varchar(50);default:''"`
|
||||||
|
|
||||||
|
Plugin *datatypes.JSONType[PluginType] `json:"plugin" form:"plugin" gorm:"type:json"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PluginType map[string]map[string]interface{}
|
||||||
|
|
||||||
var allowedChannelOrderFields = map[string]bool{
|
var allowedChannelOrderFields = map[string]bool{
|
||||||
"id": true,
|
"id": true,
|
||||||
"name": true,
|
"name": true,
|
||||||
|
@ -15,8 +15,6 @@ type aliStreamHandler struct {
|
|||||||
lastStreamResponse string
|
lastStreamResponse string
|
||||||
}
|
}
|
||||||
|
|
||||||
const AliEnableSearchModelSuffix = "-internet"
|
|
||||||
|
|
||||||
func (p *AliProvider) CreateChatCompletion(request *types.ChatCompletionRequest) (*types.ChatCompletionResponse, *types.OpenAIErrorWithStatusCode) {
|
func (p *AliProvider) CreateChatCompletion(request *types.ChatCompletionRequest) (*types.ChatCompletionResponse, *types.OpenAIErrorWithStatusCode) {
|
||||||
req, errWithCode := p.getAliChatRequest(request)
|
req, errWithCode := p.getAliChatRequest(request)
|
||||||
if errWithCode != nil {
|
if errWithCode != nil {
|
||||||
@ -70,7 +68,7 @@ func (p *AliProvider) getAliChatRequest(request *types.ChatCompletionRequest) (*
|
|||||||
headers["X-DashScope-SSE"] = "enable"
|
headers["X-DashScope-SSE"] = "enable"
|
||||||
}
|
}
|
||||||
|
|
||||||
aliRequest := convertFromChatOpenai(request)
|
aliRequest := p.convertFromChatOpenai(request)
|
||||||
// 创建请求
|
// 创建请求
|
||||||
req, err := p.Requester.NewRequest(http.MethodPost, fullRequestURL, p.Requester.WithBody(aliRequest), p.Requester.WithHeader(headers))
|
req, err := p.Requester.NewRequest(http.MethodPost, fullRequestURL, p.Requester.WithBody(aliRequest), p.Requester.WithHeader(headers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -110,7 +108,7 @@ func (p *AliProvider) convertToChatOpenai(response *AliChatResponse, request *ty
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 阿里云聊天请求体
|
// 阿里云聊天请求体
|
||||||
func convertFromChatOpenai(request *types.ChatCompletionRequest) *AliChatRequest {
|
func (p *AliProvider) convertFromChatOpenai(request *types.ChatCompletionRequest) *AliChatRequest {
|
||||||
messages := make([]AliMessage, 0, len(request.Messages))
|
messages := make([]AliMessage, 0, len(request.Messages))
|
||||||
for i := 0; i < len(request.Messages); i++ {
|
for i := 0; i < len(request.Messages); i++ {
|
||||||
message := request.Messages[i]
|
message := request.Messages[i]
|
||||||
@ -141,24 +139,35 @@ func convertFromChatOpenai(request *types.ChatCompletionRequest) *AliChatRequest
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enableSearch := false
|
aliChatRequest := &AliChatRequest{
|
||||||
aliModel := request.Model
|
Model: request.Model,
|
||||||
if strings.HasSuffix(aliModel, AliEnableSearchModelSuffix) {
|
|
||||||
enableSearch = true
|
|
||||||
aliModel = strings.TrimSuffix(aliModel, AliEnableSearchModelSuffix)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &AliChatRequest{
|
|
||||||
Model: aliModel,
|
|
||||||
Input: AliInput{
|
Input: AliInput{
|
||||||
Messages: messages,
|
Messages: messages,
|
||||||
},
|
},
|
||||||
Parameters: AliParameters{
|
Parameters: AliParameters{
|
||||||
ResultFormat: "message",
|
ResultFormat: "message",
|
||||||
EnableSearch: enableSearch,
|
|
||||||
IncrementalOutput: request.Stream,
|
IncrementalOutput: request.Stream,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.pluginHandle(aliChatRequest)
|
||||||
|
|
||||||
|
return aliChatRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *AliProvider) pluginHandle(request *AliChatRequest) {
|
||||||
|
if p.Channel.Plugin == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin := p.Channel.Plugin.Data()
|
||||||
|
|
||||||
|
// 检测是否开启了 web_search 插件
|
||||||
|
if pWeb, ok := plugin["web_search"]; ok {
|
||||||
|
if enable, ok := pWeb["enable"].(bool); ok && enable {
|
||||||
|
request.Parameters.EnableSearch = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 转换为OpenAI聊天流式请求体
|
// 转换为OpenAI聊天流式请求体
|
||||||
@ -185,11 +194,11 @@ func (h *aliStreamHandler) handlerStream(rawLine *[]byte, dataChan chan string,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
h.convertToOpenaiStream(&aliResponse, dataChan, errChan)
|
h.convertToOpenaiStream(&aliResponse, dataChan)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *aliStreamHandler) convertToOpenaiStream(aliResponse *AliChatResponse, dataChan chan string, errChan chan error) {
|
func (h *aliStreamHandler) convertToOpenaiStream(aliResponse *AliChatResponse, dataChan chan string) {
|
||||||
content := aliResponse.Output.Choices[0].Message.StringContent()
|
content := aliResponse.Output.Choices[0].Message.StringContent()
|
||||||
|
|
||||||
var choice types.ChatCompletionStreamChoice
|
var choice types.ChatCompletionStreamChoice
|
||||||
|
@ -220,10 +220,10 @@ func (h *minimaxStreamHandler) handlerStream(rawLine *[]byte, dataChan chan stri
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
h.convertToOpenaiStream(miniResponse, dataChan, errChan)
|
h.convertToOpenaiStream(miniResponse, dataChan)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *minimaxStreamHandler) convertToOpenaiStream(miniResponse *MiniMaxChatResponse, dataChan chan string, errChan chan error) {
|
func (h *minimaxStreamHandler) convertToOpenaiStream(miniResponse *MiniMaxChatResponse, dataChan chan string) {
|
||||||
streamResponse := types.ChatCompletionStreamResponse{
|
streamResponse := types.ChatCompletionStreamResponse{
|
||||||
ID: miniResponse.RequestID,
|
ID: miniResponse.RequestID,
|
||||||
Object: "chat.completion.chunk",
|
Object: "chat.completion.chunk",
|
||||||
|
@ -165,11 +165,11 @@ func (h *palmStreamHandler) handlerStream(rawLine *[]byte, dataChan chan string,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
h.convertToOpenaiStream(&palmChatResponse, dataChan, errChan)
|
h.convertToOpenaiStream(&palmChatResponse, dataChan)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *palmStreamHandler) convertToOpenaiStream(palmChatResponse *PaLMChatResponse, dataChan chan string, errChan chan error) {
|
func (h *palmStreamHandler) convertToOpenaiStream(palmChatResponse *PaLMChatResponse, dataChan chan string) {
|
||||||
var choice types.ChatCompletionStreamChoice
|
var choice types.ChatCompletionStreamChoice
|
||||||
if len(palmChatResponse.Candidates) > 0 {
|
if len(palmChatResponse.Candidates) > 0 {
|
||||||
choice.Delta.Content = palmChatResponse.Candidates[0].Content
|
choice.Delta.Content = palmChatResponse.Candidates[0].Content
|
||||||
|
@ -180,11 +180,11 @@ func (h *tencentStreamHandler) handlerStream(rawLine *[]byte, dataChan chan stri
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
h.convertToOpenaiStream(&tencentChatResponse, dataChan, errChan)
|
h.convertToOpenaiStream(&tencentChatResponse, dataChan)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *tencentStreamHandler) convertToOpenaiStream(tencentChatResponse *TencentChatResponse, dataChan chan string, errChan chan error) {
|
func (h *tencentStreamHandler) convertToOpenaiStream(tencentChatResponse *TencentChatResponse, dataChan chan string) {
|
||||||
streamResponse := types.ChatCompletionStreamResponse{
|
streamResponse := types.ChatCompletionStreamResponse{
|
||||||
Object: "chat.completion.chunk",
|
Object: "chat.completion.chunk",
|
||||||
Created: common.GetTimestamp(),
|
Created: common.GetTimestamp(),
|
||||||
|
@ -256,7 +256,7 @@ func (h *xunfeiHandler) handlerStream(rawLine *[]byte, dataChan chan string, err
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
h.convertToOpenaiStream(xunfeiChatResponse, dataChan, errChan)
|
h.convertToOpenaiStream(xunfeiChatResponse, dataChan)
|
||||||
|
|
||||||
if isFinished {
|
if isFinished {
|
||||||
errChan <- io.EOF
|
errChan <- io.EOF
|
||||||
@ -264,7 +264,7 @@ func (h *xunfeiHandler) handlerStream(rawLine *[]byte, dataChan chan string, err
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *xunfeiHandler) convertToOpenaiStream(xunfeiChatResponse *XunfeiChatResponse, dataChan chan string, errChan chan error) {
|
func (h *xunfeiHandler) convertToOpenaiStream(xunfeiChatResponse *XunfeiChatResponse, dataChan chan string) {
|
||||||
if len(xunfeiChatResponse.Payload.Choices.Text) == 0 {
|
if len(xunfeiChatResponse.Payload.Choices.Text) == 0 {
|
||||||
xunfeiChatResponse.Payload.Choices.Text = []XunfeiChatResponseTextItem{{}}
|
xunfeiChatResponse.Payload.Choices.Text = []XunfeiChatResponseTextItem{{}}
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,6 @@ func (p *ZhipuProvider) GetRequestHeaders() (headers map[string]string) {
|
|||||||
headers = make(map[string]string)
|
headers = make(map[string]string)
|
||||||
p.CommonRequestHeaders(headers)
|
p.CommonRequestHeaders(headers)
|
||||||
headers["Authorization"] = p.getZhipuToken()
|
headers["Authorization"] = p.getZhipuToken()
|
||||||
|
|
||||||
return headers
|
return headers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ func (p *ZhipuProvider) getChatRequest(request *types.ChatCompletionRequest) (*h
|
|||||||
// 获取请求头
|
// 获取请求头
|
||||||
headers := p.GetRequestHeaders()
|
headers := p.GetRequestHeaders()
|
||||||
|
|
||||||
zhipuRequest := convertFromChatOpenai(request)
|
zhipuRequest := p.convertFromChatOpenai(request)
|
||||||
|
|
||||||
// 创建请求
|
// 创建请求
|
||||||
req, err := p.Requester.NewRequest(http.MethodPost, fullRequestURL, p.Requester.WithBody(zhipuRequest), p.Requester.WithHeader(headers))
|
req, err := p.Requester.NewRequest(http.MethodPost, fullRequestURL, p.Requester.WithBody(zhipuRequest), p.Requester.WithHeader(headers))
|
||||||
@ -94,7 +94,7 @@ func (p *ZhipuProvider) convertToChatOpenai(response *ZhipuResponse, request *ty
|
|||||||
ID: response.ID,
|
ID: response.ID,
|
||||||
Object: "chat.completion",
|
Object: "chat.completion",
|
||||||
Created: response.Created,
|
Created: response.Created,
|
||||||
Model: response.Model,
|
Model: request.Model,
|
||||||
Choices: response.Choices,
|
Choices: response.Choices,
|
||||||
Usage: response.Usage,
|
Usage: response.Usage,
|
||||||
}
|
}
|
||||||
@ -104,7 +104,7 @@ func (p *ZhipuProvider) convertToChatOpenai(response *ZhipuResponse, request *ty
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertFromChatOpenai(request *types.ChatCompletionRequest) *ZhipuRequest {
|
func (p *ZhipuProvider) convertFromChatOpenai(request *types.ChatCompletionRequest) *ZhipuRequest {
|
||||||
for i := range request.Messages {
|
for i := range request.Messages {
|
||||||
request.Messages[i].Role = convertRole(request.Messages[i].Role)
|
request.Messages[i].Role = convertRole(request.Messages[i].Role)
|
||||||
}
|
}
|
||||||
@ -153,7 +153,7 @@ func convertFromChatOpenai(request *types.ChatCompletionRequest) *ZhipuRequest {
|
|||||||
for _, function := range request.Functions {
|
for _, function := range request.Functions {
|
||||||
zhipuRequest.Tools = append(zhipuRequest.Tools, ZhipuTool{
|
zhipuRequest.Tools = append(zhipuRequest.Tools, ZhipuTool{
|
||||||
Type: "function",
|
Type: "function",
|
||||||
Function: *function,
|
Function: function,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else if request.Tools != nil {
|
} else if request.Tools != nil {
|
||||||
@ -161,14 +161,57 @@ func convertFromChatOpenai(request *types.ChatCompletionRequest) *ZhipuRequest {
|
|||||||
for _, tool := range request.Tools {
|
for _, tool := range request.Tools {
|
||||||
zhipuRequest.Tools = append(zhipuRequest.Tools, ZhipuTool{
|
zhipuRequest.Tools = append(zhipuRequest.Tools, ZhipuTool{
|
||||||
Type: "function",
|
Type: "function",
|
||||||
Function: tool.Function,
|
Function: &tool.Function,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.pluginHandle(zhipuRequest)
|
||||||
|
|
||||||
return zhipuRequest
|
return zhipuRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *ZhipuProvider) pluginHandle(request *ZhipuRequest) {
|
||||||
|
if p.Channel.Plugin == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin := p.Channel.Plugin.Data()
|
||||||
|
|
||||||
|
// 检测是否开启了 retrieval 插件
|
||||||
|
if pRetrieval, ok := plugin["retrieval"]; ok {
|
||||||
|
if knowledge_id, ok := pRetrieval["knowledge_id"].(string); ok && knowledge_id != "" {
|
||||||
|
retrieval := ZhipuTool{
|
||||||
|
Type: "retrieval",
|
||||||
|
Retrieval: &ZhipuRetrieval{
|
||||||
|
KnowledgeId: knowledge_id,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if prompt_template, ok := pRetrieval["prompt_template"].(string); ok && prompt_template != "" {
|
||||||
|
retrieval.Retrieval.PromptTemplate = prompt_template
|
||||||
|
}
|
||||||
|
|
||||||
|
request.Tools = append(request.Tools, retrieval)
|
||||||
|
|
||||||
|
// 如果开启了 retrieval 插件,web_search 无效
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测是否开启了 web_search 插件
|
||||||
|
if pWeb, ok := plugin["web_search"]; ok {
|
||||||
|
if enable, ok := pWeb["enable"].(bool); ok && enable {
|
||||||
|
request.Tools = append(request.Tools, ZhipuTool{
|
||||||
|
Type: "web_search",
|
||||||
|
WebSearch: &ZhipuWebSearch{
|
||||||
|
Enable: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 转换为OpenAI聊天流式请求体
|
// 转换为OpenAI聊天流式请求体
|
||||||
func (h *zhipuStreamHandler) handlerStream(rawLine *[]byte, dataChan chan string, errChan chan error) {
|
func (h *zhipuStreamHandler) handlerStream(rawLine *[]byte, dataChan chan string, errChan chan error) {
|
||||||
// 如果rawLine 前缀不为data: 或者 meta:,则直接返回
|
// 如果rawLine 前缀不为data: 或者 meta:,则直接返回
|
||||||
@ -198,10 +241,10 @@ func (h *zhipuStreamHandler) handlerStream(rawLine *[]byte, dataChan chan string
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
h.convertToOpenaiStream(zhipuResponse, dataChan, errChan)
|
h.convertToOpenaiStream(zhipuResponse, dataChan)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *zhipuStreamHandler) convertToOpenaiStream(zhipuResponse *ZhipuStreamResponse, dataChan chan string, errChan chan error) {
|
func (h *zhipuStreamHandler) convertToOpenaiStream(zhipuResponse *ZhipuStreamResponse, dataChan chan string) {
|
||||||
streamResponse := types.ChatCompletionStreamResponse{
|
streamResponse := types.ChatCompletionStreamResponse{
|
||||||
ID: zhipuResponse.ID,
|
ID: zhipuResponse.ID,
|
||||||
Object: "chat.completion.chunk",
|
Object: "chat.completion.chunk",
|
||||||
|
@ -37,10 +37,10 @@ func (p *ZhipuProvider) CreateImageGenerations(request *types.ImageRequest) (*ty
|
|||||||
return nil, errWithCode
|
return nil, errWithCode
|
||||||
}
|
}
|
||||||
|
|
||||||
return p.convertToImageOpenai(zhipuResponse, request)
|
return p.convertToImageOpenai(zhipuResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ZhipuProvider) convertToImageOpenai(response *ZhipuImageGenerationResponse, request *types.ImageRequest) (openaiResponse *types.ImageResponse, errWithCode *types.OpenAIErrorWithStatusCode) {
|
func (p *ZhipuProvider) convertToImageOpenai(response *ZhipuImageGenerationResponse) (openaiResponse *types.ImageResponse, errWithCode *types.OpenAIErrorWithStatusCode) {
|
||||||
error := errorHandle(&response.Error)
|
error := errorHandle(&response.Error)
|
||||||
if error != nil {
|
if error != nil {
|
||||||
errWithCode = &types.OpenAIErrorWithStatusCode{
|
errWithCode = &types.OpenAIErrorWithStatusCode{
|
||||||
|
@ -10,10 +10,16 @@ type ZhipuWebSearch struct {
|
|||||||
SearchQuery string `json:"search_query,omitempty"`
|
SearchQuery string `json:"search_query,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ZhipuRetrieval struct {
|
||||||
|
KnowledgeId string `json:"knowledge_id"`
|
||||||
|
PromptTemplate string `json:"prompt_template,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type ZhipuTool struct {
|
type ZhipuTool struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Function types.ChatCompletionFunction `json:"function"`
|
Function *types.ChatCompletionFunction `json:"function,omitempty"`
|
||||||
WebSearch string `json:"web_search,omitempty"`
|
WebSearch *ZhipuWebSearch `json:"web_search,omitempty"`
|
||||||
|
Retrieval *ZhipuRetrieval `json:"retrieval,omitempty"`
|
||||||
}
|
}
|
||||||
type ZhipuRequest struct {
|
type ZhipuRequest struct {
|
||||||
Model string `json:"model"`
|
Model string `json:"model"`
|
||||||
|
@ -22,7 +22,9 @@ import {
|
|||||||
Autocomplete,
|
Autocomplete,
|
||||||
FormHelperText,
|
FormHelperText,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
Switch
|
Switch,
|
||||||
|
FormControlLabel,
|
||||||
|
Typography
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
|
|
||||||
import { Formik } from 'formik';
|
import { Formik } from 'formik';
|
||||||
@ -32,6 +34,7 @@ import { createFilterOptions } from '@mui/material/Autocomplete';
|
|||||||
import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank';
|
import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank';
|
||||||
import CheckBoxIcon from '@mui/icons-material/CheckBox';
|
import CheckBoxIcon from '@mui/icons-material/CheckBox';
|
||||||
|
|
||||||
|
const pluginList = require('../type/Plugin.json');
|
||||||
const icon = <CheckBoxOutlineBlankIcon fontSize="small" />;
|
const icon = <CheckBoxOutlineBlankIcon fontSize="small" />;
|
||||||
const checkedIcon = <CheckBoxIcon fontSize="small" />;
|
const checkedIcon = <CheckBoxIcon fontSize="small" />;
|
||||||
|
|
||||||
@ -91,7 +94,24 @@ const EditModal = ({ open, channelId, onCancel, onOk, groupOptions }) => {
|
|||||||
|
|
||||||
return typeConfig[typeValue]?.input;
|
return typeConfig[typeValue]?.input;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleTypeChange = (setFieldValue, typeValue, values) => {
|
const handleTypeChange = (setFieldValue, typeValue, values) => {
|
||||||
|
// 处理插件事务
|
||||||
|
if (pluginList[typeValue]) {
|
||||||
|
const newPluginValues = {};
|
||||||
|
const pluginConfig = pluginList[typeValue];
|
||||||
|
for (const pluginName in pluginConfig) {
|
||||||
|
const plugin = pluginConfig[pluginName];
|
||||||
|
const oldValve = values['plugin'] ? values['plugin'][pluginName] || {} : {};
|
||||||
|
newPluginValues[pluginName] = {};
|
||||||
|
for (const paramName in plugin.params) {
|
||||||
|
const param = plugin.params[paramName];
|
||||||
|
newPluginValues[pluginName][paramName] = oldValve[paramName] || (param.type === 'bool' ? false : '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setFieldValue('plugin', newPluginValues);
|
||||||
|
}
|
||||||
|
|
||||||
const newInput = initChannel(typeValue);
|
const newInput = initChannel(typeValue);
|
||||||
|
|
||||||
if (newInput) {
|
if (newInput) {
|
||||||
@ -233,6 +253,9 @@ const EditModal = ({ open, channelId, onCancel, onOk, groupOptions }) => {
|
|||||||
|
|
||||||
data.base_url = data.base_url ?? '';
|
data.base_url = data.base_url ?? '';
|
||||||
data.is_edit = true;
|
data.is_edit = true;
|
||||||
|
if (data.plugin === null) {
|
||||||
|
data.plugin = {};
|
||||||
|
}
|
||||||
initChannel(data.type);
|
initChannel(data.type);
|
||||||
setInitialInput(data);
|
setInitialInput(data);
|
||||||
} else {
|
} else {
|
||||||
@ -597,6 +620,53 @@ const EditModal = ({ open, channelId, onCancel, onOk, groupOptions }) => {
|
|||||||
)}
|
)}
|
||||||
</FormControl>
|
</FormControl>
|
||||||
)}
|
)}
|
||||||
|
{pluginList[values.type] &&
|
||||||
|
Object.keys(pluginList[values.type]).map((pluginId) => {
|
||||||
|
const plugin = pluginList[values.type][pluginId];
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Divider sx={{ ...theme.typography.otherInput }} />
|
||||||
|
<Typography variant="h3">{plugin.name}</Typography>
|
||||||
|
{Object.keys(plugin.params).map((paramId) => {
|
||||||
|
const param = plugin.params[paramId];
|
||||||
|
const name = `plugin.${pluginId}.${paramId}`;
|
||||||
|
return param.type === 'bool' ? (
|
||||||
|
<FormControl key={name} fullWidth sx={{ ...theme.typography.otherInput }}>
|
||||||
|
<FormControlLabel
|
||||||
|
key={name}
|
||||||
|
required
|
||||||
|
control={
|
||||||
|
<Switch
|
||||||
|
key={name}
|
||||||
|
name={name}
|
||||||
|
checked={values.plugin?.[pluginId]?.[paramId] || false}
|
||||||
|
onChange={(event) => {
|
||||||
|
setFieldValue(name, event.target.checked);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="是否启用"
|
||||||
|
/>
|
||||||
|
<FormHelperText id="helper-tex-channel-key-label"> {param.description} </FormHelperText>
|
||||||
|
</FormControl>
|
||||||
|
) : (
|
||||||
|
<FormControl key={name} fullWidth sx={{ ...theme.typography.otherInput }}>
|
||||||
|
<TextField
|
||||||
|
multiline
|
||||||
|
key={name}
|
||||||
|
name={name}
|
||||||
|
value={values.plugin?.[pluginId]?.[paramId] || ''}
|
||||||
|
label={param.name}
|
||||||
|
placeholder={param.description}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
<FormHelperText id="helper-tex-channel-key-label"> {param.description} </FormHelperText>
|
||||||
|
</FormControl>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
})}
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button onClick={onCancel}>取消</Button>
|
<Button onClick={onCancel}>取消</Button>
|
||||||
<Button disableElevation disabled={isSubmitting} type="submit" variant="contained" color="primary">
|
<Button disableElevation disabled={isSubmitting} type="submit" variant="contained" color="primary">
|
||||||
|
@ -9,7 +9,8 @@ const defaultConfig = {
|
|||||||
test_model: '',
|
test_model: '',
|
||||||
model_mapping: '',
|
model_mapping: '',
|
||||||
models: [],
|
models: [],
|
||||||
groups: ['default']
|
groups: ['default'],
|
||||||
|
plugin: {}
|
||||||
},
|
},
|
||||||
inputLabel: {
|
inputLabel: {
|
||||||
name: '渠道名称',
|
name: '渠道名称',
|
||||||
@ -76,8 +77,8 @@ const typeConfig = {
|
|||||||
},
|
},
|
||||||
16: {
|
16: {
|
||||||
input: {
|
input: {
|
||||||
models: ['chatglm_turbo', 'chatglm_pro', 'chatglm_std', 'chatglm_lite'],
|
models: ['glm-3-turbo', 'glm-4', 'glm-4v', 'embedding-2', 'cogview-3'],
|
||||||
test_model: 'chatglm_lite'
|
test_model: 'glm-3-turbo'
|
||||||
},
|
},
|
||||||
modelGroup: 'Zhipu'
|
modelGroup: 'Zhipu'
|
||||||
},
|
},
|
||||||
@ -86,17 +87,7 @@ const typeConfig = {
|
|||||||
other: '插件参数'
|
other: '插件参数'
|
||||||
},
|
},
|
||||||
input: {
|
input: {
|
||||||
models: [
|
models: ['qwen-turbo', 'qwen-plus', 'qwen-max', 'qwen-max-longcontext', 'text-embedding-v1'],
|
||||||
'qwen-turbo',
|
|
||||||
'qwen-plus',
|
|
||||||
'qwen-max',
|
|
||||||
'qwen-max-longcontext',
|
|
||||||
'text-embedding-v1',
|
|
||||||
'qwen-turbo-internet',
|
|
||||||
'qwen-plus-internet',
|
|
||||||
'qwen-max-internet',
|
|
||||||
'qwen-max-longcontext-internet'
|
|
||||||
],
|
|
||||||
test_model: 'qwen-turbo'
|
test_model: 'qwen-turbo'
|
||||||
},
|
},
|
||||||
prompt: {
|
prompt: {
|
||||||
@ -174,19 +165,22 @@ const typeConfig = {
|
|||||||
},
|
},
|
||||||
prompt: {
|
prompt: {
|
||||||
key: '按照如下格式输入:APISecret|groupID'
|
key: '按照如下格式输入:APISecret|groupID'
|
||||||
}
|
},
|
||||||
|
modelGroup: 'MiniMax'
|
||||||
},
|
},
|
||||||
28: {
|
28: {
|
||||||
input: {
|
input: {
|
||||||
models: ['deepseek-coder', 'deepseek-chat'],
|
models: ['deepseek-coder', 'deepseek-chat'],
|
||||||
test_model: 'deepseek-chat'
|
test_model: 'deepseek-chat'
|
||||||
}
|
},
|
||||||
|
modelGroup: 'Deepseek'
|
||||||
},
|
},
|
||||||
29: {
|
29: {
|
||||||
input: {
|
input: {
|
||||||
models: ['moonshot-v1-8k', 'moonshot-v1-32k', 'moonshot-v1-128k'],
|
models: ['moonshot-v1-8k', 'moonshot-v1-32k', 'moonshot-v1-128k'],
|
||||||
test_model: 'moonshot-v1-8k'
|
test_model: 'moonshot-v1-8k'
|
||||||
}
|
},
|
||||||
|
modelGroup: 'Moonshot'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
48
web/src/views/Channel/type/Plugin.json
Normal file
48
web/src/views/Channel/type/Plugin.json
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"16": {
|
||||||
|
"retrieval": {
|
||||||
|
"name": "知识库",
|
||||||
|
"description": "请前往开放平台的知识库上传文档,然后使用知识库功能进行检索。",
|
||||||
|
"params": {
|
||||||
|
"knowledge_id": {
|
||||||
|
"name": "知识库ID",
|
||||||
|
"description": "当涉及到知识库ID时,请前往开放平台的知识库模块进行创建或获取(是知识库ID不是文档ID!)",
|
||||||
|
"type": "string",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"prompt_template": {
|
||||||
|
"name": "知识库模板",
|
||||||
|
"description": "请求模型时的知识库模板, 请查看文档填写,否则不用填写",
|
||||||
|
"type": "string",
|
||||||
|
"required": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"web_search": {
|
||||||
|
"name": "网页搜索",
|
||||||
|
"description": "使用网页搜索功能,对用户输入的内容进行搜索",
|
||||||
|
"params": {
|
||||||
|
"enable": {
|
||||||
|
"name": "启用",
|
||||||
|
"description": "是否启用网页搜索",
|
||||||
|
"type": "bool",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"17": {
|
||||||
|
"web_search": {
|
||||||
|
"name": "网页搜索",
|
||||||
|
"description": "使用网页搜索功能,对用户输入的内容进行搜索",
|
||||||
|
"params": {
|
||||||
|
"enable": {
|
||||||
|
"name": "启用",
|
||||||
|
"description": "是否启用网页搜索",
|
||||||
|
"type": "bool",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user