diff --git a/dto/openai_image.go b/dto/openai_image.go index 7431935b..970f5bb4 100644 --- a/dto/openai_image.go +++ b/dto/openai_image.go @@ -9,19 +9,22 @@ import ( ) type ImageRequest struct { - Model string `json:"model"` - Prompt string `json:"prompt" binding:"required"` - N uint `json:"n,omitempty"` + Model string `json:"model"` + Prompt string `json:"prompt" binding:"required"` + N uint `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"` + 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"` } func (i *ImageRequest) GetTokenCountMeta() *types.TokenCountMeta { 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") || 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/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 ( 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); } }} > 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 { 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 {