/* Copyright (C) 2023-2026 QuantumNous This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . For commercial licensing, please contact support@quantumnous.com */ import { splitBillingExprAndRequestRules } from '@/features/pricing/lib/billing-expr' import { safeJsonParse } from '../utils/json-parser' import { formatPricingNumber } from './pricing-format' export type ModelPricingSnapshotInput = { modelPrice: string modelRatio: string cacheRatio: string createCacheRatio: string completionRatio: string imageRatio: string audioRatio: string audioCompletionRatio: string billingMode: string billingExpr: string } export type ModelPricingSnapshot = { name: string price?: string ratio?: string cacheRatio?: string createCacheRatio?: string completionRatio?: string imageRatio?: string audioRatio?: string audioCompletionRatio?: string billingMode?: string billingExpr?: string requestRuleExpr?: string hasConflict: boolean } export type ModelRow = ModelPricingSnapshot & { saved?: ModelPricingSnapshot draft?: ModelPricingSnapshot isDraftChanged: boolean isDraftDeleted: boolean isDraftNew: boolean } export const hasPricingValue = (value?: string) => value !== undefined && value !== '' const toNumberOrNull = (value?: string) => { if (!hasPricingValue(value)) return null const num = Number(value) return Number.isFinite(num) ? num : null } const ratioToPrice = (ratio?: string, denominator?: string) => { const ratioNumber = toNumberOrNull(ratio) const denominatorNumber = denominator ? toNumberOrNull(denominator) : 2 if (ratioNumber === null || denominatorNumber === null) return '' return formatPricingNumber(ratioNumber * denominatorNumber) } export const getModeLabel = (mode?: string) => { if (mode === 'per-request') return 'Per-request' if (mode === 'tiered_expr') return 'Expression' return 'Per-token' } export const getModeVariant = ( mode?: string ): 'warning' | 'info' | 'success' => { if (mode === 'per-request') return 'warning' if (mode === 'tiered_expr') return 'info' return 'success' } const getExpressionSummary = ( row: ModelPricingSnapshot, t: (key: string) => string ) => { const tierCount = (row.billingExpr?.match(/tier\(/g) || []).length if (tierCount > 0) { return `${t('Tiered pricing')} · ${tierCount} ${t('tiers')}` } return t('Expression pricing') } export const getPriceSummary = ( row: ModelPricingSnapshot, t: (key: string) => string ) => { if (row.billingMode === 'tiered_expr') { return getExpressionSummary(row, t) } if (row.billingMode === 'per-request') { return row.price ? `$${row.price} / ${t('request')}` : t('Unset price') } const inputPrice = ratioToPrice(row.ratio) if (!inputPrice) return t('Unset price') const extraCount = [ row.completionRatio, row.cacheRatio, row.createCacheRatio, row.imageRatio, row.audioRatio, row.audioCompletionRatio, ].filter(hasPricingValue).length return extraCount > 0 ? `${t('Input')} $${inputPrice} · ${extraCount} ${t('extras')}` : `${t('Input')} $${inputPrice}` } export const getPriceDetail = ( row: ModelPricingSnapshot, t: (key: string) => string ) => { if (row.billingMode === 'tiered_expr') { return row.requestRuleExpr ? t('Includes request rules') : t('Expression based') } if (row.billingMode === 'per-request') { return t('Fixed request price') } const inputPrice = ratioToPrice(row.ratio) if (!inputPrice) return t('No base input price') const details = [ row.completionRatio && `${t('Output')} $${ratioToPrice(row.completionRatio, inputPrice)}`, row.cacheRatio && `${t('Cache')} $${ratioToPrice(row.cacheRatio, inputPrice)}`, row.createCacheRatio && `${t('Cache write')} $${ratioToPrice(row.createCacheRatio, inputPrice)}`, ] .filter(Boolean) .slice(0, 2) return details.length > 0 ? details.join(' · ') : t('Base input price only') } export const buildModelSnapshots = ({ modelPrice, modelRatio, cacheRatio, createCacheRatio, completionRatio, imageRatio, audioRatio, audioCompletionRatio, billingMode, billingExpr, }: ModelPricingSnapshotInput): ModelPricingSnapshot[] => { const priceMap = safeJsonParse>(modelPrice, { fallback: {}, context: 'model prices', }) const ratioMap = safeJsonParse>(modelRatio, { fallback: {}, context: 'model ratios', }) const cacheMap = safeJsonParse>(cacheRatio, { fallback: {}, context: 'cache ratios', }) const createCacheMap = safeJsonParse>( createCacheRatio, { fallback: {}, context: 'create cache ratios' } ) const completionMap = safeJsonParse>(completionRatio, { fallback: {}, context: 'completion ratios', }) const imageMap = safeJsonParse>(imageRatio, { fallback: {}, context: 'image ratios', }) const audioMap = safeJsonParse>(audioRatio, { fallback: {}, context: 'audio ratios', }) const audioCompletionMap = safeJsonParse>( audioCompletionRatio, { fallback: {}, context: 'audio completion ratios' } ) const billingModeMap = safeJsonParse>(billingMode, { fallback: {}, context: 'billing mode', }) const billingExprMap = safeJsonParse>(billingExpr, { fallback: {}, context: 'billing expression', }) const modelNames = new Set([ ...Object.keys(priceMap), ...Object.keys(ratioMap), ...Object.keys(cacheMap), ...Object.keys(createCacheMap), ...Object.keys(completionMap), ...Object.keys(imageMap), ...Object.keys(audioMap), ...Object.keys(audioCompletionMap), ...Object.keys(billingModeMap), ...Object.keys(billingExprMap), ]) return Array.from(modelNames).map((name) => { const price = priceMap[name]?.toString() || '' const ratio = ratioMap[name]?.toString() || '' const cache = cacheMap[name]?.toString() || '' const createCache = createCacheMap[name]?.toString() || '' const completion = completionMap[name]?.toString() || '' const image = imageMap[name]?.toString() || '' const audio = audioMap[name]?.toString() || '' const audioCompletion = audioCompletionMap[name]?.toString() || '' const modeForModel = billingModeMap[name] if (modeForModel === 'tiered_expr') { const fullExpr = billingExprMap[name] || '' const { billingExpr: pureExpr, requestRuleExpr } = splitBillingExprAndRequestRules(fullExpr) return { name, billingMode: 'tiered_expr', billingExpr: pureExpr, requestRuleExpr, price, ratio, cacheRatio: cache, createCacheRatio: createCache, completionRatio: completion, imageRatio: image, audioRatio: audio, audioCompletionRatio: audioCompletion, hasConflict: false, } } return { name, price, ratio, cacheRatio: cache, createCacheRatio: createCache, completionRatio: completion, imageRatio: image, audioRatio: audio, audioCompletionRatio: audioCompletion, billingMode: price !== '' ? 'per-request' : 'per-token', hasConflict: price !== '' && (ratio !== '' || completion !== '' || cache !== '' || createCache !== '' || image !== '' || audio !== '' || audioCompletion !== ''), } }) } export const getSnapshotSignature = (snapshot?: ModelPricingSnapshot) => { if (!snapshot) return '' return JSON.stringify({ price: snapshot.price || '', ratio: snapshot.ratio || '', cacheRatio: snapshot.cacheRatio || '', createCacheRatio: snapshot.createCacheRatio || '', completionRatio: snapshot.completionRatio || '', imageRatio: snapshot.imageRatio || '', audioRatio: snapshot.audioRatio || '', audioCompletionRatio: snapshot.audioCompletionRatio || '', billingMode: snapshot.billingMode || 'per-token', billingExpr: snapshot.billingExpr || '', requestRuleExpr: snapshot.requestRuleExpr || '', }) }