Commit 97bbb7c8 by CaIon

feat(pricing): enhance dynamic pricing calculations with group selection support

parent 28e0115a
...@@ -36,6 +36,7 @@ export interface ModelCardGridProps { ...@@ -36,6 +36,7 @@ export interface ModelCardGridProps {
usdExchangeRate?: number usdExchangeRate?: number
tokenUnit?: TokenUnit tokenUnit?: TokenUnit
showRechargePrice?: boolean showRechargePrice?: boolean
selectedGroup?: string
} }
export function ModelCardGrid(props: ModelCardGridProps) { export function ModelCardGrid(props: ModelCardGridProps) {
...@@ -81,6 +82,7 @@ export function ModelCardGrid(props: ModelCardGridProps) { ...@@ -81,6 +82,7 @@ export function ModelCardGrid(props: ModelCardGridProps) {
priceRate={props.priceRate} priceRate={props.priceRate}
usdExchangeRate={props.usdExchangeRate} usdExchangeRate={props.usdExchangeRate}
showRechargePrice={props.showRechargePrice} showRechargePrice={props.showRechargePrice}
selectedGroup={props.selectedGroup}
perf={perfMap.get(model.model_name || '')} perf={perfMap.get(model.model_name || '')}
onClick={() => props.onModelClick(model.model_name || '')} onClick={() => props.onModelClick(model.model_name || '')}
/> />
......
...@@ -17,7 +17,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. ...@@ -17,7 +17,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com For commercial licensing, please contact support@quantumnous.com
*/ */
import { ChevronRight, Copy } from 'lucide-react' import { ChevronRight, Copy } from 'lucide-react'
import { memo } from 'react' import { memo, type ReactNode } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { StatusBadge } from '@/components/status-badge' import { StatusBadge } from '@/components/status-badge'
...@@ -43,6 +43,7 @@ export interface ModelCardProps { ...@@ -43,6 +43,7 @@ export interface ModelCardProps {
usdExchangeRate?: number usdExchangeRate?: number
tokenUnit?: TokenUnit tokenUnit?: TokenUnit
showRechargePrice?: boolean showRechargePrice?: boolean
selectedGroup?: string
perf?: ModelPerfBadgeData perf?: ModelPerfBadgeData
} }
...@@ -71,7 +72,10 @@ export const ModelCard = memo(function ModelCard(props: ModelCardProps) { ...@@ -71,7 +72,10 @@ export const ModelCard = memo(function ModelCard(props: ModelCardProps) {
showRechargePrice, showRechargePrice,
priceRate, priceRate,
usdExchangeRate, usdExchangeRate,
groupRatioMultiplier: getDynamicDisplayGroupRatio(props.model), groupRatioMultiplier: getDynamicDisplayGroupRatio(
props.model,
props.selectedGroup
),
}) })
: null : null
...@@ -87,6 +91,111 @@ export const ModelCard = memo(function ModelCard(props: ModelCardProps) { ...@@ -87,6 +91,111 @@ export const ModelCard = memo(function ModelCard(props: ModelCardProps) {
copyToClipboard(props.model.model_name || '') 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 ( return (
<div <div
className={cn( className={cn(
...@@ -109,95 +218,7 @@ export const ModelCard = memo(function ModelCard(props: ModelCardProps) { ...@@ -109,95 +218,7 @@ export const ModelCard = memo(function ModelCard(props: ModelCardProps) {
{props.model.model_name} {props.model.model_name}
</h3> </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'> <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 ? ( {priceSummary}
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>
)}
</div> </div>
</div> </div>
</div> </div>
......
...@@ -16,7 +16,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. ...@@ -16,7 +16,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com 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 { useTranslation } from 'react-i18next'
import { import {
...@@ -51,6 +51,7 @@ export interface PricingColumnsOptions { ...@@ -51,6 +51,7 @@ export interface PricingColumnsOptions {
priceRate?: number priceRate?: number
usdExchangeRate?: number usdExchangeRate?: number
showRechargePrice?: boolean showRechargePrice?: boolean
selectedGroup?: string
} }
export function usePricingColumns( export function usePricingColumns(
...@@ -62,6 +63,7 @@ export function usePricingColumns( ...@@ -62,6 +63,7 @@ export function usePricingColumns(
priceRate = 1, priceRate = 1,
usdExchangeRate = 1, usdExchangeRate = 1,
showRechargePrice = false, showRechargePrice = false,
selectedGroup,
} = options } = options
const tokenUnitLabel = tokenUnit === 'K' ? '1K' : '1M' const tokenUnitLabel = tokenUnit === 'K' ? '1K' : '1M'
...@@ -124,7 +126,10 @@ export function usePricingColumns( ...@@ -124,7 +126,10 @@ export function usePricingColumns(
showRechargePrice, showRechargePrice,
priceRate, priceRate,
usdExchangeRate, usdExchangeRate,
groupRatioMultiplier: getDynamicDisplayGroupRatio(model), groupRatioMultiplier: getDynamicDisplayGroupRatio(
model,
selectedGroup
),
}) })
if (dynamicSummary) { if (dynamicSummary) {
...@@ -186,7 +191,8 @@ export function usePricingColumns( ...@@ -186,7 +191,8 @@ export function usePricingColumns(
tokenUnit, tokenUnit,
showRechargePrice, showRechargePrice,
priceRate, priceRate,
usdExchangeRate usdExchangeRate,
selectedGroup
) )
) )
const outputPrice = stripTrailingZeros( const outputPrice = stripTrailingZeros(
...@@ -196,7 +202,8 @@ export function usePricingColumns( ...@@ -196,7 +202,8 @@ export function usePricingColumns(
tokenUnit, tokenUnit,
showRechargePrice, showRechargePrice,
priceRate, priceRate,
usdExchangeRate usdExchangeRate,
selectedGroup
) )
) )
...@@ -219,7 +226,8 @@ export function usePricingColumns( ...@@ -219,7 +226,8 @@ export function usePricingColumns(
model, model,
showRechargePrice, showRechargePrice,
priceRate, priceRate,
usdExchangeRate usdExchangeRate,
selectedGroup
) )
) )
...@@ -247,7 +255,10 @@ export function usePricingColumns( ...@@ -247,7 +255,10 @@ export function usePricingColumns(
showRechargePrice, showRechargePrice,
priceRate, priceRate,
usdExchangeRate, usdExchangeRate,
groupRatioMultiplier: getDynamicDisplayGroupRatio(model), groupRatioMultiplier: getDynamicDisplayGroupRatio(
model,
selectedGroup
),
}) })
if (dynamicSummary) { if (dynamicSummary) {
...@@ -291,7 +302,8 @@ export function usePricingColumns( ...@@ -291,7 +302,8 @@ export function usePricingColumns(
tokenUnit, tokenUnit,
showRechargePrice, showRechargePrice,
priceRate, priceRate,
usdExchangeRate usdExchangeRate,
selectedGroup
) )
) )
......
...@@ -16,7 +16,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. ...@@ -16,7 +16,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com 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 { useState, useCallback } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
...@@ -38,6 +38,7 @@ export interface PricingTableProps { ...@@ -38,6 +38,7 @@ export interface PricingTableProps {
usdExchangeRate?: number usdExchangeRate?: number
tokenUnit?: TokenUnit tokenUnit?: TokenUnit
showRechargePrice?: boolean showRechargePrice?: boolean
selectedGroup?: string
onModelClick?: (modelName: string) => void onModelClick?: (modelName: string) => void
} }
...@@ -50,6 +51,7 @@ export function PricingTable(props: PricingTableProps) { ...@@ -50,6 +51,7 @@ export function PricingTable(props: PricingTableProps) {
usdExchangeRate = 1, usdExchangeRate = 1,
tokenUnit = DEFAULT_TOKEN_UNIT, tokenUnit = DEFAULT_TOKEN_UNIT,
showRechargePrice = false, showRechargePrice = false,
selectedGroup,
onModelClick, onModelClick,
} = props } = props
...@@ -63,6 +65,7 @@ export function PricingTable(props: PricingTableProps) { ...@@ -63,6 +65,7 @@ export function PricingTable(props: PricingTableProps) {
priceRate, priceRate,
usdExchangeRate, usdExchangeRate,
showRechargePrice, showRechargePrice,
selectedGroup,
}) })
const { table } = useDataTable({ const { table } = useDataTable({
......
...@@ -130,6 +130,7 @@ export function Pricing() { ...@@ -130,6 +130,7 @@ export function Pricing() {
usdExchangeRate={usdExchangeRate} usdExchangeRate={usdExchangeRate}
tokenUnit={tokenUnit} tokenUnit={tokenUnit}
showRechargePrice={showRechargePrice} showRechargePrice={showRechargePrice}
selectedGroup={groupFilter}
/> />
) )
} }
...@@ -141,6 +142,7 @@ export function Pricing() { ...@@ -141,6 +142,7 @@ export function Pricing() {
usdExchangeRate={usdExchangeRate} usdExchangeRate={usdExchangeRate}
tokenUnit={tokenUnit} tokenUnit={tokenUnit}
showRechargePrice={showRechargePrice} showRechargePrice={showRechargePrice}
selectedGroup={groupFilter}
onModelClick={handleModelClick} onModelClick={handleModelClick}
/> />
) )
......
...@@ -28,6 +28,7 @@ import { ...@@ -28,6 +28,7 @@ import {
type BillingVar, type BillingVar,
type ParsedTier, type ParsedTier,
} from './billing-expr' } from './billing-expr'
import { getDisplayGroupRatio } from './model-helpers'
type DynamicPriceOptions = { type DynamicPriceOptions = {
tokenUnit: TokenUnit tokenUnit: TokenUnit
...@@ -65,20 +66,11 @@ export function isDynamicPricingModel(model: PricingModel): boolean { ...@@ -65,20 +66,11 @@ export function isDynamicPricingModel(model: PricingModel): boolean {
return model.billing_mode === 'tiered_expr' && Boolean(model.billing_expr) return model.billing_mode === 'tiered_expr' && Boolean(model.billing_expr)
} }
export function getDynamicDisplayGroupRatio(model: PricingModel): number { export function getDynamicDisplayGroupRatio(
const groups = Array.isArray(model.enable_groups) ? model.enable_groups : [] model: PricingModel,
const ratios = model.group_ratio || {} selectedGroup?: string
if (groups.length === 0) return 1 ): number {
return getDisplayGroupRatio(model, selectedGroup)
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
} }
function applyRechargeRate( function applyRechargeRate(
......
...@@ -16,7 +16,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. ...@@ -16,7 +16,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com 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' import type { PricingModel } from '../types'
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
...@@ -40,10 +40,65 @@ export function getAvailableGroups( ...@@ -40,10 +40,65 @@ export function getAvailableGroups(
} }
/** /**
* 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 * Replace model placeholder in endpoint path
*/ */
export function replaceModelInPath(path: string, modelName: string): string { export function replaceModelInPath(path: string, modelName: string): string {
return path.replace(/\{model\}/g, modelName) return path.replaceAll('{model}', modelName)
} }
/** /**
......
...@@ -20,6 +20,7 @@ import { formatCurrencyFromUSD } from '@/lib/currency' ...@@ -20,6 +20,7 @@ import { formatCurrencyFromUSD } from '@/lib/currency'
import { QUOTA_TYPE_VALUES, TOKEN_UNIT_DIVISORS } from '../constants' import { QUOTA_TYPE_VALUES, TOKEN_UNIT_DIVISORS } from '../constants'
import type { PricingModel, TokenUnit, PriceType } from '../types' import type { PricingModel, TokenUnit, PriceType } from '../types'
import { getConfiguredGroupRatio, getDisplayGroupRatio } from './model-helpers'
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Price Calculation Utilities // Price Calculation Utilities
...@@ -36,11 +37,11 @@ export function stripTrailingZeros(formatted: string): string { ...@@ -36,11 +37,11 @@ export function stripTrailingZeros(formatted: string): string {
const [, symbol, number, suffix] = match const [, symbol, number, suffix] = match
// Remove commas for processing // Remove commas for processing
const cleanNumber = number.replace(/,/g, '') const cleanNumber = number.replaceAll(',', '')
// Convert to number and back to remove trailing zeros // Convert to number and back to remove trailing zeros
const parsed = parseFloat(cleanNumber) const parsed = Number.parseFloat(cleanNumber)
if (isNaN(parsed)) return formatted if (Number.isNaN(parsed)) return formatted
// Convert to string, which automatically removes trailing zeros // Convert to string, which automatically removes trailing zeros
let result = parsed.toString() let result = parsed.toString()
...@@ -54,27 +55,6 @@ export function stripTrailingZeros(formatted: string): string { ...@@ -54,27 +55,6 @@ export function stripTrailingZeros(formatted: string): string {
} }
/** /**
* 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. * Calculate token price in USD.
* *
* Returns NaN when the required ratio field is missing/null so callers can * Returns NaN when the required ratio field is missing/null so callers can
...@@ -95,26 +75,26 @@ function calculateTokenPrice( ...@@ -95,26 +75,26 @@ function calculateTokenPrice(
case 'cache': case 'cache':
return hasRatio(model.cache_ratio) return hasRatio(model.cache_ratio)
? base * Number(model.cache_ratio) ? base * Number(model.cache_ratio)
: NaN : Number.NaN
case 'create_cache': case 'create_cache':
return hasRatio(model.create_cache_ratio) return hasRatio(model.create_cache_ratio)
? base * Number(model.create_cache_ratio) ? base * Number(model.create_cache_ratio)
: NaN : Number.NaN
case 'image': case 'image':
return hasRatio(model.image_ratio) return hasRatio(model.image_ratio)
? base * Number(model.image_ratio) ? base * Number(model.image_ratio)
: NaN : Number.NaN
case 'audio_input': case 'audio_input':
return hasRatio(model.audio_ratio) return hasRatio(model.audio_ratio)
? base * Number(model.audio_ratio) ? base * Number(model.audio_ratio)
: NaN : Number.NaN
case 'audio_output': case 'audio_output':
return hasRatio(model.audio_ratio) && return hasRatio(model.audio_ratio) &&
hasRatio(model.audio_completion_ratio) hasRatio(model.audio_completion_ratio)
? base * ? base *
Number(model.audio_ratio) * Number(model.audio_ratio) *
Number(model.audio_completion_ratio) Number(model.audio_completion_ratio)
: NaN : Number.NaN
} }
} }
...@@ -167,19 +147,16 @@ export function formatPrice( ...@@ -167,19 +147,16 @@ export function formatPrice(
tokenUnit: TokenUnit, tokenUnit: TokenUnit,
showWithRecharge = false, showWithRecharge = false,
priceRate = 1, priceRate = 1,
usdExchangeRate = 1 usdExchangeRate = 1,
selectedGroup?: string
): string { ): string {
if (model.quota_type === QUOTA_TYPE_VALUES.REQUEST) { if (model.quota_type === QUOTA_TYPE_VALUES.REQUEST) {
return '-' return '-'
} }
const enableGroups = Array.isArray(model.enable_groups) const displayGroupRatio = getDisplayGroupRatio(model, selectedGroup)
? model.enable_groups
: []
const groupRatio = model.group_ratio || {}
const minRatio = getMinGroupRatio(enableGroups, groupRatio)
let priceInUSD = calculateTokenPrice(model, type, minRatio) let priceInUSD = calculateTokenPrice(model, type, displayGroupRatio)
priceInUSD = applyRechargeRate( priceInUSD = applyRechargeRate(
priceInUSD, priceInUSD,
showWithRecharge, showWithRecharge,
...@@ -212,7 +189,7 @@ export function formatGroupPrice( ...@@ -212,7 +189,7 @@ export function formatGroupPrice(
return '-' return '-'
} }
const ratio = groupRatio[group] || 1 const ratio = getConfiguredGroupRatio(groupRatio, group)
let priceInUSD = calculateTokenPrice(model, type, ratio) let priceInUSD = calculateTokenPrice(model, type, ratio)
priceInUSD = applyRechargeRate( priceInUSD = applyRechargeRate(
...@@ -245,7 +222,7 @@ export function formatFixedPrice( ...@@ -245,7 +222,7 @@ export function formatFixedPrice(
return '-' return '-'
} }
const ratio = groupRatio[group] || 1 const ratio = getConfiguredGroupRatio(groupRatio, group)
let priceInUSD = (model.model_price || 0) * ratio let priceInUSD = (model.model_price || 0) * ratio
priceInUSD = applyRechargeRate( priceInUSD = applyRechargeRate(
...@@ -269,19 +246,16 @@ export function formatRequestPrice( ...@@ -269,19 +246,16 @@ export function formatRequestPrice(
model: PricingModel, model: PricingModel,
showWithRecharge = false, showWithRecharge = false,
priceRate = 1, priceRate = 1,
usdExchangeRate = 1 usdExchangeRate = 1,
selectedGroup?: string
): string { ): string {
if (model.quota_type !== QUOTA_TYPE_VALUES.REQUEST) { if (model.quota_type !== QUOTA_TYPE_VALUES.REQUEST) {
return '-' return '-'
} }
const enableGroups = Array.isArray(model.enable_groups) const displayGroupRatio = getDisplayGroupRatio(model, selectedGroup)
? model.enable_groups
: []
const groupRatio = model.group_ratio || {}
const minRatio = getMinGroupRatio(enableGroups, groupRatio)
let priceInUSD = (model.model_price || 0) * minRatio let priceInUSD = (model.model_price || 0) * displayGroupRatio
priceInUSD = applyRechargeRate( priceInUSD = applyRechargeRate(
priceInUSD, priceInUSD,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment