Files
Faktenkompass/templates/admin/claims/assistant.html
T
Pirmin Hinderling (fedora) b0ecdc6cfb Show loading animation while the fact assistant generates a draft.
Disables the form and displays a spinner overlay after clicking Entwurf generieren.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-07 21:43:31 +02:00

203 lines
6.4 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "admin/base_site.html" %}
{% load i18n %}
{% block extrastyle %}
{{ block.super }}
<style>
.assistant-wrap { max-width: 820px; }
.chat-box {
background: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 8px;
padding: 1rem;
min-height: 120px;
margin-bottom: 1.5rem;
}
.chat-hint { color: #6c757d; font-size: 0.9rem; }
.assistant-card {
border: 1px solid #dee2e6;
border-radius: 8px;
padding: 1.25rem;
background: #fff;
position: relative;
}
.assistant-card.is-loading {
pointer-events: none;
}
.fk-assistant-loading {
position: absolute;
inset: 0;
z-index: 2;
display: flex;
align-items: center;
justify-content: center;
border-radius: 8px;
background: rgba(255, 255, 255, 0.92);
}
.fk-assistant-loading[hidden] {
display: none !important;
}
.fk-assistant-loading-inner {
text-align: center;
color: #374151;
}
.fk-assistant-loading-inner p {
margin: 0.75rem 0 0;
font-weight: 500;
}
.fk-assistant-loading-hint {
margin-top: 0.35rem !important;
font-size: 0.85rem;
font-weight: 400 !important;
color: #6b7280;
}
.fk-spinner {
display: inline-block;
width: 2.25rem;
height: 2.25rem;
border: 3px solid #d1d5db;
border-top-color: #0d9488;
border-radius: 50%;
animation: fk-spin 0.75s linear infinite;
}
@keyframes fk-spin {
to { transform: rotate(360deg); }
}
.fk-generate-btn.is-loading .fk-btn-label {
display: none;
}
.fk-generate-btn.is-loading .fk-btn-loading {
display: inline-flex;
align-items: center;
gap: 0.5rem;
}
.fk-btn-loading {
display: none;
}
.fk-btn-loading .fk-spinner {
width: 1rem;
height: 1rem;
border-width: 2px;
}
</style>
{% endblock %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">Start</a>
&rsaquo; <a href="{% url 'admin:claims_claimdraft_changelist' %}">Fakten-Entwürfe</a>
&rsaquo; Assistent
</div>
{% endblock %}
{% block content %}
<div class="assistant-wrap">
<h1>Fakten-Assistent</h1>
<p class="chat-hint">
Link, Bild und/oder Beschreibung eingeben. Die KI erstellt einen <strong>Entwurf zur Prüfung</strong>
nichts wird automatisch veröffentlicht.
</p>
<div class="chat-box">
<p class="mb-1"><strong>So funktioniert es:</strong></p>
<ol class="mb-0 ps-3">
<li>Eingaben senden (Artikel-URL, Beschreibung, optional Bild/PDF)</li>
<li>KI analysiert den Kontext und schlägt Kategorie &amp; Fakteneintrag vor</li>
<li>Sie prüfen, bearbeiten und veröffentlichen erst nach Freigabe</li>
</ol>
</div>
<div class="assistant-card" id="fk-assistant-card">
<div class="fk-assistant-loading" id="fk-assistant-loading" hidden>
<div class="fk-assistant-loading-inner">
<span class="fk-spinner" aria-hidden="true"></span>
<p>Entwurf wird generiert…</p>
<p class="fk-assistant-loading-hint">Die KI analysiert Ihre Eingaben. Das kann einige Sekunden dauern.</p>
</div>
</div>
<form method="post" enctype="multipart/form-data" novalidate id="fk-assistant-form">
{% csrf_token %}
{% if form.non_field_errors %}
<div class="alert alert-danger">{{ form.non_field_errors }}</div>
{% endif %}
<div class="mb-3">
<label class="form-label" for="{{ form.article_url.id_for_label }}">{{ form.article_url.label }}</label>
{{ form.article_url }}
{% if form.article_url.errors %}<div class="text-danger small">{{ form.article_url.errors }}</div>{% endif %}
</div>
<div class="mb-3">
<label class="form-label" for="{{ form.user_notes.id_for_label }}">{{ form.user_notes.label }}</label>
{{ form.user_notes }}
{% if form.user_notes.errors %}<div class="text-danger small">{{ form.user_notes.errors }}</div>{% endif %}
</div>
<div class="mb-3">
<label class="form-label" for="{{ form.uploaded_file.id_for_label }}">{{ form.uploaded_file.label }}</label>
{{ form.uploaded_file }}
<div class="form-text">JPG, PNG, GIF, WebP, SVG oder PDF. SVG wird für die KI intern in PNG umgewandelt.</div>
</div>
<button type="submit" class="button default fk-generate-btn" id="fk-generate-draft-btn">
<span class="fk-btn-label">Entwurf generieren</span>
<span class="fk-btn-loading">
<span class="fk-spinner" aria-hidden="true"></span>
Wird generiert…
</span>
</button>
</form>
</div>
{% if recent_drafts %}
<div class="mt-4">
<h2 class="h6 text-muted">Letzte Entwürfe</h2>
<ul>
{% for draft in recent_drafts %}
<li>
<a href="{% url 'admin:claims_claimdraft_review' draft.pk %}">
{{ draft.title|default:"(ohne Titel)" }}
</a>
{{ draft.get_status_display }}
<span class="text-muted">({{ draft.created_at|date:"d.m.Y H:i" }})</span>
</li>
{% endfor %}
</ul>
</div>
{% endif %}
</div>
{% endblock %}
{% block extrahead %}
{{ block.super }}
<script>
(function () {
var form = document.getElementById('fk-assistant-form');
if (!form) {
return;
}
form.addEventListener('submit', function () {
var card = document.getElementById('fk-assistant-card');
var overlay = document.getElementById('fk-assistant-loading');
var button = document.getElementById('fk-generate-draft-btn');
if (card) {
card.classList.add('is-loading');
}
if (overlay) {
overlay.hidden = false;
}
if (button) {
button.classList.add('is-loading');
button.disabled = true;
}
form.querySelectorAll('input:not([type="hidden"]), textarea, select, button').forEach(function (field) {
field.disabled = true;
});
});
})();
</script>
{% endblock %}