Просмотр исходного кода

feat(pricing): 分组价格表格添加缓存读取和缓存创建价格列

- calculateModelPrice 新增缓存读取/创建价格计算逻辑
- ModelPricingTable 条件显示缓存价格列(仅 cache_ratio !== 1 时)
- deploy.sh 添加镜像拉取超时(120s)和3次重试机制
master
fengsilin 1 неделю назад
Родитель
Сommit
7af60d3214
3 измененных файлов: 70 добавлений и 1 удалений
  1. +12
    -1
      scripts/deploy.sh
  2. +41
    -0
      web/src/components/table/model-pricing/modal/components/ModelPricingTable.jsx
  3. +17
    -0
      web/src/helpers/utils.jsx

+ 12
- 1
scripts/deploy.sh Просмотреть файл

@@ -127,7 +127,18 @@ echo " [1/4] 更新 image tag..."
sed -i "s|${REGISTRY}:.*|${REGISTRY}:${TAG}|" docker-compose.yml sed -i "s|${REGISTRY}:.*|${REGISTRY}:${TAG}|" docker-compose.yml


echo " [2/4] 拉取新镜像..." echo " [2/4] 拉取新镜像..."
docker compose pull new-api
PULL_TIMEOUT=120
for i in 1 2 3; do
if timeout "${PULL_TIMEOUT}" docker compose pull --quiet new-api; then
break
fi
if [ "$i" -eq 3 ]; then
echo " [2/4] 拉取失败,已重试 3 次(每次 ${PULL_TIMEOUT}s 超时)"
exit 1
fi
echo " [2/4] 拉取超时或失败(${PULL_TIMEOUT}s),第 $((i+1)) 次重试..."
sleep 5
done


echo " [3/4] 重启服务..." echo " [3/4] 重启服务..."
docker compose up -d new-api docker compose up -d new-api


+ 41
- 0
web/src/components/table/model-pricing/modal/components/ModelPricingTable.jsx Просмотреть файл

@@ -79,6 +79,14 @@ const ModelPricingTable = ({
modelData?.quota_type === 0 modelData?.quota_type === 0
? priceData.completionPrice || priceData.outputPrice ? priceData.completionPrice || priceData.outputPrice
: '-', : '-',
cachePrice:
modelData?.quota_type === 0 && priceData.cacheRatio !== 1
? priceData.cachePrice
: '-',
cacheCreationPrice:
modelData?.quota_type === 0 && priceData.cacheRatio !== 1
? priceData.cacheCreationPrice
: '-',
fixedPrice: modelData?.quota_type === 1 ? priceData.price : '-', fixedPrice: modelData?.quota_type === 1 ? priceData.price : '-',
}; };
}); });
@@ -126,6 +134,9 @@ const ModelPricingTable = ({
}, },
}); });


// 检查是否有缓存价格数据(模型支持缓存时同时显示缓存读取和缓存创建)
const hasCachePricing = tableData.some((row) => row.cachePrice !== '-');

// 根据计费类型添加价格列 // 根据计费类型添加价格列
if (modelData?.quota_type === 0) { if (modelData?.quota_type === 0) {
// 按量计费 // 按量计费
@@ -155,6 +166,36 @@ const ModelPricingTable = ({
), ),
}, },
); );
// 缓存读取价格列(仅在有缓存倍率时显示)
if (hasCachePricing) {
columns.push({
title: t('缓存读取'),
dataIndex: 'cachePrice',
render: (text) => (
<>
<div className='font-semibold text-orange-600'>{text}</div>
<div className='text-xs text-gray-500'>
/ {tokenUnit === 'K' ? '1K' : '1M'} tokens
</div>
</>
),
});
}
// 缓存创建价格列(仅在有缓存价格数据时显示,与缓存读取列同时出现)
if (hasCachePricing) {
columns.push({
title: t('缓存创建'),
dataIndex: 'cacheCreationPrice',
render: (text) => (
<>
<div className='font-semibold text-orange-600'>{text}</div>
<div className='text-xs text-gray-500'>
/ {tokenUnit === 'K' ? '1K' : '1M'} tokens
</div>
</>
),
});
}
} else { } else {
// 按次计费 // 按次计费
columns.push({ columns.push({


+ 17
- 0
web/src/helpers/utils.jsx Просмотреть файл

@@ -652,16 +652,29 @@ export const calculateModelPrice = ({
const completionRatioPriceUSD = const completionRatioPriceUSD =
record.model_ratio * record.completion_ratio * 2 * usedGroupRatio; record.model_ratio * record.completion_ratio * 2 * usedGroupRatio;


// 缓存读取价格 = 输入价格 × 缓存倍率(默认 1 表示与输入价格相同)
const cacheRatio = record.cache_ratio ?? 1;
const cacheRatioPriceUSD = inputRatioPriceUSD * cacheRatio;
// 缓存创建价格 = 输入价格 × 缓存创建倍率(默认 1.25)
const cacheCreationRatio = record.cache_creation_ratio ?? 1.25;
const cacheCreationRatioPriceUSD = inputRatioPriceUSD * cacheCreationRatio;

const unitDivisor = tokenUnit === 'K' ? 1000 : 1; const unitDivisor = tokenUnit === 'K' ? 1000 : 1;
const unitLabel = tokenUnit === 'K' ? 'K' : 'M'; const unitLabel = tokenUnit === 'K' ? 'K' : 'M';


const rawDisplayInput = displayPrice(inputRatioPriceUSD); const rawDisplayInput = displayPrice(inputRatioPriceUSD);
const rawDisplayCompletion = displayPrice(completionRatioPriceUSD); const rawDisplayCompletion = displayPrice(completionRatioPriceUSD);
const rawDisplayCache = displayPrice(cacheRatioPriceUSD);
const rawDisplayCacheCreation = displayPrice(cacheCreationRatioPriceUSD);


const numInput = const numInput =
parseFloat(rawDisplayInput.replace(/[^0-9.]/g, '')) / unitDivisor; parseFloat(rawDisplayInput.replace(/[^0-9.]/g, '')) / unitDivisor;
const numCompletion = const numCompletion =
parseFloat(rawDisplayCompletion.replace(/[^0-9.]/g, '')) / unitDivisor; parseFloat(rawDisplayCompletion.replace(/[^0-9.]/g, '')) / unitDivisor;
const numCache =
parseFloat(rawDisplayCache.replace(/[^0-9.]/g, '')) / unitDivisor;
const numCacheCreation =
parseFloat(rawDisplayCacheCreation.replace(/[^0-9.]/g, '')) / unitDivisor;


let symbol = '$'; let symbol = '$';
if (currency === 'CNY') { if (currency === 'CNY') {
@@ -683,6 +696,10 @@ export const calculateModelPrice = ({
return { return {
inputPrice: `${symbol}${numInput.toFixed(precision)}`, inputPrice: `${symbol}${numInput.toFixed(precision)}`,
completionPrice: `${symbol}${numCompletion.toFixed(precision)}`, completionPrice: `${symbol}${numCompletion.toFixed(precision)}`,
cachePrice: `${symbol}${numCache.toFixed(precision)}`,
cacheCreationPrice: `${symbol}${numCacheCreation.toFixed(precision)}`,
cacheRatio,
cacheCreationRatio,
unitLabel, unitLabel,
isPerToken: true, isPerToken: true,
usedGroup, usedGroup,


Загрузка…
Отмена
Сохранить