2025-07-22 12:08:35 +08:00
|
|
|
|
/*
|
|
|
|
|
|
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';
|
2025-07-23 11:20:55 +08:00
|
|
|
|
import { IconHelpCircle } from '@douyinfe/semi-icons';
|
2025-07-22 12:08:35 +08:00
|
|
|
|
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>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-23 01:58:51 +08:00
|
|
|
|
export const getPricingTableColumns = ({
|
2025-07-22 12:08:35 +08:00
|
|
|
|
t,
|
|
|
|
|
|
selectedGroup,
|
|
|
|
|
|
groupRatio,
|
|
|
|
|
|
copyText,
|
|
|
|
|
|
setModalImageUrl,
|
|
|
|
|
|
setIsModalOpenurl,
|
|
|
|
|
|
currency,
|
|
|
|
|
|
tokenUnit,
|
|
|
|
|
|
setTokenUnit,
|
|
|
|
|
|
displayPrice,
|
2025-07-23 01:58:51 +08:00
|
|
|
|
showRatio,
|
2025-07-22 12:08:35 +08:00
|
|
|
|
}) => {
|
2025-07-23 02:23:25 +08:00
|
|
|
|
const endpointColumn = {
|
|
|
|
|
|
title: t('可用端点类型'),
|
|
|
|
|
|
dataIndex: 'supported_endpoint_types',
|
2025-07-23 11:20:55 +08:00
|
|
|
|
fixed: 'right',
|
2025-07-23 02:23:25 +08:00
|
|
|
|
render: (text, record, index) => {
|
|
|
|
|
|
return renderSupportedEndpoints(text);
|
2025-07-22 12:08:35 +08:00
|
|
|
|
},
|
2025-07-23 02:23:25 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const modelNameColumn = {
|
|
|
|
|
|
title: t('模型名称'),
|
|
|
|
|
|
dataIndex: 'model_name',
|
|
|
|
|
|
render: (text, record, index) => {
|
|
|
|
|
|
return renderModelTag(text, {
|
|
|
|
|
|
onClick: () => {
|
|
|
|
|
|
copyText(text);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2025-07-22 12:08:35 +08:00
|
|
|
|
},
|
2025-07-23 02:23:25 +08:00
|
|
|
|
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);
|
2025-07-22 12:08:35 +08:00
|
|
|
|
},
|
2025-07-23 02:23:25 +08:00
|
|
|
|
sorter: (a, b) => a.quota_type - b.quota_type,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-07-23 11:20:55 +08:00
|
|
|
|
const baseColumns = [modelNameColumn, quotaColumn];
|
2025-07-23 01:58:51 +08:00
|
|
|
|
|
|
|
|
|
|
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) => {
|
2025-07-23 11:20:55 +08:00
|
|
|
|
const completionRatio = parseFloat(record.completion_ratio.toFixed(3));
|
|
|
|
|
|
const content = (
|
2025-07-23 01:58:51 +08:00
|
|
|
|
<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>
|
2025-07-22 12:08:35 +08:00
|
|
|
|
</div>
|
2025-07-23 01:58:51 +08:00
|
|
|
|
);
|
|
|
|
|
|
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) {
|
2025-07-23 11:20:55 +08:00
|
|
|
|
const inputRatioPriceUSD = record.model_ratio * 2 * groupRatio[selectedGroup];
|
|
|
|
|
|
const completionRatioPriceUSD =
|
2025-07-23 01:58:51 +08:00
|
|
|
|
record.model_ratio * record.completion_ratio * 2 * groupRatio[selectedGroup];
|
|
|
|
|
|
|
|
|
|
|
|
const unitDivisor = tokenUnit === 'K' ? 1000 : 1;
|
|
|
|
|
|
const unitLabel = tokenUnit === 'K' ? 'K' : 'M';
|
|
|
|
|
|
|
2025-07-23 11:20:55 +08:00
|
|
|
|
const rawDisplayInput = displayPrice(inputRatioPriceUSD);
|
|
|
|
|
|
const rawDisplayCompletion = displayPrice(completionRatioPriceUSD);
|
2025-07-23 01:58:51 +08:00
|
|
|
|
|
2025-07-23 11:20:55 +08:00
|
|
|
|
const numInput = parseFloat(rawDisplayInput.replace(/[^0-9.]/g, '')) / unitDivisor;
|
|
|
|
|
|
const numCompletion = parseFloat(rawDisplayCompletion.replace(/[^0-9.]/g, '')) / unitDivisor;
|
2025-07-23 01:58:51 +08:00
|
|
|
|
|
2025-07-23 11:20:55 +08:00
|
|
|
|
const displayInput = `${currency === 'CNY' ? '¥' : '$'}${numInput.toFixed(3)}`;
|
|
|
|
|
|
const displayCompletion = `${currency === 'CNY' ? '¥' : '$'}${numCompletion.toFixed(3)}`;
|
|
|
|
|
|
return (
|
2025-07-22 12:08:35 +08:00
|
|
|
|
<div className="space-y-1">
|
|
|
|
|
|
<div className="text-gray-700">
|
2025-07-23 01:58:51 +08:00
|
|
|
|
{t('提示')} {displayInput} / 1{unitLabel} tokens
|
2025-07-22 12:08:35 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div className="text-gray-700">
|
2025-07-23 01:58:51 +08:00
|
|
|
|
{t('补全')} {displayCompletion} / 1{unitLabel} tokens
|
2025-07-22 12:08:35 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
2025-07-23 01:58:51 +08:00
|
|
|
|
} else {
|
2025-07-23 11:20:55 +08:00
|
|
|
|
const priceUSD = parseFloat(text) * groupRatio[selectedGroup];
|
|
|
|
|
|
const displayVal = displayPrice(priceUSD);
|
|
|
|
|
|
return (
|
2025-07-23 01:58:51 +08:00
|
|
|
|
<div className="text-gray-700">
|
|
|
|
|
|
{t('模型价格')}:{displayVal}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2025-07-22 12:08:35 +08:00
|
|
|
|
},
|
2025-07-23 01:58:51 +08:00
|
|
|
|
};
|
2025-07-22 12:08:35 +08:00
|
|
|
|
|
2025-07-23 01:58:51 +08:00
|
|
|
|
const columns = [...baseColumns];
|
|
|
|
|
|
if (showRatio) {
|
|
|
|
|
|
columns.push(ratioColumn);
|
|
|
|
|
|
}
|
|
|
|
|
|
columns.push(priceColumn);
|
2025-07-23 11:20:55 +08:00
|
|
|
|
columns.push(endpointColumn);
|
2025-07-23 01:58:51 +08:00
|
|
|
|
return columns;
|
2025-07-22 12:08:35 +08:00
|
|
|
|
};
|