Merge branch 'alpha' into refactor_relay
# Conflicts: # dto/openai_image.go
This commit is contained in:
@@ -9,19 +9,22 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ImageRequest struct {
|
type ImageRequest struct {
|
||||||
Model string `json:"model"`
|
Model string `json:"model"`
|
||||||
Prompt string `json:"prompt" binding:"required"`
|
Prompt string `json:"prompt" binding:"required"`
|
||||||
N uint `json:"n,omitempty"`
|
N uint `json:"n,omitempty"`
|
||||||
Size string `json:"size,omitempty"`
|
Size string `json:"size,omitempty"`
|
||||||
Quality string `json:"quality,omitempty"`
|
Quality string `json:"quality,omitempty"`
|
||||||
ResponseFormat string `json:"response_format,omitempty"`
|
ResponseFormat string `json:"response_format,omitempty"`
|
||||||
Style string `json:"style,omitempty"`
|
Style json.RawMessage `json:"style,omitempty"`
|
||||||
User string `json:"user,omitempty"`
|
User json.RawMessage `json:"user,omitempty"`
|
||||||
ExtraFields json.RawMessage `json:"extra_fields,omitempty"`
|
ExtraFields json.RawMessage `json:"extra_fields,omitempty"`
|
||||||
Background string `json:"background,omitempty"`
|
Background json.RawMessage `json:"background,omitempty"`
|
||||||
Moderation string `json:"moderation,omitempty"`
|
Moderation json.RawMessage `json:"moderation,omitempty"`
|
||||||
OutputFormat string `json:"output_format,omitempty"`
|
OutputFormat json.RawMessage `json:"output_format,omitempty"`
|
||||||
Watermark *bool `json:"watermark,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 {
|
func (i *ImageRequest) GetTokenCountMeta() *types.TokenCountMeta {
|
||||||
|
|||||||
@@ -197,8 +197,10 @@ func TokenAuth() func(c *gin.Context) {
|
|||||||
// 或者是否 x-api-key 不为空且存在anthropic-version
|
// 或者是否 x-api-key 不为空且存在anthropic-version
|
||||||
// 谁知道有多少不符合规范没写anthropic-version的
|
// 谁知道有多少不符合规范没写anthropic-version的
|
||||||
// 所以就这样随它去吧(
|
// 所以就这样随它去吧(
|
||||||
if strings.Contains(c.Request.URL.Path, "/v1/messages") || (anthropicKey != "" && c.Request.Header.Get("anthropic-version") != "") {
|
if strings.Contains(c.Request.URL.Path, "/v1/messages") {
|
||||||
c.Request.Header.Set("Authorization", "Bearer "+anthropicKey)
|
if anthropicKey != "" {
|
||||||
|
c.Request.Header.Set("Authorization", "Bearer "+anthropicKey)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// gemini api 从query中获取key
|
// gemini api 从query中获取key
|
||||||
if strings.HasPrefix(c.Request.URL.Path, "/v1beta/models") ||
|
if strings.HasPrefix(c.Request.URL.Path, "/v1beta/models") ||
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ const PricingTopSection = ({
|
|||||||
models,
|
models,
|
||||||
filteredModels,
|
filteredModels,
|
||||||
loading,
|
loading,
|
||||||
|
searchValue,
|
||||||
t
|
t
|
||||||
}) => {
|
}) => {
|
||||||
const [showFilterModal, setShowFilterModal] = useState(false);
|
const [showFilterModal, setShowFilterModal] = useState(false);
|
||||||
@@ -46,6 +47,7 @@ const PricingTopSection = ({
|
|||||||
<Input
|
<Input
|
||||||
prefix={<IconSearch />}
|
prefix={<IconSearch />}
|
||||||
placeholder={t('模糊搜索模型名称')}
|
placeholder={t('模糊搜索模型名称')}
|
||||||
|
value={searchValue}
|
||||||
onCompositionStart={handleCompositionStart}
|
onCompositionStart={handleCompositionStart}
|
||||||
onCompositionEnd={handleCompositionEnd}
|
onCompositionEnd={handleCompositionEnd}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
@@ -78,7 +80,7 @@ const PricingTopSection = ({
|
|||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
), [selectedRowKeys, t, handleCompositionStart, handleCompositionEnd, handleChange, copyText, isMobile]);
|
), [selectedRowKeys, t, handleCompositionStart, handleCompositionEnd, handleChange, copyText, isMobile, searchValue]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -128,19 +128,6 @@ const PricingCardView = ({
|
|||||||
return record.description || '';
|
return record.description || '';
|
||||||
};
|
};
|
||||||
|
|
||||||
// 渲染价格信息
|
|
||||||
const renderPriceInfo = (record) => {
|
|
||||||
const priceData = calculateModelPrice({
|
|
||||||
record,
|
|
||||||
selectedGroup,
|
|
||||||
groupRatio,
|
|
||||||
tokenUnit,
|
|
||||||
displayPrice,
|
|
||||||
currency,
|
|
||||||
});
|
|
||||||
return formatPriceInfo(priceData, t);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 渲染标签
|
// 渲染标签
|
||||||
const renderTags = (record) => {
|
const renderTags = (record) => {
|
||||||
// 计费类型标签(左边)
|
// 计费类型标签(左边)
|
||||||
@@ -221,6 +208,15 @@ const PricingCardView = ({
|
|||||||
const modelKey = getModelKey(model);
|
const modelKey = getModelKey(model);
|
||||||
const isSelected = selectedRowKeys.includes(modelKey);
|
const isSelected = selectedRowKeys.includes(modelKey);
|
||||||
|
|
||||||
|
const priceData = calculateModelPrice({
|
||||||
|
record: model,
|
||||||
|
selectedGroup,
|
||||||
|
groupRatio,
|
||||||
|
tokenUnit,
|
||||||
|
displayPrice,
|
||||||
|
currency,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
key={modelKey || index}
|
key={modelKey || index}
|
||||||
@@ -238,7 +234,7 @@ const PricingCardView = ({
|
|||||||
{model.model_name}
|
{model.model_name}
|
||||||
</h3>
|
</h3>
|
||||||
<div className="flex items-center gap-3 text-xs mt-1">
|
<div className="flex items-center gap-3 text-xs mt-1">
|
||||||
{renderPriceInfo(model)}
|
{formatPriceInfo(priceData, t)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -313,7 +309,7 @@ const PricingCardView = ({
|
|||||||
{t('补全')}: {model.quota_type === 0 ? parseFloat(model.completion_ratio.toFixed(3)) : t('无')}
|
{t('补全')}: {model.quota_type === 0 ? parseFloat(model.completion_ratio.toFixed(3)) : t('无')}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{t('分组')}: {priceData.usedGroupRatio}
|
{t('分组')}: {priceData?.usedGroupRatio ?? '-'}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -98,6 +98,25 @@ export const getPricingTableColumns = ({
|
|||||||
displayPrice,
|
displayPrice,
|
||||||
showRatio,
|
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 = {
|
const endpointColumn = {
|
||||||
title: t('可用端点类型'),
|
title: t('可用端点类型'),
|
||||||
dataIndex: 'supported_endpoint_types',
|
dataIndex: 'supported_endpoint_types',
|
||||||
@@ -167,21 +186,21 @@ export const getPricingTableColumns = ({
|
|||||||
dataIndex: 'model_ratio',
|
dataIndex: 'model_ratio',
|
||||||
render: (text, record, index) => {
|
render: (text, record, index) => {
|
||||||
const completionRatio = parseFloat(record.completion_ratio.toFixed(3));
|
const completionRatio = parseFloat(record.completion_ratio.toFixed(3));
|
||||||
const content = (
|
const priceData = getPriceData(record);
|
||||||
|
|
||||||
|
return (
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<div className="text-gray-700">
|
<div className="text-gray-700">
|
||||||
{t('模型倍率')}:{record.quota_type === 0 ? text : t('无')}
|
{t('模型倍率')}:{record.quota_type === 0 ? text : t('无')}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-gray-700">
|
<div className="text-gray-700">
|
||||||
{t('补全倍率')}:
|
{t('补全倍率')}:{record.quota_type === 0 ? completionRatio : t('无')}
|
||||||
{record.quota_type === 0 ? completionRatio : t('无')}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="text-gray-700">
|
<div className="text-gray-700">
|
||||||
{t('分组倍率')}:{groupRatio[selectedGroup]}
|
{t('分组倍率')}:{priceData?.usedGroupRatio ?? '-'}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
return content;
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -190,14 +209,7 @@ export const getPricingTableColumns = ({
|
|||||||
dataIndex: 'model_price',
|
dataIndex: 'model_price',
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
render: (text, record, index) => {
|
render: (text, record, index) => {
|
||||||
const priceData = calculateModelPrice({
|
const priceData = getPriceData(record);
|
||||||
record,
|
|
||||||
selectedGroup,
|
|
||||||
groupRatio,
|
|
||||||
tokenUnit,
|
|
||||||
displayPrice,
|
|
||||||
currency
|
|
||||||
});
|
|
||||||
|
|
||||||
if (priceData.isPerToken) {
|
if (priceData.isPerToken) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -305,6 +305,7 @@ const renderOperations = (text, record, onOpenLink, setEditingToken, setShowEdit
|
|||||||
node: 'item',
|
node: 'item',
|
||||||
key: i,
|
key: i,
|
||||||
name,
|
name,
|
||||||
|
value: item[name],
|
||||||
onClick: () => onOpenLink(name, item[name], record),
|
onClick: () => onOpenLink(name, item[name], record),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -326,11 +327,8 @@ const renderOperations = (text, record, onOpenLink, setEditingToken, setShowEdit
|
|||||||
if (chatsArray.length === 0) {
|
if (chatsArray.length === 0) {
|
||||||
showError(t('请联系管理员配置聊天链接'));
|
showError(t('请联系管理员配置聊天链接'));
|
||||||
} else {
|
} else {
|
||||||
onOpenLink(
|
const first = chatsArray[0];
|
||||||
'default',
|
onOpenLink(first.name, first.value, record);
|
||||||
chatsArray[0].name ? (parsed => parsed)(localStorage.getItem('chats')) : '',
|
|
||||||
record,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -211,9 +211,6 @@ export const useModelPricingData = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleChange = (value) => {
|
const handleChange = (value) => {
|
||||||
if (compositionRef.current.isComposition) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const newSearchValue = value ? value : '';
|
const newSearchValue = value ? value : '';
|
||||||
setSearchValue(newSearchValue);
|
setSearchValue(newSearchValue);
|
||||||
};
|
};
|
||||||
@@ -231,9 +228,7 @@ export const useModelPricingData = () => {
|
|||||||
|
|
||||||
const handleGroupClick = (group) => {
|
const handleGroupClick = (group) => {
|
||||||
setSelectedGroup(group);
|
setSelectedGroup(group);
|
||||||
// 同时将分组过滤设置为该分组
|
|
||||||
setFilterGroup(group);
|
setFilterGroup(group);
|
||||||
|
|
||||||
if (group === 'all') {
|
if (group === 'all') {
|
||||||
showInfo(t('已切换至最优倍率视图,每个模型使用其最低倍率分组'));
|
showInfo(t('已切换至最优倍率视图,每个模型使用其最低倍率分组'));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -104,34 +104,27 @@ export const usePricingFilterCounts = ({
|
|||||||
// 生成不同视图所需的模型集合
|
// 生成不同视图所需的模型集合
|
||||||
const quotaTypeModels = useMemo(
|
const quotaTypeModels = useMemo(
|
||||||
() => allModels.filter((m) => matchesFilters(m, ['quota'])),
|
() => allModels.filter((m) => matchesFilters(m, ['quota'])),
|
||||||
[allModels, filterGroup, filterEndpointType, filterVendor, filterTag]
|
[allModels, filterGroup, filterEndpointType, filterVendor, filterTag, searchValue]
|
||||||
);
|
);
|
||||||
|
|
||||||
const endpointTypeModels = useMemo(
|
const endpointTypeModels = useMemo(
|
||||||
() => allModels.filter((m) => matchesFilters(m, ['endpoint'])),
|
() => allModels.filter((m) => matchesFilters(m, ['endpoint'])),
|
||||||
[allModels, filterGroup, filterQuotaType, filterVendor, filterTag]
|
[allModels, filterGroup, filterQuotaType, filterVendor, filterTag, searchValue]
|
||||||
);
|
);
|
||||||
|
|
||||||
const vendorModels = useMemo(
|
const vendorModels = useMemo(
|
||||||
() => allModels.filter((m) => matchesFilters(m, ['vendor'])),
|
() => allModels.filter((m) => matchesFilters(m, ['vendor'])),
|
||||||
[allModels, filterGroup, filterQuotaType, filterEndpointType, filterTag]
|
[allModels, filterGroup, filterQuotaType, filterEndpointType, filterTag, searchValue]
|
||||||
);
|
);
|
||||||
|
|
||||||
const tagModels = useMemo(
|
const tagModels = useMemo(
|
||||||
() => allModels.filter((m) => matchesFilters(m, ['tag'])),
|
() => allModels.filter((m) => matchesFilters(m, ['tag'])),
|
||||||
[allModels, filterGroup, filterQuotaType, filterEndpointType, filterVendor]
|
[allModels, filterGroup, filterQuotaType, filterEndpointType, filterVendor, searchValue]
|
||||||
);
|
);
|
||||||
|
|
||||||
const groupCountModels = useMemo(
|
const groupCountModels = useMemo(
|
||||||
() => allModels.filter((m) => matchesFilters(m, ['group'])),
|
() => allModels.filter((m) => matchesFilters(m, ['group'])),
|
||||||
[
|
[allModels, filterQuotaType, filterEndpointType, filterVendor, filterTag, searchValue]
|
||||||
allModels,
|
|
||||||
filterQuotaType,
|
|
||||||
filterEndpointType,
|
|
||||||
filterVendor,
|
|
||||||
filterTag,
|
|
||||||
searchValue,
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
Reference in New Issue
Block a user