optimize ux

This commit is contained in:
team 1
2026-04-05 19:37:50 +02:00
parent 41d4e1991d
commit bd818f5228
15 changed files with 323 additions and 271 deletions

View File

@@ -39,6 +39,12 @@ form, input, button, textarea {
font-size: 0.85rem !important; font-size: 0.85rem !important;
} }
input, textarea,select {
background-color: #121a25 !important;
color: #fff !important;
border-color: #020617 !important;
}
.container { .container {
max-width: 900px; max-width: 900px;
margin: 0 auto; margin: 0 auto;
@@ -47,6 +53,11 @@ form, input, button, textarea {
height: calc(100vh - 4rem); height: calc(100vh - 4rem);
} }
::placeholder {
color: #556070 !important;
opacity: .5; /* wichtig v. a. für Firefox */
}
.header { .header {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -62,7 +73,7 @@ form, input, button, textarea {
flex: 1; flex: 1;
overflow-y: auto; overflow-y: auto;
padding: 1rem; padding: 1rem;
background: var(--panel); background: #121a25;
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: 6px; border-radius: 6px;
} }
@@ -81,7 +92,7 @@ form, input, button, textarea {
} }
.message.assistant .bubble { .message.assistant .bubble {
background: var(--assistant); background: #16202f;
border: 1px solid var(--border); border: 1px solid var(--border);
} }

View File

@@ -14,7 +14,7 @@
<script src="/assets/js/purify.min.js"></script> <script src="/assets/js/purify.min.js"></script>
<script src="/assets/js/base.js"></script> <script src="/assets/js/base.js"></script>
</head> </head>
<body> <body class="bg-black">
<div class="container"> <div class="container">
<div class="header"> <div class="header">

View File

@@ -47,7 +47,8 @@ final readonly class PromptBuilder
throw new \RuntimeException('No active system prompt configured.'); throw new \RuntimeException('No active system prompt configured.');
} }
$activeSystemPrompt = str_replace('{%now%}', $now, $activePrompt->getContent()); $activeSystemPrompt = str_replace('{% now %}', $now, $activePrompt->getContent());
$systemBlock = "SYSTEM:\n" . $activeSystemPrompt; $systemBlock = "SYSTEM:\n" . $activeSystemPrompt;
// ------------------------------------------------------------ // ------------------------------------------------------------

View File

@@ -57,7 +57,7 @@
<a class="nav-link text-light {% if route starts with 'admin_dashboard' %}active fw-bold{% endif %}" <a class="nav-link text-light {% if route starts with 'admin_dashboard' %}active fw-bold{% endif %}"
href="{{ path('admin_dashboard') }}"> href="{{ path('admin_dashboard') }}">
<i class="bi bi-hdd-rack"></i> Dashboard <i class="bi bi-hdd-rack"></i> Systemübersicht
</a> </a>
<hr class="border-secondary"> <hr class="border-secondary">
@@ -81,7 +81,7 @@
<a class="nav-link text-light {% if route starts with 'admin_system_agent' %}active fw-bold{% endif %}" <a class="nav-link text-light {% if route starts with 'admin_system_agent' %}active fw-bold{% endif %}"
href="{{ path('admin_system_agent') }}"> href="{{ path('admin_system_agent') }}">
<i class="bi bi-body-text"></i> Wissensbasis (Chunk-Index) <i class="bi bi-robot"></i> Wissensbasis (Chunk-Index)
</a> </a>
<hr class="border-secondary"> <hr class="border-secondary">
@@ -97,7 +97,7 @@
<a class="nav-link text-light {% if route starts with 'admin_ingest_profile' %}active fw-bold{% endif %}" <a class="nav-link text-light {% if route starts with 'admin_ingest_profile' %}active fw-bold{% endif %}"
href="{{ path('admin_ingest_profile_list') }}"> href="{{ path('admin_ingest_profile_list') }}">
<i class="bi bi-diagram-3-fill"></i> Indexierungsprofile (Ingest) <i class="bi bi-search"></i> Indexierungsprofile (Ingest)
</a> </a>
<hr class="border-secondary"> <hr class="border-secondary">
@@ -108,7 +108,7 @@
<a class="nav-link text-light {% if route starts with 'admin_model_config' %}active fw-bold{% endif %}" <a class="nav-link text-light {% if route starts with 'admin_model_config' %}active fw-bold{% endif %}"
href="{{ path('admin_model_config_list') }}"> href="{{ path('admin_model_config_list') }}">
<i class="bi bi-motherboard-fill"></i> LLM-Setup (Parameter) <i class="bi bi-rocket-takeoff-fill"></i> LLM-Setup (Parameter)
</a> </a>
<hr class="border-secondary"> <hr class="border-secondary">
<div class="text-info text-uppercase small mb-2"> <div class="text-info text-uppercase small mb-2">
@@ -117,7 +117,7 @@
<a class="nav-link text-light {% if route starts with 'admin_model_config' %}active fw-bold{% endif %}" <a class="nav-link text-light {% if route starts with 'admin_model_config' %}active fw-bold{% endif %}"
href="{{ path('admin_guides_index') }}"> href="{{ path('admin_guides_index') }}">
<i class="bi bi-collection"></i> How-To & Leitfäden <i class="bi bi-mortarboard-fill"></i> How-To & Leitfäden
</a> </a>
<hr class="border-secondary"> <hr class="border-secondary">
<div class="text-info text-uppercase small mb-2"> <div class="text-info text-uppercase small mb-2">
@@ -125,15 +125,15 @@
</div> </div>
<a class="nav-link text-light {% if route starts with 'admin_job' %}active fw-bold{% endif %}" <a class="nav-link text-light {% if route starts with 'admin_job' %}active fw-bold{% endif %}"
href="{{ path('admin_jobs') }}"> href="{{ path('admin_jobs') }}">
<i class="bi bi-binoculars-fill"></i> Indexierungs-Log (Ingest Jobs) <i class="bi bi-terminal"></i> Indexierungs-Log (Ingest Jobs)
</a> </a>
<a class="nav-link text-light {% if route starts with 'admin_job' %}active fw-bold{% endif %}" <a class="nav-link text-light {% if route starts with 'admin_job' %}active fw-bold{% endif %}"
href="{{ path('admin_vector_log') }}"> href="{{ path('admin_vector_log') }}">
<i class="bi bi-binoculars-fill"></i> Vector-Log Python <i class="bi bi-terminal"></i> Vector-Log Python
</a> </a>
<a class="nav-link text-light {% if route starts with 'admin_job' %}active fw-bold{% endif %}" <a class="nav-link text-light {% if route starts with 'admin_job' %}active fw-bold{% endif %}"
href="{{ path('admin_system_logs_index') }}"> href="{{ path('admin_system_logs_index') }}">
<i class="bi bi-binoculars-fill"></i> System-Logs <i class="bi bi-terminal"></i> System-Logs
</a> </a>
</nav> </nav>

