mirror of
https://github.com/perstarkse/minne.git
synced 2026-03-20 16:44:12 +01:00
192 lines
9.1 KiB
HTML
192 lines
9.1 KiB
HTML
{% extends 'body_base.html' %}
|
||
|
||
{% block title %}Minne - Admin{% endblock %}
|
||
|
||
{% block main %}
|
||
<div class="flex justify-center grow mt-2 sm:mt-4 pb-4">
|
||
<div class="container">
|
||
<section class="mb-4">
|
||
<div class="nb-panel p-3 flex items-center justify-between">
|
||
<h1 class="text-xl font-extrabold tracking-tight">Admin Dashboard</h1>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="mb-4">
|
||
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
||
<div class="nb-stat">
|
||
<div class="text-xs opacity-70">Page Loads</div>
|
||
<div class="text-3xl font-extrabold">{{analytics.page_loads}}</div>
|
||
<div class="text-xs opacity-60">Total page load events</div>
|
||
</div>
|
||
<div class="nb-stat">
|
||
<div class="text-xs opacity-70">Unique Visitors</div>
|
||
<div class="text-3xl font-extrabold">{{analytics.visitors}}</div>
|
||
<div class="text-xs opacity-60">Distinct users by fingerprint</div>
|
||
</div>
|
||
<div class="nb-stat">
|
||
<div class="text-xs opacity-70">Users</div>
|
||
<div class="text-3xl font-extrabold">{{users}}</div>
|
||
<div class="text-xs opacity-60">Registered accounts</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="grid grid-cols-1 xl:grid-cols-2 gap-4">
|
||
{% block system_prompt_section %}
|
||
<div id="system_prompt_section" class="nb-panel p-4">
|
||
<div class="text-sm font-semibold mb-3">System Prompts</div>
|
||
<div class="flex gap-2 flex-col sm:flex-row">
|
||
<button type="button" class="nb-btn btn-sm" hx-get="/edit-query-prompt" hx-target="#modal"
|
||
hx-swap="innerHTML">Edit Query Prompt</button>
|
||
<button type="button" class="nb-btn btn-sm" hx-get="/edit-ingestion-prompt" hx-target="#modal"
|
||
hx-swap="innerHTML">Edit Ingestion Prompt</button>
|
||
<button type="button" class="nb-btn btn-sm" hx-get="/edit-image-prompt" hx-target="#modal"
|
||
hx-swap="innerHTML">Edit Image Prompt</button>
|
||
</div>
|
||
</div>
|
||
{% endblock %}
|
||
|
||
<div class="nb-panel p-4">
|
||
<div class="text-sm font-semibold mb-3">AI Models</div>
|
||
{% block model_settings_form %}
|
||
<form hx-patch="/update-model-settings" hx-swap="outerHTML" class="grid grid-cols-1 gap-4">
|
||
<!-- Query Model -->
|
||
<div>
|
||
<div class="text-sm opacity-80 mb-1">Query Model</div>
|
||
<select name="query_model" class="nb-select w-full">
|
||
{% for model in available_models.data %}
|
||
<option value="{{model.id}}" {% if settings.query_model==model.id %} selected {% endif %}>{{model.id}}
|
||
</option>
|
||
{% endfor %}
|
||
</select>
|
||
<p class="text-xs opacity-70 mt-1">Current: <span class="font-mono">{{settings.query_model}}</span></p>
|
||
</div>
|
||
|
||
<!-- Processing Model -->
|
||
<div>
|
||
<div class="text-sm opacity-80 mb-1">Processing Model</div>
|
||
<select name="processing_model" class="nb-select w-full">
|
||
{% for model in available_models.data %}
|
||
<option value="{{model.id}}" {% if settings.processing_model==model.id %} selected {% endif %}>
|
||
{{model.id}}</option>
|
||
{% endfor %}
|
||
</select>
|
||
<p class="text-xs opacity-70 mt-1">Current: <span class="font-mono">{{settings.processing_model}}</span></p>
|
||
</div>
|
||
|
||
<!-- Image Processing Model -->
|
||
<div>
|
||
<div class="text-sm opacity-80 mb-1">Image Processing Model</div>
|
||
<select name="image_processing_model" class="nb-select w-full">
|
||
{% for model in available_models.data %}
|
||
<option value="{{model.id}}" {% if settings.image_processing_model==model.id %} selected {% endif %}>
|
||
{{model.id}}</option>
|
||
{% endfor %}
|
||
</select>
|
||
<p class="text-xs opacity-70 mt-1">Current: <span
|
||
class="font-mono">{{settings.image_processing_model}}</span></p>
|
||
</div>
|
||
|
||
<!-- Voice Processing Model -->
|
||
<div>
|
||
<div class="text-sm opacity-80 mb-1">Voice Processing Model</div>
|
||
<select name="voice_processing_model" class="nb-select w-full">
|
||
{% for model in available_models.data %}
|
||
<option value="{{model.id}}" {% if settings.voice_processing_model==model.id %} selected {% endif %}>
|
||
{{model.id}}</option>
|
||
{% endfor %}
|
||
</select>
|
||
<p class="text-xs opacity-70 mt-1">Current: <span
|
||
class="font-mono">{{settings.voice_processing_model}}</span></p>
|
||
</div>
|
||
|
||
<!-- Embedding Model -->
|
||
<div>
|
||
<div class="text-sm opacity-80 mb-1">Embedding Model</div>
|
||
{% if settings.embedding_backend == "fastembed" or settings.embedding_backend == "hashed" %}
|
||
<input type="text" name="embedding_model" class="nb-input w-full opacity-60 cursor-not-allowed"
|
||
value="{{settings.embedding_model}}" disabled />
|
||
<p class="text-xs opacity-70 mt-1">Model: <span class="font-mono">{{settings.embedding_model}}
|
||
({{settings.embedding_dimensions}} dims)</span></p>
|
||
<p class="text-xs text-info mt-1">ℹ️ Embedding model is controlled by config when using <span
|
||
class="font-mono">{{settings.embedding_backend}}</span> backend.</p>
|
||
{% else %}
|
||
<select name="embedding_model" class="nb-select w-full">
|
||
{% for model in available_models.data %}
|
||
<option value="{{model.id}}" {% if settings.embedding_model==model.id %} selected {% endif %}>{{model.id}}
|
||
</option>
|
||
{% endfor %}
|
||
</select>
|
||
<p class="text-xs opacity-70 mt-1">Current: <span class="font-mono">{{settings.embedding_model}}
|
||
({{settings.embedding_dimensions}} dims)</span></p>
|
||
{% endif %}
|
||
</div>
|
||
|
||
<!-- Embedding Dimensions -->
|
||
<div>
|
||
<div class="text-sm opacity-80 mb-1" for="embedding_dimensions">Embedding Dimensions</div>
|
||
{% if settings.embedding_backend == "fastembed" or settings.embedding_backend == "hashed" %}
|
||
<input type="number" id="embedding_dimensions" name="embedding_dimensions"
|
||
class="nb-input w-full opacity-60 cursor-not-allowed" value="{{ settings.embedding_dimensions }}"
|
||
disabled />
|
||
<p class="text-xs text-info mt-1">ℹ️ Dimensions are fixed for <span
|
||
class="font-mono">{{settings.embedding_backend}}</span> backend. Set <span
|
||
class="font-mono">EMBEDDING_BACKEND=openai</span> to use OpenAI embeddings.</p>
|
||
{% else %}
|
||
<input type="number" id="embedding_dimensions" name="embedding_dimensions" class="nb-input w-full"
|
||
value="{{ settings.embedding_dimensions }}" required />
|
||
{% endif %}
|
||
</div>
|
||
|
||
<!-- Alert -->
|
||
{% if settings.embedding_backend != "fastembed" and settings.embedding_backend != "hashed" %}
|
||
<div id="embedding-change-alert" class="nb-panel p-3 bg-warning/20 hidden">
|
||
<div class="text-sm"><strong>Warning:</strong> Changing dimensions will require re-creating all embeddings.
|
||
Look up your model's required dimensions or use a model that allows specifying them.</div>
|
||
</div>
|
||
{% endif %}
|
||
|
||
<div class="flex justify-end">
|
||
<button type="submit" class="nb-btn nb-cta btn-sm">Save Model Settings</button>
|
||
</div>
|
||
</form>
|
||
|
||
{% if settings.embedding_backend != "fastembed" and settings.embedding_backend != "hashed" %}
|
||
<script>
|
||
// Rebind after HTMX swaps
|
||
(() => {
|
||
const dimensionInput = document.getElementById('embedding_dimensions');
|
||
const alertElement = document.getElementById('embedding-change-alert');
|
||
const initialDimensions = '{{ settings.embedding_dimensions }}';
|
||
if (dimensionInput && alertElement) {
|
||
dimensionInput.addEventListener('input', (event) => {
|
||
if (String(event.target.value) !== String(initialDimensions)) {
|
||
alertElement.classList.remove('hidden');
|
||
} else {
|
||
alertElement.classList.add('hidden');
|
||
}
|
||
});
|
||
}
|
||
})();
|
||
</script>
|
||
{% endif %}
|
||
{% endblock %}
|
||
</div>
|
||
|
||
<div class="nb-panel p-4">
|
||
<div class="text-sm font-semibold mb-3">Registration</div>
|
||
<label class="flex items-center gap-3">
|
||
{% block registration_status_input %}
|
||
<form hx-patch="/toggle-registrations" hx-swap="outerHTML" hx-trigger="change">
|
||
<input name="registration_open" type="checkbox" class="nb-checkbox" {% if settings.registrations_enabled
|
||
%}checked{% endif %} />
|
||
</form>
|
||
{% endblock %}
|
||
<span class="text-sm">Enable Registrations</span>
|
||
</label>
|
||
<div id="registration-status" class="text-xs opacity-70 mt-2"></div>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
</div>
|
||
{% endblock %} |