feat(pricing): enhance dynamic pricing calculations with group selection support
This commit is contained in:
@@ -36,6 +36,7 @@ export interface ModelCardGridProps {
|
||||
usdExchangeRate?: number
|
||||
tokenUnit?: TokenUnit
|
||||
showRechargePrice?: boolean
|
||||
selectedGroup?: string
|
||||
}
|
||||
|
||||
export function ModelCardGrid(props: ModelCardGridProps) {
|
||||
@@ -81,6 +82,7 @@ export function ModelCardGrid(props: ModelCardGridProps) {
|
||||
priceRate={props.priceRate}
|
||||
usdExchangeRate={props.usdExchangeRate}
|
||||
showRechargePrice={props.showRechargePrice}
|
||||
selectedGroup={props.selectedGroup}
|
||||
perf={perfMap.get(model.model_name || '')}
|
||||
onClick={() => props.onModelClick(model.model_name || '')}
|
||||
/>
|
||||
|
||||
+112
-91
@@ -17,7 +17,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
For commercial licensing, please contact support@quantumnous.com
|
||||
*/
|
||||
import { ChevronRight, Copy } from 'lucide-react'
|
||||
import { memo } from 'react'
|
||||
import { memo, type ReactNode } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import { StatusBadge } from '@/components/status-badge'
|
||||
@@ -43,6 +43,7 @@ export interface ModelCardProps {
|
||||
usdExchangeRate?: number
|
||||
tokenUnit?: TokenUnit
|
||||
showRechargePrice?: boolean
|
||||
selectedGroup?: string
|
||||
perf?: ModelPerfBadgeData
|
||||
}
|
||||
|
||||
@@ -71,7 +72,10 @@ export const ModelCard = memo(function ModelCard(props: ModelCardProps) {
|
||||
showRechargePrice,
|
||||
priceRate,
|
||||
usdExchangeRate,
|
||||
groupRatioMultiplier: getDynamicDisplayGroupRatio(props.model),
|
||||
groupRatioMultiplier: getDynamicDisplayGroupRatio(
|
||||
props.model,
|
||||
props.selectedGroup
|
||||
),
|
||||
})
|
||||
: null
|
||||
|
||||
@@ -87,6 +91,111 @@ export const ModelCard = memo(function ModelCard(props: ModelCardProps) {
|
||||
copyToClipboard(props.model.model_name || '')
|
||||
}
|
||||
|
||||
let priceSummary: ReactNode
|
||||
if (dynamicSummary) {
|
||||
if (dynamicSummary.isSpecialExpression) {
|
||||
priceSummary = (
|
||||
<span className='min-w-0'>
|
||||
<span className='text-amber-700 dark:text-amber-300'>
|
||||
{t('Special billing expression')}
|
||||
</span>
|
||||
<code className='text-muted-foreground/70 mt-0.5 line-clamp-1 block font-mono text-[11px] break-all'>
|
||||
{dynamicSummary.rawExpression}
|
||||
</code>
|
||||
</span>
|
||||
)
|
||||
} else if (dynamicSummary.primaryEntries.length > 0) {
|
||||
priceSummary = (
|
||||
<>
|
||||
{dynamicSummary.primaryEntries.map((entry) => (
|
||||
<span
|
||||
key={entry.key}
|
||||
className='text-muted-foreground whitespace-nowrap'
|
||||
>
|
||||
{t(entry.shortLabel)}{' '}
|
||||
<span className='text-foreground font-mono font-semibold'>
|
||||
{entry.formatted}
|
||||
</span>
|
||||
/{tokenUnitLabel}
|
||||
</span>
|
||||
))}
|
||||
</>
|
||||
)
|
||||
} else {
|
||||
priceSummary = (
|
||||
<span className='text-muted-foreground text-xs'>
|
||||
{t('Dynamic Pricing')}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
} else if (isTokenBased) {
|
||||
priceSummary = (
|
||||
<>
|
||||
<span className='text-muted-foreground whitespace-nowrap'>
|
||||
{t('Input')}{' '}
|
||||
<span className='text-foreground font-mono font-semibold'>
|
||||
{formatPrice(
|
||||
props.model,
|
||||
'input',
|
||||
tokenUnit,
|
||||
showRechargePrice,
|
||||
priceRate,
|
||||
usdExchangeRate,
|
||||
props.selectedGroup
|
||||
)}
|
||||
</span>
|
||||
/{tokenUnitLabel}
|
||||
</span>
|
||||
<span className='text-muted-foreground whitespace-nowrap'>
|
||||
{t('Output')}{' '}
|
||||
<span className='text-foreground font-mono font-semibold'>
|
||||
{formatPrice(
|
||||
props.model,
|
||||
'output',
|
||||
tokenUnit,
|
||||
showRechargePrice,
|
||||
priceRate,
|
||||
usdExchangeRate,
|
||||
props.selectedGroup
|
||||
)}
|
||||
</span>
|
||||
/{tokenUnitLabel}
|
||||
</span>
|
||||
{hasCachedPrice && (
|
||||
<span className='text-muted-foreground/60 whitespace-nowrap'>
|
||||
{t('Cached')}{' '}
|
||||
<span className='font-mono'>
|
||||
{formatPrice(
|
||||
props.model,
|
||||
'cache',
|
||||
tokenUnit,
|
||||
showRechargePrice,
|
||||
priceRate,
|
||||
usdExchangeRate,
|
||||
props.selectedGroup
|
||||
)}
|
||||
</span>
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
} else {
|
||||
priceSummary = (
|
||||
<span className='text-muted-foreground whitespace-nowrap'>
|
||||
<span className='text-foreground font-mono font-semibold'>
|
||||
{formatRequestPrice(
|
||||
props.model,
|
||||
showRechargePrice,
|
||||
priceRate,
|
||||
usdExchangeRate,
|
||||
props.selectedGroup
|
||||
)}
|
||||
</span>{' '}
|
||||
/ {t('request')}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
@@ -109,95 +218,7 @@ export const ModelCard = memo(function ModelCard(props: ModelCardProps) {
|
||||
{props.model.model_name}
|
||||
</h3>
|
||||
<div className='mt-0.5 flex flex-wrap items-baseline gap-x-2 gap-y-0.5 text-xs sm:mt-1 sm:gap-x-3'>
|
||||
{dynamicSummary ? (
|
||||
dynamicSummary.isSpecialExpression ? (
|
||||
<span className='min-w-0'>
|
||||
<span className='text-amber-700 dark:text-amber-300'>
|
||||
{t('Special billing expression')}
|
||||
</span>
|
||||
<code className='text-muted-foreground/70 mt-0.5 line-clamp-1 block font-mono text-[11px] break-all'>
|
||||
{dynamicSummary.rawExpression}
|
||||
</code>
|
||||
</span>
|
||||
) : dynamicSummary.primaryEntries.length > 0 ? (
|
||||
<>
|
||||
{dynamicSummary.primaryEntries.map((entry) => (
|
||||
<span
|
||||
key={entry.key}
|
||||
className='text-muted-foreground whitespace-nowrap'
|
||||
>
|
||||
{t(entry.shortLabel)}{' '}
|
||||
<span className='text-foreground font-mono font-semibold'>
|
||||
{entry.formatted}
|
||||
</span>
|
||||
/{tokenUnitLabel}
|
||||
</span>
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
<span className='text-muted-foreground text-xs'>
|
||||
{t('Dynamic Pricing')}
|
||||
</span>
|
||||
)
|
||||
) : isTokenBased ? (
|
||||
<>
|
||||
<span className='text-muted-foreground whitespace-nowrap'>
|
||||
{t('Input')}{' '}
|
||||
<span className='text-foreground font-mono font-semibold'>
|
||||
{formatPrice(
|
||||
props.model,
|
||||
'input',
|
||||
tokenUnit,
|
||||
showRechargePrice,
|
||||
priceRate,
|
||||
usdExchangeRate
|
||||
)}
|
||||
</span>
|
||||
/{tokenUnitLabel}
|
||||
</span>
|
||||
<span className='text-muted-foreground whitespace-nowrap'>
|
||||
{t('Output')}{' '}
|
||||
<span className='text-foreground font-mono font-semibold'>
|
||||
{formatPrice(
|
||||
props.model,
|
||||
'output',
|
||||
tokenUnit,
|
||||
showRechargePrice,
|
||||
priceRate,
|
||||
usdExchangeRate
|
||||
)}
|
||||
</span>
|
||||
/{tokenUnitLabel}
|
||||
</span>
|
||||
{hasCachedPrice && (
|
||||
<span className='text-muted-foreground/60 whitespace-nowrap'>
|
||||
{t('Cached')}{' '}
|
||||
<span className='font-mono'>
|
||||
{formatPrice(
|
||||
props.model,
|
||||
'cache',
|
||||
tokenUnit,
|
||||
showRechargePrice,
|
||||
priceRate,
|
||||
usdExchangeRate
|
||||
)}
|
||||
</span>
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<span className='text-muted-foreground whitespace-nowrap'>
|
||||
<span className='text-foreground font-mono font-semibold'>
|
||||
{formatRequestPrice(
|
||||
props.model,
|
||||
showRechargePrice,
|
||||
priceRate,
|
||||
usdExchangeRate
|
||||
)}
|
||||
</span>{' '}
|
||||
/ {t('request')}
|
||||
</span>
|
||||
)}
|
||||
{priceSummary}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -16,7 +16,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
For commercial licensing, please contact support@quantumnous.com
|
||||
*/
|
||||
import { type ColumnDef } from '@tanstack/react-table'
|
||||
import type { ColumnDef } from '@tanstack/react-table'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import {
|
||||
@@ -51,6 +51,7 @@ export interface PricingColumnsOptions {
|
||||
priceRate?: number
|
||||
usdExchangeRate?: number
|
||||
showRechargePrice?: boolean
|
||||
selectedGroup?: string
|
||||
}
|
||||
|
||||
export function usePricingColumns(
|
||||
@@ -62,6 +63,7 @@ export function usePricingColumns(
|
||||
priceRate = 1,
|
||||
usdExchangeRate = 1,
|
||||
showRechargePrice = false,
|
||||
selectedGroup,
|
||||
} = options
|
||||
|
||||
const tokenUnitLabel = tokenUnit === 'K' ? '1K' : '1M'
|
||||
@@ -124,7 +126,10 @@ export function usePricingColumns(
|
||||
showRechargePrice,
|
||||
priceRate,
|
||||
usdExchangeRate,
|
||||
groupRatioMultiplier: getDynamicDisplayGroupRatio(model),
|
||||
groupRatioMultiplier: getDynamicDisplayGroupRatio(
|
||||
model,
|
||||
selectedGroup
|
||||
),
|
||||
})
|
||||
|
||||
if (dynamicSummary) {
|
||||
@@ -186,7 +191,8 @@ export function usePricingColumns(
|
||||
tokenUnit,
|
||||
showRechargePrice,
|
||||
priceRate,
|
||||
usdExchangeRate
|
||||
usdExchangeRate,
|
||||
selectedGroup
|
||||
)
|
||||
)
|
||||
const outputPrice = stripTrailingZeros(
|
||||
@@ -196,7 +202,8 @@ export function usePricingColumns(
|
||||
tokenUnit,
|
||||
showRechargePrice,
|
||||
priceRate,
|
||||
usdExchangeRate
|
||||
usdExchangeRate,
|
||||
selectedGroup
|
||||
)
|
||||
)
|
||||
|
||||
@@ -219,7 +226,8 @@ export function usePricingColumns(
|
||||
model,
|
||||
showRechargePrice,
|
||||
priceRate,
|
||||
usdExchangeRate
|
||||
usdExchangeRate,
|
||||
selectedGroup
|
||||
)
|
||||
)
|
||||
|
||||
@@ -247,7 +255,10 @@ export function usePricingColumns(
|
||||
showRechargePrice,
|
||||
priceRate,
|
||||
usdExchangeRate,
|
||||
groupRatioMultiplier: getDynamicDisplayGroupRatio(model),
|
||||
groupRatioMultiplier: getDynamicDisplayGroupRatio(
|
||||
model,
|
||||
selectedGroup
|
||||
),
|
||||
})
|
||||
|
||||
if (dynamicSummary) {
|
||||
@@ -291,7 +302,8 @@ export function usePricingColumns(
|
||||
tokenUnit,
|
||||
showRechargePrice,
|
||||
priceRate,
|
||||
usdExchangeRate
|
||||
usdExchangeRate,
|
||||
selectedGroup
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
For commercial licensing, please contact support@quantumnous.com
|
||||
*/
|
||||
import { type Row, type PaginationState } from '@tanstack/react-table'
|
||||
import type { Row, PaginationState } from '@tanstack/react-table'
|
||||
import { useState, useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
@@ -38,6 +38,7 @@ export interface PricingTableProps {
|
||||
usdExchangeRate?: number
|
||||
tokenUnit?: TokenUnit
|
||||
showRechargePrice?: boolean
|
||||
selectedGroup?: string
|
||||
onModelClick?: (modelName: string) => void
|
||||
}
|
||||
|
||||
@@ -50,6 +51,7 @@ export function PricingTable(props: PricingTableProps) {
|
||||
usdExchangeRate = 1,
|
||||
tokenUnit = DEFAULT_TOKEN_UNIT,
|
||||
showRechargePrice = false,
|
||||
selectedGroup,
|
||||
onModelClick,
|
||||
} = props
|
||||
|
||||
@@ -63,6 +65,7 @@ export function PricingTable(props: PricingTableProps) {
|
||||
priceRate,
|
||||
usdExchangeRate,
|
||||
showRechargePrice,
|
||||
selectedGroup,
|
||||
})
|
||||
|
||||
const { table } = useDataTable({
|
||||
|
||||
+2
@@ -130,6 +130,7 @@ export function Pricing() {
|
||||
usdExchangeRate={usdExchangeRate}
|
||||
tokenUnit={tokenUnit}
|
||||
showRechargePrice={showRechargePrice}
|
||||
selectedGroup={groupFilter}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -141,6 +142,7 @@ export function Pricing() {
|
||||
usdExchangeRate={usdExchangeRate}
|
||||
tokenUnit={tokenUnit}
|
||||
showRechargePrice={showRechargePrice}
|
||||
selectedGroup={groupFilter}
|
||||
onModelClick={handleModelClick}
|
||||
/>
|
||||
)
|
||||
|
||||
+6
-14
@@ -28,6 +28,7 @@ import {
|
||||
type BillingVar,
|
||||
type ParsedTier,
|
||||
} from './billing-expr'
|
||||
import { getDisplayGroupRatio } from './model-helpers'
|
||||
|
||||
type DynamicPriceOptions = {
|
||||
tokenUnit: TokenUnit
|
||||
@@ -65,20 +66,11 @@ export function isDynamicPricingModel(model: PricingModel): boolean {
|
||||
return model.billing_mode === 'tiered_expr' && Boolean(model.billing_expr)
|
||||
}
|
||||
|
||||
export function getDynamicDisplayGroupRatio(model: PricingModel): number {
|
||||
const groups = Array.isArray(model.enable_groups) ? model.enable_groups : []
|
||||
const ratios = model.group_ratio || {}
|
||||
if (groups.length === 0) return 1
|
||||
|
||||
let minRatio = Number.POSITIVE_INFINITY
|
||||
for (const group of groups) {
|
||||
const ratio = ratios[group]
|
||||
if (ratio !== undefined && ratio < minRatio) {
|
||||
minRatio = ratio
|
||||
}
|
||||
}
|
||||
|
||||
return minRatio === Number.POSITIVE_INFINITY ? 1 : minRatio
|
||||
export function getDynamicDisplayGroupRatio(
|
||||
model: PricingModel,
|
||||
selectedGroup?: string
|
||||
): number {
|
||||
return getDisplayGroupRatio(model, selectedGroup)
|
||||
}
|
||||
|
||||
function applyRechargeRate(
|
||||
|
||||
+57
-2
@@ -16,7 +16,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
For commercial licensing, please contact support@quantumnous.com
|
||||
*/
|
||||
import { EXCLUDED_GROUPS, QUOTA_TYPE_VALUES } from '../constants'
|
||||
import { EXCLUDED_GROUPS, FILTER_ALL, QUOTA_TYPE_VALUES } from '../constants'
|
||||
import type { PricingModel } from '../types'
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -39,11 +39,66 @@ export function getAvailableGroups(
|
||||
.filter((g) => modelEnableGroups.includes(g))
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a configured group ratio while preserving valid zero ratios.
|
||||
*/
|
||||
export function getConfiguredGroupRatio(
|
||||
groupRatio: Record<string, number>,
|
||||
group: string
|
||||
): number {
|
||||
const ratio = groupRatio[group]
|
||||
return typeof ratio === 'number' && Number.isFinite(ratio) ? ratio : 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the group ratio used by model square summary prices.
|
||||
*
|
||||
* When no specific group is selected, the model square shows the best price
|
||||
* available to the viewer. When a group filter is active, it mirrors classic
|
||||
* and shows that group's price.
|
||||
*/
|
||||
export function getDisplayGroupRatio(
|
||||
model: PricingModel,
|
||||
selectedGroup?: string
|
||||
): number {
|
||||
const modelEnableGroups = Array.isArray(model.enable_groups)
|
||||
? model.enable_groups
|
||||
: []
|
||||
const groupRatio = model.group_ratio || {}
|
||||
|
||||
if (
|
||||
selectedGroup &&
|
||||
selectedGroup !== FILTER_ALL &&
|
||||
modelEnableGroups.includes(selectedGroup)
|
||||
) {
|
||||
return getConfiguredGroupRatio(groupRatio, selectedGroup)
|
||||
}
|
||||
|
||||
if (modelEnableGroups.length === 0) {
|
||||
return 1
|
||||
}
|
||||
|
||||
let minRatio = Number.POSITIVE_INFINITY
|
||||
|
||||
for (const group of modelEnableGroups) {
|
||||
const ratio = groupRatio[group]
|
||||
if (
|
||||
typeof ratio === 'number' &&
|
||||
Number.isFinite(ratio) &&
|
||||
ratio < minRatio
|
||||
) {
|
||||
minRatio = ratio
|
||||
}
|
||||
}
|
||||
|
||||
return minRatio === Number.POSITIVE_INFINITY ? 1 : minRatio
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace model placeholder in endpoint path
|
||||
*/
|
||||
export function replaceModelInPath(path: string, modelName: string): string {
|
||||
return path.replace(/\{model\}/g, modelName)
|
||||
return path.replaceAll('{model}', modelName)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+19
-45
@@ -20,6 +20,7 @@ import { formatCurrencyFromUSD } from '@/lib/currency'
|
||||
|
||||
import { QUOTA_TYPE_VALUES, TOKEN_UNIT_DIVISORS } from '../constants'
|
||||
import type { PricingModel, TokenUnit, PriceType } from '../types'
|
||||
import { getConfiguredGroupRatio, getDisplayGroupRatio } from './model-helpers'
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Price Calculation Utilities
|
||||
@@ -36,11 +37,11 @@ export function stripTrailingZeros(formatted: string): string {
|
||||
const [, symbol, number, suffix] = match
|
||||
|
||||
// Remove commas for processing
|
||||
const cleanNumber = number.replace(/,/g, '')
|
||||
const cleanNumber = number.replaceAll(',', '')
|
||||
|
||||
// Convert to number and back to remove trailing zeros
|
||||
const parsed = parseFloat(cleanNumber)
|
||||
if (isNaN(parsed)) return formatted
|
||||
const parsed = Number.parseFloat(cleanNumber)
|
||||
if (Number.isNaN(parsed)) return formatted
|
||||
|
||||
// Convert to string, which automatically removes trailing zeros
|
||||
let result = parsed.toString()
|
||||
@@ -53,27 +54,6 @@ export function stripTrailingZeros(formatted: string): string {
|
||||
return `${symbol}${result}${suffix}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Find minimum group ratio from enabled groups
|
||||
*/
|
||||
function getMinGroupRatio(
|
||||
enableGroups: string[],
|
||||
groupRatio: Record<string, number>
|
||||
): number {
|
||||
if (enableGroups.length === 0) return 1
|
||||
|
||||
let minRatio = Number.POSITIVE_INFINITY
|
||||
|
||||
for (const group of enableGroups) {
|
||||
const ratio = groupRatio[group]
|
||||
if (ratio !== undefined && ratio < minRatio) {
|
||||
minRatio = ratio
|
||||
}
|
||||
}
|
||||
|
||||
return minRatio === Number.POSITIVE_INFINITY ? 1 : minRatio
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate token price in USD.
|
||||
*
|
||||
@@ -95,26 +75,26 @@ function calculateTokenPrice(
|
||||
case 'cache':
|
||||
return hasRatio(model.cache_ratio)
|
||||
? base * Number(model.cache_ratio)
|
||||
: NaN
|
||||
: Number.NaN
|
||||
case 'create_cache':
|
||||
return hasRatio(model.create_cache_ratio)
|
||||
? base * Number(model.create_cache_ratio)
|
||||
: NaN
|
||||
: Number.NaN
|
||||
case 'image':
|
||||
return hasRatio(model.image_ratio)
|
||||
? base * Number(model.image_ratio)
|
||||
: NaN
|
||||
: Number.NaN
|
||||
case 'audio_input':
|
||||
return hasRatio(model.audio_ratio)
|
||||
? base * Number(model.audio_ratio)
|
||||
: NaN
|
||||
: Number.NaN
|
||||
case 'audio_output':
|
||||
return hasRatio(model.audio_ratio) &&
|
||||
hasRatio(model.audio_completion_ratio)
|
||||
? base *
|
||||
Number(model.audio_ratio) *
|
||||
Number(model.audio_completion_ratio)
|
||||
: NaN
|
||||
: Number.NaN
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,19 +147,16 @@ export function formatPrice(
|
||||
tokenUnit: TokenUnit,
|
||||
showWithRecharge = false,
|
||||
priceRate = 1,
|
||||
usdExchangeRate = 1
|
||||
usdExchangeRate = 1,
|
||||
selectedGroup?: string
|
||||
): string {
|
||||
if (model.quota_type === QUOTA_TYPE_VALUES.REQUEST) {
|
||||
return '-'
|
||||
}
|
||||
|
||||
const enableGroups = Array.isArray(model.enable_groups)
|
||||
? model.enable_groups
|
||||
: []
|
||||
const groupRatio = model.group_ratio || {}
|
||||
const minRatio = getMinGroupRatio(enableGroups, groupRatio)
|
||||
const displayGroupRatio = getDisplayGroupRatio(model, selectedGroup)
|
||||
|
||||
let priceInUSD = calculateTokenPrice(model, type, minRatio)
|
||||
let priceInUSD = calculateTokenPrice(model, type, displayGroupRatio)
|
||||
priceInUSD = applyRechargeRate(
|
||||
priceInUSD,
|
||||
showWithRecharge,
|
||||
@@ -212,7 +189,7 @@ export function formatGroupPrice(
|
||||
return '-'
|
||||
}
|
||||
|
||||
const ratio = groupRatio[group] || 1
|
||||
const ratio = getConfiguredGroupRatio(groupRatio, group)
|
||||
let priceInUSD = calculateTokenPrice(model, type, ratio)
|
||||
|
||||
priceInUSD = applyRechargeRate(
|
||||
@@ -245,7 +222,7 @@ export function formatFixedPrice(
|
||||
return '-'
|
||||
}
|
||||
|
||||
const ratio = groupRatio[group] || 1
|
||||
const ratio = getConfiguredGroupRatio(groupRatio, group)
|
||||
let priceInUSD = (model.model_price || 0) * ratio
|
||||
|
||||
priceInUSD = applyRechargeRate(
|
||||
@@ -269,19 +246,16 @@ export function formatRequestPrice(
|
||||
model: PricingModel,
|
||||
showWithRecharge = false,
|
||||
priceRate = 1,
|
||||
usdExchangeRate = 1
|
||||
usdExchangeRate = 1,
|
||||
selectedGroup?: string
|
||||
): string {
|
||||
if (model.quota_type !== QUOTA_TYPE_VALUES.REQUEST) {
|
||||
return '-'
|
||||
}
|
||||
|
||||
const enableGroups = Array.isArray(model.enable_groups)
|
||||
? model.enable_groups
|
||||
: []
|
||||
const groupRatio = model.group_ratio || {}
|
||||
const minRatio = getMinGroupRatio(enableGroups, groupRatio)
|
||||
const displayGroupRatio = getDisplayGroupRatio(model, selectedGroup)
|
||||
|
||||
let priceInUSD = (model.model_price || 0) * minRatio
|
||||
let priceInUSD = (model.model_price || 0) * displayGroupRatio
|
||||
|
||||
priceInUSD = applyRechargeRate(
|
||||
priceInUSD,
|
||||
|
||||
Reference in New Issue
Block a user