View File

@@ -10,7 +10,7 @@
<!-- ===================================================== --> <!-- ===================================================== -->
<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übersicht</h1> <h1 class="h3 mb-0"><i class="bi bi-hdd-rack"></i> Systemübersicht</h1>
<span class="badge bg-secondary">RAG Enterprise</span> <span class="badge bg-secondary">RAG Enterprise</span>
</div> </div>
@@ -34,7 +34,7 @@
<div class="col-lg-6 col-xl-3"> <div class="col-lg-6 col-xl-3">
<div class="card bg-black border-secondary text-light h-100"> <div class="card bg-black border-secondary text-light h-100">
<div class="card-body"> <div class="card-body">
<div class="small text-light mb-2">Chunk-Vektor</div> <div class="small text-light mb-2"><i class="bi bi-files"></i> Chunk-Vektor</div>
{% if vectorHealth is defined %} {% if vectorHealth is defined %}
<h4 class="mb-0"> <h4 class="mb-0">
@@ -65,7 +65,7 @@
<div class="col-lg-6 col-xl-3"> <div class="col-lg-6 col-xl-3">
<div class="card bg-black border-secondary text-light h-100"> <div class="card bg-black border-secondary text-light h-100">
<div class="card-body"> <div class="card-body">
<div class="small text-light mb-2">Tag-Vektor</div> <div class="small text-light mb-2"><i class="bi bi-tags"></i> Tag-Vektor</div>
{% if tagVectorHealth is defined %} {% if tagVectorHealth is defined %}
<h4 class="mb-0"> <h4 class="mb-0">
@@ -88,7 +88,7 @@
<div class="col-lg-6 col-xl-3"> <div class="col-lg-6 col-xl-3">
<div class="card bg-black border-secondary text-light h-100"> <div class="card bg-black border-secondary text-light h-100">
<div class="card-body"> <div class="card-body">
<div class="small text-light mb-2">Wissenskapazität</div> <div class="small text-light mb-2"><i class="bi bi-robot"></i> Wissenskapazität</div>
<h4 class="mb-2"> <h4 class="mb-2">
{{ chunkCount|number_format(0, ',', '.') }} {{ chunkCount|number_format(0, ',', '.') }}
@@ -121,7 +121,7 @@
<div class="col-lg-6 col-xl-3"> <div class="col-lg-6 col-xl-3">
<div class="card bg-black border-secondary text-light h-100"> <div class="card bg-black border-secondary text-light h-100">
<div class="card-body"> <div class="card-body">
<div class="small text-light mb-2">System-Governance</div> <div class="small text-light mb-2"><i class="bi bi-shield-check"></i> System-Governance</div>
<div class="small"> <div class="small">
<strong>Benutzer</strong><br> <strong>Benutzer</strong><br>
@@ -148,7 +148,7 @@
<div class="col-lg-4"> <div class="col-lg-4">
<div class="card bg-black border-secondary text-light h-100"> <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">Chunk-Vektor-Details</h5> <h5 class="text-info mb-3"><i class="bi bi-files"></i> Chunk-Vektor-Details</h5>
<div class="small text-info">NDJSON-Chunks</div> <div class="small text-info">NDJSON-Chunks</div>
<div class="h5 mb-3"> <div class="h5 mb-3">
@@ -168,7 +168,7 @@
<div class="col-lg-4"> <div class="col-lg-4">
<div class="card bg-black border-secondary text-light h-100"> <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">Tag-Vektor-Details</h5> <h5 class="text-info mb-3"><i class="bi bi-tags"></i> Tag-Vektor-Details</h5>
<div class="small text-info">NDJSON-Tags</div> <div class="small text-info">NDJSON-Tags</div>
<div class="h5 mb-3"> <div class="h5 mb-3">
@@ -188,7 +188,7 @@
<div class="col-lg-4"> <div class="col-lg-4">
<div class="card bg-black border-secondary text-light h-100"> <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">Indexierung (Ingest Jobs)</h5> <h5 class="text-info mb-3"><i class="bi bi-search"></i> Indexierung (Ingest Jobs)</h5>
<div class="text-muted small mb-3"> <div class="text-muted small mb-3">
Erstellt den kompletten Wissensindex neu. Erstellt den kompletten Wissensindex neu.
@@ -216,7 +216,7 @@
<div class="col-lg-4"> <div class="col-lg-4">
<div class="card bg-black border-danger text-light h-100"> <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">Kritische Systemoperationen</h5> <h5 class="text-danger mb-3"><i class="bi bi-sign-stop-fill"></i> Kritische Systemoperationen</h5>
<div class="small mb-3 text-secondary"> <div class="small mb-3 text-secondary">
Entfernt alle Dokumente, Versionen, Indizes und Jobs. Entfernt alle Dokumente, Versionen, Indizes und Jobs.

View File

