Преглед изворни кода

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

- calculateModelPrice 新增缓存读取/创建价格计算逻辑
- ModelPricingTable 条件显示缓存价格列(仅 cache_ratio !== 1 时)
- deploy.sh 添加镜像拉取超时(120s)和3次重试机制
master
fengsilin пре 1 недеља
родитељ
комит
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

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] 重启服务..."
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
? 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 : '-',
};
});
@@ -126,6 +134,9 @@ const ModelPricingTable = ({
},
});

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

// 根据计费类型添加价格列
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 {
// 按次计费
columns.push({


+ 17
- 0
web/src/helpers/utils.jsx Прегледај датотеку

@@ -652,16 +652,29 @@ export const calculateModelPrice = ({
const completionRatioPriceUSD =
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 unitLabel = tokenUnit === 'K' ? 'K' : 'M';

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

const numInput =
parseFloat(rawDisplayInput.replace(/[^0-9.]/g, '')) / unitDivisor;
const numCompletion =
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 = '$';
if (currency === 'CNY') {
@@ -683,6 +696,10 @@ export const calculateModelPrice = ({
return {
inputPrice: `${symbol}${numInput.toFixed(precision)}`,
completionPrice: `${symbol}${numCompletion.toFixed(precision)}`,
cachePrice: `${symbol}${numCache.toFixed(precision)}`,
cacheCreationPrice: `${symbol}${numCacheCreation.toFixed(precision)}`,
cacheRatio,
cacheCreationRatio,
unitLabel,
isPerToken: true,
usedGroup,


Loading…
Откажи
Сачувај