From 9c12e02cb50ad696aab25170c2cace1ad3eb3691 Mon Sep 17 00:00:00 2001
From: skynono <6811626@qq.com>
Date: Mon, 19 May 2025 14:28:29 +0800
Subject: [PATCH 1/5] fix: if default model is not exist, set the first one as
default
---
web/src/pages/Playground/Playground.js | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/web/src/pages/Playground/Playground.js b/web/src/pages/Playground/Playground.js
index e8138c01..08eada17 100644
--- a/web/src/pages/Playground/Playground.js
+++ b/web/src/pages/Playground/Playground.js
@@ -64,8 +64,9 @@ const Playground = () => {
},
];
+ const defaultModel = 'gpt-4o-mini';
const [inputs, setInputs] = useState({
- model: 'gpt-4o-mini',
+ model: defaultModel,
group: '',
max_tokens: 0,
temperature: 0,
@@ -108,6 +109,11 @@ const Playground = () => {
value: model,
}));
setModels(localModelOptions);
+ // if default model is not in the list, set the first one as default
+ const hasDefault = localModelOptions.some(option => option.value === defaultModel);
+ if (!hasDefault && localModelOptions.length > 0) {
+ setInputs((inputs) => ({ ...inputs, model: localModelOptions[0].value }));
+ }
} else {
showError(t(message));
}
From e1190f98e9de90f8f7fa090043bc1ae02cc5a7a7 Mon Sep 17 00:00:00 2001
From: skynono <6811626@qq.com>
Date: Mon, 19 May 2025 15:42:36 +0800
Subject: [PATCH 2/5] fix: typo in oidc_enabled field (previously oidc)
---
web/src/pages/Home/index.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/web/src/pages/Home/index.js b/web/src/pages/Home/index.js
index 599c7930..84fabf6f 100644
--- a/web/src/pages/Home/index.js
+++ b/web/src/pages/Home/index.js
@@ -158,7 +158,7 @@ const Home = () => {
{t('OIDC 身份验证')}:
- {statusState?.status?.oidc === true
+ {statusState?.status?.oidc_enabled === true
? t('已启用')
: t('未启用')}
From 2cc2d4f6526ad809e35cb405e8e6597691e3a5e1 Mon Sep 17 00:00:00 2001
From: skynono <6811626@qq.com>
Date: Fri, 23 May 2025 13:51:11 +0800
Subject: [PATCH 3/5] fix: keep BatchDelete and TagMode enabled status
---
web/src/components/ChannelsTable.js | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/web/src/components/ChannelsTable.js b/web/src/components/ChannelsTable.js
index 9b1dd602..f490e14a 100644
--- a/web/src/components/ChannelsTable.js
+++ b/web/src/components/ChannelsTable.js
@@ -888,9 +888,13 @@ const ChannelsTable = () => {
const localIdSort = localStorage.getItem('id-sort') === 'true';
const localPageSize =
parseInt(localStorage.getItem('page-size')) || ITEMS_PER_PAGE;
+ const localEnableTagMode = localStorage.getItem('enable-tag-mode') === 'true';
+ const localEnableBatchDelete = localStorage.getItem('enable-batch-delete') === 'true';
setIdSort(localIdSort);
setPageSize(localPageSize);
- loadChannels(0, localPageSize, localIdSort, enableTagMode)
+ setEnableTagMode(localEnableTagMode);
+ setEnableBatchDelete(localEnableBatchDelete);
+ loadChannels(0, localPageSize, localIdSort, localEnableTagMode)
.then()
.catch((reason) => {
showError(reason);
@@ -1486,10 +1490,12 @@ const ChannelsTable = () => {
{t('开启批量操作')}
{
+ localStorage.setItem('enable-batch-delete', v + '');
setEnableBatchDelete(v);
}}
/>
@@ -1553,6 +1559,7 @@ const ChannelsTable = () => {
uncheckedText={t('关')}
aria-label={t('是否启用标签聚合')}
onChange={(v) => {
+ localStorage.setItem('enable-tag-mode', v + '');
setEnableTagMode(v);
loadChannels(0, pageSize, idSort, v);
}}
From 368fd75c86aa775a52fcfd6270144213b0c02f2c Mon Sep 17 00:00:00 2001
From: skynono <6811626@qq.com>
Date: Mon, 26 May 2025 17:11:45 +0800
Subject: [PATCH 4/5] fix: ali parameter.enable_thinking must be set to false
for non-streaming calls
---
relay/channel/ali/adaptor.go | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/relay/channel/ali/adaptor.go b/relay/channel/ali/adaptor.go
index ab632d22..31e926d6 100644
--- a/relay/channel/ali/adaptor.go
+++ b/relay/channel/ali/adaptor.go
@@ -57,6 +57,12 @@ func (a *Adaptor) ConvertOpenAIRequest(c *gin.Context, info *relaycommon.RelayIn
if request == nil {
return nil, errors.New("request is nil")
}
+
+ // fix: ali parameter.enable_thinking must be set to false for non-streaming calls
+ if !info.IsStream {
+ request.EnableThinking = false
+ }
+
switch info.RelayMode {
default:
aliReq := requestOpenAI2Ali(*request)
From 30d5a11f466d0ec95d86028bb6455b51e39f7be4 Mon Sep 17 00:00:00 2001
From: creamlike1024
Date: Mon, 26 May 2025 18:53:41 +0800
Subject: [PATCH 5/5] fix: search-preview model web search billing
---
dto/openai_request.go | 6 ++++++
relay/relay-text.go | 43 +++++++++++++++++++++++++++++++++++++++----
2 files changed, 45 insertions(+), 4 deletions(-)
diff --git a/dto/openai_request.go b/dto/openai_request.go
index e8833b3d..e491812a 100644
--- a/dto/openai_request.go
+++ b/dto/openai_request.go
@@ -53,6 +53,7 @@ type GeneralOpenAIRequest struct {
Audio any `json:"audio,omitempty"`
EnableThinking any `json:"enable_thinking,omitempty"` // ali
ExtraBody any `json:"extra_body,omitempty"`
+ WebSearchOptions *WebSearchOptions `json:"web_search_options,omitempty"`
}
type ToolCallRequest struct {
@@ -371,6 +372,11 @@ func (m *Message) ParseContent() []MediaContent {
return contentList
}
+type WebSearchOptions struct {
+ SearchContextSize string `json:"search_context_size,omitempty"`
+ UserLocation json.RawMessage `json:"user_location,omitempty"`
+}
+
type OpenAIResponsesRequest struct {
Model string `json:"model"`
Input json.RawMessage `json:"input,omitempty"`
diff --git a/relay/relay-text.go b/relay/relay-text.go
index 8d5cd384..f1105907 100644
--- a/relay/relay-text.go
+++ b/relay/relay-text.go
@@ -47,6 +47,20 @@ func getAndValidateTextRequest(c *gin.Context, relayInfo *relaycommon.RelayInfo)
if textRequest.Model == "" {
return nil, errors.New("model is required")
}
+ if textRequest.WebSearchOptions != nil {
+ if textRequest.WebSearchOptions.SearchContextSize != "" {
+ validSizes := map[string]bool{
+ "high": true,
+ "medium": true,
+ "low": true,
+ }
+ if !validSizes[textRequest.WebSearchOptions.SearchContextSize] {
+ return nil, errors.New("invalid search_context_size, must be one of: high, medium, low")
+ }
+ } else {
+ textRequest.WebSearchOptions.SearchContextSize = "medium"
+ }
+ }
switch relayInfo.RelayMode {
case relayconstant.RelayModeCompletions:
if textRequest.Prompt == "" {
@@ -76,6 +90,10 @@ func TextHelper(c *gin.Context) (openaiErr *dto.OpenAIErrorWithStatusCode) {
// get & validate textRequest 获取并验证文本请求
textRequest, err := getAndValidateTextRequest(c, relayInfo)
+ if textRequest.WebSearchOptions != nil {
+ c.Set("chat_completion_web_search_context_size", textRequest.WebSearchOptions.SearchContextSize)
+ }
+
if err != nil {
common.LogError(c, fmt.Sprintf("getAndValidateTextRequest failed: %s", err.Error()))
return service.OpenAIErrorWrapperLocal(err, "invalid_text_request", http.StatusBadRequest)
@@ -370,9 +388,20 @@ func postConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo,
dWebSearchQuota = decimal.NewFromFloat(webSearchPrice).
Mul(decimal.NewFromInt(int64(webSearchTool.CallCount))).
Div(decimal.NewFromInt(1000)).Mul(dGroupRatio).Mul(dQuotaPerUnit)
- extraContent += fmt.Sprintf("Web Search 调用 %d 次,上下文大小 %s,调用花费 $%s",
+ extraContent += fmt.Sprintf("Web Search 调用 %d 次,上下文大小 %s,调用花费 %s",
webSearchTool.CallCount, webSearchTool.SearchContextSize, dWebSearchQuota.String())
}
+ } else if strings.HasSuffix(modelName, "search-preview") {
+ // search-preview 模型不支持 response api
+ searchContextSize := ctx.GetString("chat_completion_web_search_context_size")
+ if searchContextSize == "" {
+ searchContextSize = "medium"
+ }
+ webSearchPrice = operation_setting.GetWebSearchPricePerThousand(modelName, searchContextSize)
+ dWebSearchQuota = decimal.NewFromFloat(webSearchPrice).
+ Div(decimal.NewFromInt(1000)).Mul(dGroupRatio).Mul(dQuotaPerUnit)
+ extraContent += fmt.Sprintf("Web Search 调用 1 次,上下文大小 %s,调用花费 %s",
+ searchContextSize, dWebSearchQuota.String())
}
// file search tool 计费
var dFileSearchQuota decimal.Decimal
@@ -463,10 +492,16 @@ func postConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo,
other["image_ratio"] = imageRatio
other["image_output"] = imageTokens
}
- if !dWebSearchQuota.IsZero() && relayInfo.ResponsesUsageInfo != nil {
- if webSearchTool, exists := relayInfo.ResponsesUsageInfo.BuiltInTools[dto.BuildInToolWebSearchPreview]; exists {
+ if !dWebSearchQuota.IsZero() {
+ if relayInfo.ResponsesUsageInfo != nil {
+ if webSearchTool, exists := relayInfo.ResponsesUsageInfo.BuiltInTools[dto.BuildInToolWebSearchPreview]; exists {
+ other["web_search"] = true
+ other["web_search_call_count"] = webSearchTool.CallCount
+ other["web_search_price"] = webSearchPrice
+ }
+ } else if strings.HasSuffix(modelName, "search-preview") {
other["web_search"] = true
- other["web_search_call_count"] = webSearchTool.CallCount
+ other["web_search_call_count"] = 1
other["web_search_price"] = webSearchPrice
}
}