import React, { useState, useEffect } from "react"; import { useTranslation } from "react-i18next"; import { ChevronDown, RefreshCw, AlertCircle } from "lucide-react"; interface KimiModel { id: string; object: string; created: number; owned_by: string; } interface KimiModelSelectorProps { apiKey: string; anthropicModel: string; anthropicSmallFastModel: string; onModelChange: ( field: "ANTHROPIC_MODEL" | "ANTHROPIC_SMALL_FAST_MODEL", value: string, ) => void; disabled?: boolean; } const KimiModelSelector: React.FC = ({ apiKey, anthropicModel, anthropicSmallFastModel, onModelChange, disabled = false, }) => { const { t } = useTranslation(); const [models, setModels] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(""); const [debouncedKey, setDebouncedKey] = useState(""); // 获取模型列表 const fetchModelsWithKey = async (key: string) => { if (!key) { setError(t("kimiSelector.fillApiKeyFirst")); return; } setLoading(true); setError(""); try { const response = await fetch("https://api.moonshot.cn/v1/models", { headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json", }, }); if (!response.ok) { throw new Error( t("kimiSelector.requestFailed", { error: `${response.status} ${response.statusText}`, }), ); } const data = await response.json(); if (data.data && Array.isArray(data.data)) { setModels(data.data); } else { throw new Error(t("kimiSelector.invalidData")); } } catch (err) { console.error(t("kimiSelector.fetchModelsFailed") + ":", err); setError( err instanceof Error ? err.message : t("kimiSelector.fetchModelsFailed"), ); } finally { setLoading(false); } }; // 500ms 防抖 API Key useEffect(() => { const timer = setTimeout(() => { setDebouncedKey(apiKey.trim()); }, 500); return () => clearTimeout(timer); }, [apiKey]); // 当防抖后的 Key 改变时自动获取模型列表 useEffect(() => { if (debouncedKey) { fetchModelsWithKey(debouncedKey); } else { setModels([]); setError(""); } }, [debouncedKey]); const selectClass = `w-full px-3 py-2 border rounded-lg text-sm transition-colors appearance-none bg-white dark:bg-gray-800 ${ disabled ? "bg-gray-100 dark:bg-gray-800 border-gray-200 dark:border-gray-700 text-gray-400 dark:text-gray-500 cursor-not-allowed" : "border-gray-200 dark:border-gray-700 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500/20 dark:focus:ring-blue-400/20 focus:border-blue-500 dark:focus:border-blue-400" }`; const ModelSelect: React.FC<{ label: string; value: string; onChange: (value: string) => void; }> = ({ label, value, onChange }) => (
); return (

{t("kimiSelector.modelConfig")}

{error && (

{error}

)}
onModelChange("ANTHROPIC_MODEL", value)} /> onModelChange("ANTHROPIC_SMALL_FAST_MODEL", value) } />
{!apiKey.trim() && (

{t("kimiSelector.apiKeyHint")}

)}
); }; export default KimiModelSelector;