💱 feat: implement currency configuration helper and update currency display logic in RechargeCard and render functions

This commit is contained in:
CaIon
2025-10-03 21:49:24 +08:00
parent 0077957630
commit 9aaa0f4830
3 changed files with 221 additions and 158 deletions
@@ -419,7 +419,7 @@ export const getLogsColumns = ({
}, },
{ {
key: COLUMN_KEYS.PROMPT, key: COLUMN_KEYS.PROMPT,
title: t('提示'), title: t('输入'),
dataIndex: 'prompt_tokens', dataIndex: 'prompt_tokens',
render: (text, record, index) => { render: (text, record, index) => {
return record.type === 0 || record.type === 2 || record.type === 5 ? ( return record.type === 0 || record.type === 2 || record.type === 5 ? (
@@ -431,7 +431,7 @@ export const getLogsColumns = ({
}, },
{ {
key: COLUMN_KEYS.COMPLETION, key: COLUMN_KEYS.COMPLETION,
title: t('补全'), title: t('输出'),
dataIndex: 'completion_tokens', dataIndex: 'completion_tokens',
render: (text, record, index) => { render: (text, record, index) => {
return parseInt(text) > 0 && return parseInt(text) > 0 &&
+18 -53
View File
@@ -37,6 +37,7 @@ import { SiAlipay, SiWechat, SiStripe } from 'react-icons/si';
import { CreditCard, Coins, Wallet, BarChart2, TrendingUp } from 'lucide-react'; import { CreditCard, Coins, Wallet, BarChart2, TrendingUp } from 'lucide-react';
import { IconGift } from '@douyinfe/semi-icons'; import { IconGift } from '@douyinfe/semi-icons';
import { useMinimumLoadingTime } from '../../hooks/common/useMinimumLoadingTime'; import { useMinimumLoadingTime } from '../../hooks/common/useMinimumLoadingTime';
import { getCurrencyConfig } from '../../helpers/render';
const { Text } = Typography; const { Text } = Typography;
@@ -343,25 +344,8 @@ const RechargeCard = ({
<div className='flex items-center gap-2'> <div className='flex items-center gap-2'>
<span>{t('选择充值额度')}</span> <span>{t('选择充值额度')}</span>
{(() => { {(() => {
const quotaDisplayType = localStorage.getItem('quota_display_type') || 'USD'; const { symbol, rate, type } = getCurrencyConfig();
if (quotaDisplayType === 'USD') return null; if (type === 'USD') return null;
const statusStr = localStorage.getItem('status');
let symbol = '¥';
let rate = 7;
try {
if (statusStr) {
const s = JSON.parse(statusStr);
if (quotaDisplayType === 'CNY') {
rate = s?.usd_exchange_rate || 7;
symbol = '¥';
} else if (quotaDisplayType === 'CUSTOM') {
rate = s?.custom_currency_exchange_rate || 1;
symbol = s?.custom_currency_symbol || '¤';
}
}
} catch (e) {}
return ( return (
<span style={{ color: 'var(--semi-color-text-2)', fontSize: '12px', fontWeight: 'normal' }}> <span style={{ color: 'var(--semi-color-text-2)', fontSize: '12px', fontWeight: 'normal' }}>
@@ -385,15 +369,9 @@ const RechargeCard = ({
const save = originalPrice - discountedPrice; const save = originalPrice - discountedPrice;
// 根据当前货币类型换算显示金额和数量 // 根据当前货币类型换算显示金额和数量
const quotaDisplayType = localStorage.getItem('quota_display_type') || 'USD'; const { symbol, rate, type } = getCurrencyConfig();
let symbol = '¥';
let displayValue = preset.value; // 显示的数量
let displayActualPay = actualPay;
let displaySave = save;
// 获取汇率
const statusStr = localStorage.getItem('status'); const statusStr = localStorage.getItem('status');
let usdRate = 7; // 默认汇率 1 USD = 7 CNY let usdRate = 7; // 默认CNY汇率
try { try {
if (statusStr) { if (statusStr) {
const s = JSON.parse(statusStr); const s = JSON.parse(statusStr);
@@ -401,35 +379,22 @@ const RechargeCard = ({
} }
} catch (e) {} } catch (e) {}
if (quotaDisplayType === 'USD') { let displayValue = preset.value; // 显示的数量
symbol = '$'; let displayActualPay = actualPay;
// 数量和价格都保持美元(系统默认) let displaySave = save;
displayValue = preset.value;
if (type === 'USD') {
// 数量保持USD,价格从CNY转USD
displayActualPay = actualPay / usdRate; displayActualPay = actualPay / usdRate;
displaySave = save / usdRate; displaySave = save / usdRate;
} else if (quotaDisplayType === 'CNY') { } else if (type === 'CNY') {
symbol = '¥'; // 数量转CNY,价格已是CNY
// 数量需要换算为人民币
displayValue = preset.value * usdRate; displayValue = preset.value * usdRate;
// 价格已经是人民币,保持不变 } else if (type === 'CUSTOM') {
displayActualPay = actualPay; // 数量和价格都转自定义货币
displaySave = save; displayValue = preset.value * rate;
} else if (quotaDisplayType === 'CUSTOM') { displayActualPay = (actualPay / usdRate) * rate;
let customSymbol = '¤'; displaySave = (save / usdRate) * rate;
let customRate = 1;
try {
if (statusStr) {
const s = JSON.parse(statusStr);
customSymbol = s?.custom_currency_symbol || '¤';
customRate = s?.custom_currency_exchange_rate || 1;
}
} catch (e) {}
symbol = customSymbol;
// 数量从USD转为自定义货币
displayValue = preset.value * customRate;
// 价格从CNY先转USD再转自定义货币
displayActualPay = (actualPay / usdRate) * customRate;
displaySave = (save / usdRate) * customRate;
} }
return ( return (
+201 -103
View File
@@ -922,6 +922,50 @@ export function renderQuotaWithAmount(amount) {
return '$' + amount; return '$' + amount;
} }
/**
* 获取当前货币配置信息
* @returns {Object} - { symbol, rate, type }
*/
export function getCurrencyConfig() {
const quotaDisplayType = localStorage.getItem('quota_display_type') || 'USD';
const statusStr = localStorage.getItem('status');
let symbol = '$';
let rate = 1;
if (quotaDisplayType === 'CNY') {
symbol = '¥';
try {
if (statusStr) {
const s = JSON.parse(statusStr);
rate = s?.usd_exchange_rate || 7;
}
} catch (e) {}
} else if (quotaDisplayType === 'CUSTOM') {
try {
if (statusStr) {
const s = JSON.parse(statusStr);
symbol = s?.custom_currency_symbol || '¤';
rate = s?.custom_currency_exchange_rate || 1;
}
} catch (e) {}
}
return { symbol, rate, type: quotaDisplayType };
}
/**
* 将美元金额转换为当前选择的货币
* @param {number} usdAmount - 美元金额
* @param {number} digits - 小数位数
* @returns {string} - 格式化后的货币字符串
*/
export function convertUSDToCurrency(usdAmount, digits = 2) {
const { symbol, rate } = getCurrencyConfig();
const convertedAmount = usdAmount * rate;
return symbol + convertedAmount.toFixed(digits);
}
export function renderQuota(quota, digits = 2) { export function renderQuota(quota, digits = 2) {
let quotaPerUnit = localStorage.getItem('quota_per_unit'); let quotaPerUnit = localStorage.getItem('quota_per_unit');
const quotaDisplayType = localStorage.getItem('quota_display_type') || 'USD'; const quotaDisplayType = localStorage.getItem('quota_display_type') || 'USD';
@@ -1085,13 +1129,19 @@ export function renderModelPrice(
); );
groupRatio = effectiveGroupRatio; groupRatio = effectiveGroupRatio;
// 获取货币配置
const { symbol, rate } = getCurrencyConfig();
if (modelPrice !== -1) { if (modelPrice !== -1) {
const displayPrice = (modelPrice * rate).toFixed(6);
const displayTotal = (modelPrice * groupRatio * rate).toFixed(6);
return i18next.t( return i18next.t(
'模型价格:${{price}} * {{ratioType}}{{ratio}} = ${{total}}', '模型价格:{{symbol}}{{price}} * {{ratioType}}{{ratio}} = {{symbol}}{{total}}',
{ {
price: modelPrice, symbol: symbol,
price: displayPrice,
ratio: groupRatio, ratio: groupRatio,
total: modelPrice * groupRatio, total: displayTotal,
ratioType: ratioLabel, ratioType: ratioLabel,
}, },
); );
@@ -1127,19 +1177,21 @@ export function renderModelPrice(
<> <>
<article> <article>
<p> <p>
{i18next.t('输入价格:${{price}} / 1M tokens{{audioPrice}}', { {i18next.t('输入价格:{{symbol}}{{price}} / 1M tokens{{audioPrice}}', {
price: inputRatioPrice, symbol: symbol,
price: (inputRatioPrice * rate).toFixed(6),
audioPrice: audioInputSeperatePrice audioPrice: audioInputSeperatePrice
? `,音频 $${audioInputPrice} / 1M tokens` ? `,音频 ${symbol}${(audioInputPrice * rate).toFixed(6)} / 1M tokens`
: '', : '',
})} })}
</p> </p>
<p> <p>
{i18next.t( {i18next.t(
'输出价格:${{price}} * {{completionRatio}} = ${{total}} / 1M tokens (补全倍率: {{completionRatio}})', '输出价格:{{symbol}}{{price}} * {{completionRatio}} = {{symbol}}{{total}} / 1M tokens (补全倍率: {{completionRatio}})',
{ {
price: inputRatioPrice, symbol: symbol,
total: completionRatioPrice, price: (inputRatioPrice * rate).toFixed(6),
total: (completionRatioPrice * rate).toFixed(6),
completionRatio: completionRatio, completionRatio: completionRatio,
}, },
)} )}
@@ -1147,10 +1199,11 @@ export function renderModelPrice(
{cacheTokens > 0 && ( {cacheTokens > 0 && (
<p> <p>
{i18next.t( {i18next.t(
'缓存价格:${{price}} * {{cacheRatio}} = ${{total}} / 1M tokens (缓存倍率: {{cacheRatio}})', '缓存价格:{{symbol}}{{price}} * {{cacheRatio}} = {{symbol}}{{total}} / 1M tokens (缓存倍率: {{cacheRatio}})',
{ {
price: inputRatioPrice, symbol: symbol,
total: inputRatioPrice * cacheRatio, price: (inputRatioPrice * rate).toFixed(6),
total: (inputRatioPrice * cacheRatio * rate).toFixed(6),
cacheRatio: cacheRatio, cacheRatio: cacheRatio,
}, },
)} )}
@@ -1159,11 +1212,12 @@ export function renderModelPrice(
{image && imageOutputTokens > 0 && ( {image && imageOutputTokens > 0 && (
<p> <p>
{i18next.t( {i18next.t(
'图片输入价格:${{price}} * {{ratio}} = ${{total}} / 1M tokens (图片倍率: {{imageRatio}})', '图片输入价格:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (图片倍率: {{imageRatio}})',
{ {
price: imageRatioPrice, symbol: symbol,
price: (imageRatioPrice * rate).toFixed(6),
ratio: groupRatio, ratio: groupRatio,
total: imageRatioPrice * groupRatio, total: (imageRatioPrice * groupRatio * rate).toFixed(6),
imageRatio: imageRatio, imageRatio: imageRatio,
}, },
)} )}
@@ -1171,22 +1225,25 @@ export function renderModelPrice(
)} )}
{webSearch && webSearchCallCount > 0 && ( {webSearch && webSearchCallCount > 0 && (
<p> <p>
{i18next.t('Web搜索价格:${{price}} / 1K 次', { {i18next.t('Web搜索价格:{{symbol}}{{price}} / 1K 次', {
price: webSearchPrice, symbol: symbol,
price: (webSearchPrice * rate).toFixed(6),
})} })}
</p> </p>
)} )}
{fileSearch && fileSearchCallCount > 0 && ( {fileSearch && fileSearchCallCount > 0 && (
<p> <p>
{i18next.t('文件搜索价格:${{price}} / 1K 次', { {i18next.t('文件搜索价格:{{symbol}}{{price}} / 1K 次', {
price: fileSearchPrice, symbol: symbol,
price: (fileSearchPrice * rate).toFixed(6),
})} })}
</p> </p>
)} )}
{imageGenerationCall && imageGenerationCallPrice > 0 && ( {imageGenerationCall && imageGenerationCallPrice > 0 && (
<p> <p>
{i18next.t('图片生成调用:${{price}} / 1次', { {i18next.t('图片生成调用:{{symbol}}{{price}} / 1次', {
price: imageGenerationCallPrice, symbol: symbol,
price: (imageGenerationCallPrice * rate).toFixed(6),
})} })}
</p> </p>
)} )}
@@ -1196,50 +1253,55 @@ export function renderModelPrice(
let inputDesc = ''; let inputDesc = '';
if (image && imageOutputTokens > 0) { if (image && imageOutputTokens > 0) {
inputDesc = i18next.t( inputDesc = i18next.t(
'(输入 {{nonImageInput}} tokens + 图片输入 {{imageInput}} tokens * {{imageRatio}} / 1M tokens * ${{price}}', '(输入 {{nonImageInput}} tokens + 图片输入 {{imageInput}} tokens * {{imageRatio}} / 1M tokens * {{symbol}}{{price}}',
{ {
nonImageInput: inputTokens - imageOutputTokens, nonImageInput: inputTokens - imageOutputTokens,
imageInput: imageOutputTokens, imageInput: imageOutputTokens,
imageRatio: imageRatio, imageRatio: imageRatio,
price: inputRatioPrice, symbol: symbol,
price: (inputRatioPrice * rate).toFixed(6),
}, },
); );
} else if (cacheTokens > 0) { } else if (cacheTokens > 0) {
inputDesc = i18next.t( inputDesc = i18next.t(
'(输入 {{nonCacheInput}} tokens / 1M tokens * ${{price}} + 缓存 {{cacheInput}} tokens / 1M tokens * ${{cachePrice}}', '(输入 {{nonCacheInput}} tokens / 1M tokens * {{symbol}}{{price}} + 缓存 {{cacheInput}} tokens / 1M tokens * {{symbol}}{{cachePrice}}',
{ {
nonCacheInput: inputTokens - cacheTokens, nonCacheInput: inputTokens - cacheTokens,
cacheInput: cacheTokens, cacheInput: cacheTokens,
price: inputRatioPrice, symbol: symbol,
cachePrice: cacheRatioPrice, price: (inputRatioPrice * rate).toFixed(6),
cachePrice: (cacheRatioPrice * rate).toFixed(6),
}, },
); );
} else if (audioInputSeperatePrice && audioInputTokens > 0) { } else if (audioInputSeperatePrice && audioInputTokens > 0) {
inputDesc = i18next.t( inputDesc = i18next.t(
'(输入 {{nonAudioInput}} tokens / 1M tokens * ${{price}} + 音频输入 {{audioInput}} tokens / 1M tokens * ${{audioPrice}}', '(输入 {{nonAudioInput}} tokens / 1M tokens * {{symbol}}{{price}} + 音频输入 {{audioInput}} tokens / 1M tokens * {{symbol}}{{audioPrice}}',
{ {
nonAudioInput: inputTokens - audioInputTokens, nonAudioInput: inputTokens - audioInputTokens,
audioInput: audioInputTokens, audioInput: audioInputTokens,
price: inputRatioPrice, symbol: symbol,
audioPrice: audioInputPrice, price: (inputRatioPrice * rate).toFixed(6),
audioPrice: (audioInputPrice * rate).toFixed(6),
}, },
); );
} else { } else {
inputDesc = i18next.t( inputDesc = i18next.t(
'(输入 {{input}} tokens / 1M tokens * ${{price}}', '(输入 {{input}} tokens / 1M tokens * {{symbol}}{{price}}',
{ {
input: inputTokens, input: inputTokens,
price: inputRatioPrice, symbol: symbol,
price: (inputRatioPrice * rate).toFixed(6),
}, },
); );
} }
// 构建输出部分描述 // 构建输出部分描述
const outputDesc = i18next.t( const outputDesc = i18next.t(
'输出 {{completion}} tokens / 1M tokens * ${{compPrice}}) * {{ratioType}} {{ratio}}', '输出 {{completion}} tokens / 1M tokens * {{symbol}}{{compPrice}}) * {{ratioType}} {{ratio}}',
{ {
completion: completionTokens, completion: completionTokens,
compPrice: completionRatioPrice, symbol: symbol,
compPrice: (completionRatioPrice * rate).toFixed(6),
ratio: groupRatio, ratio: groupRatio,
ratioType: ratioLabel, ratioType: ratioLabel,
}, },
@@ -1249,10 +1311,11 @@ export function renderModelPrice(
const extraServices = [ const extraServices = [
webSearch && webSearchCallCount > 0 webSearch && webSearchCallCount > 0
? i18next.t( ? i18next.t(
' + Web搜索 {{count}}次 / 1K 次 * ${{price}} * {{ratioType}} {{ratio}}', ' + Web搜索 {{count}}次 / 1K 次 * {{symbol}}{{price}} * {{ratioType}} {{ratio}}',
{ {
count: webSearchCallCount, count: webSearchCallCount,
price: webSearchPrice, symbol: symbol,
price: (webSearchPrice * rate).toFixed(6),
ratio: groupRatio, ratio: groupRatio,
ratioType: ratioLabel, ratioType: ratioLabel,
}, },
@@ -1260,10 +1323,11 @@ export function renderModelPrice(
: '', : '',
fileSearch && fileSearchCallCount > 0 fileSearch && fileSearchCallCount > 0
? i18next.t( ? i18next.t(
' + 文件搜索 {{count}}次 / 1K 次 * ${{price}} * {{ratioType}} {{ratio}}', ' + 文件搜索 {{count}}次 / 1K 次 * {{symbol}}{{price}} * {{ratioType}} {{ratio}}',
{ {
count: fileSearchCallCount, count: fileSearchCallCount,
price: fileSearchPrice, symbol: symbol,
price: (fileSearchPrice * rate).toFixed(6),
ratio: groupRatio, ratio: groupRatio,
ratioType: ratioLabel, ratioType: ratioLabel,
}, },
@@ -1271,9 +1335,10 @@ export function renderModelPrice(
: '', : '',
imageGenerationCall && imageGenerationCallPrice > 0 imageGenerationCall && imageGenerationCallPrice > 0
? i18next.t( ? i18next.t(
' + 图片生成调用 ${{price}} / 1次 * {{ratioType}} {{ratio}}', ' + 图片生成调用 {{symbol}}{{price}} / 1次 * {{ratioType}} {{ratio}}',
{ {
price: imageGenerationCallPrice, symbol: symbol,
price: (imageGenerationCallPrice * rate).toFixed(6),
ratio: groupRatio, ratio: groupRatio,
ratioType: ratioLabel, ratioType: ratioLabel,
}, },
@@ -1282,12 +1347,13 @@ export function renderModelPrice(
].join(''); ].join('');
return i18next.t( return i18next.t(
'{{inputDesc}} + {{outputDesc}}{{extraServices}} = ${{total}}', '{{inputDesc}} + {{outputDesc}}{{extraServices}} = {{symbol}}{{total}}',
{ {
inputDesc, inputDesc,
outputDesc, outputDesc,
extraServices, extraServices,
total: price.toFixed(6), symbol: symbol,
total: (price * rate).toFixed(6),
}, },
); );
})()} })()}
@@ -1319,9 +1385,13 @@ export function renderLogContent(
useUserGroupRatio: useUserGroupRatio, useUserGroupRatio: useUserGroupRatio,
} = getEffectiveRatio(groupRatio, user_group_ratio); } = getEffectiveRatio(groupRatio, user_group_ratio);
// 获取货币配置
const { symbol, rate } = getCurrencyConfig();
if (modelPrice !== -1) { if (modelPrice !== -1) {
return i18next.t('模型价格 ${{price}}{{ratioType}} {{ratio}}', { return i18next.t('模型价格 {{symbol}}{{price}}{{ratioType}} {{ratio}}', {
price: modelPrice, symbol: symbol,
price: (modelPrice * rate).toFixed(6),
ratioType: ratioLabel, ratioType: ratioLabel,
ratio, ratio,
}); });
@@ -1414,14 +1484,19 @@ export function renderAudioModelPrice(
user_group_ratio, user_group_ratio,
); );
groupRatio = effectiveGroupRatio; groupRatio = effectiveGroupRatio;
// 获取货币配置
const { symbol, rate } = getCurrencyConfig();
// 1 ratio = $0.002 / 1K tokens // 1 ratio = $0.002 / 1K tokens
if (modelPrice !== -1) { if (modelPrice !== -1) {
return i18next.t( return i18next.t(
'模型价格:${{price}} * {{ratioType}}{{ratio}} = ${{total}}', '模型价格:{{symbol}}{{price}} * {{ratioType}}{{ratio}} = {{symbol}}{{total}}',
{ {
price: modelPrice, symbol: symbol,
price: (modelPrice * rate).toFixed(6),
ratio: groupRatio, ratio: groupRatio,
total: modelPrice * groupRatio, total: (modelPrice * groupRatio * rate).toFixed(6),
ratioType: ratioLabel, ratioType: ratioLabel,
}, },
); );
@@ -1456,16 +1531,18 @@ export function renderAudioModelPrice(
<> <>
<article> <article>
<p> <p>
{i18next.t('提示价格:${{price}} / 1M tokens', { {i18next.t('提示价格:{{symbol}}{{price}} / 1M tokens', {
price: inputRatioPrice, symbol: symbol,
price: (inputRatioPrice * rate).toFixed(6),
})} })}
</p> </p>
<p> <p>
{i18next.t( {i18next.t(
'补全价格:${{price}} * {{completionRatio}} = ${{total}} / 1M tokens (补全倍率: {{completionRatio}})', '补全价格:{{symbol}}{{price}} * {{completionRatio}} = {{symbol}}{{total}} / 1M tokens (补全倍率: {{completionRatio}})',
{ {
price: inputRatioPrice, symbol: symbol,
total: completionRatioPrice, price: (inputRatioPrice * rate).toFixed(6),
total: (completionRatioPrice * rate).toFixed(6),
completionRatio: completionRatio, completionRatio: completionRatio,
}, },
)} )}
@@ -1473,10 +1550,11 @@ export function renderAudioModelPrice(
{cacheTokens > 0 && ( {cacheTokens > 0 && (
<p> <p>
{i18next.t( {i18next.t(
'缓存价格:${{price}} * {{cacheRatio}} = ${{total}} / 1M tokens (缓存倍率: {{cacheRatio}})', '缓存价格:{{symbol}}{{price}} * {{cacheRatio}} = {{symbol}}{{total}} / 1M tokens (缓存倍率: {{cacheRatio}})',
{ {
price: inputRatioPrice, symbol: symbol,
total: inputRatioPrice * cacheRatio, price: (inputRatioPrice * rate).toFixed(6),
total: (inputRatioPrice * cacheRatio * rate).toFixed(6),
cacheRatio: cacheRatio, cacheRatio: cacheRatio,
}, },
)} )}
@@ -1484,20 +1562,22 @@ export function renderAudioModelPrice(
)} )}
<p> <p>
{i18next.t( {i18next.t(
'音频提示价格:${{price}} * {{audioRatio}} = ${{total}} / 1M tokens (音频倍率: {{audioRatio}})', '音频提示价格:{{symbol}}{{price}} * {{audioRatio}} = {{symbol}}{{total}} / 1M tokens (音频倍率: {{audioRatio}})',
{ {
price: inputRatioPrice, symbol: symbol,
total: inputRatioPrice * audioRatio, price: (inputRatioPrice * rate).toFixed(6),
total: (inputRatioPrice * audioRatio * rate).toFixed(6),
audioRatio: audioRatio, audioRatio: audioRatio,
}, },
)} )}
</p> </p>
<p> <p>
{i18next.t( {i18next.t(
'音频补全价格:${{price}} * {{audioRatio}} * {{audioCompRatio}} = ${{total}} / 1M tokens (音频补全倍率: {{audioCompRatio}})', '音频补全价格:{{symbol}}{{price}} * {{audioRatio}} * {{audioCompRatio}} = {{symbol}}{{total}} / 1M tokens (音频补全倍率: {{audioCompRatio}})',
{ {
price: inputRatioPrice, symbol: symbol,
total: inputRatioPrice * audioRatio * audioCompletionRatio, price: (inputRatioPrice * rate).toFixed(6),
total: (inputRatioPrice * audioRatio * audioCompletionRatio * rate).toFixed(6),
audioRatio: audioRatio, audioRatio: audioRatio,
audioCompRatio: audioCompletionRatio, audioCompRatio: audioCompletionRatio,
}, },
@@ -1506,48 +1586,52 @@ export function renderAudioModelPrice(
<p> <p>
{cacheTokens > 0 {cacheTokens > 0
? i18next.t( ? i18next.t(
'文字提示 {{nonCacheInput}} tokens / 1M tokens * ${{price}} + 缓存 {{cacheInput}} tokens / 1M tokens * ${{cachePrice}} + 文字补全 {{completion}} tokens / 1M tokens * ${{compPrice}} = ${{total}}', '文字提示 {{nonCacheInput}} tokens / 1M tokens * {{symbol}}{{price}} + 缓存 {{cacheInput}} tokens / 1M tokens * {{symbol}}{{cachePrice}} + 文字补全 {{completion}} tokens / 1M tokens * {{symbol}}{{compPrice}} = {{symbol}}{{total}}',
{ {
nonCacheInput: inputTokens - cacheTokens, nonCacheInput: inputTokens - cacheTokens,
cacheInput: cacheTokens, cacheInput: cacheTokens,
cachePrice: inputRatioPrice * cacheRatio, symbol: symbol,
price: inputRatioPrice, cachePrice: (inputRatioPrice * cacheRatio * rate).toFixed(6),
price: (inputRatioPrice * rate).toFixed(6),
completion: completionTokens, completion: completionTokens,
compPrice: completionRatioPrice, compPrice: (completionRatioPrice * rate).toFixed(6),
total: textPrice.toFixed(6), total: (textPrice * rate).toFixed(6),
}, },
) )
: i18next.t( : i18next.t(
'文字提示 {{input}} tokens / 1M tokens * ${{price}} + 文字补全 {{completion}} tokens / 1M tokens * ${{compPrice}} = ${{total}}', '文字提示 {{input}} tokens / 1M tokens * {{symbol}}{{price}} + 文字补全 {{completion}} tokens / 1M tokens * {{symbol}}{{compPrice}} = {{symbol}}{{total}}',
{ {
input: inputTokens, input: inputTokens,
price: inputRatioPrice, symbol: symbol,
price: (inputRatioPrice * rate).toFixed(6),
completion: completionTokens, completion: completionTokens,
compPrice: completionRatioPrice, compPrice: (completionRatioPrice * rate).toFixed(6),
total: textPrice.toFixed(6), total: (textPrice * rate).toFixed(6),
}, },
)} )}
</p> </p>
<p> <p>
{i18next.t( {i18next.t(
'音频提示 {{input}} tokens / 1M tokens * ${{audioInputPrice}} + 音频补全 {{completion}} tokens / 1M tokens * ${{audioCompPrice}} = ${{total}}', '音频提示 {{input}} tokens / 1M tokens * {{symbol}}{{audioInputPrice}} + 音频补全 {{completion}} tokens / 1M tokens * {{symbol}}{{audioCompPrice}} = {{symbol}}{{total}}',
{ {
input: audioInputTokens, input: audioInputTokens,
completion: audioCompletionTokens, completion: audioCompletionTokens,
audioInputPrice: audioRatio * inputRatioPrice, symbol: symbol,
audioInputPrice: (audioRatio * inputRatioPrice * rate).toFixed(6),
audioCompPrice: audioCompPrice:
audioRatio * audioCompletionRatio * inputRatioPrice, (audioRatio * audioCompletionRatio * inputRatioPrice * rate).toFixed(6),
total: audioPrice.toFixed(6), total: (audioPrice * rate).toFixed(6),
}, },
)} )}
</p> </p>
<p> <p>
{i18next.t( {i18next.t(
'总价:文字价格 {{textPrice}} + 音频价格 {{audioPrice}} = ${{total}}', '总价:文字价格 {{textPrice}} + 音频价格 {{audioPrice}} = {{symbol}}{{total}}',
{ {
total: price.toFixed(6), symbol: symbol,
textPrice: textPrice.toFixed(6), total: (price * rate).toFixed(6),
audioPrice: audioPrice.toFixed(6), textPrice: (textPrice * rate).toFixed(6),
audioPrice: (audioPrice * rate).toFixed(6),
}, },
)} )}
</p> </p>
@@ -1585,14 +1669,18 @@ export function renderClaudeModelPrice(
); );
groupRatio = effectiveGroupRatio; groupRatio = effectiveGroupRatio;
// 获取货币配置
const { symbol, rate } = getCurrencyConfig();
if (modelPrice !== -1) { if (modelPrice !== -1) {
return i18next.t( return i18next.t(
'模型价格:${{price}} * {{ratioType}}{{ratio}} = ${{total}}', '模型价格:{{symbol}}{{price}} * {{ratioType}}{{ratio}} = {{symbol}}{{total}}',
{ {
price: modelPrice, symbol: symbol,
price: (modelPrice * rate).toFixed(6),
ratioType: ratioLabel, ratioType: ratioLabel,
ratio: groupRatio, ratio: groupRatio,
total: modelPrice * groupRatio, total: (modelPrice * groupRatio * rate).toFixed(6),
}, },
); );
} else { } else {
@@ -1621,28 +1709,31 @@ export function renderClaudeModelPrice(
<> <>
<article> <article>
<p> <p>
{i18next.t('提示价格:${{price}} / 1M tokens', { {i18next.t('提示价格:{{symbol}}{{price}} / 1M tokens', {
price: inputRatioPrice, symbol: symbol,
price: (inputRatioPrice * rate).toFixed(6),
})} })}
</p> </p>
<p> <p>
{i18next.t( {i18next.t(
'补全价格:${{price}} * {{ratio}} = ${{total}} / 1M tokens', '补全价格:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens',
{ {
price: inputRatioPrice, symbol: symbol,
price: (inputRatioPrice * rate).toFixed(6),
ratio: completionRatio, ratio: completionRatio,
total: completionRatioPrice, total: (completionRatioPrice * rate).toFixed(6),
}, },
)} )}
</p> </p>
{cacheTokens > 0 && ( {cacheTokens > 0 && (
<p> <p>
{i18next.t( {i18next.t(
'缓存价格:${{price}} * {{ratio}} = ${{total}} / 1M tokens (缓存倍率: {{cacheRatio}})', '缓存价格:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (缓存倍率: {{cacheRatio}})',
{ {
price: inputRatioPrice, symbol: symbol,
price: (inputRatioPrice * rate).toFixed(6),
ratio: cacheRatio, ratio: cacheRatio,
total: cacheRatioPrice, total: (cacheRatioPrice * rate).toFixed(2),
cacheRatio: cacheRatio, cacheRatio: cacheRatio,
}, },
)} )}
@@ -1651,11 +1742,12 @@ export function renderClaudeModelPrice(
{cacheCreationTokens > 0 && ( {cacheCreationTokens > 0 && (
<p> <p>
{i18next.t( {i18next.t(
'缓存创建价格:${{price}} * {{ratio}} = ${{total}} / 1M tokens (缓存创建倍率: {{cacheCreationRatio}})', '缓存创建价格:{{symbol}}{{price}} * {{ratio}} = {{symbol}}{{total}} / 1M tokens (缓存创建倍率: {{cacheCreationRatio}})',
{ {
price: inputRatioPrice, symbol: symbol,
price: (inputRatioPrice * rate).toFixed(6),
ratio: cacheCreationRatio, ratio: cacheCreationRatio,
total: cacheCreationRatioPrice, total: (cacheCreationRatioPrice * rate).toFixed(6),
cacheCreationRatio: cacheCreationRatio, cacheCreationRatio: cacheCreationRatio,
}, },
)} )}
@@ -1665,33 +1757,35 @@ export function renderClaudeModelPrice(
<p> <p>
{cacheTokens > 0 || cacheCreationTokens > 0 {cacheTokens > 0 || cacheCreationTokens > 0
? i18next.t( ? i18next.t(
'提示 {{nonCacheInput}} tokens / 1M tokens * ${{price}} + 缓存 {{cacheInput}} tokens / 1M tokens * ${{cachePrice}} + 缓存创建 {{cacheCreationInput}} tokens / 1M tokens * ${{cacheCreationPrice}} + 补全 {{completion}} tokens / 1M tokens * ${{compPrice}} * {{ratioType}} {{ratio}} = ${{total}}', '提示 {{nonCacheInput}} tokens / 1M tokens * {{symbol}}{{price}} + 缓存 {{cacheInput}} tokens / 1M tokens * {{symbol}}{{cachePrice}} + 缓存创建 {{cacheCreationInput}} tokens / 1M tokens * {{symbol}}{{cacheCreationPrice}} + 补全 {{completion}} tokens / 1M tokens * {{symbol}}{{compPrice}} * {{ratioType}} {{ratio}} = {{symbol}}{{total}}',
{ {
nonCacheInput: nonCachedTokens, nonCacheInput: nonCachedTokens,
cacheInput: cacheTokens, cacheInput: cacheTokens,
cacheRatio: cacheRatio, cacheRatio: cacheRatio,
cacheCreationInput: cacheCreationTokens, cacheCreationInput: cacheCreationTokens,
cacheCreationRatio: cacheCreationRatio, cacheCreationRatio: cacheCreationRatio,
cachePrice: cacheRatioPrice, symbol: symbol,
cacheCreationPrice: cacheCreationRatioPrice, cachePrice: (cacheRatioPrice * rate).toFixed(2),
price: inputRatioPrice, cacheCreationPrice: (cacheCreationRatioPrice * rate).toFixed(6),
price: (inputRatioPrice * rate).toFixed(6),
completion: completionTokens, completion: completionTokens,
compPrice: completionRatioPrice, compPrice: (completionRatioPrice * rate).toFixed(6),
ratio: groupRatio, ratio: groupRatio,
ratioType: ratioLabel, ratioType: ratioLabel,
total: price.toFixed(6), total: (price * rate).toFixed(6),
}, },
) )
: i18next.t( : i18next.t(
'提示 {{input}} tokens / 1M tokens * ${{price}} + 补全 {{completion}} tokens / 1M tokens * ${{compPrice}} * {{ratioType}} {{ratio}} = ${{total}}', '提示 {{input}} tokens / 1M tokens * {{symbol}}{{price}} + 补全 {{completion}} tokens / 1M tokens * {{symbol}}{{compPrice}} * {{ratioType}} {{ratio}} = {{symbol}}{{total}}',
{ {
input: inputTokens, input: inputTokens,
price: inputRatioPrice, symbol: symbol,
price: (inputRatioPrice * rate).toFixed(6),
completion: completionTokens, completion: completionTokens,
compPrice: completionRatioPrice, compPrice: (completionRatioPrice * rate).toFixed(6),
ratio: groupRatio, ratio: groupRatio,
ratioType: ratioLabel, ratioType: ratioLabel,
total: price.toFixed(6), total: (price * rate).toFixed(6),
}, },
)} )}
</p> </p>
@@ -1717,9 +1811,13 @@ export function renderClaudeLogContent(
); );
groupRatio = effectiveGroupRatio; groupRatio = effectiveGroupRatio;
// 获取货币配置
const { symbol, rate } = getCurrencyConfig();
if (modelPrice !== -1) { if (modelPrice !== -1) {
return i18next.t('模型价格 ${{price}}{{ratioType}} {{ratio}}', { return i18next.t('模型价格 {{symbol}}{{price}}{{ratioType}} {{ratio}}', {
price: modelPrice, symbol: symbol,
price: (modelPrice * rate).toFixed(6),
ratioType: ratioLabel, ratioType: ratioLabel,
ratio: groupRatio, ratio: groupRatio,
}); });