import { useState, useEffect } from "react"; import { useTranslation } from "react-i18next"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { Label } from "@/components/ui/label"; import { Alert, AlertDescription } from "@/components/ui/alert"; import { Save, Loader2 } from "lucide-react"; import { toast } from "sonner"; import { getStreamCheckConfig, saveStreamCheckConfig, type StreamCheckConfig, } from "@/lib/api/model-test"; export function ModelTestConfigPanel() { const { t } = useTranslation(); const [isLoading, setIsLoading] = useState(true); const [isSaving, setIsSaving] = useState(false); const [error, setError] = useState(null); // 使用字符串状态以支持完全清空数字输入框 const [config, setConfig] = useState({ timeoutSecs: "45", maxRetries: "2", degradedThresholdMs: "6000", claudeModel: "claude-haiku-4-5-20251001", codexModel: "gpt-5.4@low", geminiModel: "gemini-3-flash-preview", testPrompt: "Who are you?", }); useEffect(() => { loadConfig(); }, []); async function loadConfig() { try { setIsLoading(true); setError(null); const data = await getStreamCheckConfig(); setConfig({ timeoutSecs: String(data.timeoutSecs), maxRetries: String(data.maxRetries), degradedThresholdMs: String(data.degradedThresholdMs), claudeModel: data.claudeModel, codexModel: data.codexModel, geminiModel: data.geminiModel, testPrompt: data.testPrompt || "Who are you?", }); } catch (e) { setError(String(e)); } finally { setIsLoading(false); } } async function handleSave() { // 解析数字,空值使用默认值,0 是有效值 const parseNum = (val: string, defaultVal: number) => { const n = parseInt(val); return isNaN(n) ? defaultVal : n; }; try { setIsSaving(true); const parsed: StreamCheckConfig = { timeoutSecs: parseNum(config.timeoutSecs, 45), maxRetries: parseNum(config.maxRetries, 2), degradedThresholdMs: parseNum(config.degradedThresholdMs, 6000), claudeModel: config.claudeModel, codexModel: config.codexModel, geminiModel: config.geminiModel, testPrompt: config.testPrompt || "Who are you?", }; await saveStreamCheckConfig(parsed); toast.success(t("streamCheck.configSaved"), { closeButton: true, }); } catch (e) { toast.error(t("streamCheck.configSaveFailed") + ": " + String(e)); } finally { setIsSaving(false); } } if (isLoading) { return (
); } return (
{error && ( {error} )} {/* 测试模型配置 */}

{t("streamCheck.testModels")}

setConfig({ ...config, claudeModel: e.target.value }) } placeholder="claude-3-5-haiku-latest" />
setConfig({ ...config, codexModel: e.target.value }) } placeholder="gpt-4o-mini" />
setConfig({ ...config, geminiModel: e.target.value }) } placeholder="gemini-1.5-flash" />
{/* 检查参数配置 */}

{t("streamCheck.checkParams")}

setConfig({ ...config, timeoutSecs: e.target.value }) } />
setConfig({ ...config, maxRetries: e.target.value }) } />
setConfig({ ...config, degradedThresholdMs: e.target.value }) } />
{/* 检查提示词配置 */}