fix: unify pricing labels and expand marketplace pricing display
Keep the model pricing editor wording aligned with the new price-based UI while exposing cache, image, and audio pricing in the marketplace so users can see the full configured pricing model.
This commit is contained in:
134
web/src/helpers/utils.jsx
vendored
134
web/src/helpers/utils.jsx
vendored
@@ -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>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user