import React, { useEffect, useState } from 'react'; import { Settings, X, RefreshCw, Cpu, Server, Key, AlertTriangle, Code } from 'lucide-react'; import { ModelSettings } from '../types'; import { AVAILABLE_TEXT_MODELS, AVAILABLE_IMAGE_MODELS } from '../constants'; import { fetchAvailableGeminiModels } from '../services/gemini/client'; import { fetchOpenAIModels } from '../services/openai/client'; interface SettingsModalProps { isOpen: boolean; onClose: () => void; modelSettings: ModelSettings; onUpdateSettings: (settings: ModelSettings) => void; } const SettingsModal: React.FC = ({ isOpen, onClose, modelSettings, onUpdateSettings }) => { const [loadingGoogleModels, setLoadingGoogleModels] = useState(false); const [loadingOpenAIModels, setLoadingOpenAIModels] = useState(false); const [openAIError, setOpenAIError] = useState(null); useEffect(() => { if (isOpen && modelSettings.provider === 'google' && modelSettings.googleApiKey) { // Optional: auto-fetch on open if key exists? // Better to let user click refresh to save quota/calls } }, [isOpen]); const loadDynamicGoogleModels = async () => { if (!modelSettings.googleApiKey) { alert("請先輸入 Google API Key"); return; } setLoadingGoogleModels(true); try { const { textModels, imageModels } = await fetchAvailableGeminiModels(modelSettings.googleApiKey); if (textModels.length > 0 || imageModels.length > 0) { onUpdateSettings({ ...modelSettings, availableTextModels: textModels, availableImageModels: imageModels }); } } catch (e: any) { alert(`Google Models 更新失敗: ${e.message}`); } finally { setLoadingGoogleModels(false); } }; const loadDynamicOpenAIModels = async () => { if (!modelSettings.openaiApiKey) { alert("請先輸入 API Key"); return; } setLoadingOpenAIModels(true); setOpenAIError(null); try { const models = await fetchOpenAIModels(modelSettings.openaiBaseUrl, modelSettings.openaiApiKey); if (models.length > 0) { onUpdateSettings({ ...modelSettings, availableOpenAIModels: models }); } else { setOpenAIError("未找到可用模型,請檢查 URL 或 Key"); } } catch (e: any) { console.error(e); setOpenAIError(e.message); } finally { setLoadingOpenAIModels(false); } }; if (!isOpen) return null; const googleTextModels = modelSettings.availableTextModels?.length ? modelSettings.availableTextModels : AVAILABLE_TEXT_MODELS; const googleImageModels = modelSettings.availableImageModels?.length ? modelSettings.availableImageModels : AVAILABLE_IMAGE_MODELS; const openAIModels = modelSettings.availableOpenAIModels || []; return (

系統設定 (System Settings)

{/* Provider Toggle */}
{modelSettings.provider === 'google' ? ( // GOOGLE SETTINGS
onUpdateSettings({ ...modelSettings, googleApiKey: e.target.value })} placeholder="AIza..." />
) : ( // OPENAI / GROK SETTINGS
onUpdateSettings({ ...modelSettings, openaiBaseUrl: e.target.value })} placeholder="https://api.x.ai/v1" />

例如: Grok (https://api.x.ai/v1), OpenAI (https://api.openai.com/v1)

onUpdateSettings({ ...modelSettings, openaiApiKey: e.target.value })} placeholder="sk-..." />
{openAIError && (
{openAIError}
)} {openAIModels.length > 0 ? ( ) : ( onUpdateSettings({ ...modelSettings, openaiModel: e.target.value })} placeholder="grok-beta" /> )}
注意:OpenAI / Grok 僅用於「結構分析」與「文字生成」。圖像生成仍需依賴 Google Gemini Image Model (請上方輸入 Google Key)。
)} {/* DEV MODE Toggle */}

啟用後,圖片生成失敗時會自動使用隨機佔位圖片

Use placeholder images when generation fails

); }; export default SettingsModal;