/* 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, { useState, useEffect } from 'react'; import { Empty, Skeleton, Space, Tag, Collapsible, Tabs, TabPane, Typography, Avatar, } from '@douyinfe/semi-ui'; import { IllustrationNoContent, IllustrationNoContentDark, } from '@douyinfe/semi-illustrations'; import { IconChevronDown, IconChevronUp } from '@douyinfe/semi-icons'; import { Settings } from 'lucide-react'; import { renderModelTag, getModelCategories } from '../../../../helpers'; const ModelsList = ({ t, models, modelsLoading, copyText }) => { const [isModelsExpanded, setIsModelsExpanded] = useState(() => { // Initialize from localStorage if available const savedState = localStorage.getItem('modelsExpanded'); return savedState ? JSON.parse(savedState) : false; }); const [activeModelCategory, setActiveModelCategory] = useState('all'); const MODELS_DISPLAY_COUNT = 25; // 默认显示的模型数量 // Save models expanded state to localStorage whenever it changes useEffect(() => { localStorage.setItem('modelsExpanded', JSON.stringify(isModelsExpanded)); }, [isModelsExpanded]); return (
{/* 卡片头部 */}
{t('可用模型')}
{t('查看当前可用的所有模型')}
{/* 可用模型部分 */}
{modelsLoading ? ( // 骨架屏加载状态 - 模拟实际加载后的布局
{/* 模拟分类标签 */}
{Array.from({ length: 8 }).map((_, index) => ( ))}
{/* 模拟模型标签列表 */}
{Array.from({ length: 20 }).map((_, index) => ( ))}
) : models.length === 0 ? (
} darkModeImage={ } description={t('没有可用模型')} style={{ padding: '24px 0' }} />
) : ( <> {/* 模型分类标签页 */}
setActiveModelCategory(key)} className='mt-2' collapsible > {Object.entries(getModelCategories(t)).map( ([key, category]) => { // 计算该分类下的模型数量 const modelCount = key === 'all' ? models.length : models.filter((model) => category.filter({ model_name: model }), ).length; if (modelCount === 0 && key !== 'all') return null; return ( {category.icon && ( {category.icon} )} {category.label} {modelCount} } itemKey={key} key={key} /> ); }, )}
{(() => { // 根据当前选中的分类过滤模型 const categories = getModelCategories(t); const filteredModels = activeModelCategory === 'all' ? models : models.filter((model) => categories[activeModelCategory].filter({ model_name: model, }), ); // 如果过滤后没有模型,显示空状态 if (filteredModels.length === 0) { return ( } darkModeImage={ } description={t('该分类下没有可用模型')} style={{ padding: '16px 0' }} /> ); } if (filteredModels.length <= MODELS_DISPLAY_COUNT) { return ( {filteredModels.map((model) => renderModelTag(model, { size: 'small', shape: 'circle', onClick: () => copyText(model), }), )} ); } else { return ( <> {filteredModels.map((model) => renderModelTag(model, { size: 'small', shape: 'circle', onClick: () => copyText(model), }), )} setIsModelsExpanded(false)} icon={} > {t('收起')} {!isModelsExpanded && ( {filteredModels .slice(0, MODELS_DISPLAY_COUNT) .map((model) => renderModelTag(model, { size: 'small', shape: 'circle', onClick: () => copyText(model), }), )} setIsModelsExpanded(true)} icon={} > {t('更多')}{' '} {filteredModels.length - MODELS_DISPLAY_COUNT}{' '} {t('个模型')} )} ); } })()}
)}
); }; export default ModelsList;