@@ -5,7 +5,7 @@
{% block body %} {% block body %}
<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">Dokumente</h1> <h1 class="h3 mb-0"><i class="bi bi-card-list"></i> Dokumente</h1>
<a href="{{ path('admin_document_new') }}" <a href="{{ path('admin_document_new') }}"
class="btn btn-sm btn-outline-info"> class="btn btn-sm btn-outline-info">
@@ -52,7 +52,7 @@
</td> </td>
{# ID #} {# ID #}
<td class="small text-secondary"> <td class="small text-info">
{{ document.id }} {{ document.id }}
</td> </td>

View File

@@ -15,7 +15,7 @@
</a> </a>
</div> </div>
<div class="card bg-black border-secondary mb-4 text-light"> <div class="card bg-dark border-secondary mb-4 text-light">
<div class="card-body"> <div class="card-body">
<div class="mb-3"> <div class="mb-3">

View File

@@ -19,7 +19,7 @@
{# Dokument-Meta #} {# Dokument-Meta #}
{# ============================= #} {# ============================= #}
<div class="card bg-black border-secondary mb-5 text-light"> <div class="card bg-dark border-secondary mb-5 text-light">
<div class="card-body"> <div class="card-body">
<div class="mb-2"> <div class="mb-2">
@@ -79,7 +79,7 @@
{% else %} {% else %}
<div class="card bg-black border-secondary"> <div class="card bg-black border-secondary">
<div class="card-body p-0"> <div class="card-body">
<table class="table table-dark table-striped table-hover align-middle mb-0"> <table class="table table-dark table-striped table-hover align-middle mb-0">
<thead class="table-secondary text-dark"> <thead class="table-secondary text-dark">

View File

@@ -8,7 +8,7 @@
{# Tag-Rebuild Status (Echte Live-Anzeige) #} {# Tag-Rebuild Status (Echte Live-Anzeige) #}
{# ============================================= #} {# ============================================= #}
<div id="rebuild-status"></div> <div id="rebuild-status" class="mb-5" style="min-height:54px"></div>
<script> <script>
let polling = null; let polling = null;
@@ -90,10 +90,10 @@
{# Bereits zugewiesene Tags #} {# Bereits zugewiesene Tags #}
{# ============================================= #} {# ============================================= #}
<div class="card bg-black border-secondary mb-4"> <div class="card bg-dark border-secondary mb-4">
<div class="card-body"> <div class="card-body">
<h5 class="text-info mb-3">Zugewiesene Tags</h5> <h5 class="mb-3">Zugewiesene Tags für: <span class="text-info ">{{ document.title }}</span></h5>
{% if document.tags is empty %} {% if document.tags is empty %}
<div class="alert alert-secondary mb-0"> <div class="alert alert-secondary mb-0">
@@ -119,7 +119,7 @@
<div class="card bg-black border-secondary"> <div class="card bg-black border-secondary">
<div class="card-body"> <div class="card-body">
<h5 class="text-info mb-3">Tags bearbeiten</h5> <h5 class="text-info mb-3">Tags zuweisen</h5>
<form method="post" <form method="post"
action="{{ path('admin_document_tags_save', {id: document.id}) }}"> action="{{ path('admin_document_tags_save', {id: document.id}) }}">
@@ -130,7 +130,7 @@
<div class="row"> <div class="row">
{% for tag in allTags %} {% for tag in allTags %}
<div class="col-md-4 mb-2"> <div class="col-md-2 mb-2">
<div class="form-check"> <div class="form-check">
@@ -143,7 +143,7 @@
{% if tag in document.tags %}checked{% endif %} {% if tag in document.tags %}checked{% endif %}
> >
<label class="form-check-label text-dark bg-info badge" <label class="form-check-label bg-info text-black badge"{% if tag not in document.tags %} style="opacity: .5;"{% endif %}
for="tag_{{ tag.id }}"> for="tag_{{ tag.id }}">
{{ tag.label }} {{ tag.label }}
</label> </label>

View File

@@ -3,20 +3,12 @@
{% block title %}Indexierungsprofile{% endblock %} {% block title %}Indexierungsprofile{% endblock %}
{% block body %} {% block body %}
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3">Indexierungsprofile</h1>
<a class="btn btn-sm btn-outline-info"
href="{{ path('admin_ingest_profile_create') }}">
Neues Profil anlegen
</a>
</div>
{# ============================= #} {# ============================= #}
{# Strukturstatus Alert #} {# Strukturstatus Alert #}
{# ============================= #} {# ============================= #}
{% if structureMismatch %} {% if structureMismatch %}
<div class="alert alert-danger d-flex justify-content-between align-items-center mb-4"> <div class="alert alert-danger d-flex justify-content-between align-items-center mb-5">
<div> <div>
<strong>Strukturabweichung erkannt.</strong> <strong>Strukturabweichung erkannt.</strong>
Die aktuelle Indexstruktur entspricht nicht dem aktiven Profil. Die aktuelle Indexstruktur entspricht nicht dem aktiven Profil.
@@ -28,50 +20,63 @@
</a> </a>
</div> </div>
{% else %} {% else %}
<div class="alert alert-success"> <div class="alert alert-success mb-5">
Die Indexstruktur entspricht dem aktiven Profil. <i class="bi bi-check-lg"></i> Die Indexstruktur entspricht dem aktiven Profil.
</div> </div>
{% endif %} {% endif %}
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3"><i class="bi bi-search"></i> Indexierungsprofile</h1>
<a class="btn btn-sm btn-outline-info"
href="{{ path('admin_ingest_profile_create') }}">
Neues Profil anlegen
</a>
</div>
{# ========================================================= #} {# ========================================================= #}
{# PROFIL SYSTEM DESCRIPTION #} {# PROFIL SYSTEM DESCRIPTION #}
{# ========================================================= #} {# ========================================================= #}
<div class="card bg-black border-secondary mb-4 shadow-sm"> <div class="card bg-dark border-secondary mb-4 shadow-sm">
<div class="card-body text-light"> <div class="card-body text-light row">
<h5 class="text-info mb-3">Was sind Indexierungsprofile?</h5> <div class="col-lg-6">
<h5 class="text-info mb-3">Was sind Indexierungsprofile?</h5>
<p class="small text-light mb-3"> <p class="small text-light mb-3">
Indexierungsprofile definieren die strukturellen Regeln des RAG-Systems. Indexierungsprofile definieren die strukturellen Regeln des RAG-Systems.
Sie bestimmen, wie Dokumente in Chunks zerlegt, eingebettet Sie bestimmen, wie Dokumente in Chunks zerlegt, eingebettet
und später bewertet werden. und später bewertet werden.
</p> </p>
<ul class="small text-light mb-3"> <ul class="small text-light mb-3">
<li>Chunk-Größe und Overlap (Textsegmentierung)</li> <li>Chunk-Größe und Overlap (Textsegmentierung)</li>
<li>Embedding-Modell und Dimension</li> <li>Embedding-Modell und Dimension</li>
<li>Scoring-Version (Retrieval-Logik)</li> <li>Scoring-Version (Retrieval-Logik)</li>
</ul> </ul>
<h6 class="text-info mt-3">Warum sind Profile versioniert?</h6> </div>
<div class="col-lg-6">
<h6 class="text-info mt-3">Warum sind Profile versioniert?</h6>
<p class="small text-light mb-3"> <p class="small text-light mb-3">
Jede strukturelle Änderung beeinflusst die gesamte Indexarchitektur. Jede strukturelle Änderung beeinflusst die gesamte Indexarchitektur.
Deshalb ist ein Profil immer versioniert und unveränderlich. Deshalb ist ein Profil immer versioniert und unveränderlich.
Bei Aktivierung eines neuen Profils kann eine vollständige Bei Aktivierung eines neuen Profils kann eine vollständige
Neuindizierung erforderlich werden. Neuindizierung erforderlich werden.
</p> </p>
<h6 class="text-info mt-3">Wie prüft das System Konsistenz?</h6> <h6 class="text-info mt-3">Wie prüft das System Konsistenz?</h6>
<p class="small text-light mb-0"> <p class="small text-light mb-0">
Das System vergleicht das aktive Profil mit der aktuellen Das System vergleicht das aktive Profil mit der aktuellen
<code>index_meta.json</code>. Weichen Parameter wie <code>index_meta.json</code>. Weichen Parameter wie
Embedding-Dimension, Chunking oder Scoring ab, Embedding-Dimension, Chunking oder Scoring ab,
wird eine Strukturabweichung erkannt und ein Global Reindex wird eine Strukturabweichung erkannt und ein Global Reindex
empfohlen oder erzwungen. empfohlen oder erzwungen.
</p> </p>
</div>
</div> </div>
</div> </div>
@@ -79,10 +84,9 @@
{# Profile Tabelle #} {# Profile Tabelle #}
{# ============================= #} {# ============================= #}
<h2 class="text-light mb-3">Profile</h2> <h2 class="text-light mb-3">Meta-Profile</h2>
<div class="card bg-black border-secondary mb-5"> <div class="card bg-black border-secondary mb-3">
<div class="card-body p-0"> <div class="card-body">
<table class="table table-dark table-striped table-hover align-middle mb-0"> <table class="table table-dark table-striped table-hover align-middle mb-0">
<thead class="table-secondary text-dark"> <thead class="table-secondary text-dark">
<tr> <tr>
@@ -174,7 +178,6 @@
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
@@ -182,15 +185,12 @@
{# Struktur-Diff #} {# Struktur-Diff #}
{# ============================= #} {# ============================= #}
<h2 class="text-light mb-3">Index-Struktur Vergleich</h2>
<div class="card bg-black border-secondary"> <div class="card bg-black border-secondary">
<div class="card-body text-light"> <div class="card-body text-light">
{% if indexMeta %} {% if indexMeta %}
<div class="mb-3 small text-light"> <div class="mb-3 small text-light">
Aktuelle Index-Version: Aktuell erstellte Index-Version:
<strong>{{ indexMeta.index_version }}</strong> <strong>{{ indexMeta.index_version }}</strong>
</div> </div>
{% else %} {% else %}
@@ -203,8 +203,8 @@
<thead class="table-secondary text-dark"> <thead class="table-secondary text-dark">
<tr> <tr>
<th>Parameter</th> <th>Parameter</th>
<th>Index Meta</th> <th>Aktiver Meta-Index (System)</th>
<th>Aktives Profil</th> <th>Aktives Meta-Profil</th>
<th>Status</th> <th>Status</th>
</tr> </tr>
</thead> </thead>

View File

@@ -5,7 +5,7 @@
{% block body %} {% block body %}
<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">KI Modell-Generierung</h1> <h1 class="h3 mb-0"><i class="bi bi-rocket-takeoff-fill"></i> KI Modell-Generierung</h1>
{% if is_granted('ROLE_SUPER_ADMIN') %} {% if is_granted('ROLE_SUPER_ADMIN') %}
<a href="{{ path('admin_model_config_create') }}" <a href="{{ path('admin_model_config_create') }}"
@@ -18,49 +18,54 @@
{# ========================================================= #} {# ========================================================= #}
{# MODEL CONFIG DESCRIPTION #} {# MODEL CONFIG DESCRIPTION #}
{# ========================================================= #} {# ========================================================= #}
<div class="card bg-black border-secondary text-light mb-4 shadow-sm"> <div class="card bg-dark border-secondary text-light mb-4 shadow-sm">
<div class="card-body"> <div class="card-body row">
<h5 class="text-info mb-3">Was steuert die Modell-Konfiguration?</h5> <div class="col-lg-6">
<h5 class="text-info mb-3">Was steuert die Modell-Konfiguration?</h5>
<p class="small text-light mb-3"> <p class="small text-light mb-3">
Die Modell-Konfiguration definiert die vollständige Die Modell-Konfiguration definiert die vollständige
Generierungsumgebung des Agents. Sie trennt strikt zwischen: Generierungsumgebung des Agents. Sie trennt strikt zwischen:
</p> </p>
<ul class="small text-light mb-3"> <ul class="small text-light mb-3">
<li>LLM-Verhalten (Sampling & Kontext)</li> <li>LLM-Verhalten (Sampling & Kontext)</li>
<li>Retrieval-Parameter (Vektor-Wissen)</li> <li>Retrieval-Parameter (Vektor-Wissen)</li>
<li>Streaming-Modus</li> <li>Streaming-Modus</li>
</ul> </ul>
<h6 class="text-info mt-3">LLM Sampling</h6> <h6 class="text-info mt-3">LLM Sampling</h6>
<p class="small text-light mb-3"> <p class="small text-light mb-3">
Parameter wie Temperature, TopK und TopP beeinflussen die Parameter wie Temperature, TopK und TopP beeinflussen die
kreative Varianz der Antwort. Repeat Penalty steuert Wiederholungen, kreative Varianz der Antwort. Repeat Penalty steuert Wiederholungen,
während <code>numCtx</code> die maximale Kontextgröße des Modells festlegt. während <code>numCtx</code> die maximale Kontextgröße des Modells festlegt.
</p> </p>
</div>
<h6 class="text-info mt-3">Retrieval Vector Wissen</h6> <div class="col-lg-6">
<h6 class="text-info mt-3">Retrieval Vector Wissen</h6>
<p class="small text-light mb-3"> <p class="small text-light mb-3">
Retrieval-Parameter bestimmen, wie viele Chunks aus dem Retrieval-Parameter bestimmen, wie viele Chunks aus dem
NDJSON-Vektorindex geladen werden und wie viele NDJSON-Vektorindex geladen werden und wie viele
Top-K Kandidaten aus der FAISS-Suche berücksichtigt werden. Top-K Kandidaten aus der FAISS-Suche berücksichtigt werden.
Diese Werte beeinflussen die Wissensbreite der Antwort, Diese Werte beeinflussen die Wissensbreite der Antwort,
nicht deren Kreativität. nicht deren Kreativität.
</p> </p>
<h6 class="text-info mt-3">Architektur-Prinzip</h6> <h6 class="text-info mt-3">Architektur-Prinzip</h6>
<p class="small text-light mb-0">
Das Retrieval ist deterministisch und vom LLM getrennt.
Das Modell erhält ausschließlich die vorselektierten
Chunks als Kontext. Änderungen hier verändern die
Wissensbasis der Antwort — nicht den gespeicherten Index.
Pro Modell kann genau eine Konfiguration aktiv sein.
</p>
</div>
<p class="small text-light mb-0">
Das Retrieval ist deterministisch und vom LLM getrennt.
Das Modell erhält ausschließlich die vorselektierten
Chunks als Kontext. Änderungen hier verändern die
Wissensbasis der Antwort — nicht den gespeicherten Index.
Pro Modell kann genau eine Konfiguration aktiv sein.
</p>
</div> </div>
</div> </div>
@@ -75,7 +80,7 @@
<th>Profil-Version</th> <th>Profil-Version</th>
<th>Streaming</th> <th>Streaming</th>
<th>LLM Sampling</th> <th>LLM Sampling</th>
<th class="text-warning">Retrieval Vector Wissen</th> <th class="">Retrieval Vector Wissen</th>
<th>Status</th> <th>Status</th>
<th class="text-end">Aktionen</th> <th class="text-end">Aktionen</th>
</tr> </tr>
@@ -186,10 +191,10 @@
Hinweis: Änderungen wirken sich unmittelbar auf Sampling- und Retrieval-Parameter Hinweis: Änderungen wirken sich unmittelbar auf Sampling- und Retrieval-Parameter
des aktiven Modells aus. Pro Modell kann nur eine Version aktiv sein. des aktiven Modells aus. Pro Modell kann nur eine Version aktiv sein.
</div> </div>
<hr>
<h2 class="h4 mb-4">Agent Live Test</h2> <h2 class="h4 mb-4">Agent Live Test</h2>
<div class="card bg-black border-info"> <div class="card bg-black border-secondary">
<div class="card-body p-0"> <div class="card-body p-0">
<iframe <iframe
src="/index.html?admin_test=1" src="/index.html?admin_test=1"

View File

@@ -1,11 +1,11 @@
{% extends 'admin/base.html.twig' %} {% extends 'admin/base.html.twig' %}
{% block title %}Retrieval Wissensbasis (Chunk-Index){% endblock %} {% block title %}Retrieval Wissensbasis{% endblock %}
{% block body %} {% block body %}
<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">Retrieval Wissensbasis (Chunk-Index)</h1> <h1 class="h3"><i class="bi bi-robot"></i> Retrieval Wissensbasis</h1>
<a href="{{ path('admin_dashboard') }}" <a href="{{ path('admin_dashboard') }}"
class="btn btn-sm btn-outline-secondary"> class="btn btn-sm btn-outline-secondary">
@@ -17,10 +17,10 @@
{# Index Meta Section #} {# Index Meta Section #}
{# ============================= #} {# ============================= #}
<div class="card bg-black border-secondary mb-5"> <div class="card bg-dark border-secondary mb-5">
<div class="card-body"> <div class="card-body">
<h5 class="text-info mb-3">Wissensdaten Generierungsmatrix Index Meta (index_meta.json)</h5> <h5 class="text-info mb-3">Generierungsmatrix (index_meta.json)</h5>
{% if meta.error is defined %} {% if meta.error is defined %}
<div class="alert alert-danger"> <div class="alert alert-danger">
@@ -35,12 +35,12 @@
<tbody> <tbody>
{% for key, value in meta %} {% for key, value in meta %}
<tr> <tr>
<th style="width:260px;" class="text-secondary"> <td style="width:260px;" class="text-info">
{{ key }} {{ key }}
</th> </td>
<td> <td>
{% if value is iterable %} {% if value is iterable %}
<pre class="mb-0 small text-info"> <pre class="mb-0 small text-light">
{{ value|json_encode(constant('JSON_PRETTY_PRINT')) }} {{ value|json_encode(constant('JSON_PRETTY_PRINT')) }}
</pre> </pre>
{% else %} {% else %}
@@ -75,7 +75,7 @@
<div class="d-flex justify-content-between align-items-center mb-3"> <div class="d-flex justify-content-between align-items-center mb-3">
<h5 class="text-info mb-0"> <h5 class="text-info mb-0">
Chunks Index | NDJSON-Index Übersicht (index.ndjson) Wissensdaten Chunks | Übersicht (index.ndjson)
</h5> </h5>
<div class="btn-group"> <div class="btn-group">
@@ -83,7 +83,7 @@
page: currentPage > 1 ? currentPage - 1 : 1, page: currentPage > 1 ? currentPage - 1 : 1,
limit: currentLimit limit: currentLimit
}) }}" }) }}"
class="btn btn-sm btn-outline-light"> class="btn btn-sm btn-outline-info">
← Zurück ← Zurück
</a> </a>
@@ -91,7 +91,7 @@
page: currentPage + 1, page: currentPage + 1,
limit: currentLimit limit: currentLimit
}) }}" }) }}"
class="btn btn-sm btn-outline-light"> class="btn btn-sm btn-outline-info">
Weiter → Weiter →
</a> </a>
</div> </div>
@@ -131,13 +131,14 @@
{% for item in ndjson.items|default([]) %} {% for item in ndjson.items|default([]) %}
<tr> <tr>
<td class="small">{{ item.chunk_id ?? '-' }}</td> <td class="small text-info">{{ item.chunk_id ?? '-' }}</td>
<td> <td class="small text-info">
{% if item.document_id %} {% if item.document_id %}
{{ item.document_id }}<br>
<a href="{{ path('admin_document_show', {id: item.document_id}) }}" <a href="{{ path('admin_document_show', {id: item.document_id}) }}"
class="text-decoration-none text-light"> class="text-light small">
{{ item.document_id }} ansehen
</a> </a>
{% else %} {% else %}
- -

View File

@@ -6,58 +6,63 @@
<div class="container-fluid"> <div class="container-fluid">
<!-- Flash Messages -->
{% for message in app.flashes('success') %}
<div class="alert alert-success mb-5">{{ message }}</div>
{% endfor %}
{% for message in app.flashes('danger') %}
<div class="alert alert-danger mb-5">{{ message }}</div>
{% endfor %}
<!-- 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">System Prompt Verwaltung</h1> <h1 class="h3"><i class="bi bi-chat-right-dots-fill"></i> System Prompt Verwaltung</h1>
</div> </div>
{# ========================================================= #} {# ========================================================= #}
{# SYSTEM PROMPT DESCRIPTION #} {# SYSTEM PROMPT DESCRIPTION #}
{# ========================================================= #} {# ========================================================= #}
<div class="card bg-black border-secondary text-light mb-4 shadow-sm"> <div class="card bg-dark border-secondary text-light mb-4 shadow-sm">
<div class="card-body"> <div class="card-body row">
<h5 class="text-info mb-3">Was steuert der System Prompt?</h5> <div class="col-lg-6">
<h5 class="text-info mb-3">Was steuert der System Prompt?</h5>
<p class="small text-light mb-3"> <p class="small text-light mb-3">
Der System Prompt definiert das globale Antwortverhalten des LLM. Der System Prompt definiert das globale Antwortverhalten des LLM.
Er ist die oberste Steuerungsebene des Systems und beeinflusst: Er ist die oberste Steuerungsebene des Systems und beeinflusst:
</p> </p>
<ul class="small text-light mb-3"> <ul class="small text-light mb-3">
<li>Ton und Stil der Antworten</li> <li>Ton und Stil der Antworten</li>
<li>Struktur der Ausgaben</li> <li>Struktur der Ausgaben</li>
<li>Umgang mit Unsicherheiten</li> <li>Umgang mit Unsicherheiten</li>
<li>Bezug auf Wissensquellen</li> <li>Bezug auf Wissensquellen</li>
</ul> </ul>
</div>
<h6 class="text-info mt-3">Architektur-Prinzip</h6> <div class="col-lg-6">
<h6 class="text-info mt-3">Architektur-Prinzip</h6>
<p class="small text-light mb-3"> <p class="small text-light mb-3">
Der System Prompt ist strikt von der Wissensebene getrennt. Der System Prompt ist strikt von der Wissensebene getrennt.
Er verändert keine Dokumente, Chunks oder Vektoren, Er verändert keine Dokumente, Chunks oder Vektoren,
sondern nur die Interpretation und Darstellung der Retrieval-Ergebnisse. sondern nur die Interpretation und Darstellung der Retrieval-Ergebnisse.
</p> </p>
<h6 class="text-info mt-3">Warum Versionierung?</h6> <h6 class="text-info mt-3">Warum Versionierung?</h6>
<p class="small text-light mb-0"> <p class="small text-light mb-0">
Jede Änderung kann das Antwortverhalten signifikant verändern. Jede Änderung kann das Antwortverhalten signifikant verändern.
Daher ist der Prompt versioniert, rollbackfähig und nur eine Version kann aktiv sein. Daher ist der Prompt versioniert, rollbackfähig und nur eine Version kann aktiv sein.
Aktivierungen wirken unmittelbar auf alle nachfolgenden Anfragen. Aktivierungen wirken unmittelbar auf alle nachfolgenden Anfragen.
</p> </p>
</div>
</div> </div>
</div> </div>
<!-- Flash Messages -->
{% for message in app.flashes('success') %}
<div class="alert alert-success">{{ message }}</div>
{% endfor %}
{% for message in app.flashes('danger') %}
<div class="alert alert-danger">{{ message }}</div>
{% endfor %}
<div class="row g-4"> <div class="row g-4">
<!-- LEFT SIDE Versionen --> <!-- LEFT SIDE Versionen -->

View File

@@ -4,9 +4,18 @@
{% block body %} {% block body %}
{# ========================================================= #}
{# LIVE REBUILD STATUS (SSE) #}
{# ========================================================= #}
<div id="rebuild-status" class="mb-5">
<div class="alert alert-secondary shadow-sm">
Status wird geladen…
</div>
</div>
<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"> <h1 class="h3 mb-0">
Tag: {{ tag.label }} <i class="bi bi-tag-fill"></i> Tag: {{ tag.label }}
</h1> </h1>
<a href="{{ path('admin_tags_index') }}" <a href="{{ path('admin_tags_index') }}"
@@ -15,15 +24,6 @@
</a> </a>
</div> </div>
{# ========================================================= #}
{# LIVE REBUILD STATUS (SSE) #}
{# ========================================================= #}
<div id="rebuild-status">
<div class="alert alert-secondary shadow-sm">
Status wird geladen…
</div>
</div>
<script> <script>
const statusBox = document.getElementById('rebuild-status'); const statusBox = document.getElementById('rebuild-status');
@@ -37,7 +37,7 @@
html = ` html = `
<div class="alert alert-info shadow-sm d-flex justify-content-between align-items-center"> <div class="alert alert-info shadow-sm d-flex justify-content-between align-items-center">
<div> <div>
<strong>Tag-Rebuild läuft</strong><br> Tag-Rebuild läuft<br>
${data.startedAt ? 'Gestartet: ' + new Date(data.startedAt).toLocaleString() : ''} ${data.startedAt ? 'Gestartet: ' + new Date(data.startedAt).toLocaleString() : ''}
</div> </div>
<div class="spinner-border spinner-border-sm"></div> <div class="spinner-border spinner-border-sm"></div>
@@ -46,19 +46,19 @@
} else if (data.status === '{{ statusQueued }}') { } else if (data.status === '{{ statusQueued }}') {
html = ` html = `
<div class="alert alert-secondary shadow-sm"> <div class="alert alert-secondary shadow-sm">
<strong>Tag-Rebuild in Warteschlange</strong> Tag-Rebuild in Warteschlange
</div> </div>
`; `;
} else if (data.status === '{{ statusCompleted }}') { } else if (data.status === '{{ statusCompleted }}') {
html = ` html = `
<div class="alert alert-success shadow-sm"> <div class="alert alert-success shadow-sm">
<strong>Tag-Rebuild erfolgreich abgeschlossen</strong> <i class="bi bi-check-lg"></i> Tag-Rebuild erfolgreich abgeschlossen
</div> </div>
`; `;
} else if (data.status === '{{ statusFailed }}') { } else if (data.status === '{{ statusFailed }}') {
html = ` html = `
<div class="alert alert-danger shadow-sm"> <div class="alert alert-danger shadow-sm">
<strong>Tag-Rebuild fehlgeschlagen</strong><br> Tag-Rebuild fehlgeschlagen<br>
${data.error ? '<code>' + data.error + '</code>' : ''} ${data.error ? '<code>' + data.error + '</code>' : ''}
</div> </div>
`; `;
@@ -99,39 +99,64 @@
value="{{ csrf_token('assign_tag_' ~ tag.id) }}"> value="{{ csrf_token('assign_tag_' ~ tag.id) }}">
<div class="card bg-black border-secondary"> <div class="card bg-black border-secondary">
<div class="card-body p-0"> <div class="card-body p-0 row">
<div class=" col-lg-6">
<table class="table table-dark table-striped table-hover mb-0 align-middle"> <table class="table table-dark table-striped table-hover mb-0 align-middle">
<thead class="table-secondary text-dark"> <thead class="table-secondary text-dark">
<tr>
<th style="width:60px;"></th>
<th>Dokument</th>
</tr>
</thead>
<tbody>
{% for doc in documents %}
<tr> <tr>
<td> <th style="width:60px;"><i class="bi bi-three-dots"></i></th>
<input type="checkbox" <th>Zugewiesene Dokumente</th>
name="documents[]"
value="{{ doc.id }}"
{% if doc.id in assignedDocIds %}checked{% endif %}>
</td>
<td>
{{ doc.title }}
</td>
</tr> </tr>
{% else %} </thead>
<tr>
<td colspan="2" class="text-center text-muted">
Keine Dokumente vorhanden.
</td>
</tr>
{% endfor %}
</tbody>
</table>
<tbody>
{% for doc in documents %}
{% if doc.id in assignedDocIds %}
<tr>
<td>
<input type="checkbox"
name="documents[]"
value="{{ doc.id }}"
checked>
</td>
<td>
{{ doc.title }}
</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
<div class=" col-lg-6">
<table class="table table-dark table-striped table-hover mb-0 align-middle col-lg-6">
<thead class="table-secondary text-dark">
<tr>
<th style="width:60px;"><i class="bi bi-three-dots"></i></th>
<th>Nicht zugewiesene Dokumente</th>
</tr>
</thead>
<tbody>
{% for doc in documents %}
{% if doc.id not in assignedDocIds %}
<tr>
<td>
<input type="checkbox"
name="documents[]"
value="{{ doc.id }}"
>
</td>
<td class="opacity-50">
{{ doc.title }}
</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
</div> </div>
</div> </div>

View File

@@ -4,75 +4,79 @@
{% block body %} {% block body %}
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3 mb-0">Tag-Management</h1>
</div>
{# ========================================================= #} {# ========================================================= #}
{# LIVE REBUILD STATUS (SSE) #} {# LIVE REBUILD STATUS (SSE) #}
{# ========================================================= #} {# ========================================================= #}
<div id="rebuild-status"> <div id="rebuild-status" class="mb-5">
{% if latestJob %} {% if latestJob %}
<div class="alert alert-secondary shadow-sm"> <div class="alert alert-secondary shadow-sm">
Status wird geladen… Status wird geladen…
</div> </div>
{% endif %} {% endif %}
</div> </div>
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3 mb-0"><i class="bi bi-tag-fill"></i> Tag-Management</h1>
</div>
{# ========================================================= #} {# ========================================================= #}
{# TAG SYSTEM DESCRIPTION #} {# TAG SYSTEM DESCRIPTION #}
{# ========================================================= #} {# ========================================================= #}
<div class="card bg-black border-secondary text-light mb-4 shadow-sm"> <div class="card bg-dark border-secondary text-light mb-4 shadow-sm">
<div class="card-body"> <div class="card-body row">
<h5 class="text-info mb-3">Was machen Tags im System?</h5> <div class="col-lg-6">
<h5 class="text-info mb-3">Was machen Tags im System?</h5>
<p class="small text-light mb-2"> <p class="small text-light mb-2">
Tags dienen als semantische Routing-Ebene innerhalb des RAG-Systems. Tags dienen als semantische Routing-Ebene innerhalb des RAG-Systems.
Sie strukturieren Dokumente thematisch und beeinflussen, Sie strukturieren Dokumente thematisch und beeinflussen,
welche Inhalte bei einer Nutzeranfrage priorisiert werden. welche Inhalte bei einer Nutzeranfrage priorisiert werden.
</p> </p>
<ul class="small text-light mb-3"> <ul class="small text-light mb-3">
<li> <li>
Tags werden Dokumenten manuell zugewiesen. Tags werden Dokumenten manuell zugewiesen.
</li> </li>
<li> <li>
Beim Rebuild wird aus allen Tags eine eigene Beim Rebuild wird aus allen Tags eine eigene
<code>tags.ndjson</code> erzeugt. <code>tags.ndjson</code> erzeugt.
</li> </li>
<li> <li>
Zusätzlich wird ein separater Vektorindex Zusätzlich wird ein separater Vektorindex
(<code>vector_tags.index</code>) aufgebaut. (<code>vector_tags.index</code>) aufgebaut.
</li> </li>
<li> <li>
Bei einer Anfrage erfolgt zunächst ein Tag-Matching, Bei einer Anfrage erfolgt zunächst ein Tag-Matching,
danach wird das Chunk-Retrieval entsprechend gewichtet. danach wird das Chunk-Retrieval entsprechend gewichtet.
</li> </li>
</ul> </ul>
</div>
<div class="col-lg-6">
<h6 class="text-info mt-3">Wie werden Tags bewertet?</h6>
<h6 class="text-info mt-3">Wie werden Tags bewertet?</h6> <p class="small text-light mb-2">
Die Bewertung erfolgt über einen eigenen Vektor-Similarity-Score
im Tag-Index. Das System berechnet:
</p>
<p class="small text-light mb-2"> <ul class="small text-light">
Die Bewertung erfolgt über einen eigenen Vektor-Similarity-Score <li>
im Tag-Index. Das System berechnet: Ähnlichkeit zwischen Nutzeranfrage und Tag-Embedding
</p> </li>
<li>
Top-K Treffer im Tag-Index
</li>
<li>
Gewichtete Übergabe an das Chunk-Retrieval
</li>
</ul>
<ul class="small text-light"> <p class="small text-light mt-2 mb-0">
<li> Tags wirken somit als semantischer Verstärker.
Ähnlichkeit zwischen Nutzeranfrage und Tag-Embedding Sie ersetzen kein Chunk-Retrieval, sondern steuern dessen Priorisierung.
</li> </p>
<li> </div>
Top-K Treffer im Tag-Index
</li>
<li>
Gewichtete Übergabe an das Chunk-Retrieval
</li>
</ul>
<p class="small text-light mt-2 mb-0">
Tags wirken somit als semantischer Verstärker.
Sie ersetzen kein Chunk-Retrieval, sondern steuern dessen Priorisierung.
</p>
</div> </div>
</div> </div>
@@ -88,7 +92,7 @@
html = ` html = `
<div class="alert alert-info shadow-sm d-flex justify-content-between align-items-center"> <div class="alert alert-info shadow-sm d-flex justify-content-between align-items-center">
<div> <div>
<strong>Tag-Rebuild läuft</strong><br> Tag-Rebuild läuft<br>
${data.startedAt ? 'Gestartet: ' + new Date(data.startedAt).toLocaleString() : ''} ${data.startedAt ? 'Gestartet: ' + new Date(data.startedAt).toLocaleString() : ''}
</div> </div>
<div class="spinner-border spinner-border-sm"></div> <div class="spinner-border spinner-border-sm"></div>
@@ -97,19 +101,19 @@
} else if (data.status === '{{ statusQueued }}') { } else if (data.status === '{{ statusQueued }}') {
html = ` html = `
<div class="alert alert-secondary shadow-sm"> <div class="alert alert-secondary shadow-sm">
<strong>Tag-Rebuild in Warteschlange</strong> Tag-Rebuild in Warteschlange
</div> </div>
`; `;
} else if (data.status === '{{ statusCompleted }}') { } else if (data.status === '{{ statusCompleted }}') {
html = ` html = `
<div class="alert alert-success shadow-sm"> <div class="alert alert-success shadow-sm">
<strong>Tag-Rebuild erfolgreich abgeschlossen</strong> <i class="bi bi-check-lg"></i> Tag-Rebuild erfolgreich abgeschlossen
</div> </div>
`; `;
} else if (data.status === '{{ statusFailed }}') { } else if (data.status === '{{ statusFailed }}') {
html = ` html = `
<div class="alert alert-danger shadow-sm"> <div class="alert alert-danger shadow-sm">
<strong>Tag-Rebuild fehlgeschlagen</strong><br> Tag-Rebuild fehlgeschlagen<br>
${data.error ? '<code>' + data.error + '</code>' : ''} ${data.error ? '<code>' + data.error + '</code>' : ''}
</div> </div>
`; `;
@@ -128,7 +132,7 @@
{# ========================================================= #} {# ========================================================= #}
<div class="card bg-black border-secondary text-light mb-4 shadow-sm"> <div class="card bg-black border-secondary text-light mb-4 shadow-sm">
<div class="card-body"> <div class="card-body">
<h5 class="text-info mb-3">Neuen Tag erstellen</h5> <h5 class="text-info mb-3">Neuen Tag hinzufügen</h5>
<form method="post" action="{{ path('admin_tags_create') }}" class="row g-3"> <form method="post" action="{{ path('admin_tags_create') }}" class="row g-3">
<input type="hidden" name="_token" value="{{ csrf_token('admin_tag_create') }}"/> <input type="hidden" name="_token" value="{{ csrf_token('admin_tag_create') }}"/>
@@ -179,10 +183,10 @@
{# Tag Table #} {# Tag Table #}
{# ========================================================= #} {# ========================================================= #}
<div class="card bg-black border-secondary text-light shadow-sm"> <div class="card bg-black border-secondary text-light shadow-sm">
<div class="card-body p-0"> <div class="card-body">
<div class="px-3 py-2 border-bottom border-secondary"> <div class="mb-3">
<strong>Vorhandene Tags</strong> <strong class="text-info">Vorhandene Tags:</strong>
<span class="text-muted small ms-2"> <span class="text-muted small ms-2">
{{ tags|length }} Einträge {{ tags|length }} Einträge
</span> </span>