Faktenkompass: UI-Rebrand, Admin-Assistent und Produktions-Setup.
Modernisiert die öffentliche Oberfläche mit Inter, Dark Mode und Live-Suche, ergänzt KI-gestützte Entwürfe im Admin mit Nachweis-Uploads und dokumentiert Daphne/Nginx für den Serverbetrieb. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
{% 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;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<div class="breadcrumbs">
|
||||
<a href="{% url 'admin:index' %}">Start</a>
|
||||
› <a href="{% url 'admin:claims_claimdraft_changelist' %}">Fakten-Entwürfe</a>
|
||||
› 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 & Fakteneintrag vor</li>
|
||||
<li>Sie prüfen, bearbeiten und veröffentlichen erst nach Freigabe</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="assistant-card">
|
||||
<form method="post" enctype="multipart/form-data" novalidate>
|
||||
{% 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">Entwurf generieren</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 %}
|
||||
@@ -0,0 +1,17 @@
|
||||
{% extends "admin/change_form.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
{% if original and original.pk %}
|
||||
<div class="fk-claim-meta-links">
|
||||
<a href="{{ original.get_absolute_url }}" target="_blank" rel="noopener">↗ Auf Website ansehen</a>
|
||||
<a href="{% url 'admin:claims_claimdraft_assistant' %}">+ Fakten-Assistent</a>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="fk-claim-help">
|
||||
Neue Behauptung anlegen: zuerst Titel und Kurzantwort ausfüllen, dann speichern.
|
||||
Nachweise, Quellen und Gegenargumente können danach ergänzt werden.
|
||||
</div>
|
||||
{% endif %}
|
||||
{{ block.super }}
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,8 @@
|
||||
{% extends "admin/change_list.html" %}
|
||||
|
||||
{% block object-tools-items %}
|
||||
<li>
|
||||
<a href="{% url 'admin:claims_claimdraft_assistant' %}" class="addlink">Fakten-Assistent</a>
|
||||
</li>
|
||||
{{ block.super }}
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,158 @@
|
||||
{% extends "admin/base_site.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block extrastyle %}
|
||||
{{ block.super }}
|
||||
<style>
|
||||
.review-grid { display: grid; grid-template-columns: 1fr 320px; gap: 1.5rem; }
|
||||
@media (max-width: 960px) { .review-grid { grid-template-columns: 1fr; } }
|
||||
.preview-card, .chat-panel {
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
padding: 1rem;
|
||||
}
|
||||
.chat-panel { background: #f8f9fa; max-height: 420px; overflow-y: auto; }
|
||||
.chat-msg { margin-bottom: 0.75rem; font-size: 0.92rem; }
|
||||
.chat-msg.user { color: #0d3d66; }
|
||||
.chat-msg.assistant { color: #333; }
|
||||
.status-badge {
|
||||
display: inline-block;
|
||||
padding: 0.2rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
font-size: 0.8rem;
|
||||
background: #e9ecef;
|
||||
}
|
||||
.field-box { margin-bottom: 1rem; }
|
||||
.field-box label { display: block; font-weight: 600; margin-bottom: 0.25rem; }
|
||||
.actions-bar { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1rem; }
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<div class="breadcrumbs">
|
||||
<a href="{% url 'admin:index' %}">Start</a>
|
||||
› <a href="{% url 'admin:claims_claimdraft_changelist' %}">Fakten-Entwürfe</a>
|
||||
› <a href="{% url 'admin:claims_claimdraft_assistant' %}">Assistent</a>
|
||||
› Prüfen
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Entwurf prüfen</h1>
|
||||
|
||||
<p>
|
||||
Status: <span class="status-badge">{{ draft.get_status_display }}</span>
|
||||
{% if draft.published_claim %}
|
||||
· <a href="{% url 'admin:claims_claim_change' draft.published_claim.pk %}">Veröffentlichte Behauptung öffnen</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
{% if draft.error_message %}
|
||||
<div class="alert alert-danger">{{ draft.error_message }}</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="review-grid">
|
||||
<div>
|
||||
<form method="post" class="preview-card">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="action" value="save" id="form-action">
|
||||
|
||||
<div class="field-box">
|
||||
<label for="{{ form.category_choice.id_for_label }}">{{ form.category_choice.label }}</label>
|
||||
{{ form.category_choice }}
|
||||
</div>
|
||||
|
||||
<div class="field-box">
|
||||
<label for="{{ form.new_category_name.id_for_label }}">Neue Kategorie (falls leer oben)</label>
|
||||
{{ form.new_category_name }}
|
||||
{{ form.new_category_description }}
|
||||
{{ form.new_category_icon }}
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<div class="field-box">
|
||||
<label for="{{ form.title.id_for_label }}">{{ form.title.label }}</label>
|
||||
{{ form.title }}
|
||||
</div>
|
||||
|
||||
<div class="field-box">
|
||||
<label for="{{ form.claim_status.id_for_label }}">{{ form.claim_status.label }}</label>
|
||||
{{ form.claim_status }}
|
||||
</div>
|
||||
|
||||
<div class="field-box">
|
||||
<label for="{{ form.evidence_level.id_for_label }}">{{ form.evidence_level.label }}</label>
|
||||
{{ form.evidence_level }}
|
||||
</div>
|
||||
|
||||
<div class="field-box">
|
||||
<label for="{{ form.short_answer.id_for_label }}">{{ form.short_answer.label }}</label>
|
||||
{{ form.short_answer }}
|
||||
</div>
|
||||
|
||||
<div class="field-box">
|
||||
<label for="{{ form.detailed_explanation.id_for_label }}">{{ form.detailed_explanation.label }}</label>
|
||||
{{ form.detailed_explanation }}
|
||||
</div>
|
||||
|
||||
<div class="field-box">
|
||||
<label for="{{ form.tags_text.id_for_label }}">{{ form.tags_text.label }}</label>
|
||||
{{ form.tags_text }}
|
||||
</div>
|
||||
|
||||
<div class="field-box">
|
||||
<label for="{{ form.sources_json.id_for_label }}">{{ form.sources_json.label }}</label>
|
||||
{{ form.sources_json }}
|
||||
</div>
|
||||
|
||||
<div class="field-box">
|
||||
<label for="{{ form.counter_arguments_json.id_for_label }}">{{ form.counter_arguments_json.label }}</label>
|
||||
{{ form.counter_arguments_json }}
|
||||
</div>
|
||||
|
||||
<div class="actions-bar">
|
||||
<button type="submit" class="button" onclick="document.getElementById('form-action').value='save'">Speichern</button>
|
||||
{% if draft.status != 'published' %}
|
||||
<button type="submit" class="button default" onclick="document.getElementById('form-action').value='publish'">
|
||||
Veröffentlichen
|
||||
</button>
|
||||
<button type="submit" class="button" formaction="." formmethod="post" name="action" value="reject"
|
||||
onclick="return confirm('Entwurf wirklich verwerfen?')">Verwerfen</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="chat-panel mb-3">
|
||||
<h2 class="h6">Konversation</h2>
|
||||
{% for msg in draft.conversation %}
|
||||
<div class="chat-msg {{ msg.role }}">
|
||||
<strong>{% if msg.role == 'user' %}Sie{% else %}Assistent{% endif %}:</strong>
|
||||
{{ msg.content|linebreaksbr }}
|
||||
</div>
|
||||
{% empty %}
|
||||
<p class="text-muted mb-0">Noch keine Nachrichten.</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% if draft.uploaded_file %}
|
||||
<p class="small text-muted mb-2">Datei: {{ draft.uploaded_file.name }}</p>
|
||||
{% endif %}
|
||||
{% if draft.article_url %}
|
||||
<p class="small mb-3"><a href="{{ draft.article_url }}" target="_blank" rel="noopener">Artikel öffnen</a></p>
|
||||
{% endif %}
|
||||
|
||||
{% if draft.status != 'published' %}
|
||||
<form method="post" class="preview-card">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="action" value="refine">
|
||||
<h2 class="h6">Überarbeiten lassen</h2>
|
||||
{{ refine_form.refinement }}
|
||||
<button type="submit" class="button mt-2">KI erneut fragen</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user