- Replace model count with group ratio display (x2.2, x1) in group filter - Remove redundant "Available Groups" column from pricing table - Remove "Availability" column and related logic completely - Move "Supported Endpoint Types" column to fixed right position - Clean up unused parameters and variables in PricingTableColumns.js - Optimize variable declarations (let → const) and simplify render logic - Improve code readability and reduce memory allocations This refactor enhances user experience by: - Providing clearer group ratio information in filters - Simplifying table layout while maintaining essential functionality - Improving performance through better code organization Breaking changes: None
206 lines
5.9 KiB
JavaScript
206 lines
5.9 KiB
JavaScript
/*
|
||
Copyright (C) 2025 QuantumNous
|
||
|
||
This program is free software: you can redistribute it and/or modify
|
||
it under the terms of the GNU Affero General Public License as
|
||
published by the Free Software Foundation, either version 3 of the
|
||
License, or (at your option) any later version.
|
||
|
||
This program is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
GNU Affero General Public License for more details.
|
||
|
||
You should have received a copy of the GNU Affero General Public License
|
||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||
|
||
For commercial licensing, please contact support@quantumnous.com
|
||
*/
|
||
|
||
import React from 'react';
|
||
import { Tag, Space, Tooltip, Switch } from '@douyinfe/semi-ui';
|
||
import { IconHelpCircle } from '@douyinfe/semi-icons';
|
||
import { renderModelTag, stringToColor } from '../../../helpers';
|
||
|
||
function renderQuotaType(type, t) {
|
||
switch (type) {
|
||
case 1:
|
||
return (
|
||
<Tag color='teal' shape='circle'>
|
||
{t('按次计费')}
|
||
</Tag>
|
||
);
|
||
case 0:
|
||
return (
|
||
<Tag color='violet' shape='circle'>
|
||
{t('按量计费')}
|
||
</Tag>
|
||
);
|
||
default:
|
||
return t('未知');
|
||
}
|
||
}
|
||
|
||
function renderSupportedEndpoints(endpoints) {
|
||
if (!endpoints || endpoints.length === 0) {
|
||
return null;
|
||
}
|
||
return (
|
||
<Space wrap>
|
||
{endpoints.map((endpoint, idx) => (
|
||
<Tag
|
||
key={endpoint}
|
||
color={stringToColor(endpoint)}
|
||
shape='circle'
|
||
>
|
||
{endpoint}
|
||
</Tag>
|
||
))}
|
||
</Space>
|
||
);
|
||
}
|
||
|
||
export const getPricingTableColumns = ({
|
||
t,
|
||
selectedGroup,
|
||
groupRatio,
|
||
copyText,
|
||
setModalImageUrl,
|
||
setIsModalOpenurl,
|
||
currency,
|
||
tokenUnit,
|
||
setTokenUnit,
|
||
displayPrice,
|
||
showRatio,
|
||
}) => {
|
||
const endpointColumn = {
|
||
title: t('可用端点类型'),
|
||
dataIndex: 'supported_endpoint_types',
|
||
fixed: 'right',
|
||
render: (text, record, index) => {
|
||
return renderSupportedEndpoints(text);
|
||
},
|
||
};
|
||
|
||
const modelNameColumn = {
|
||
title: t('模型名称'),
|
||
dataIndex: 'model_name',
|
||
render: (text, record, index) => {
|
||
return renderModelTag(text, {
|
||
onClick: () => {
|
||
copyText(text);
|
||
}
|
||
});
|
||
},
|
||
onFilter: (value, record) =>
|
||
record.model_name.toLowerCase().includes(value.toLowerCase()),
|
||
};
|
||
|
||
const quotaColumn = {
|
||
title: t('计费类型'),
|
||
dataIndex: 'quota_type',
|
||
render: (text, record, index) => {
|
||
return renderQuotaType(parseInt(text), t);
|
||
},
|
||
sorter: (a, b) => a.quota_type - b.quota_type,
|
||
};
|
||
|
||
const baseColumns = [modelNameColumn, quotaColumn];
|
||
|
||
const ratioColumn = {
|
||
title: () => (
|
||
<div className="flex items-center space-x-1">
|
||
<span>{t('倍率')}</span>
|
||
<Tooltip content={t('倍率是为了方便换算不同价格的模型')}>
|
||
<IconHelpCircle
|
||
className="text-blue-500 cursor-pointer"
|
||
onClick={() => {
|
||
setModalImageUrl('/ratio.png');
|
||
setIsModalOpenurl(true);
|
||
}}
|
||
/>
|
||
</Tooltip>
|
||
</div>
|
||
),
|
||
dataIndex: 'model_ratio',
|
||
render: (text, record, index) => {
|
||
const completionRatio = parseFloat(record.completion_ratio.toFixed(3));
|
||
const content = (
|
||
<div className="space-y-1">
|
||
<div className="text-gray-700">
|
||
{t('模型倍率')}:{record.quota_type === 0 ? text : t('无')}
|
||
</div>
|
||
<div className="text-gray-700">
|
||
{t('补全倍率')}:
|
||
{record.quota_type === 0 ? completionRatio : t('无')}
|
||
</div>
|
||
<div className="text-gray-700">
|
||
{t('分组倍率')}:{groupRatio[selectedGroup]}
|
||
</div>
|
||
</div>
|
||
);
|
||
return content;
|
||
},
|
||
};
|
||
|
||
const priceColumn = {
|
||
title: (
|
||
<div className="flex items-center space-x-2">
|
||
<span>{t('模型价格')}</span>
|
||
{/* 计费单位切换 */}
|
||
<Switch
|
||
checked={tokenUnit === 'K'}
|
||
onChange={(checked) => setTokenUnit(checked ? 'K' : 'M')}
|
||
checkedText="K"
|
||
uncheckedText="M"
|
||
/>
|
||
</div>
|
||
),
|
||
dataIndex: 'model_price',
|
||
render: (text, record, index) => {
|
||
if (record.quota_type === 0) {
|
||
const inputRatioPriceUSD = record.model_ratio * 2 * groupRatio[selectedGroup];
|
||
const completionRatioPriceUSD =
|
||
record.model_ratio * record.completion_ratio * 2 * groupRatio[selectedGroup];
|
||
|
||
const unitDivisor = tokenUnit === 'K' ? 1000 : 1;
|
||
const unitLabel = tokenUnit === 'K' ? 'K' : 'M';
|
||
|
||
const rawDisplayInput = displayPrice(inputRatioPriceUSD);
|
||
const rawDisplayCompletion = displayPrice(completionRatioPriceUSD);
|
||
|
||
const numInput = parseFloat(rawDisplayInput.replace(/[^0-9.]/g, '')) / unitDivisor;
|
||
const numCompletion = parseFloat(rawDisplayCompletion.replace(/[^0-9.]/g, '')) / unitDivisor;
|
||
|
||
const displayInput = `${currency === 'CNY' ? '¥' : '$'}${numInput.toFixed(3)}`;
|
||
const displayCompletion = `${currency === 'CNY' ? '¥' : '$'}${numCompletion.toFixed(3)}`;
|
||
return (
|
||
<div className="space-y-1">
|
||
<div className="text-gray-700">
|
||
{t('提示')} {displayInput} / 1{unitLabel} tokens
|
||
</div>
|
||
<div className="text-gray-700">
|
||
{t('补全')} {displayCompletion} / 1{unitLabel} tokens
|
||
</div>
|
||
</div>
|
||
);
|
||
} else {
|
||
const priceUSD = parseFloat(text) * groupRatio[selectedGroup];
|
||
const displayVal = displayPrice(priceUSD);
|
||
return (
|
||
<div className="text-gray-700">
|
||
{t('模型价格')}:{displayVal}
|
||
</div>
|
||
);
|
||
}
|
||
},
|
||
};
|
||
|
||
const columns = [...baseColumns];
|
||
if (showRatio) {
|
||
columns.push(ratioColumn);
|
||
}
|
||
columns.push(priceColumn);
|
||
columns.push(endpointColumn);
|
||
return columns;
|
||
};
|