/* Copyright (C) 2025 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 React from 'react'; import { Card, Tag, Tooltip, Checkbox, Empty, Pagination, Button, Avatar } from '@douyinfe/semi-ui'; import { IconHelpCircle, IconCopy } from '@douyinfe/semi-icons'; import { IllustrationNoResult, IllustrationNoResultDark } from '@douyinfe/semi-illustrations'; import { stringToColor, getModelCategories, calculateModelPrice, formatPriceInfo } from '../../../../../helpers'; import PricingCardSkeleton from './PricingCardSkeleton'; import { useMinimumLoadingTime } from '../../../../../hooks/common/useMinimumLoadingTime'; const CARD_STYLES = { container: "w-12 h-12 rounded-2xl flex items-center justify-center relative shadow-sm", icon: "w-8 h-8 flex items-center justify-center", selected: "border-blue-500 bg-blue-50", default: "border-gray-200 hover:border-gray-300" }; const PricingCardView = ({ filteredModels, loading, rowSelection, pageSize, setPageSize, currentPage, setCurrentPage, selectedGroup, groupRatio, copyText, setModalImageUrl, setIsModalOpenurl, currency, tokenUnit, displayPrice, showRatio, t, selectedRowKeys = [], setSelectedRowKeys, activeKey, availableCategories, }) => { const showSkeleton = useMinimumLoadingTime(loading); const startIndex = (currentPage - 1) * pageSize; const endIndex = startIndex + pageSize; const paginatedModels = filteredModels.slice(startIndex, endIndex); const getModelKey = (model) => model.key ?? model.model_name ?? model.id; const handleCheckboxChange = (model, checked) => { if (!setSelectedRowKeys) return; const modelKey = getModelKey(model); const newKeys = checked ? Array.from(new Set([...selectedRowKeys, modelKey])) : selectedRowKeys.filter((key) => key !== modelKey); setSelectedRowKeys(newKeys); rowSelection?.onChange?.(newKeys, null); }; // 获取模型图标 const getModelIcon = (modelName) => { const categories = getModelCategories(t); let icon = null; // 遍历分类,找到匹配的模型图标 for (const [key, category] of Object.entries(categories)) { if (key !== 'all' && category.filter({ model_name: modelName })) { icon = category.icon; break; } } // 如果找到了匹配的图标,返回包装后的图标 if (icon) { return (
{React.cloneElement(icon, { size: 32 })}
); } const avatarText = modelName.slice(0, 2).toUpperCase(); return (
{avatarText}
); }; // 获取模型描述 const getModelDescription = (modelName) => { return t('高性能AI模型,适用于各种文本生成和理解任务。'); }; // 渲染价格信息 const renderPriceInfo = (record) => { const priceData = calculateModelPrice({ record, selectedGroup, groupRatio, tokenUnit, displayPrice, currency }); return formatPriceInfo(priceData, t); }; // 渲染标签 const renderTags = (record) => { const tags = []; // 计费类型标签 const billingType = record.quota_type === 1 ? 'teal' : 'violet'; const billingText = record.quota_type === 1 ? t('按次计费') : t('按量计费'); tags.push( {billingText} ); // 热门模型标签 if (record.model_name.includes('gpt')) { tags.push( {t('热')} ); } // 端点类型标签 if (record.supported_endpoint_types?.length > 0) { record.supported_endpoint_types.slice(0, 2).forEach((endpoint, index) => { tags.push( {endpoint} ); }); } // 上下文长度标签 const contextMatch = record.model_name.match(/(\d+)k/i); const contextSize = contextMatch ? contextMatch[1] + 'K' : '4K'; tags.push( {contextSize} ); return tags; }; // 显示骨架屏 if (showSkeleton) { return ( ); } if (!filteredModels || filteredModels.length === 0) { return (
} darkModeImage={} description={t('搜索无结果')} />
); } return (
{paginatedModels.map((model, index) => { const modelKey = getModelKey(model); const isSelected = selectedRowKeys.includes(modelKey); return ( {/* 头部:图标 + 模型名称 + 操作按钮 */}
{getModelIcon(model.model_name)}

{model.model_name}

{renderPriceInfo(model)}
{/* 复制按钮 */}
{/* 模型描述 */}

{getModelDescription(model.model_name)}

{/* 标签区域 */}
{renderTags(model)}
{/* 倍率信息(可选) */} {showRatio && (
{t('倍率信息')} { setModalImageUrl('/ratio.png'); setIsModalOpenurl(true); }} />
{t('模型')}: {model.quota_type === 0 ? model.model_ratio : t('无')}
{t('补全')}: {model.quota_type === 0 ? parseFloat(model.completion_ratio.toFixed(3)) : t('无')}
{t('分组')}: {groupRatio[selectedGroup]}
)}
); })}
{/* 分页 */} {filteredModels.length > 0 && (
setCurrentPage(page)} onPageSizeChange={(size) => { setPageSize(size); setCurrentPage(1); }} />
)}
); }; export default PricingCardView;