BareGit
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>LLM Model Switcher</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div id="app"></div>

    <script type="module">
        import { h, render } from 'https://esm.sh/preact';
        import { useState, useEffect } from 'https://esm.sh/preact/hooks';
        import htm from 'https://esm.sh/htm';

        const html = htm.bind(h);

        function App() {
            const [models, setModels] = useState([]);
            const [currentModel, setCurrentModel] = useState(null);
            const [selectedModel, setSelectedModel] = useState(null);
            const [loading, setLoading] = useState(true);
            const [switching, setSwitching] = useState(false);
            const [message, setMessage] = useState({ text: '', type: '' });
            
            // Log state
            const [logs, setLogs] = useState([]);
            const [loadingLogs, setLoadingLogs] = useState(false);

            const fetchModels = async () => {
                try {
                    setLoading(true);
                    const response = await fetch('/api/models');
                    const data = await response.json();
                    if (data.error) throw new Error(data.error);
                    
                    setModels(data.models || []);
                    setCurrentModel(data.current);
                    if (data.current) setSelectedModel(data.current);
                } catch (err) {
                    setMessage({ text: 'Failed to load models: ' + err.message, type: 'error' });
                } finally {
                    setLoading(false);
                }
            };

            const fetchLogs = async () => {
                try {
                    setLoadingLogs(true);
                    const response = await fetch('/api/logs');
                    const data = await response.json();
                    if (data.error) throw new Error(data.error);
                    
                    setLogs(data.logs || []);
                } catch (err) {
                    // Just log to console or show a small error in the log section?
                    // We'll put a fake log entry for error
                    setLogs(['Error fetching logs: ' + err.message]);
                } finally {
                    setLoadingLogs(false);
                }
            };

            const switchModel = async () => {
                if (!selectedModel || selectedModel === currentModel) return;

                try {
                    setSwitching(true);
                    setMessage({ text: 'Switching model and restarting service...', type: 'info' });
                    
                    const response = await fetch('/api/switch', {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify({ model: selectedModel })
                    });
                    
                    const data = await response.json();
                    if (data.error) throw new Error(data.error);
                    
                    setMessage({ text: 'Model switched successfully!', type: 'success' });
                    setCurrentModel(selectedModel);
                    // Refresh logs after switch
                    setTimeout(fetchLogs, 2000); 
                } catch (err) {
                    setMessage({ text: 'Failed to switch model: ' + err.message, type: 'error' });
                } finally {
                    setSwitching(false);
                }
            };

            useEffect(() => {
                fetchModels();
                fetchLogs();
            }, []);

            if (loading) return html`<div class="container"><p>Loading models...</p></div>`;

            return html`
                <div class="container">
                    <header>
                        <h1>LLM Model Switcher</h1>
                        <p class="status">
                            Current Model: <strong>${currentModel || 'None'}</strong>
                        </p>
                    </header>

                    <main>
                        <div class="model-list">
                            ${models.length === 0 ? html`<p>No models found in <code>/etc/llama.cpp.d</code></p>` : 
                                models.map(model => html`
                                    <label class="model-item ${selectedModel === model ? 'selected' : ''} ${currentModel === model ? 'active' : ''}">
                                        <input 
                                            type="radio" 
                                            name="model" 
                                            value="${model}" 
                                            checked="${selectedModel === model}"
                                            onChange="${() => setSelectedModel(model)}"
                                            disabled="${switching}"
                                        />
                                        <span class="model-name">${model}</span>
                                        ${currentModel === model && html`<span class="badge">Active</span>`}
                                    </label>
                                `)
                            }
                        </div>

                        <div class="actions">
                            <button 
                                onClick="${switchModel}" 
                                disabled="${switching || !selectedModel || selectedModel === currentModel}"
                                class="${switching ? 'loading' : ''}"
                            >
                                ${switching ? 'Restarting...' : 'Apply Selection'}
                            </button>
                            <button class="secondary" onClick="${fetchModels}" disabled="${switching}">Refresh Models</button>
                        </div>

                        ${message.text && html`
                            <div class="message ${message.type}">
                                ${message.text}
                            </div>
                        `}

                        <div class="log-section">
                            <div class="log-header">
                                <h2>Service Logs</h2>
                                <button class="secondary" style="width: auto; padding: 0.4rem 0.8rem; font-size: 0.8rem;" onClick="${fetchLogs}" disabled="${loadingLogs}">
                                    ${loadingLogs ? 'Refreshing...' : 'Refresh Logs'}
                                </button>
                            </div>
                            <div class="log-viewer">
                                ${logs.length === 0 
                                    ? html`<div class="log-entry">No logs available or service not found.</div>` 
                                    : logs.map((line, i) => html`<div class="log-entry" key="${i}">${line}</div>`)
                                }
                            </div>
                        </div>
                    </main>
                </div>
            `;
        }

        render(html`<${App} />`, document.getElementById('app'));
    </script>
</body>
</html>