/* Instellingen screen */ function SchermInstellingen() { const [providers, setProviders] = useState({}); const [form, setForm] = useState({ provider: 'anthropic', api_key: '', base_url: 'http://localhost:11434', region: 'eu-central-1' }); const [status, setStatus] = useState(null); const [testen, setTesten] = useState(false); const [logboek, setLogboek] = useState([]); const [logLaden, setLogLaden] = useState(false); const isOllama = form.provider === 'ollama'; const isBedrock = form.provider === 'bedrock'; // Standaard provider + model voor de pipeline-startform const [std, setStd] = useState({ provider: 'anthropic', model: '' }); const [stdOllamaModellen, setStdOllamaModellen] = useState([]); const [stdStatus, setStdStatus] = useState(null); const [stdBezig, setStdBezig] = useState(false); const [providerModellen, setProviderModellen] = useState({}); const [modelForm, setModelForm] = useState({ provider: 'anthropic', nieuw: '' }); const [modelStatus, setModelStatus] = useState(null); async function laadModellen() { try { const d = await fetch(`${API}/config/providers/models`).then(r => r.ok ? r.json() : {}); setProviderModellen(d); } catch (e) {} } useEffect(() => { laadModellen(); }, []); async function laadStandaard() { const d = await fetch(`${API}/config/standaard`).then(r => r.ok ? r.json() : {}).catch(() => ({})); if (d && d.provider) setStd({ provider: d.provider, model: d.model || '' }); } useEffect(() => { laadStandaard(); }, []); useEffect(() => { if (std.provider !== 'ollama') { setStdOllamaModellen([]); return; } fetch(`${API}/config/providers/ollama/models`) .then(r => r.ok ? r.json() : { models: [] }) .then(d => setStdOllamaModellen(d.models || [])) .catch(() => setStdOllamaModellen([])); }, [std.provider]); const stdModelOpties = std.provider === 'ollama' ? stdOllamaModellen : (providerModellen[std.provider] || []); async function slaStandaardOp() { setStdStatus(null); setStdBezig(true); try { const r = await fetch(`${API}/config/standaard`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ provider: std.provider, model: std.model || null }), }); setStdStatus(r.ok ? { kind: 'success', msg: 'Standaard opgeslagen.' } : { kind: 'error', msg: 'Opslaan mislukt.' }); } catch (e) { setStdStatus({ kind: 'error', msg: `Opslaan mislukt: ${e.message}` }); } finally { setStdBezig(false); } } async function laadLogboek() { setLogLaden(true); try { const d = await fetch(`${API}/auth-log?limit=100`).then(r => r.ok ? r.json() : []).catch(() => []); setLogboek(Array.isArray(d) ? d : []); } finally { setLogLaden(false); } } useEffect(() => { laadLogboek(); }, []); const LOG_KIND = { login_ok: 'success', login_fout: 'error', lockout: 'warning', logout: 'neutral' }; const LOG_LABEL = { login_ok: 'Ingelogd', login_fout: 'Mislukt', lockout: 'Geblokkeerd', logout: 'Uitgelogd' }; async function laad() { const p = await fetch(`${API}/config/providers`).then(r => r.json()).catch(() => ({})); setProviders(p); const details = await fetch(`${API}/config/providers/public`).then(r => r.json()).catch(() => ({})); setForm(f => ({ ...f, base_url: details.ollama?.base_url || f.base_url, region: details.bedrock?.region || f.region, })); } useEffect(() => { laad(); }, []); async function opslaan() { setStatus(null); const r = await fetch(`${API}/config/providers`, { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify(form) }); if (r.ok) { setStatus({ kind: 'success', msg: 'Opgeslagen.' }); setForm(f => ({...f, api_key: ''})); laad(); } else { setStatus({ kind: 'error', msg: 'Opslaan mislukt.' }); } } async function testProvider() { setStatus(null); setTesten(true); try { const params = new URLSearchParams(); if (isOllama && form.base_url) params.append('base_url', form.base_url); if (!isOllama && form.api_key) params.append('api_key', form.api_key); const qs = params.toString() ? `?${params.toString()}` : ''; const data = await fetch(`${API}/config/providers/test/${form.provider}${qs}`).then(r => r.json()); if (data.ok) { const extra = isOllama && data.models?.length ? ` Modellen: ${data.models.join(', ')}` : ''; setStatus({ kind: 'success', msg: `Verbinding werkt.${extra}` }); } else { setStatus({ kind: 'error', msg: `Test mislukt: ${data.fout || 'onbekende fout'}` }); } } catch(e) { setStatus({ kind: 'error', msg: `Test mislukt: ${e.message}` }); } finally { setTesten(false); } } async function voegModelToe() { const naam = modelForm.nieuw.trim(); if (!naam) return; const huidig = providerModellen[modelForm.provider] || []; if (huidig.includes(naam)) { setModelStatus({ kind: 'error', msg: `"${naam}" staat al in de lijst.` }); return; } const nieuw = [...huidig, naam]; setModelStatus(null); try { const r = await fetch(`${API}/config/providers/models`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ provider: modelForm.provider, models: nieuw }), }); if (r.ok) { setProviderModellen(p => ({ ...p, [modelForm.provider]: nieuw })); setModelForm(f => ({ ...f, nieuw: '' })); setModelStatus({ kind: 'success', msg: `"${naam}" toegevoegd.` }); laadModellen(); } else { setModelStatus({ kind: 'error', msg: 'Toevoegen mislukt.' }); } } catch (e) { setModelStatus({ kind: 'error', msg: `Toevoegen mislukt: ${e.message}` }); } } async function verwijderModel(model) { const huidig = providerModellen[modelForm.provider] || []; const nieuw = huidig.filter(m => m !== model); setModelStatus(null); try { const r = await fetch(`${API}/config/providers/models`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ provider: modelForm.provider, models: nieuw }), }); if (r.ok) { setProviderModellen(p => ({ ...p, [modelForm.provider]: nieuw })); setModelStatus({ kind: 'success', msg: `"${model}" verwijderd.` }); laadModellen(); } else { setModelStatus({ kind: 'error', msg: 'Verwijderen mislukt.' }); } } catch (e) { setModelStatus({ kind: 'error', msg: `Verwijderen mislukt: ${e.message}` }); } } return (
Configureer AI-providers en systeemopties.
Provider en model die de pipeline-startform standaard voorinvult.
{stdStatus &&Voeg modellen toe of verwijder ze per provider. Ollama-modellen worden automatisch opgehaald.
{modelStatus &&| Tijd | Gebeurtenis | Gebruiker | IP | Detail |
|---|---|---|---|---|
| {(r.tijd || '').replace('T',' ').slice(0,19)} | {r.gebruikersnaam || '—'} | {r.ip || '—'} | {r.detail || (r.user_agent ? r.user_agent.slice(0,60) : '')} |