From 50d40f04ec387aaee6774f5d82418bb3386f7c25 Mon Sep 17 00:00:00 2001 From: RedwindA Date: Wed, 4 Jun 2025 02:18:54 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E6=94=AF=E6=8C=81Gemini=20inline=5Fdata?= =?UTF-8?q?=E7=9A=84=E8=9B=87=E5=BD=A2=E5=91=BD=E5=90=8D=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- relay/channel/gemini/dto.go | 53 +++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/relay/channel/gemini/dto.go b/relay/channel/gemini/dto.go index a0e38cb4..d717371d 100644 --- a/relay/channel/gemini/dto.go +++ b/relay/channel/gemini/dto.go @@ -1,5 +1,7 @@ package gemini +import "encoding/json" + type GeminiChatRequest struct { Contents []GeminiChatContent `json:"contents"` SafetySettings []GeminiChatSafetySettings `json:"safetySettings,omitempty"` @@ -22,6 +24,30 @@ type GeminiInlineData struct { Data string `json:"data"` } +// UnmarshalJSON custom unmarshaler for GeminiInlineData to support snake_case and camelCase for MimeType +func (g *GeminiInlineData) UnmarshalJSON(data []byte) error { + type Alias GeminiInlineData // Use type alias to avoid recursion + var aux struct { + Alias + MimeTypeSnake string `json:"mime_type"` + } + + if err := json.Unmarshal(data, &aux); err != nil { + return err + } + + *g = GeminiInlineData(aux.Alias) // Copy other fields if any in future + + // Prioritize snake_case if present + if aux.MimeTypeSnake != "" { + g.MimeType = aux.MimeTypeSnake + } else if aux.MimeType != "" { // Fallback to camelCase from Alias + g.MimeType = aux.MimeType + } + // g.Data would be populated by aux.Alias.Data + return nil +} + type FunctionCall struct { FunctionName string `json:"name"` Arguments any `json:"args"` @@ -63,6 +89,33 @@ type GeminiPart struct { CodeExecutionResult *GeminiPartCodeExecutionResult `json:"codeExecutionResult,omitempty"` } +// UnmarshalJSON custom unmarshaler for GeminiPart to support snake_case and camelCase for InlineData +func (p *GeminiPart) UnmarshalJSON(data []byte) error { + // Alias to avoid recursion during unmarshalling + type Alias GeminiPart + var aux struct { + Alias + InlineDataSnake *GeminiInlineData `json:"inline_data,omitempty"` // snake_case variant + } + + if err := json.Unmarshal(data, &aux); err != nil { + return err + } + + // Assign fields from alias + *p = GeminiPart(aux.Alias) + + // Prioritize snake_case for InlineData if present + if aux.InlineDataSnake != nil { + p.InlineData = aux.InlineDataSnake + } else if aux.InlineData != nil { // Fallback to camelCase from Alias + p.InlineData = aux.InlineData + } + // Other fields like Text, FunctionCall etc. are already populated via aux.Alias + + return nil +} + type GeminiChatContent struct { Role string `json:"role,omitempty"` Parts []GeminiPart `json:"parts"` From 1b78a33aacab1359ec7ceb5c51435ec84e44abc9 Mon Sep 17 00:00:00 2001 From: RedwindA Date: Sun, 8 Jun 2025 14:35:56 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=90=9B=20fix(Gemini):=20improve=20JSO?= =?UTF-8?q?N=20parsing=20for=20tool=20content=20handling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- relay/channel/gemini/relay-gemini.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/relay/channel/gemini/relay-gemini.go b/relay/channel/gemini/relay-gemini.go index 4022c9b0..e856b12b 100644 --- a/relay/channel/gemini/relay-gemini.go +++ b/relay/channel/gemini/relay-gemini.go @@ -211,7 +211,22 @@ func CovertGemini2OpenAI(textRequest dto.GeneralOpenAIRequest, info *relaycommon } else if val, exists := tool_call_ids[message.ToolCallId]; exists { name = val } - contentMap := common.StrToMap(message.StringContent()) + var contentMap map[string]interface{} + contentStr := message.StringContent() + + // 1. 尝试解析为 JSON 对象 + if err := json.Unmarshal([]byte(contentStr), &contentMap); err != nil { + // 2. 如果失败,尝试解析为 JSON 数组 + var contentSlice []interface{} + if err := json.Unmarshal([]byte(contentStr), &contentSlice); err == nil { + // 如果是数组,包装成对象 + contentMap = map[string]interface{}{"result": contentSlice} + } else { + // 3. 如果再次失败,作为纯文本处理 + contentMap = map[string]interface{}{"content": contentStr} + } + } + functionResp := &FunctionResponse{ Name: name, Response: contentMap, From 17e1ea5f4bb59ccb31fbda6db85c6ee25369f7e6 Mon Sep 17 00:00:00 2001 From: skynono <6811626@qq.com> Date: Mon, 9 Jun 2025 01:16:35 +0800 Subject: [PATCH 3/5] fix: balance unit sync --- web/src/components/table/ChannelsTable.js | 6 +++--- web/src/helpers/render.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/web/src/components/table/ChannelsTable.js b/web/src/components/table/ChannelsTable.js index 105aa217..8302f5ce 100644 --- a/web/src/components/table/ChannelsTable.js +++ b/web/src/components/table/ChannelsTable.js @@ -6,7 +6,7 @@ import { showSuccess, timestamp2string, renderGroup, - renderNumberWithPoint, + renderQuotaWithAmount, renderQuota } from '../../helpers/index.js'; @@ -328,7 +328,7 @@ const ChannelsTable = () => { {renderQuota(record.used_quota)} - + { shape='circle' onClick={() => updateChannelBalance(record)} > - ${renderNumberWithPoint(record.balance)} + {renderQuotaWithAmount(record.balance)} diff --git a/web/src/helpers/render.js b/web/src/helpers/render.js index 833a046d..6a6752ed 100644 --- a/web/src/helpers/render.js +++ b/web/src/helpers/render.js @@ -764,7 +764,7 @@ export function renderQuotaWithAmount(amount) { if (displayInCurrency) { return '$' + amount; } else { - return renderUnitWithQuota(amount); + return renderNumber(renderUnitWithQuota(amount)); } } From a80bc02b96cdd99fdc1987f3d6b029666d3e3bcc Mon Sep 17 00:00:00 2001 From: RedwindA Date: Mon, 9 Jun 2025 02:15:39 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=F0=9F=90=9B=20fix:=20update=20condition=20?= =?UTF-8?q?to=20check=20for=20empty=20content=20in=20assistant=20role=20me?= =?UTF-8?q?ssages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- relay/channel/mistral/text.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/relay/channel/mistral/text.go b/relay/channel/mistral/text.go index fb901551..e26c6101 100644 --- a/relay/channel/mistral/text.go +++ b/relay/channel/mistral/text.go @@ -47,7 +47,7 @@ func requestOpenAI2Mistral(request *dto.GeneralOpenAIRequest) *dto.GeneralOpenAI } mediaMessages := message.ParseContent() - if message.Role == "assistant" && message.ToolCalls != nil && message.Content != "null" { + if message.Role == "assistant" && message.ToolCalls != nil && message.Content == "" { mediaMessages = []dto.MediaContent{} } for j, mediaMessage := range mediaMessages { From 96183e666419919900f696ac5ee3763b80a95197 Mon Sep 17 00:00:00 2001 From: CaIon <1808837298@qq.com> Date: Mon, 9 Jun 2025 20:50:37 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E2=9C=A8=20feat(ChannelsTable):=20add=20re?= =?UTF-8?q?nderQuotaWithAmount=20function=20and=20clean=20up=20imports?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/components/table/ChannelsTable.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/src/components/table/ChannelsTable.js b/web/src/components/table/ChannelsTable.js index 9b38a883..68babe2e 100644 --- a/web/src/components/table/ChannelsTable.js +++ b/web/src/components/table/ChannelsTable.js @@ -6,9 +6,9 @@ import { showSuccess, timestamp2string, renderGroup, - renderNumberWithPoint, renderQuota, - getChannelIcon + getChannelIcon, + renderQuotaWithAmount } from '../../helpers/index.js'; import {