|
|
@@ -648,20 +648,9 @@ export const calculateModelPrice = ({
|
|
|
if (record.quota_type === 0) {
|
|
|
// 按量计费
|
|
|
const inputRatioPriceUSD = record.model_ratio * 2 * usedGroupRatio;
|
|
|
- const completionRatioPriceUSD =
|
|
|
- record.model_ratio * record.completion_ratio * 2 * usedGroupRatio;
|
|
|
-
|
|
|
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;
|
|
|
-
|
|
|
let symbol = '$';
|
|
|
if (currency === 'CNY') {
|
|
|
symbol = '¥';
|
|
|
@@ -678,9 +667,48 @@ export const calculateModelPrice = ({
|
|
|
symbol = '¤';
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ const formatTokenPrice = (priceUSD) => {
|
|
|
+ const rawDisplayPrice = displayPrice(priceUSD);
|
|
|
+ const numericPrice =
|
|
|
+ parseFloat(rawDisplayPrice.replace(/[^0-9.]/g, '')) / unitDivisor;
|
|
|
+ return `${symbol}${numericPrice.toFixed(precision)}`;
|
|
|
+ };
|
|
|
+
|
|
|
+ const hasRatioValue = (value) =>
|
|
|
+ value !== undefined &&
|
|
|
+ value !== null &&
|
|
|
+ value !== '' &&
|
|
|
+ Number.isFinite(Number(value));
|
|
|
+
|
|
|
+ const inputPrice = formatTokenPrice(inputRatioPriceUSD);
|
|
|
+ const audioInputPrice = hasRatioValue(record.audio_ratio)
|
|
|
+ ? formatTokenPrice(inputRatioPriceUSD * Number(record.audio_ratio))
|
|
|
+ : null;
|
|
|
+
|
|
|
return {
|
|
|
- inputPrice: `${symbol}${numInput.toFixed(precision)}`,
|
|
|
- completionPrice: `${symbol}${numCompletion.toFixed(precision)}`,
|
|
|
+ inputPrice,
|
|
|
+ completionPrice: formatTokenPrice(
|
|
|
+ inputRatioPriceUSD * Number(record.completion_ratio),
|
|
|
+ ),
|
|
|
+ cachePrice: hasRatioValue(record.cache_ratio)
|
|
|
+ ? formatTokenPrice(inputRatioPriceUSD * Number(record.cache_ratio))
|
|
|
+ : null,
|
|
|
+ createCachePrice: hasRatioValue(record.create_cache_ratio)
|
|
|
+ ? formatTokenPrice(inputRatioPriceUSD * Number(record.create_cache_ratio))
|
|
|
+ : null,
|
|
|
+ imagePrice: hasRatioValue(record.image_ratio)
|
|
|
+ ? formatTokenPrice(inputRatioPriceUSD * Number(record.image_ratio))
|
|
|
+ : null,
|
|
|
+ audioInputPrice,
|
|
|
+ audioOutputPrice:
|
|
|
+ audioInputPrice && hasRatioValue(record.audio_completion_ratio)
|
|
|
+ ? formatTokenPrice(
|
|
|
+ inputRatioPriceUSD *
|
|
|
+ Number(record.audio_ratio) *
|
|
|
+ Number(record.audio_completion_ratio),
|
|
|
+ )
|
|
|
+ : null,
|
|
|
unitLabel,
|
|
|
isPerToken: true,
|
|
|
usedGroup,
|
|
|
@@ -710,26 +738,76 @@ export const calculateModelPrice = ({
|
|
|
};
|
|
|
};
|
|
|
|
|
|
-// 格式化价格信息(用于卡片视图)
|
|
|
-export const formatPriceInfo = (priceData, t) => {
|
|
|
+export const getModelPriceItems = (priceData, t) => {
|
|
|
if (priceData.isPerToken) {
|
|
|
- return (
|
|
|
- <>
|
|
|
- <span style={{ color: 'var(--semi-color-text-1)' }}>
|
|
|
- {t('输入')} {priceData.inputPrice}/{priceData.unitLabel}
|
|
|
- </span>
|
|
|
- <span style={{ color: 'var(--semi-color-text-1)' }}>
|
|
|
- {t('输出')} {priceData.completionPrice}/{priceData.unitLabel}
|
|
|
- </span>
|
|
|
- </>
|
|
|
- );
|
|
|
- }
|
|
|
+ const unitSuffix = ` / 1${priceData.unitLabel} Tokens`;
|
|
|
+ return [
|
|
|
+ {
|
|
|
+ key: 'input',
|
|
|
+ label: t('输入价格'),
|
|
|
+ value: priceData.inputPrice,
|
|
|
+ suffix: unitSuffix,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'completion',
|
|
|
+ label: t('补全价格'),
|
|
|
+ value: priceData.completionPrice,
|
|
|
+ suffix: unitSuffix,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'cache',
|
|
|
+ label: t('缓存读取价格'),
|
|
|
+ value: priceData.cachePrice,
|
|
|
+ suffix: unitSuffix,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'create-cache',
|
|
|
+ label: t('缓存创建价格'),
|
|
|
+ value: priceData.createCachePrice,
|
|
|
+ suffix: unitSuffix,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'image',
|
|
|
+ label: t('图片输入价格'),
|
|
|
+ value: priceData.imagePrice,
|
|
|
+ suffix: unitSuffix,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'audio-input',
|
|
|
+ label: t('音频输入价格'),
|
|
|
+ value: priceData.audioInputPrice,
|
|
|
+ suffix: unitSuffix,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'audio-output',
|
|
|
+ label: t('音频补全价格'),
|
|
|
+ value: priceData.audioOutputPrice,
|
|
|
+ suffix: unitSuffix,
|
|
|
+ },
|
|
|
+ ].filter((item) => item.value !== null && item.value !== undefined && item.value !== '');
|
|
|
+ }
|
|
|
+
|
|
|
+ return [
|
|
|
+ {
|
|
|
+ key: 'fixed',
|
|
|
+ label: t('模型价格'),
|
|
|
+ value: priceData.price,
|
|
|
+ suffix: ` / ${t('次')}`,
|
|
|
+ },
|
|
|
+ ].filter((item) => item.value !== null && item.value !== undefined && item.value !== '');
|
|
|
+};
|
|
|
|
|
|
+// 格式化价格信息(用于卡片视图)
|
|
|
+export const formatPriceInfo = (priceData, t) => {
|
|
|
+ const items = getModelPriceItems(priceData, t);
|
|
|
return (
|
|
|
<>
|
|
|
- <span style={{ color: 'var(--semi-color-text-1)' }}>
|
|
|
- {t('模型价格')} {priceData.price}
|
|
|
- </span>
|
|
|
+ {items.map((item) => (
|
|
|
+ <span key={item.key} style={{ color: 'var(--semi-color-text-1)' }}>
|
|
|
+ {item.label} {item.value}
|
|
|
+ {item.suffix}
|
|
|
+ </span>
|
|
|
+ ))}
|
|
|
</>
|
|
|
);
|
|
|
};
|