/* 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 type { ColumnDef } from '@tanstack/react-table' import { useTranslation } from 'react-i18next' import { BadgeCell, BadgeListCell, DataTableColumnHeader, } from '@/components/data-table' import { GroupBadge } from '@/components/group-badge' import { StatusBadge } from '@/components/status-badge' import { getLobeIcon } from '@/lib/lobe-icon' import { DEFAULT_TOKEN_UNIT, QUOTA_TYPE_VALUES } from '../constants' import { getDynamicDisplayGroupRatio, getDynamicPricingSummary, } from '../lib/dynamic-price' import { parseTags } from '../lib/filters' import { isTokenBasedModel } from '../lib/model-helpers' import { formatPrice, formatRequestPrice, stripTrailingZeros, } from '../lib/price' import type { PricingModel, TokenUnit } from '../types' // ---------------------------------------------------------------------------- // Pricing Table Columns // ---------------------------------------------------------------------------- export interface PricingColumnsOptions { tokenUnit?: TokenUnit priceRate?: number usdExchangeRate?: number showRechargePrice?: boolean selectedGroup?: string } export function usePricingColumns( options: PricingColumnsOptions = {} ): ColumnDef[] { const { t } = useTranslation() const { tokenUnit = DEFAULT_TOKEN_UNIT, priceRate = 1, usdExchangeRate = 1, showRechargePrice = false, selectedGroup, } = options const tokenUnitLabel = tokenUnit === 'K' ? '1K' : '1M' return [ // Model column { accessorKey: 'model_name', meta: { label: t('Model') }, header: ({ column }) => ( ), cell: ({ row }) => { const model = row.original const modelIconKey = model.icon || model.vendor_icon const modelIcon = modelIconKey ? getLobeIcon(modelIconKey, 14) : null return (
{modelIcon} {model.model_name}
) }, minSize: 200, }, // Type column { accessorKey: 'quota_type', header: t('Type'), cell: ({ row }) => { const isTokenBased = row.original.quota_type === QUOTA_TYPE_VALUES.TOKEN return ( ) }, size: 80, enableSorting: false, }, // Price column { accessorKey: 'price', meta: { label: t('Price') }, header: ({ column }) => ( ), cell: ({ row }) => { const model = row.original const dynamicSummary = getDynamicPricingSummary(model, { tokenUnit, showRechargePrice, priceRate, usdExchangeRate, groupRatioMultiplier: getDynamicDisplayGroupRatio( model, selectedGroup ), }) if (dynamicSummary) { if (dynamicSummary.isSpecialExpression) { return (
{t('Special billing expression')}
{t('Unable to parse structured pricing')}
{dynamicSummary.rawExpression}
) } const primaryEntries = dynamicSummary.primaryEntries.slice(0, 2) if (primaryEntries.length === 0) { return ( {t('Dynamic Pricing')} ) } return (
{primaryEntries.map((entry, index) => ( {index > 0 && ( / )} {stripTrailingZeros(entry.formatted)} ))}
/ {tokenUnitLabel} tokens {dynamicSummary.tierCount > 1 && ` ยท ${t('{{count}} tiers', { count: dynamicSummary.tierCount, })}`}
) } const isTokenBased = isTokenBasedModel(model) if (isTokenBased) { const inputPrice = stripTrailingZeros( formatPrice( model, 'input', tokenUnit, showRechargePrice, priceRate, usdExchangeRate, selectedGroup ) ) const outputPrice = stripTrailingZeros( formatPrice( model, 'output', tokenUnit, showRechargePrice, priceRate, usdExchangeRate, selectedGroup ) ) return (
{inputPrice} / {outputPrice}
/ {tokenUnitLabel} tokens
) } const price = stripTrailingZeros( formatRequestPrice( model, showRechargePrice, priceRate, usdExchangeRate, selectedGroup ) ) return (
{price}
/ {t('request')}
) }, size: 180, enableSorting: false, }, // Cached price column (Vercel AI Gateway style) { id: 'cached_price', header: t('Cached'), cell: ({ row }) => { const model = row.original const dynamicSummary = getDynamicPricingSummary(model, { tokenUnit, showRechargePrice, priceRate, usdExchangeRate, groupRatioMultiplier: getDynamicDisplayGroupRatio( model, selectedGroup ), }) if (dynamicSummary) { if (dynamicSummary.isSpecialExpression) { return ( {t('Special billing expression')} ) } const cacheEntry = dynamicSummary.entries.find( (entry) => entry.field === 'cacheReadPrice' ) if (!cacheEntry) { return โ€” } return (
{stripTrailingZeros(cacheEntry.formatted)}
/ {tokenUnitLabel}
) } const isTokenBased = isTokenBasedModel(model) if (!isTokenBased || model.cache_ratio == null) { return โ€” } const cachedPrice = stripTrailingZeros( formatPrice( model, 'cache', tokenUnit, showRechargePrice, priceRate, usdExchangeRate, selectedGroup ) ) return (
{cachedPrice}
/ {tokenUnitLabel}
) }, size: 110, enableSorting: false, }, // Vendor column { accessorKey: 'vendor_name', header: t('Vendor'), cell: ({ row }) => { const model = row.original if (!model.vendor_name) { return โ€” } const vendorIcon = model.vendor_icon ? getLobeIcon(model.vendor_icon, 12) : null return ( {vendorIcon} ) }, size: 130, enableSorting: false, }, // Tags column { accessorKey: 'tags', header: t('Tags'), cell: ({ row }) => { const tags = parseTags(row.original.tags) return ( ( ))} /> ) }, size: 140, enableSorting: false, }, // Endpoints column { accessorKey: 'supported_endpoint_types', header: t('Endpoints'), cell: ({ row }) => { const endpoints = row.original.supported_endpoint_types || [] return ( ( ))} /> ) }, size: 130, enableSorting: false, }, // Enable Groups column { accessorKey: 'enable_groups', header: t('Groups'), cell: ({ row }) => { const groups = row.original.enable_groups || [] return ( ( ))} tooltipClassName='max-w-[280px] p-2' /> ) }, size: 130, enableSorting: false, }, ] }