"use client"; import { useState, useEffect, useCallback } from "react"; import { Link } from "react-router-dom"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"; import { aiSettingsApi, type AIConfigListItem, type AIConfigCreate, type AIConfigUpdate, } from "@/lib/api/client"; import { Loader2, Zap, Plus, Pencil, Trash2, CheckCircle } from "lucide-react"; import { toast } from "sonner"; const PROVIDERS = ["OpenAI", "DeepSeek", "Custom"]; export default function SettingsAIPage() { const [list, setList] = useState([]); const [loading, setLoading] = useState(true); const [dialogOpen, setDialogOpen] = useState(false); const [editingId, setEditingId] = useState(null); const [saving, setSaving] = useState(false); const [testing, setTesting] = useState(null); const [formName, setFormName] = useState(""); const [provider, setProvider] = useState("OpenAI"); const [apiKey, setApiKey] = useState(""); const [apiKeyConfigured, setApiKeyConfigured] = useState(false); const [baseUrl, setBaseUrl] = useState(""); const [modelName, setModelName] = useState("gpt-4o-mini"); const [temperature, setTemperature] = useState("0.2"); const [systemPromptOverride, setSystemPromptOverride] = useState(""); const loadList = useCallback(async () => { try { const data = await aiSettingsApi.list(); setList(data); } catch { toast.error("加载模型列表失败"); } finally { setLoading(false); } }, []); useEffect(() => { void loadList(); }, [loadList]); const openAdd = () => { setEditingId(null); setFormName(""); setProvider("OpenAI"); setApiKey(""); setApiKeyConfigured(false); setBaseUrl(""); setModelName("gpt-4o-mini"); setTemperature("0.2"); setSystemPromptOverride(""); setDialogOpen(true); }; const openEdit = async (id: string) => { try { const c = await aiSettingsApi.getById(id); setEditingId(id); setFormName(c.name || ""); setProvider(c.provider || "OpenAI"); setApiKey(""); setApiKeyConfigured(!!(c.api_key && c.api_key.length > 0)); setBaseUrl(c.base_url || ""); setModelName(c.model_name || "gpt-4o-mini"); setTemperature(String(c.temperature ?? 0.2)); setSystemPromptOverride(c.system_prompt_override || ""); setDialogOpen(true); } catch { toast.error("加载配置失败"); } }; const handleSave = async (e: React.FormEvent) => { e.preventDefault(); setSaving(true); try { if (editingId) { const payload: AIConfigUpdate = { name: formName.trim() || undefined, provider: provider || undefined, base_url: baseUrl.trim() || undefined, model_name: modelName.trim() || undefined, temperature: parseFloat(temperature), system_prompt_override: systemPromptOverride.trim() || undefined, }; if (apiKey.trim()) payload.api_key = apiKey.trim(); await aiSettingsApi.update(editingId, payload); toast.success("已更新"); } else { const payload: AIConfigCreate = { name: formName.trim() || undefined, provider: provider || undefined, api_key: apiKey.trim() || undefined, base_url: baseUrl.trim() || undefined, model_name: modelName.trim() || undefined, temperature: parseFloat(temperature), system_prompt_override: systemPromptOverride.trim() || undefined, }; await aiSettingsApi.create(payload); toast.success("已添加"); } setDialogOpen(false); await loadList(); window.dispatchEvent(new CustomEvent("ai-settings-changed")); } catch (e) { toast.error(e instanceof Error ? e.message : "保存失败"); } finally { setSaving(false); } }; const handleActivate = async (id: string) => { try { await aiSettingsApi.activate(id); toast.success("已选用该模型"); await loadList(); window.dispatchEvent(new CustomEvent("ai-settings-changed")); } catch (e) { toast.error(e instanceof Error ? e.message : "选用失败"); } }; const handleDelete = async (id: string) => { if (!confirm("确定删除该模型配置?")) return; try { await aiSettingsApi.delete(id); toast.success("已删除"); await loadList(); window.dispatchEvent(new CustomEvent("ai-settings-changed")); } catch (e) { toast.error(e instanceof Error ? e.message : "删除失败"); } }; const handleTest = async (id: string) => { setTesting(id); try { const res = await aiSettingsApi.test(id); toast.success(res.message ? `连接成功:${res.message}` : "连接成功"); } catch (e) { toast.error(e instanceof Error ? e.message : "连接失败"); } finally { setTesting(null); } }; if (loading) { return (
加载中…
); } return (
← 设置
已配置的模型

在此查看、选用或编辑多套 AI 模型配置;需求解析与测试将使用当前选用的配置。

{list.length === 0 ? (

暂无模型配置。点击「添加模型」填写 API Key、模型名称等,保存后即可在列表中选用。

) : ( 名称 提供商 模型 API Key 操作 {list.map((item) => ( {item.name || "未命名"} {item.is_active && ( 当前选用 )} {item.provider} {item.model_name || "—"} {item.api_key_configured ? "已配置" : "未配置"}
{!item.is_active && ( )}
))}
)}
{editingId ? "编辑模型配置" : "添加模型配置"}
setFormName(e.target.value)} placeholder="如:OpenAI 生产、DeepSeek 备用" />
setApiKey(e.target.value)} placeholder={apiKeyConfigured ? "已配置,输入新值以修改" : "请输入 API Key"} autoComplete="off" />
setBaseUrl(e.target.value)} placeholder="https://api.openai.com/v1" />
setModelName(e.target.value)} placeholder="gpt-4o-mini / deepseek-chat 等" />
setTemperature(e.target.value)} />