new layouts

This commit is contained in:
team2
2026-02-18 19:31:46 +01:00
parent b6e7c7cbab
commit 88cce79e29
3 changed files with 399 additions and 344 deletions

View File

@@ -1,53 +1,27 @@
{% extends 'admin/base.html.twig' %} {% extends 'admin/base.html.twig' %}
{% block title %}System Dashboard{% endblock %} {% block title %}System-Dashboard{% endblock %}
{% block body %} {% block body %}
<div class="container-fluid"> <div class="container-fluid">
{# ===================================================== #} <!-- ===================================================== -->
{# HEADER #} <!-- HEADER -->
{# ===================================================== #} <!-- ===================================================== -->
<div class="d-flex justify-content-between align-items-center mb-4"> <div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3 mb-0">System Overview</h1> <h1 class="h3 mb-0">Systemübersicht</h1>
<span class="badge bg-secondary">RAG Enterprise</span> <span class="badge bg-secondary">RAG Enterprise</span>
</div> </div>
{# ===================================================== #} <!-- ===================================================== -->
{# GOVERNANCE BLOCK #} <!-- KPI ROW -->
{# ===================================================== #} <!-- ===================================================== -->
<div class="card bg-black border-secondary text-light mb-4"> <div class="row g-4 mb-4">
<div class="card-body">
<h5 class="text-info mb-3">System Governance</h5>
<div class="row">
<div class="col-md-6">
<strong>Current User:</strong><br>
{{ app.user.userIdentifier }}
</div>
<div class="col-md-6">
<strong>Roles:</strong><br>
{{ app.user.roles|join(', ') }}
</div>
</div>
</div>
</div>
{# ===================================================== #}
{# VECTOR INFRASTRUCTURE #}
{# ===================================================== #}
{% if vectorHealth is defined %} {% if vectorHealth is defined %}
{% set status = vectorHealth.status %} {% set status = vectorHealth.status %}
{% set badgeClass = {% set badgeClass =
status starts with 'OK' status starts with 'OK'
? 'bg-success' ? 'bg-success'
@@ -55,72 +29,54 @@
? 'bg-warning text-dark' ? 'bg-warning text-dark'
: 'bg-danger') : 'bg-danger')
%} %}
{% endif %}
<div class="card bg-black border-secondary text-light mb-4"> <!-- Vector Status -->
<div class="col-lg-6 col-xl-4">
<div class="card bg-black border-secondary text-light h-100">
<div class="card-body"> <div class="card-body">
<h5 class="text-info mb-3">Vector Infrastructure</h5> <div class="small text-secondary mb-2">Vektor-Infrastruktur</div>
<div class="row mb-3"> {% if vectorHealth is defined %}
<h4 class="mb-2">
<div class="col-md-4">
<strong>Status</strong><br>
<span class="badge {{ badgeClass }}"> <span class="badge {{ badgeClass }}">
{{ status }} {{ vectorHealth.status }}
</span> </span>
</div> </h4>
<div class="col-md-4"> <div class="small text-secondary">
<strong>NDJSON Chunks</strong><br> NDJSON-Chunks: {{ vectorHealth.ndjson_chunk_count|number_format(0, ',', '.') }}
{{ vectorHealth.ndjson_chunk_count|number_format(0, ',', '.') }} <br>
</div> Vektor-Index-Chunks: {{ vectorHealth.vector_chunk_count|number_format(0, ',', '.') }}
<div class="col-md-4">
<strong>Vector Index Chunks</strong><br>
{{ vectorHealth.vector_chunk_count|number_format(0, ',', '.') }}
</div>
</div>
{% if status starts with 'OK' %}
<div class="small text-success">
Infrastructure is consistent.
</div>
{% elseif status == 'INCONSISTENT_MISSING_VECTOR' %}
<div class="small text-warning">
Vector index missing. Rebuild recommended.
</div> </div>
{% else %} {% else %}
<div class="small text-danger"> <div class="text-secondary small">
Index inconsistency detected. Immediate review required. Keine Infrastrukturdaten verfügbar.
</div> </div>
{% endif %} {% endif %}
</div> </div>
</div> </div>
</div>
{% endif %} <!-- Knowledge Capacity -->
{# ===================================================== #}
{# KNOWLEDGE CAPACITY #}
{# ===================================================== #}
{% set percent = chunkLimit > 0 ? (chunkCount / chunkLimit * 100)|round(1) : 0 %} {% set percent = chunkLimit > 0 ? (chunkCount / chunkLimit * 100)|round(1) : 0 %}
<div class="card bg-black border-secondary text-light mb-4"> <div class="col-lg-6 col-xl-4">
<div class="card bg-black border-secondary text-light h-100">
<div class="card-body"> <div class="card-body">
<h5 class="text-info mb-3">Knowledge Capacity</h5> <div class="small text-secondary mb-2">Wissenskapazität</div>
<div class="mb-2"> <h4 class="mb-2">
<strong>Chunks:</strong>
{{ chunkCount|number_format(0, ',', '.') }} {{ chunkCount|number_format(0, ',', '.') }}
/ <span class="text-secondary small">
{{ chunkLimit|number_format(0, ',', '.') }} / {{ chunkLimit|number_format(0, ',', '.') }}
</div> </span>
</h4>
<div class="progress bg-dark" style="height: 20px;"> <div class="progress bg-dark mb-2" style="height: 14px;">
<div <div
class="progress-bar class="progress-bar
{% if percent >= 95 %} {% if percent >= 95 %}
@@ -130,48 +86,96 @@
{% else %} {% else %}
bg-success bg-success
{% endif %}" {% endif %}"
role="progressbar" style="width: {{ percent }}%;">
style="width: {{ percent }}%;" </div>
aria-valuenow="{{ percent }}" </div>
aria-valuemin="0"
aria-valuemax="100" <div class="small text-secondary">
> {{ percent }} % ausgelastet
{{ percent }}% </div>
</div>
</div>
</div>
<!-- Governance Snapshot -->
<div class="col-lg-6 col-xl-4">
<div class="card bg-black border-secondary text-light h-100">
<div class="card-body">
<div class="small text-secondary mb-2">System-Governance</div>
<div class="small">
<strong>Benutzer</strong><br>
{{ app.user.userIdentifier }}
</div>
<div class="small mt-3">
<strong>Rollen</strong><br>
{{ app.user.roles|join(', ') }}
</div>
</div>
</div>
</div>
</div>
<!-- ===================================================== -->
<!-- DETAIL ROW -->
<!-- ===================================================== -->
<div class="row g-4">
{% if vectorHealth is defined %}
<!-- Vector Detail -->
<div class="col-lg-6">
<div class="card bg-black border-secondary text-light h-100">
<div class="card-body">
<h5 class="text-info mb-3">Details zur Vektor-Infrastruktur</h5>
<div class="row">
<div class="col-6">
<div class="small text-secondary">NDJSON-Chunks</div>
<div class="h5">
{{ vectorHealth.ndjson_chunk_count|number_format(0, ',', '.') }}
</div>
</div>
<div class="col-6">
<div class="small text-secondary">Vektor-Index-Chunks</div>
<div class="h5">
{{ vectorHealth.vector_chunk_count|number_format(0, ',', '.') }}
</div>
</div>
</div>
</div>
</div> </div>
</div> </div>
<div class="mt-3 small text-secondary">
System optimized for maximum
{{ chunkLimit|number_format(0, ',', '.') }} chunks.
{% if percent >= 95 %}
<br><strong class="text-danger">Capacity limit nearly reached.</strong>
{% endif %} {% endif %}
</div>
</div>
</div>
{# ===================================================== #}
{# CRITICAL OPERATIONS (SUPER ADMIN ONLY) #}
{# ===================================================== #}
{% if is_granted('ROLE_SUPER_ADMIN') %} {% if is_granted('ROLE_SUPER_ADMIN') %}
<div class="card bg-black border-danger text-light"> <!-- Critical Operations -->
<div class="col-lg-6">
<div class="card bg-black border-danger text-light h-100">
<div class="card-body"> <div class="card-body">
<h5 class="text-danger mb-3">Critical Operations</h5> <h5 class="text-danger mb-3">Kritische Systemoperationen</h5>
<div class="small mb-3"> <div class="small mb-3 text-secondary">
Full system reset removes: Ein vollständiger System-Reset entfernt:
<ul> <ul>
<li>All documents & versions</li> <li>Alle Dokumente und Versionen</li>
<li>NDJSON index</li> <li>Den NDJSON-Index</li>
<li>FAISS vector index</li> <li>Den FAISS-Vektorindex</li>
<li>All ingest jobs</li> <li>Alle Ingest-Jobs</li>
</ul> </ul>
<strong>This action is irreversible.</strong> <strong>Diese Aktion ist nicht rückgängig zu machen.</strong>
</div> </div>
{% for label, messages in app.flashes %} {% for label, messages in app.flashes %}
@@ -184,7 +188,7 @@
<form method="post" <form method="post"
action="{{ path('admin_document_reset') }}" action="{{ path('admin_document_reset') }}"
onsubmit="return confirm('Confirm full system reset? This cannot be undone.');"> onsubmit="return confirm('System vollständig zurücksetzen? Diese Aktion kann nicht rückgängig gemacht werden.');">
<input type="hidden" <input type="hidden"
name="_token" name="_token"
@@ -192,16 +196,18 @@
<button type="submit" <button type="submit"
class="btn btn-outline-danger"> class="btn btn-outline-danger">
Execute Full System Reset Vollständigen System-Reset ausführen
</button> </button>
</form> </form>
</div> </div>
</div> </div>
</div>
{% endif %} {% endif %}
</div> </div>
</div>
{% endblock %} {% endblock %}

View File

@@ -12,6 +12,13 @@
</a> </a>
</div> </div>
<div class="alert alert-warning border-warning bg-dark text-light mb-4">
<strong>Wichtiger Hinweis:</strong><br>
Änderungen am Indexierungsprofil beeinflussen die Struktur des Vektor-Indexes
(Chunking, Embedding, Scoring). Nach Aktivierung ist ein vollständiger
Global Reindex erforderlich.
</div>
<div class="card bg-black border-secondary text-light"> <div class="card bg-black border-secondary text-light">
<div class="card-body"> <div class="card-body">
@@ -22,18 +29,20 @@
<div class="row g-4"> <div class="row g-4">
<!-- ===================== --> <!-- ================================================= -->
<!-- Chunking Section --> <!-- CHUNKING -->
<!-- ===================== --> <!-- ================================================= -->
<div class="col-12"> <div class="col-12">
<h5 class="text-info">Chunking</h5> <h5 class="text-info">Chunking-Konfiguration</h5>
<hr class="border-secondary"> <hr class="border-secondary">
<p class="text-secondary small">
Definiert, wie Dokumente in semantische Textabschnitte (Chunks) zerlegt werden.
Diese Struktur beeinflusst Retrieval-Qualität, Kontextstabilität und Indexgröße.
</p>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<label class="form-label"> <label class="form-label">Chunk Size</label>
Chunk Size
</label>
<select name="chunk_size" <select name="chunk_size"
class="form-select bg-dark text-light border-secondary" class="form-select bg-dark text-light border-secondary"
required> required>
@@ -44,14 +53,18 @@
{% endfor %} {% endfor %}
</select> </select>
<div class="form-text text-secondary"> <div class="form-text text-secondary">
Größere Werte = weniger Chunks, mehr Kontext pro Chunk. Maximale Wortanzahl pro Chunk.
<br><br>
<strong>Kleinere Werte:</strong> Mehr Chunks, höhere Granularität, präziseres Retrieval.
<br>
<strong>Größere Werte:</strong> Weniger Chunks, mehr Kontext pro Treffer.
<br><br>
Empfehlung für Produkt- und Wissensdaten: 6001000.
</div> </div>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<label class="form-label"> <label class="form-label">Chunk Overlap</label>
Chunk Overlap
</label>
<select name="chunk_overlap" <select name="chunk_overlap"
class="form-select bg-dark text-light border-secondary" class="form-select bg-dark text-light border-secondary"
required> required>
@@ -62,64 +75,83 @@
{% endfor %} {% endfor %}
</select> </select>
<div class="form-text text-secondary"> <div class="form-text text-secondary">
Überlappung zwischen Chunks zur Kontextstabilisierung. Anzahl überlappender Wörter zwischen zwei Chunks.
<br><br>
Verhindert Kontextabbrüche an Chunk-Grenzen.
<br>
Typischer Bereich: 1020 % der Chunk Size.
</div> </div>
</div> </div>
<!-- ===================== --> <!-- ================================================= -->
<!-- Embedding Section --> <!-- EMBEDDING -->
<!-- ===================== --> <!-- ================================================= -->
<div class="col-12 mt-4"> <div class="col-12 mt-5">
<h5 class="text-info">Embedding</h5> <h5 class="text-info">Embedding-Konfiguration</h5>
<hr class="border-secondary"> <hr class="border-secondary">
<p class="text-secondary small">
Definiert das Modell zur Vektorisierung der Textabschnitte.
Embeddings bestimmen die semantische Ähnlichkeitsberechnung im FAISS-Index.
</p>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<label class="form-label"> <label class="form-label">Embedding Model</label>
Embedding Model
</label>
<select name="embedding_model" <select name="embedding_model"
class="form-select bg-dark text-light border-secondary" class="form-select bg-dark text-light border-secondary"
required> required>
<option value="all-MiniLM-L6-v2"> <option value="all-MiniLM-L6-v2">
all-MiniLM-L6-v2 (384) all-MiniLM-L6-v2 (384 Dimensionen)
</option> </option>
</select> </select>
<div class="form-text text-secondary">
Das Embedding-Modell erzeugt numerische Vektoren aus Text.
Modellwechsel erfordert zwingend einen Global Reindex.
</div>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<label class="form-label"> <label class="form-label">Embedding Dimension</label>
Embedding Dimension
</label>
<input type="number" <input type="number"
name="embedding_dimension" name="embedding_dimension"
value="384" value="384"
class="form-control bg-dark text-light border-secondary" class="form-control bg-dark text-light border-secondary"
readonly> readonly>
<div class="form-text text-secondary"> <div class="form-text text-secondary">
Muss mit dem Embedding-Modell übereinstimmen. Muss exakt zur Dimension des gewählten Embedding-Modells passen.
Falsche Werte führen zu inkonsistentem Vektorindex.
</div> </div>
</div> </div>
<!-- ===================== --> <!-- ================================================= -->
<!-- Scoring Section --> <!-- SCORING -->
<!-- ===================== --> <!-- ================================================= -->
<div class="col-12 mt-4"> <div class="col-12 mt-5">
<h5 class="text-info">Scoring</h5> <h5 class="text-info">Scoring & Retrieval</h5>
<hr class="border-secondary"> <hr class="border-secondary">
<p class="text-secondary small">
Definiert die Bewertungslogik für Retrieval-Ergebnisse.
Änderungen wirken sich direkt auf die Gewichtung von Keyword- und
Vektor-Treffern aus.
</p>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<label class="form-label"> <label class="form-label">Scoring Version</label>
Scoring Version
</label>
<input type="number" <input type="number"
name="scoring_version" name="scoring_version"
value="1" value="1"
class="form-control bg-dark text-light border-secondary" class="form-control bg-dark text-light border-secondary"
readonly> readonly>
<div class="form-text text-secondary"> <div class="form-text text-secondary">
Erhöhung erzwingt Global Reindex. Versionskennzeichnung der Scoring-Logik.
<br><br>
Eine Erhöhung erzwingt:
<ul class="mt-2">
<li>Neuaufbau des NDJSON-Index</li>
<li>Vollständigen FAISS-Rebuild</li>
</ul>
Gewährleistet reproduzierbare Retrieval-Ergebnisse.
</div> </div>
</div> </div>
@@ -139,7 +171,9 @@
</div> </div>
<div class="mt-4 small text-secondary"> <div class="mt-4 small text-secondary">
Hinweis: Änderungen am Indexierungsprofil wirken sich auf die Struktur des Governance-Hinweis:
Vektor-Indexes aus. Nach Aktivierung ist ein vollständiger Reindex erforderlich. Ein Indexierungsprofil ist versioniert und deterministisch.
Änderungen sollten nur geplant erfolgen, da sie die komplette
Wissensstruktur neu generieren.
</div> </div>
{% endblock %} {% endblock %}

View File

@@ -4,14 +4,14 @@
{% block body %} {% block body %}
<div class="container-fluid">
<!-- HEADER -->
<div class="d-flex justify-content-between align-items-center mb-4"> <div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3">System Prompt</h1> <h1 class="h3">System Prompt Verwaltung</h1>
</div> </div>
{# ============================= #} <!-- Flash Messages -->
{# Flash Messages #}
{# ============================= #}
{% for message in app.flashes('success') %} {% for message in app.flashes('success') %}
<div class="alert alert-success">{{ message }}</div> <div class="alert alert-success">{{ message }}</div>
{% endfor %} {% endfor %}
@@ -19,15 +19,20 @@
<div class="alert alert-danger">{{ message }}</div> <div class="alert alert-danger">{{ message }}</div>
{% endfor %} {% endfor %}
{# ============================= #} <div class="row g-4">
{# Versionen Übersicht #}
{# ============================= #}
<div class="card bg-black border-secondary"> <!-- ===================================================== -->
<!-- LEFT SIDE Versionen (50%) -->
<!-- ===================================================== -->
<div class="col-lg-6">
<div class="card bg-black border-secondary text-light h-100">
<div class="card-body"> <div class="card-body">
<h5 class="text-info mb-3">Versionen</h5> <h5 class="text-info mb-3">Versionen</h5>
<div class="table-responsive">
<table class="table table-dark table-striped table-hover align-middle"> <table class="table table-dark table-striped table-hover align-middle">
<thead class="table-secondary text-dark"> <thead class="table-secondary text-dark">
<tr> <tr>
@@ -62,7 +67,6 @@
{% if not p.active and is_granted('ROLE_SUPER_ADMIN') %} {% if not p.active and is_granted('ROLE_SUPER_ADMIN') %}
{# Aktivieren #}
<form method="post" <form method="post"
action="{{ path('admin_system_prompt_activate', {id: p.id}) }}" action="{{ path('admin_system_prompt_activate', {id: p.id}) }}"
class="d-inline" class="d-inline"
@@ -77,7 +81,6 @@
</button> </button>
</form> </form>
{# Löschen #}
<form method="post" <form method="post"
action="{{ path('admin_system_prompt_delete', {id: p.id}) }}" action="{{ path('admin_system_prompt_delete', {id: p.id}) }}"
class="d-inline" class="d-inline"
@@ -108,20 +111,28 @@
</tbody> </tbody>
</table> </table>
</div>
<hr class="border-secondary mt-4">
<div class="small text-secondary">
<strong>Governance-Hinweis:</strong><br>
Der aktive System Prompt beeinflusst das globale Antwortverhalten des LLM unmittelbar.
Änderungen sollten dokumentiert, versioniert und nachvollziehbar erfolgen.
</div>
</div> </div>
</div> </div>
<div class="mt-4 small text-secondary">
Hinweis: Der aktive System Prompt beeinflusst das Antwortverhalten
des LLM unmittelbar. Änderungen sollten dokumentiert und versioniert erfolgen.
</div> </div>
{# ============================= #} <!-- ===================================================== -->
{# Neue Version erstellen #} <!-- RIGHT SIDE Neue Version (50%) -->
{# ============================= #} <!-- ===================================================== -->
<div class="card bg-black border-secondary mb-5 text-light"> <div class="col-lg-6">
<div class="card bg-black border-secondary text-light h-100">
<div class="card-body"> <div class="card-body">
<h5 class="text-info mb-3">Neue Version erstellen</h5> <h5 class="text-info mb-3">Neue Version erstellen</h5>
@@ -143,16 +154,16 @@
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label class="form-label"> <label class="form-label">Prompt-Inhalt</label>
Prompt-Inhalt
</label>
<div class="form-text text-secondary mb-2"> <div class="form-text text-secondary mb-2">
Verfügbare Variable: Verfügbare Variable:
<code>{% verbatim %}{% now %}{% endverbatim %}</code> <code>{% verbatim %}{% now %}{% endverbatim %}</code>
(aktuelles Datum / Zeit) (aktuelles Datum / Zeit)
</div> </div>
<textarea name="content" <textarea name="content"
rows="16" rows="18"
class="form-control bg-dark text-light border-secondary" class="form-control bg-dark text-light border-secondary"
required>{{ active ? active.content : '' }}</textarea> required>{{ active ? active.content : '' }}</textarea>
</div> </div>
@@ -169,6 +180,10 @@
</div> </div>
</div> </div>
</div>
</div>
</div>
{% endblock %} {% endblock %}