From c13683e98211ab9016350f51e7bf198da4ad8765 Mon Sep 17 00:00:00 2001 From: CaIon Date: Tue, 12 Aug 2025 20:42:44 +0800 Subject: [PATCH 1/6] fix(auth): refine authorization header setting for messages endpoint #1575 --- middleware/auth.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/middleware/auth.go b/middleware/auth.go index ee8d9241..5f682eb6 100644 --- a/middleware/auth.go +++ b/middleware/auth.go @@ -197,8 +197,10 @@ func TokenAuth() func(c *gin.Context) { // 或者是否 x-api-key 不为空且存在anthropic-version // 谁知道有多少不符合规范没写anthropic-version的 // 所以就这样随它去吧( - if strings.Contains(c.Request.URL.Path, "/v1/messages") || (anthropicKey != "" && c.Request.Header.Get("anthropic-version") != "") { - c.Request.Header.Set("Authorization", "Bearer "+anthropicKey) + if strings.Contains(c.Request.URL.Path, "/v1/messages") { + if anthropicKey != "" { + c.Request.Header.Set("Authorization", "Bearer "+anthropicKey) + } } // gemini api 从query中获取key if strings.HasPrefix(c.Request.URL.Path, "/v1beta/models") || From f5abbeb353123e3118fba740cad79d2bc63557ba Mon Sep 17 00:00:00 2001 From: CaIon Date: Tue, 12 Aug 2025 21:12:00 +0800 Subject: [PATCH 2/6] fix(dalle): update ImageRequest struct to use json.RawMessage for flexible field types --- dto/dalle.go | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/dto/dalle.go b/dto/dalle.go index ce2f6361..d1e66de9 100644 --- a/dto/dalle.go +++ b/dto/dalle.go @@ -3,19 +3,22 @@ package dto import "encoding/json" type ImageRequest struct { - Model string `json:"model"` - Prompt string `json:"prompt" binding:"required"` - N int `json:"n,omitempty"` - Size string `json:"size,omitempty"` - Quality string `json:"quality,omitempty"` - ResponseFormat string `json:"response_format,omitempty"` - Style string `json:"style,omitempty"` - User string `json:"user,omitempty"` - ExtraFields json.RawMessage `json:"extra_fields,omitempty"` - Background string `json:"background,omitempty"` - Moderation string `json:"moderation,omitempty"` - OutputFormat string `json:"output_format,omitempty"` - Watermark *bool `json:"watermark,omitempty"` + Model string `json:"model"` + Prompt string `json:"prompt" binding:"required"` + N int `json:"n,omitempty"` + Size string `json:"size,omitempty"` + Quality string `json:"quality,omitempty"` + ResponseFormat string `json:"response_format,omitempty"` + Style json.RawMessage `json:"style,omitempty"` + User json.RawMessage `json:"user,omitempty"` + ExtraFields json.RawMessage `json:"extra_fields,omitempty"` + Background json.RawMessage `json:"background,omitempty"` + Moderation json.RawMessage `json:"moderation,omitempty"` + OutputFormat json.RawMessage `json:"output_format,omitempty"` + OutputCompression json.RawMessage `json:"output_compression,omitempty"` + PartialImages json.RawMessage `json:"partial_images,omitempty"` + // Stream bool `json:"stream,omitempty"` + Watermark *bool `json:"watermark,omitempty"` } type ImageResponse struct { From 936b1f8d091bc4ec3eab27d2a268ff661e9d5297 Mon Sep 17 00:00:00 2001 From: t0ng7u Date: Tue, 12 Aug 2025 23:10:29 +0800 Subject: [PATCH 3/6] =?UTF-8?q?=F0=9F=90=9B=20fix:=20group-ratio=20display?= =?UTF-8?q?=20&=20deduplicate=20price=20logic=20in=20model-pricing=20views?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary • Ensure “Group Ratio” shows correctly when “All” groups are selected. • Eliminate redundant price calculations in both card and table views. Details 1. PricingCardView.jsx • Removed obsolete renderPriceInfo function. • Calculate priceData once per model and reuse for header price string and footer ratio block. • Display priceData.usedGroupRatio as the group ratio fallback. 2. PricingTableColumns.js • Introduced WeakMap-based cache (getPriceData) to compute priceData only once per row. • Updated ratioColumn & priceColumn to reuse cached priceData. • Now displays priceData.usedGroupRatio, preventing empty cells for “All” group. Benefits • Correct visual output for group ratio across all views. • Reduced duplicate calculations, improving render performance. • Removed dead code, keeping components clean and maintainable. --- .../view/card/PricingCardView.jsx | 26 ++++++------- .../view/table/PricingTableColumns.js | 38 ++++++++++++------- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/web/src/components/table/model-pricing/view/card/PricingCardView.jsx b/web/src/components/table/model-pricing/view/card/PricingCardView.jsx index 8f8caa31..d37c9a5b 100644 --- a/web/src/components/table/model-pricing/view/card/PricingCardView.jsx +++ b/web/src/components/table/model-pricing/view/card/PricingCardView.jsx @@ -128,19 +128,6 @@ const PricingCardView = ({ return record.description || ''; }; - // 渲染价格信息 - const renderPriceInfo = (record) => { - const priceData = calculateModelPrice({ - record, - selectedGroup, - groupRatio, - tokenUnit, - displayPrice, - currency, - }); - return formatPriceInfo(priceData, t); - }; - // 渲染标签 const renderTags = (record) => { // 计费类型标签(左边) @@ -221,6 +208,15 @@ const PricingCardView = ({ const modelKey = getModelKey(model); const isSelected = selectedRowKeys.includes(modelKey); + const priceData = calculateModelPrice({ + record: model, + selectedGroup, + groupRatio, + tokenUnit, + displayPrice, + currency, + }); + return (
- {renderPriceInfo(model)} + {formatPriceInfo(priceData, t)}
@@ -313,7 +309,7 @@ const PricingCardView = ({ {t('补全')}: {model.quota_type === 0 ? parseFloat(model.completion_ratio.toFixed(3)) : t('无')}
- {t('分组')}: {priceData.usedGroupRatio} + {t('分组')}: {priceData?.usedGroupRatio ?? '-'}
diff --git a/web/src/components/table/model-pricing/view/table/PricingTableColumns.js b/web/src/components/table/model-pricing/view/table/PricingTableColumns.js index 18e1fc89..0dd963a8 100644 --- a/web/src/components/table/model-pricing/view/table/PricingTableColumns.js +++ b/web/src/components/table/model-pricing/view/table/PricingTableColumns.js @@ -98,6 +98,25 @@ export const getPricingTableColumns = ({ displayPrice, showRatio, }) => { + + const priceDataCache = new WeakMap(); + + const getPriceData = (record) => { + let cache = priceDataCache.get(record); + if (!cache) { + cache = calculateModelPrice({ + record, + selectedGroup, + groupRatio, + tokenUnit, + displayPrice, + currency, + }); + priceDataCache.set(record, cache); + } + return cache; + }; + const endpointColumn = { title: t('可用端点类型'), dataIndex: 'supported_endpoint_types', @@ -167,21 +186,21 @@ export const getPricingTableColumns = ({ dataIndex: 'model_ratio', render: (text, record, index) => { const completionRatio = parseFloat(record.completion_ratio.toFixed(3)); - const content = ( + const priceData = getPriceData(record); + + return (
{t('模型倍率')}:{record.quota_type === 0 ? text : t('无')}
- {t('补全倍率')}: - {record.quota_type === 0 ? completionRatio : t('无')} + {t('补全倍率')}:{record.quota_type === 0 ? completionRatio : t('无')}
- {t('分组倍率')}:{groupRatio[selectedGroup]} + {t('分组倍率')}:{priceData?.usedGroupRatio ?? '-'}
); - return content; }, }; @@ -190,14 +209,7 @@ export const getPricingTableColumns = ({ dataIndex: 'model_price', fixed: 'right', render: (text, record, index) => { - const priceData = calculateModelPrice({ - record, - selectedGroup, - groupRatio, - tokenUnit, - displayPrice, - currency - }); + const priceData = getPriceData(record); if (priceData.isPerToken) { return ( From 63b9457b6cb2074c99ad46f62d842ee2542dfae6 Mon Sep 17 00:00:00 2001 From: t0ng7u Date: Tue, 12 Aug 2025 23:32:25 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=F0=9F=94=8D=20fix(pricing):=20synchronize?= =?UTF-8?q?=20search=20term=20with=20sidebar=20filters=20&=20reset=20behav?= =?UTF-8?q?ior?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add `searchValue` to every dependency array in `usePricingFilterCounts` to ensure group/vendor/tag counts and disabled states update dynamically while performing fuzzy search. * Refactor `PricingTopSection` search box into a controlled component: - Accept `searchValue` prop and bind it to `Input.value` - Extend memo dependencies to include `searchValue` This keeps the UI in sync with state changes triggered by `handleChange`. * Guarantee that `resetPricingFilters` clears the search field by leveraging the new controlled input. As a result, sidebar counters/disabled states now react to search input, and the “Reset” button fully restores default filters without leaving the search term visible. --- .../layout/header/PricingTopSection.jsx | 4 +++- .../model-pricing/usePricingFilterCounts.js | 17 +++++------------ 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/web/src/components/table/model-pricing/layout/header/PricingTopSection.jsx b/web/src/components/table/model-pricing/layout/header/PricingTopSection.jsx index 1a4c301a..b255216f 100644 --- a/web/src/components/table/model-pricing/layout/header/PricingTopSection.jsx +++ b/web/src/components/table/model-pricing/layout/header/PricingTopSection.jsx @@ -35,6 +35,7 @@ const PricingTopSection = ({ models, filteredModels, loading, + searchValue, t }) => { const [showFilterModal, setShowFilterModal] = useState(false); @@ -46,6 +47,7 @@ const PricingTopSection = ({ } placeholder={t('模糊搜索模型名称')} + value={searchValue} onCompositionStart={handleCompositionStart} onCompositionEnd={handleCompositionEnd} onChange={handleChange} @@ -78,7 +80,7 @@ const PricingTopSection = ({ )} - ), [selectedRowKeys, t, handleCompositionStart, handleCompositionEnd, handleChange, copyText, isMobile]); + ), [selectedRowKeys, t, handleCompositionStart, handleCompositionEnd, handleChange, copyText, isMobile, searchValue]); return ( <> diff --git a/web/src/hooks/model-pricing/usePricingFilterCounts.js b/web/src/hooks/model-pricing/usePricingFilterCounts.js index ee7f41c7..046d3729 100644 --- a/web/src/hooks/model-pricing/usePricingFilterCounts.js +++ b/web/src/hooks/model-pricing/usePricingFilterCounts.js @@ -104,34 +104,27 @@ export const usePricingFilterCounts = ({ // 生成不同视图所需的模型集合 const quotaTypeModels = useMemo( () => allModels.filter((m) => matchesFilters(m, ['quota'])), - [allModels, filterGroup, filterEndpointType, filterVendor, filterTag] + [allModels, filterGroup, filterEndpointType, filterVendor, filterTag, searchValue] ); const endpointTypeModels = useMemo( () => allModels.filter((m) => matchesFilters(m, ['endpoint'])), - [allModels, filterGroup, filterQuotaType, filterVendor, filterTag] + [allModels, filterGroup, filterQuotaType, filterVendor, filterTag, searchValue] ); const vendorModels = useMemo( () => allModels.filter((m) => matchesFilters(m, ['vendor'])), - [allModels, filterGroup, filterQuotaType, filterEndpointType, filterTag] + [allModels, filterGroup, filterQuotaType, filterEndpointType, filterTag, searchValue] ); const tagModels = useMemo( () => allModels.filter((m) => matchesFilters(m, ['tag'])), - [allModels, filterGroup, filterQuotaType, filterEndpointType, filterVendor] + [allModels, filterGroup, filterQuotaType, filterEndpointType, filterVendor, searchValue] ); const groupCountModels = useMemo( () => allModels.filter((m) => matchesFilters(m, ['group'])), - [ - allModels, - filterQuotaType, - filterEndpointType, - filterVendor, - filterTag, - searchValue, - ] + [allModels, filterQuotaType, filterEndpointType, filterVendor, filterTag, searchValue] ); return { From 196e2a0abb39038bdf119d62648ddede5a0f4486 Mon Sep 17 00:00:00 2001 From: t0ng7u Date: Tue, 12 Aug 2025 23:37:30 +0800 Subject: [PATCH 5/6] =?UTF-8?q?=F0=9F=90=9B=20fix:=20Always=20update=20`se?= =?UTF-8?q?archValue`=20during=20IME=20composition=20to=20enable=20Chinese?= =?UTF-8?q?=20input=20in=20model=20search?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: • Removed early return in `handleChange` that blocked controlled value updates while an Input Method Editor (IME) was composing text. • Ensures that Chinese (and other IME-based) characters appear immediately in the “Fuzzy Search Model Name” field. • No change to downstream filtering logic—`searchValue` continues to drive model list filtering as before. Files affected: web/src/hooks/model-pricing/useModelPricingData.js --- web/src/hooks/model-pricing/useModelPricingData.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/web/src/hooks/model-pricing/useModelPricingData.js b/web/src/hooks/model-pricing/useModelPricingData.js index c285cf4d..d209089c 100644 --- a/web/src/hooks/model-pricing/useModelPricingData.js +++ b/web/src/hooks/model-pricing/useModelPricingData.js @@ -211,9 +211,6 @@ export const useModelPricingData = () => { }; const handleChange = (value) => { - if (compositionRef.current.isComposition) { - return; - } const newSearchValue = value ? value : ''; setSearchValue(newSearchValue); }; @@ -231,9 +228,7 @@ export const useModelPricingData = () => { const handleGroupClick = (group) => { setSelectedGroup(group); - // 同时将分组过滤设置为该分组 setFilterGroup(group); - if (group === 'all') { showInfo(t('已切换至最优倍率视图,每个模型使用其最低倍率分组')); } else { From 223f0d085088980e06371736ab1b3028fe94b0ac Mon Sep 17 00:00:00 2001 From: t0ng7u Date: Wed, 13 Aug 2025 18:31:00 +0800 Subject: [PATCH 6/6] =?UTF-8?q?=F0=9F=90=9B=20fix(tokens):=20correct=20mai?= =?UTF-8?q?n=20Chat=20button=20navigation=20to=20prevent=20404?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The primary "Chat" button on the tokens table navigated to a 404 page because it passed incorrect arguments to onOpenLink (using a raw localStorage value instead of the parsed chat value). Changes: - Build chatsArray with an explicit `value` for each item. - Use the first item's `name` and `value` for the main button, matching the dropdown behavior. - Preserve existing error handling when no chats are configured. Impact: - Main "Chat" button now opens the correct link, consistent with the dropdown action. - No API/schema changes, no UI changes. File: - web/src/components/table/tokens/TokensColumnDefs.js Verification: - Manually verified primary button and dropdown both navigate correctly. - Linter passes with no issues. --- web/src/components/table/tokens/TokensColumnDefs.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/web/src/components/table/tokens/TokensColumnDefs.js b/web/src/components/table/tokens/TokensColumnDefs.js index 1d2ab9dd..443c59d3 100644 --- a/web/src/components/table/tokens/TokensColumnDefs.js +++ b/web/src/components/table/tokens/TokensColumnDefs.js @@ -305,6 +305,7 @@ const renderOperations = (text, record, onOpenLink, setEditingToken, setShowEdit node: 'item', key: i, name, + value: item[name], onClick: () => onOpenLink(name, item[name], record), }); } @@ -326,11 +327,8 @@ const renderOperations = (text, record, onOpenLink, setEditingToken, setShowEdit if (chatsArray.length === 0) { showError(t('请联系管理员配置聊天链接')); } else { - onOpenLink( - 'default', - chatsArray[0].name ? (parsed => parsed)(localStorage.getItem('chats')) : '', - record, - ); + const first = chatsArray[0]; + onOpenLink(first.name, first.value, record); } }} >