From af9e9da99679c821315d2216d78700393aec1d22 Mon Sep 17 00:00:00 2001 From: xiamuceer-j Date: Wed, 25 Feb 2026 09:13:57 +0800 Subject: [PATCH] =?UTF-8?q?update:=20=E6=9B=B4=E6=96=B0API=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=EF=BC=8C=E6=94=AF=E6=8C=81=E6=89=8B=E5=8A=A8=E8=BE=93?= =?UTF-8?q?=E5=85=A5=E6=A8=A1=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/api/settings.py | 5 ++ frontend/src/pages/Settings.tsx | 131 ++++++++++++++++++++++---------- 2 files changed, 94 insertions(+), 42 deletions(-) diff --git a/backend/app/api/settings.py b/backend/app/api/settings.py index c75619e..5e06f20 100644 --- a/backend/app/api/settings.py +++ b/backend/app/api/settings.py @@ -356,6 +356,11 @@ async def get_available_models( except httpx.HTTPStatusError as e: logger.error(f"获取模型列表失败 (HTTP {e.response.status_code}): {e.response.text}") + if e.response.status_code == 404: + raise HTTPException( + status_code=400, + detail=f"该 API 提供商不支持模型列表查询接口 (/models 返回 404),请手动输入模型名称。当前请求地址: {api_base_url.rstrip('/')}/models" + ) raise HTTPException( status_code=400, detail=f"无法从 API 获取模型列表 (HTTP {e.response.status_code})" diff --git a/frontend/src/pages/Settings.tsx b/frontend/src/pages/Settings.tsx index db39186..d4fa90f 100644 --- a/frontend/src/pages/Settings.tsx +++ b/frontend/src/pages/Settings.tsx @@ -22,6 +22,7 @@ export default function SettingsPage() { const [modelOptions, setModelOptions] = useState>([]); const [fetchingModels, setFetchingModels] = useState(false); const [modelsFetched, setModelsFetched] = useState(false); + const [modelSearchText, setModelSearchText] = useState(''); const [testingApi, setTestingApi] = useState(false); const [testResult, setTestResult] = useState<{ success: boolean; @@ -48,6 +49,7 @@ export default function SettingsPage() { const [presetModelOptions, setPresetModelOptions] = useState>([]); const [fetchingPresetModels, setFetchingPresetModels] = useState(false); const [presetModelsFetched, setPresetModelsFetched] = useState(false); + const [presetModelSearchText, setPresetModelSearchText] = useState(''); useEffect(() => { loadSettings(); @@ -430,6 +432,7 @@ export default function SettingsPage() { // 清除预设模型列表状态 setPresetModelOptions([]); setPresetModelsFetched(false); + setPresetModelSearchText(''); }; // 预设编辑窗口:获取模型列表 @@ -1100,14 +1103,19 @@ export default function SettingsPage() { - (option?.label ?? '').toLowerCase().includes(input.toLowerCase()) || - (option?.description ?? '').toLowerCase().includes(input.toLowerCase()) - } + onSearch={(value) => setPresetModelSearchText(value)} + onSelect={() => setPresetModelSearchText('')} + onBlur={() => setPresetModelSearchText('')} + filterOption={(input, option) => { + // 手动输入的选项始终显示 + if (option?.value === input && !presetModelOptions.some(m => m.value === input)) return true; + return (option?.label ?? '').toLowerCase().includes(input.toLowerCase()) || + (option?.description ?? '').toLowerCase().includes(input.toLowerCase()); + }} dropdownRender={(menu) => ( <> {menu} @@ -1610,14 +1640,14 @@ export default function SettingsPage() { 正在获取模型列表... )} - {!fetchingPresetModels && presetModelOptions.length === 0 && presetModelsFetched && ( + {!fetchingPresetModels && presetModelOptions.length === 0 && presetModelsFetched && !presetModelSearchText && (
- 未能获取到模型列表,请检查 API 配置 + 未能获取到模型列表,可直接输入模型名称
)} - {!fetchingPresetModels && presetModelOptions.length === 0 && !presetModelsFetched && ( + {!fetchingPresetModels && presetModelOptions.length === 0 && !presetModelsFetched && !presetModelSearchText && (
- 点击输入框自动获取模型列表 + 点击输入框自动获取,或直接输入模型名称
)} @@ -1627,11 +1657,7 @@ export default function SettingsPage() {
加载中...
- ) : ( -
- 未找到匹配的模型 -
- ) + ) : null } suffixIcon={
} - options={presetModelOptions.map(model => ({ - value: model.value, - label: model.label, - description: model.description - }))} + options={(() => { + const opts = presetModelOptions.map(model => ({ + value: model.value, + label: model.label, + description: model.description + })); + // 如果用户输入了文本且不在已有选项中,添加手动输入选项 + if (presetModelSearchText && !presetModelOptions.some(m => + m.value.toLowerCase() === presetModelSearchText.toLowerCase() || + m.label.toLowerCase() === presetModelSearchText.toLowerCase() + )) { + opts.unshift({ + value: presetModelSearchText, + label: presetModelSearchText, + description: '手动输入的模型名称' + }); + } + return opts; + })()} optionRender={(option) => (
-
{option.data.label}
- {option.data.description && ( +
+ {option.data.description === '手动输入的模型名称' ? ( + + + 使用 "{option.data.label}" + + ) : option.data.label} +
+ {option.data.description && option.data.description !== '手动输入的模型名称' && (
{option.data.description}