import React, { useState, useEffect } from 'react'; interface Settings { default_llm_provider: string; embedding_provider: string; openai_api_key: string; openai_model: string; anthropic_api_key: string; anthropic_model: string; google_api_key: string; gemini_model: string; ollama_base_url: string; ollama_model: string; ollama_embedding_model: string; huggingface_api_key: string; huggingface_model: string; huggingface_embedding_model: string; } const API_BASE = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8000/api'; const SettingsView: React.FC = () => { const [settings, setSettings] = useState(null); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [error, setError] = useState(null); const [success, setSuccess] = useState(null); const [ollamaModels, setOllamaModels] = useState([]); const [hfModels, setHfModels] = useState([]); // State for tracking if custom input is shown const [showCustom, setShowCustom] = useState>({}); useEffect(() => { fetchSettings(); fetchHfModels(); }, []); useEffect(() => { if (settings?.ollama_base_url) { fetchOllamaModels(settings.ollama_base_url); } }, [settings?.ollama_base_url]); const fetchOllamaModels = async (baseUrl: string) => { try { const res = await fetch(`${API_BASE}/system/ollama/models?base_url=${encodeURIComponent(baseUrl)}`); if (res.ok) { const data = await res.json(); setOllamaModels(data.models || []); } } catch (e) { console.error(e); } }; const fetchHfModels = async () => { try { const res = await fetch(`${API_BASE}/system/huggingface/models`); if (res.ok) { const data = await res.json(); setHfModels(data.models || []); } } catch (e) { console.error(e); } }; const fetchSettings = async () => { try { const response = await fetch(`${API_BASE}/system/settings`, { headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` } }); if (!response.ok) throw new Error('Failed to fetch settings'); const data = await response.json(); // Replace nulls with empty strings for input values const sanitizedData = Object.keys(data).reduce((acc, key) => { acc[key as keyof Settings] = data[key] || ''; return acc; }, {} as Settings); setSettings(sanitizedData); } catch (err: any) { setError(err.message); } finally { setLoading(false); } }; const handleChange = (e: React.ChangeEvent) => { const { name, value } = e.target; if (settings) { if (value === '__custom__') { setShowCustom({ ...showCustom, [name]: true }); setSettings({ ...settings, [name]: '' }); } else { setSettings({ ...settings, [name]: value }); } } }; const renderDropdownOrInput = (name: keyof Settings, options: string[], placeholder: string = "") => { // Always include the current value in the options so the select doesn't break const currentValue = settings?.[name] as string; const finalOptions = [...options]; if (currentValue && !finalOptions.includes(currentValue)) { finalOptions.unshift(currentValue); } const isCustom = showCustom[name]; if (isCustom) { return (
); } return ( ); }; const handleSave = async (e: React.FormEvent) => { e.preventDefault(); setSaving(true); setError(null); setSuccess(null); try { const response = await fetch(`${API_BASE}/system/settings`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('token')}` }, body: JSON.stringify(settings) }); if (!response.ok) throw new Error('Failed to save settings'); setSuccess('Settings updated successfully!'); setTimeout(() => setSuccess(null), 3000); } catch (err: any) { setError(err.message); } finally { setSaving(false); } }; if (loading) return
Loading settings...
; return (

SYSTEM SETTINGS

{error &&
{error}
} {success &&
{success}
}
{/* Global Providers */}

Global Providers

{/* Hugging Face Settings */}

Hugging Face

{renderDropdownOrInput('huggingface_model', hfModels, 'meta-llama/Meta-Llama-3-8B-Instruct')}
{renderDropdownOrInput('huggingface_embedding_model', hfModels, 'BAAI/bge-large-en-v1.5')}
{/* Gemini Settings */}

Google Gemini

{/* Ollama Settings */}

Ollama

{renderDropdownOrInput('ollama_model', ollamaModels, 'llama3')}
{renderDropdownOrInput('ollama_embedding_model', ollamaModels, 'nomic-embed-text')}
{/* OpenAI Settings */}

OpenAI

{/* Anthropic Settings */}

Anthropic

); }; export default SettingsView;