- New web UI with OpenWebUI-like interface using Tailwind CSS - SQLite-based authentication with session management - User registration, login, and profile pages - Chat interface with conversation history - Streaming responses with visible thinking phase - File attachments support - User document uploads in profile - Rate limiting (5 requests/day for free users) - Admin panel user management with promote/demote/delete - Custom color theme matching balloon logo design - Compatible with Nuitka build system
141 lines
6.1 KiB
HTML
Executable File
141 lines
6.1 KiB
HTML
Executable File
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Endpoints - MOXIE Admin</title>
|
|
<link rel="stylesheet" href="/{{ settings.admin_path }}/static/admin.css">
|
|
</head>
|
|
<body>
|
|
<nav class="navbar">
|
|
<div class="nav-brand">MOXIE Admin</div>
|
|
<div class="nav-links">
|
|
<a href="/{{ settings.admin_path }}/">Dashboard</a>
|
|
<a href="/{{ settings.admin_path }}/endpoints">Endpoints</a>
|
|
<a href="/{{ settings.admin_path }}/documents">Documents</a>
|
|
<a href="/{{ settings.admin_path }}/comfyui">ComfyUI</a>
|
|
<a href="/{{ settings.admin_path }}/users">Users</a>
|
|
</div>
|
|
</nav>
|
|
|
|
<main class="container">
|
|
<h1>API Endpoints Configuration</h1>
|
|
|
|
<form id="endpoints-form" class="form">
|
|
<section class="form-section">
|
|
<h2>Ollama Settings</h2>
|
|
|
|
<div class="form-group">
|
|
<label for="ollama_host">Ollama Host</label>
|
|
<input type="text" id="ollama_host" name="ollama_host"
|
|
value="{{ config.get('ollama_host', 'http://127.0.0.1:11434') }}"
|
|
placeholder="http://127.0.0.1:11434">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="ollama_model">Orchestrator Model</label>
|
|
<input type="text" id="ollama_model" name="ollama_model"
|
|
value="{{ config.get('ollama_model', 'qwen2.5:2b') }}"
|
|
placeholder="qwen2.5:2b">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="embedding_model">Embedding Model</label>
|
|
<input type="text" id="embedding_model" name="embedding_model"
|
|
value="{{ config.get('embedding_model', 'qwen3-embedding:4b') }}"
|
|
placeholder="qwen3-embedding:4b">
|
|
</div>
|
|
</section>
|
|
|
|
<section class="form-section">
|
|
<h2>Gemini API</h2>
|
|
<p class="help-text">Used for "deep reasoning" tasks. Get your key from <a href="https://aistudio.google.com/apikey" target="_blank">Google AI Studio</a>.</p>
|
|
|
|
<div class="form-group">
|
|
<label for="gemini_api_key">API Key</label>
|
|
<input type="password" id="gemini_api_key" name="gemini_api_key"
|
|
value="{{ config.get('gemini_api_key', '') }}"
|
|
placeholder="AIza...">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="gemini_model">Model</label>
|
|
<input type="text" id="gemini_model" name="gemini_model"
|
|
value="{{ config.get('gemini_model', 'gemini-1.5-flash') }}"
|
|
placeholder="gemini-1.5-flash">
|
|
</div>
|
|
</section>
|
|
|
|
<section class="form-section">
|
|
<h2>OpenRouter API</h2>
|
|
<p class="help-text">Alternative reasoning endpoint. Get your key from <a href="https://openrouter.ai/keys" target="_blank">OpenRouter</a>.</p>
|
|
|
|
<div class="form-group">
|
|
<label for="openrouter_api_key">API Key</label>
|
|
<input type="password" id="openrouter_api_key" name="openrouter_api_key"
|
|
value="{{ config.get('openrouter_api_key', '') }}"
|
|
placeholder="sk-or-...">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="openrouter_model">Model</label>
|
|
<input type="text" id="openrouter_model" name="openrouter_model"
|
|
value="{{ config.get('openrouter_model', 'meta-llama/llama-3-8b-instruct:free') }}"
|
|
placeholder="meta-llama/llama-3-8b-instruct:free">
|
|
</div>
|
|
</section>
|
|
|
|
<section class="form-section">
|
|
<h2>ComfyUI</h2>
|
|
<p class="help-text">Image, video, and audio generation.</p>
|
|
|
|
<div class="form-group">
|
|
<label for="comfyui_host">ComfyUI Host</label>
|
|
<input type="text" id="comfyui_host" name="comfyui_host"
|
|
value="{{ config.get('comfyui_host', 'http://127.0.0.1:8188') }}"
|
|
placeholder="http://127.0.0.1:8188">
|
|
</div>
|
|
</section>
|
|
|
|
<div class="form-actions">
|
|
<button type="submit" class="btn btn-primary">Save Configuration</button>
|
|
</div>
|
|
</form>
|
|
|
|
<div id="toast" class="toast hidden"></div>
|
|
</main>
|
|
|
|
<script>
|
|
document.getElementById('endpoints-form').addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
|
|
const formData = new FormData(e.target);
|
|
const data = {};
|
|
formData.forEach((value, key) => data[key] = value);
|
|
|
|
try {
|
|
const response = await fetch('/{{ settings.admin_path }}/endpoints', {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify(data)
|
|
});
|
|
|
|
const result = await response.json();
|
|
|
|
showToast(result.status === 'success' ? 'Configuration saved!' : 'Failed to save',
|
|
result.status === 'success' ? 'success' : 'error');
|
|
} catch (error) {
|
|
showToast('Failed to save configuration', 'error');
|
|
}
|
|
});
|
|
|
|
function showToast(message, type) {
|
|
const toast = document.getElementById('toast');
|
|
toast.textContent = message;
|
|
toast.className = 'toast ' + type;
|
|
setTimeout(() => toast.classList.add('hidden'), 3000);
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|