From e3a0162206c909e288ab36e281be30faafead6f9 Mon Sep 17 00:00:00 2001 From: HynoR <20227709+HynoR@users.noreply.github.com> Date: Thu, 19 Dec 2024 19:08:04 +0800 Subject: [PATCH 1/4] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E5=88=87=E6=8D=A2=E6=A8=A1=E5=BC=8F=E6=97=B6?= =?UTF-8?q?=EF=BC=8C=E5=88=9D=E5=A7=8B=E5=8C=96=E7=A9=BA=E5=80=BC=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E7=9A=84=E5=88=A4=E6=96=AD=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/Setting/Operation/ModelSettingsVisualEditor.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/web/src/pages/Setting/Operation/ModelSettingsVisualEditor.js b/web/src/pages/Setting/Operation/ModelSettingsVisualEditor.js index c5ad9737..b8a1ae50 100644 --- a/web/src/pages/Setting/Operation/ModelSettingsVisualEditor.js +++ b/web/src/pages/Setting/Operation/ModelSettingsVisualEditor.js @@ -75,7 +75,7 @@ export default function ModelSettingsVisualEditor(props) { output.ModelPrice[model.name] = parseFloat(model.price) } else { if (model.ratio !== '') output.ModelRatio[model.name] = parseFloat(model.ratio); - if (model.completionRatio != '') output.CompletionRatio[model.name] = parseFloat(model.completionRatio); + if (model.completionRatio !== '') output.CompletionRatio[model.name] = parseFloat(model.completionRatio); } }); @@ -203,11 +203,6 @@ export default function ModelSettingsVisualEditor(props) { showError('模型名称已存在'); return; } - // 不允许同时添加固定价格和倍率 - if (values.price !== '' && (values.ratio !== '' || values.completionRatio !== '')) { - showError('固定价格和倍率不能同时存在'); - return; - } setModels(prev => [{ name: values.name, price: values.price || '', From 158edab97414fe3b860e3e85b15057bec6bf89d0 Mon Sep 17 00:00:00 2001 From: MartialBE Date: Fri, 20 Dec 2024 20:24:49 +0800 Subject: [PATCH 2/4] fix: Fix the issue where Gemini loses content when converting OpenAI format in the stream. --- relay/channel/gemini/relay-gemini.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/relay/channel/gemini/relay-gemini.go b/relay/channel/gemini/relay-gemini.go index e48ae087..7eea7653 100644 --- a/relay/channel/gemini/relay-gemini.go +++ b/relay/channel/gemini/relay-gemini.go @@ -236,13 +236,17 @@ func streamResponseGeminiChat2OpenAI(geminiResponse *GeminiChatResponse) *dto.Ch var choice dto.ChatCompletionsStreamResponseChoice //choice.Delta.SetContentString(geminiResponse.GetResponseText()) if len(geminiResponse.Candidates) > 0 && len(geminiResponse.Candidates[0].Content.Parts) > 0 { - respFirst := geminiResponse.Candidates[0].Content.Parts[0] - if respFirst.FunctionCall != nil { + respFirstParts := geminiResponse.Candidates[0].Content.Parts + if respFirstParts[0].FunctionCall != nil { // function response choice.Delta.ToolCalls = getToolCalls(&geminiResponse.Candidates[0]) } else { // text response - choice.Delta.SetContentString(respFirst.Text) + var texts []string + for _, part := range respFirstParts { + texts = append(texts, part.Text) + } + choice.Delta.SetContentString(strings.Join(texts, "\n")) } } var response dto.ChatCompletionsStreamResponse From f9a7f6085edfe8d10a108a206ca417b67043fc0a Mon Sep 17 00:00:00 2001 From: CalciumIon <1808837298@qq.com> Date: Fri, 20 Dec 2024 21:36:23 +0800 Subject: [PATCH 3/4] feat: Add GEMINI_VISION_MAX_IMAGE_NUM configuration - Introduced `GEMINI_VISION_MAX_IMAGE_NUM` to README files for better user guidance. - Updated `env.go` to retrieve the maximum image number from environment variables, defaulting to 16. - Modified image handling logic in `relay-gemini.go` to respect the new configuration, allowing disabling of the limit by setting it to -1. - Removed hardcoded constant for maximum image number in `constant.go` to streamline configuration management. --- README.en.md | 1 + README.md | 1 + constant/env.go | 2 ++ relay/channel/gemini/constant.go | 4 ---- relay/channel/gemini/relay-gemini.go | 7 ++++--- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/README.en.md b/README.en.md index f3e7bdaf..c45fff94 100644 --- a/README.en.md +++ b/README.en.md @@ -81,6 +81,7 @@ You can add custom models gpt-4-gizmo-* in channels. These are third-party model - `UPDATE_TASK`: Update async tasks (Midjourney, Suno), default `true` - `GEMINI_MODEL_MAP`: Specify Gemini model versions (v1/v1beta), format: "model:version", comma-separated - `COHERE_SAFETY_SETTING`: Cohere model [safety settings](https://docs.cohere.com/docs/safety-modes#overview), options: `NONE`, `CONTEXTUAL`, `STRICT`, default `NONE` +- `GEMINI_VISION_MAX_IMAGE_NUM`: Gemini model maximum image number, default `16`, set to `-1` to disable ## Deployment > [!TIP] diff --git a/README.md b/README.md index 88965f68..ddf3cd9e 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,7 @@ - `UPDATE_TASK`:是否更新异步任务(Midjourney、Suno),默认为 `true`,关闭后将不会更新任务进度。 - `GEMINI_MODEL_MAP`:Gemini模型指定版本(v1/v1beta),使用“模型:版本”指定,","分隔,例如:-e GEMINI_MODEL_MAP="gemini-1.5-pro-latest:v1beta,gemini-1.5-pro-001:v1beta",为空则使用默认配置(v1beta) - `COHERE_SAFETY_SETTING`:Cohere模型[安全设置](https://docs.cohere.com/docs/safety-modes#overview),可选值为 `NONE`, `CONTEXTUAL`,`STRICT`,默认为 `NONE`。 +- `GEMINI_VISION_MAX_IMAGE_NUM`:Gemini模型最大图片数量,默认为 `16`,设置为 `-1` 则不限制。 ## 部署 > [!TIP] > 最新版Docker镜像:`calciumion/new-api:latest` diff --git a/constant/env.go b/constant/env.go index 1bd0699d..b9a6801d 100644 --- a/constant/env.go +++ b/constant/env.go @@ -23,6 +23,8 @@ var GeminiModelMap = map[string]string{ "gemini-1.0-pro": "v1", } +var GeminiVisionMaxImageNum = common.GetEnvOrDefault("GEMINI_VISION_MAX_IMAGE_NUM", 16) + func InitEnv() { modelVersionMapStr := strings.TrimSpace(os.Getenv("GEMINI_MODEL_MAP")) if modelVersionMapStr == "" { diff --git a/relay/channel/gemini/constant.go b/relay/channel/gemini/constant.go index aa89e03d..64289359 100644 --- a/relay/channel/gemini/constant.go +++ b/relay/channel/gemini/constant.go @@ -1,9 +1,5 @@ package gemini -const ( - GeminiVisionMaxImageNum = 16 -) - var ModelList = []string{ // stable version "gemini-1.5-pro", "gemini-1.5-flash", "gemini-1.5-flash-8b", diff --git a/relay/channel/gemini/relay-gemini.go b/relay/channel/gemini/relay-gemini.go index 7eea7653..18a54a83 100644 --- a/relay/channel/gemini/relay-gemini.go +++ b/relay/channel/gemini/relay-gemini.go @@ -108,9 +108,10 @@ func CovertGemini2OpenAI(textRequest dto.GeneralOpenAIRequest) *GeminiChatReques }) } else if part.Type == dto.ContentTypeImageURL { imageNum += 1 - //if imageNum > GeminiVisionMaxImageNum { - // continue - //} + + if constant.GeminiVisionMaxImageNum != -1 && imageNum > constant.GeminiVisionMaxImageNum { + continue + } // 判断是否是url if strings.HasPrefix(part.ImageUrl.(dto.MessageImageUrl).Url, "http") { // 是url,获取图片的类型和base64编码的数据 From 03256dbdad05061654b3d722650f4d1007fdb687 Mon Sep 17 00:00:00 2001 From: CalciumIon <1808837298@qq.com> Date: Fri, 20 Dec 2024 21:50:58 +0800 Subject: [PATCH 4/4] refactor: Enhance error handling in Gemini request conversion - Updated `CovertGemini2OpenAI` function to return an error alongside the GeminiChatRequest, improving error reporting for image processing. - Modified `ConvertRequest` methods in both `adaptor.go` files to handle potential errors from the Gemini conversion, ensuring robust request handling. - Improved clarity and maintainability of the code by explicitly managing error cases during request conversion. --- relay/channel/gemini/adaptor.go | 6 +++++- relay/channel/gemini/relay-gemini.go | 8 ++++---- relay/channel/vertex/adaptor.go | 5 ++++- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/relay/channel/gemini/adaptor.go b/relay/channel/gemini/adaptor.go index d80bd833..8e9dfd1e 100644 --- a/relay/channel/gemini/adaptor.go +++ b/relay/channel/gemini/adaptor.go @@ -57,7 +57,11 @@ func (a *Adaptor) ConvertRequest(c *gin.Context, info *relaycommon.RelayInfo, re if request == nil { return nil, errors.New("request is nil") } - return CovertGemini2OpenAI(*request), nil + ai, err := CovertGemini2OpenAI(*request) + if err != nil { + return nil, err + } + return ai, nil } func (a *Adaptor) ConvertRerankRequest(c *gin.Context, relayMode int, request dto.RerankRequest) (any, error) { diff --git a/relay/channel/gemini/relay-gemini.go b/relay/channel/gemini/relay-gemini.go index 18a54a83..7a0a9694 100644 --- a/relay/channel/gemini/relay-gemini.go +++ b/relay/channel/gemini/relay-gemini.go @@ -17,7 +17,7 @@ import ( ) // Setting safety to the lowest possible values since Gemini is already powerless enough -func CovertGemini2OpenAI(textRequest dto.GeneralOpenAIRequest) *GeminiChatRequest { +func CovertGemini2OpenAI(textRequest dto.GeneralOpenAIRequest) (*GeminiChatRequest, error) { geminiRequest := GeminiChatRequest{ Contents: make([]GeminiChatContent, 0, len(textRequest.Messages)), SafetySettings: []GeminiChatSafetySettings{ @@ -110,7 +110,7 @@ func CovertGemini2OpenAI(textRequest dto.GeneralOpenAIRequest) *GeminiChatReques imageNum += 1 if constant.GeminiVisionMaxImageNum != -1 && imageNum > constant.GeminiVisionMaxImageNum { - continue + return nil, fmt.Errorf("too many images in the message, max allowed is %d", constant.GeminiVisionMaxImageNum) } // 判断是否是url if strings.HasPrefix(part.ImageUrl.(dto.MessageImageUrl).Url, "http") { @@ -125,7 +125,7 @@ func CovertGemini2OpenAI(textRequest dto.GeneralOpenAIRequest) *GeminiChatReques } else { _, format, base64String, err := service.DecodeBase64ImageData(part.ImageUrl.(dto.MessageImageUrl).Url) if err != nil { - continue + return nil, fmt.Errorf("decode base64 image data failed: %s", err.Error()) } parts = append(parts, GeminiPart{ InlineData: &GeminiInlineData{ @@ -162,7 +162,7 @@ func CovertGemini2OpenAI(textRequest dto.GeneralOpenAIRequest) *GeminiChatReques // shouldAddDummyModelMessage = false //} } - return &geminiRequest + return &geminiRequest, nil } func (g *GeminiChatResponse) GetResponseText() string { diff --git a/relay/channel/vertex/adaptor.go b/relay/channel/vertex/adaptor.go index 1b41730d..ebff8207 100644 --- a/relay/channel/vertex/adaptor.go +++ b/relay/channel/vertex/adaptor.go @@ -135,7 +135,10 @@ func (a *Adaptor) ConvertRequest(c *gin.Context, info *relaycommon.RelayInfo, re c.Set("request_model", request.Model) return vertexClaudeReq, nil } else if a.RequestMode == RequestModeGemini { - geminiRequest := gemini.CovertGemini2OpenAI(*request) + geminiRequest, err := gemini.CovertGemini2OpenAI(*request) + if err != nil { + return nil, err + } c.Set("request_model", request.Model) return geminiRequest, nil } else if a.RequestMode == RequestModeLlama {