From 94368670b71579fb4aae8d8b96e2cc28dd3757ef Mon Sep 17 00:00:00 2001 From: Oliver Hofmann Date: Tue, 28 Apr 2026 09:07:53 +0200 Subject: [PATCH] Reload Ollama models on URL change, pre-select current model - /api/ollama-models accepts optional url query param to query a different endpoint - Frontend fetches models on load and on Ollama URL blur - Keeps current model selected if available, otherwise selects first in list - Shows loading indicator while fetching --- backend/admin.py | 8 ++++++-- frontend/src/main.jsx | 33 ++++++++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/backend/admin.py b/backend/admin.py index 5e719f9..7d4ec4a 100644 --- a/backend/admin.py +++ b/backend/admin.py @@ -112,8 +112,12 @@ async def update_settings( return settings @app.get("/api/ollama-models") -async def get_ollama_models(db: Session = Depends(get_db), _ = Depends(require_admin_auth)): - ollama_url = crud.get_setting(db, "ollama_url", "http://localhost:11434") +async def get_ollama_models( + url: str = None, + db: Session = Depends(get_db), + _ = Depends(require_admin_auth), +): + ollama_url = url or crud.get_setting(db, "ollama_url", "http://localhost:11434") try: async with httpx.AsyncClient(timeout=5.0) as client: response = await client.get(f"{ollama_url}/api/tags") diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx index a8456d7..581f89c 100644 --- a/frontend/src/main.jsx +++ b/frontend/src/main.jsx @@ -51,20 +51,40 @@ const EMPTY_KEY_FORM = { function SettingsSection({ password }) { const [settings, setSettings] = useState(null); const [availableModels, setAvailableModels] = useState([]); + const [modelsLoading, setModelsLoading] = useState(false); const [proxyEndpoint, setProxyEndpoint] = useState(null); const [saved, setSaved] = useState(false); const [error, setError] = useState(null); + const fetchModels = async (url, currentModel) => { + setModelsLoading(true); + try { + const res = await axios.get('/api/ollama-models', { + headers: authHeaders(password), + params: url ? { url } : {}, + }); + const models = res.data.models; + setAvailableModels(models); + if (models.length > 0 && !models.includes(currentModel)) { + setSettings(s => ({ ...s, default_model: models[0] })); + } + } catch { + setAvailableModels([]); + } finally { + setModelsLoading(false); + } + }; + useEffect(() => { const headers = authHeaders(password); Promise.all([ axios.get('/api/settings', { headers }), - axios.get('/api/ollama-models', { headers }), axios.get('/api/proxy-info', { headers }), - ]).then(([settingsRes, modelsRes, proxyRes]) => { - setSettings(settingsRes.data); - setAvailableModels(modelsRes.data.models); + ]).then(([settingsRes, proxyRes]) => { + const s = settingsRes.data; + setSettings(s); setProxyEndpoint(proxyRes.data.endpoint); + fetchModels(s.ollama_url, s.default_model); }).catch(() => setError('Einstellungen konnten nicht geladen werden.')); }, []); @@ -100,13 +120,16 @@ function SettingsSection({ password }) { type="url" value={settings.ollama_url} onChange={(e) => setSettings({ ...settings, ollama_url: e.target.value })} + onBlur={(e) => fetchModels(e.target.value, settings.default_model)} placeholder="http://localhost:11434" required />
- {availableModels.length > 0 ? ( + {modelsLoading ? ( + Lade Modelle… + ) : availableModels.length > 0 ? (