From d8d880bf856be1659f669bb2f51883374ef79b16 Mon Sep 17 00:00:00 2001 From: Buer <42402987+MartialBE@users.noreply.github.com> Date: Fri, 8 Mar 2024 14:49:33 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20feat:=20channel=20support?= =?UTF-8?q?=20plugin=20settings=20(#89)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/model-ratio.go | 8 +-- controller/model.go | 3 + go.mod | 5 +- go.sum | 6 ++ model/channel.go | 5 ++ providers/ali/chat.go | 41 ++++++----- providers/minimax/chat.go | 4 +- providers/palm/chat.go | 4 +- providers/tencent/chat.go | 4 +- providers/xunfei/chat.go | 4 +- providers/zhipu/base.go | 1 - providers/zhipu/chat.go | 57 ++++++++++++++-- providers/zhipu/image_generations.go | 4 +- providers/zhipu/type.go | 12 +++- web/src/views/Channel/component/EditModal.js | 72 +++++++++++++++++++- web/src/views/Channel/type/Config.js | 30 ++++---- web/src/views/Channel/type/Plugin.json | 48 +++++++++++++ 17 files changed, 243 insertions(+), 65 deletions(-) create mode 100644 web/src/views/Channel/type/Plugin.json diff --git a/common/model-ratio.go b/common/model-ratio.go index 2dd0b11a..b6334059 100644 --- a/common/model-ratio.go +++ b/common/model-ratio.go @@ -110,13 +110,7 @@ func init() { "gemini-pro-vision": {[]float64{1, 1}, ChannelTypeGemini}, // ¥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}, - // ¥0.01 / 1k tokens - "chatglm_pro": {[]float64{0.7143, 0.7143}, ChannelTypeZhipu}, - // ¥0.002 / 1k tokens - "chatglm_lite": {[]float64{0.1429, 0.1429}, ChannelTypeZhipu}, + "glm-3-turbo": {[]float64{0.3572, 0.3572}, ChannelTypeZhipu}, // ¥0.1 / 1k tokens "glm-4": {[]float64{7.143, 7.143}, ChannelTypeZhipu}, "glm-4v": {[]float64{7.143, 7.143}, ChannelTypeZhipu}, diff --git a/controller/model.go b/controller/model.go index 98f99e50..2803bafe 100644 --- a/controller/model.go +++ b/controller/model.go @@ -55,6 +55,9 @@ func init() { common.ChannelType360: "360", common.ChannelTypeTencent: "Tencent", common.ChannelTypeBaichuan: "Baichuan", + common.ChannelTypeMiniMax: "MiniMax", + common.ChannelTypeDeepseek: "Deepseek", + common.ChannelTypeMoonshot: "Moonshot", } } diff --git a/go.mod b/go.mod index d8792ba3..8ffa0b6e 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/stretchr/testify v1.8.3 golang.org/x/crypto v0.17.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/sqlite v1.4.3 gorm.io/gorm v1.25.0 @@ -36,7 +36,7 @@ require ( github.com/gin-contrib/sse v0.1.0 // 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.6.0 // indirect + github.com/go-sql-driver/mysql v1.7.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/gorilla/context 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 google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + gorm.io/datatypes v1.2.0 ) diff --git a/go.sum b/go.sum index 74696c0e..bd2e401e 100644 --- a/go.sum +++ b/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-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.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.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= 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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 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/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/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8= gorm.io/driver/sqlite v1.4.3 h1:HBBcZSDnWi5BW3B3rwvVTc510KGkBkexlOg0QrmLUuU= diff --git a/model/channel.go b/model/channel.go index 6d4413ec..347d0739 100644 --- a/model/channel.go +++ b/model/channel.go @@ -4,6 +4,7 @@ import ( "one-api/common" "strings" + "gorm.io/datatypes" "gorm.io/gorm" ) @@ -28,8 +29,12 @@ type Channel struct { Priority *int64 `json:"priority" gorm:"bigint;default:0"` Proxy *string `json:"proxy" gorm:"type:varchar(255);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{ "id": true, "name": true, diff --git a/providers/ali/chat.go b/providers/ali/chat.go index 61b9b1a0..13c9cdcf 100644 --- a/providers/ali/chat.go +++ b/providers/ali/chat.go @@ -15,8 +15,6 @@ type aliStreamHandler struct { lastStreamResponse string } -const AliEnableSearchModelSuffix = "-internet" - func (p *AliProvider) CreateChatCompletion(request *types.ChatCompletionRequest) (*types.ChatCompletionResponse, *types.OpenAIErrorWithStatusCode) { req, errWithCode := p.getAliChatRequest(request) if errWithCode != nil { @@ -70,7 +68,7 @@ func (p *AliProvider) getAliChatRequest(request *types.ChatCompletionRequest) (* 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)) 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)) for i := 0; i < len(request.Messages); i++ { message := request.Messages[i] @@ -141,24 +139,35 @@ func convertFromChatOpenai(request *types.ChatCompletionRequest) *AliChatRequest } - enableSearch := false - aliModel := request.Model - if strings.HasSuffix(aliModel, AliEnableSearchModelSuffix) { - enableSearch = true - aliModel = strings.TrimSuffix(aliModel, AliEnableSearchModelSuffix) - } - - return &AliChatRequest{ - Model: aliModel, + aliChatRequest := &AliChatRequest{ + Model: request.Model, Input: AliInput{ Messages: messages, }, Parameters: AliParameters{ ResultFormat: "message", - EnableSearch: enableSearch, 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聊天流式请求体 @@ -185,11 +194,11 @@ func (h *aliStreamHandler) handlerStream(rawLine *[]byte, dataChan chan string, 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() var choice types.ChatCompletionStreamChoice diff --git a/providers/minimax/chat.go b/providers/minimax/chat.go index c75b46ab..9408ca7f 100644 --- a/providers/minimax/chat.go +++ b/providers/minimax/chat.go @@ -220,10 +220,10 @@ func (h *minimaxStreamHandler) handlerStream(rawLine *[]byte, dataChan chan stri 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{ ID: miniResponse.RequestID, Object: "chat.completion.chunk", diff --git a/providers/palm/chat.go b/providers/palm/chat.go index 088f2d64..8e0adc56 100644 --- a/providers/palm/chat.go +++ b/providers/palm/chat.go @@ -165,11 +165,11 @@ func (h *palmStreamHandler) handlerStream(rawLine *[]byte, dataChan chan string, 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 if len(palmChatResponse.Candidates) > 0 { choice.Delta.Content = palmChatResponse.Candidates[0].Content diff --git a/providers/tencent/chat.go b/providers/tencent/chat.go index 9977d274..49a1ae16 100644 --- a/providers/tencent/chat.go +++ b/providers/tencent/chat.go @@ -180,11 +180,11 @@ func (h *tencentStreamHandler) handlerStream(rawLine *[]byte, dataChan chan stri 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{ Object: "chat.completion.chunk", Created: common.GetTimestamp(), diff --git a/providers/xunfei/chat.go b/providers/xunfei/chat.go index c93920f0..d031fd61 100644 --- a/providers/xunfei/chat.go +++ b/providers/xunfei/chat.go @@ -256,7 +256,7 @@ func (h *xunfeiHandler) handlerStream(rawLine *[]byte, dataChan chan string, err return } - h.convertToOpenaiStream(xunfeiChatResponse, dataChan, errChan) + h.convertToOpenaiStream(xunfeiChatResponse, dataChan) if isFinished { 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 { xunfeiChatResponse.Payload.Choices.Text = []XunfeiChatResponseTextItem{{}} } diff --git a/providers/zhipu/base.go b/providers/zhipu/base.go index 0cebbd0d..c5b696f9 100644 --- a/providers/zhipu/base.go +++ b/providers/zhipu/base.go @@ -73,7 +73,6 @@ func (p *ZhipuProvider) GetRequestHeaders() (headers map[string]string) { headers = make(map[string]string) p.CommonRequestHeaders(headers) headers["Authorization"] = p.getZhipuToken() - return headers } diff --git a/providers/zhipu/chat.go b/providers/zhipu/chat.go index 687ffe7c..eb478a46 100644 --- a/providers/zhipu/chat.go +++ b/providers/zhipu/chat.go @@ -69,7 +69,7 @@ func (p *ZhipuProvider) getChatRequest(request *types.ChatCompletionRequest) (*h // 获取请求头 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)) @@ -94,7 +94,7 @@ func (p *ZhipuProvider) convertToChatOpenai(response *ZhipuResponse, request *ty ID: response.ID, Object: "chat.completion", Created: response.Created, - Model: response.Model, + Model: request.Model, Choices: response.Choices, Usage: response.Usage, } @@ -104,7 +104,7 @@ func (p *ZhipuProvider) convertToChatOpenai(response *ZhipuResponse, request *ty return } -func convertFromChatOpenai(request *types.ChatCompletionRequest) *ZhipuRequest { +func (p *ZhipuProvider) convertFromChatOpenai(request *types.ChatCompletionRequest) *ZhipuRequest { for i := range request.Messages { request.Messages[i].Role = convertRole(request.Messages[i].Role) } @@ -153,7 +153,7 @@ func convertFromChatOpenai(request *types.ChatCompletionRequest) *ZhipuRequest { for _, function := range request.Functions { zhipuRequest.Tools = append(zhipuRequest.Tools, ZhipuTool{ Type: "function", - Function: *function, + Function: function, }) } } else if request.Tools != nil { @@ -161,14 +161,57 @@ func convertFromChatOpenai(request *types.ChatCompletionRequest) *ZhipuRequest { for _, tool := range request.Tools { zhipuRequest.Tools = append(zhipuRequest.Tools, ZhipuTool{ Type: "function", - Function: tool.Function, + Function: &tool.Function, }) } } + p.pluginHandle(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聊天流式请求体 func (h *zhipuStreamHandler) handlerStream(rawLine *[]byte, dataChan chan string, errChan chan error) { // 如果rawLine 前缀不为data: 或者 meta:,则直接返回 @@ -198,10 +241,10 @@ func (h *zhipuStreamHandler) handlerStream(rawLine *[]byte, dataChan chan string 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{ ID: zhipuResponse.ID, Object: "chat.completion.chunk", diff --git a/providers/zhipu/image_generations.go b/providers/zhipu/image_generations.go index 9f8d2fdd..5bed657b 100644 --- a/providers/zhipu/image_generations.go +++ b/providers/zhipu/image_generations.go @@ -37,10 +37,10 @@ func (p *ZhipuProvider) CreateImageGenerations(request *types.ImageRequest) (*ty 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) if error != nil { errWithCode = &types.OpenAIErrorWithStatusCode{ diff --git a/providers/zhipu/type.go b/providers/zhipu/type.go index 6fdbca3a..a5779070 100644 --- a/providers/zhipu/type.go +++ b/providers/zhipu/type.go @@ -10,10 +10,16 @@ type ZhipuWebSearch struct { SearchQuery string `json:"search_query,omitempty"` } +type ZhipuRetrieval struct { + KnowledgeId string `json:"knowledge_id"` + PromptTemplate string `json:"prompt_template,omitempty"` +} + type ZhipuTool struct { - Type string `json:"type"` - Function types.ChatCompletionFunction `json:"function"` - WebSearch string `json:"web_search,omitempty"` + Type string `json:"type"` + Function *types.ChatCompletionFunction `json:"function,omitempty"` + WebSearch *ZhipuWebSearch `json:"web_search,omitempty"` + Retrieval *ZhipuRetrieval `json:"retrieval,omitempty"` } type ZhipuRequest struct { Model string `json:"model"` diff --git a/web/src/views/Channel/component/EditModal.js b/web/src/views/Channel/component/EditModal.js index aa52b40d..b60e9320 100644 --- a/web/src/views/Channel/component/EditModal.js +++ b/web/src/views/Channel/component/EditModal.js @@ -22,7 +22,9 @@ import { Autocomplete, FormHelperText, Checkbox, - Switch + Switch, + FormControlLabel, + Typography } from '@mui/material'; import { Formik } from 'formik'; @@ -32,6 +34,7 @@ import { createFilterOptions } from '@mui/material/Autocomplete'; import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank'; import CheckBoxIcon from '@mui/icons-material/CheckBox'; +const pluginList = require('../type/Plugin.json'); const icon = ; const checkedIcon = ; @@ -91,7 +94,24 @@ const EditModal = ({ open, channelId, onCancel, onOk, groupOptions }) => { return typeConfig[typeValue]?.input; }; + 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); if (newInput) { @@ -233,6 +253,9 @@ const EditModal = ({ open, channelId, onCancel, onOk, groupOptions }) => { data.base_url = data.base_url ?? ''; data.is_edit = true; + if (data.plugin === null) { + data.plugin = {}; + } initChannel(data.type); setInitialInput(data); } else { @@ -597,6 +620,53 @@ const EditModal = ({ open, channelId, onCancel, onOk, groupOptions }) => { )} )} + {pluginList[values.type] && + Object.keys(pluginList[values.type]).map((pluginId) => { + const plugin = pluginList[values.type][pluginId]; + return ( + <> + + {plugin.name} + {Object.keys(plugin.params).map((paramId) => { + const param = plugin.params[paramId]; + const name = `plugin.${pluginId}.${paramId}`; + return param.type === 'bool' ? ( + + { + setFieldValue(name, event.target.checked); + }} + /> + } + label="是否启用" + /> + {param.description} + + ) : ( + + + {param.description} + + ); + })} + + ); + })}