import { useEffect, useRef, useState } from 'react'; import { Check, LoaderCircle } from 'lucide-react'; import { api, errorText } from '../api'; import type { SettingsInfo } from '../types'; export function SettingsDialog({ open, onClose, onSaved }: { open: boolean; onClose: () => void; onSaved: (message: string) => void; }) { const dialog = useRef(null); const [info, setInfo] = useState(null); const [provider, setProvider] = useState('deepseek'); const [model, setModel] = useState('deepseek-flash'); const [baseUrl, setBaseUrl] = useState('https://api.deepseek.com'); const [apiKey, setApiKey] = useState(''); const [error, setError] = useState(''); const [pending, setPending] = useState(false); const [result, setResult] = useState<{ ok: boolean; message: string } | null>(null); useEffect(() => { const element = dialog.current; if (!element) return; let active = true; if (open && !element.open) { element.showModal(); setError(''); setResult(null); setApiKey(''); api.get('/settings').then(data => { if (!active) return; setInfo(data); setProvider(data.llm_provider); setModel(data.llm_model); setBaseUrl(data.llm_base_url); }).catch(err => { if (active) setError(errorText(err)); }); } else if (!open) { if (element.open) element.close(); setApiKey(''); } return () => { active = false; }; }, [open]); const available = info?.models_by_provider[provider] ?? (provider === 'deepseek' ? ['deepseek-flash', 'deepseek-v4-pro'] : ['qwen-vl-max']); const models = available.includes(model) ? available : [model, ...available]; async function persist(): Promise { const body: Record = { llm_provider: provider, llm_model: model, llm_base_url: baseUrl }; if (apiKey.trim()) body[provider === 'qwen' ? 'dashscope_api_key' : 'llm_api_key'] = apiKey.trim(); await api.put('/settings', body); setInfo(await api.get('/settings')); setApiKey(''); onSaved('模型配置已保存'); } async function save(test: boolean): Promise { setPending(true); setError(''); setResult(null); try { await persist(); if (test) { const status = await api.post<{ ok: boolean; message?: string; detail?: string; model?: string }>('/settings/test', {}); setResult({ ok: status.ok, message: status.message || status.detail || (status.ok ? `连接成功,模型 ${status.model || model}` : '连接未通过,请检查配置。') }); } else { onClose(); } } catch (err) { setError(errorText(err)); } finally { setPending(false); } } return
{ event.preventDefault(); void save(false); }}>

模型设置

deepseek-flash 支持截图理解,适合浏览器探索;deepseek-v4-pro 用于文本推理。模型能力以实际连通测试为准。

Search / Fetch 使用同一个 DeepSeek Key,单独按请求计费,只有开启公开资料查询时才调用。

{result &&
{result.ok && } {result.message}
} {error &&

{error}

}
; }