()
| 41 | ]; |
| 42 | |
| 43 | export function SharedPoolModels() { |
| 44 | const [models, setModels] = useState<ModelData[]>([]); |
| 45 | const [isLoading, setIsLoading] = useState(true); |
| 46 | const [error, setError] = useState<string | null>(null); |
| 47 | |
| 48 | useEffect(() => { |
| 49 | const loadModels = async () => { |
| 50 | try { |
| 51 | const data = await getSharedPoolStats(); |
| 52 | // 转换为数组并按指定顺序排序 |
| 53 | const modelArray = Object.entries(data.quotas_by_model).map(([name, stats]) => ({ |
| 54 | name, |
| 55 | stats |
| 56 | })); |
| 57 | // 按指定顺序排序 |
| 58 | const sorted = modelArray.sort((a, b) => { |
| 59 | const indexA = MODEL_ORDER.indexOf(a.name); |
| 60 | const indexB = MODEL_ORDER.indexOf(b.name); |
| 61 | // 如果模型不在列表中,放到最后 |
| 62 | if (indexA === -1 && indexB === -1) return 0; |
| 63 | if (indexA === -1) return 1; |
| 64 | if (indexB === -1) return -1; |
| 65 | return indexA - indexB; |
| 66 | }); |
| 67 | setModels(sorted); |
| 68 | } catch (err) { |
| 69 | setError(err instanceof Error ? err.message : '加载模型数据失败'); |
| 70 | } finally { |
| 71 | setIsLoading(false); |
| 72 | } |
| 73 | }; |
| 74 | |
| 75 | loadModels(); |
| 76 | }, []); |
| 77 | |
| 78 | const getModelDisplayName = (model: string) => { |
| 79 | const modelNames: Record<string, string> = { |
| 80 | 'gemini-2.5-flash-lite': 'Gemini 2.5 Flash Lite', |
| 81 | 'claude-sonnet-4-5-thinking': 'Claude Sonnet 4.5 (Thinking)', |
| 82 | 'claude-opus-4-5-thinking': 'Claude Opus 4.5 (Thinking)', |
| 83 | 'gemini-2.5-flash-image': 'Gemini 2.5 Flash Image', |
| 84 | 'gemini-2.5-flash-thinking': 'Gemini 2.5 Flash (Thinking)', |
| 85 | 'gemini-2.5-flash': 'Gemini 2.5 Flash', |
| 86 | 'gpt-oss-120b-medium': 'GPT OSS 120B (Medium)', |
| 87 | 'gemini-3-pro-image': 'Gemini 3 Pro Image', |
| 88 | 'gemini-3-pro-high': 'Gemini 3 Pro (High)', |
| 89 | 'gemini-3-pro-low': 'Gemini 3 Pro (Low)', |
| 90 | 'claude-sonnet-4-5': 'Claude Sonnet 4.5', |
| 91 | 'rev19-uic3-1p': 'Rev19 UIC3 1P', |
| 92 | 'gemini-2.5-pro': 'Gemini 2.5 Pro', |
| 93 | 'chat_20706': 'Chat 20706', |
| 94 | 'chat_23310': 'Chat 23310', |
| 95 | }; |
| 96 | return modelNames[model] || model; |
| 97 | }; |
| 98 | |
| 99 | const formatQuota = (quota: number) => { |
| 100 | return quota.toFixed(4); |
nothing calls this directly
no test coverage detected