Commits vergleichen

..

3 Commits

Autor SHA1 Nachricht Datum
0775a475a4 Promote develop → main (2026-05-01 21:39 UTC) 2026-05-01 23:39:22 +02:00
2b1e8c3632 requirements.txt: Export-Pakete dokumentiert
Jinja2, weasyprint und python-docx waren auf Live manuell ins venv
installiert, fehlten aber in requirements.txt — Folge: auf Staging waren
sie nicht installiert, Bericht-Export warf 500 (ModuleNotFoundError).
Jetzt im Repo dokumentiert, beim Aufsetzen neuer Umgebungen ist alles
vollständig.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 23:34:58 +02:00
b1f8113207 Bericht-Export: drei Verbesserungen
1. Faktencheck immer vollständig
   PDF-Export hatte im scope=report einen [:20]-Cap, der vollständige
   Faktencheck wurde nur bei scope=full gerendert. Jetzt ungekürzt
   überall, sortiert chronologisch absteigend (DB-Sortierung).

2. Status-Labels aus Frontend übernommen
   FC_STATUS_LABELS hatte nur 4 Werte; in der DB existieren aber 7+
   (confirmed/unconfirmed/contradicted/developing/established/
   unverified/disputed). Folge: "contradicted" und drei weitere
   wurden auf englisch ausgegeben. Jetzt 1:1 vom Monitor-UI:
     contradicted → "Widerlegt"
     developing   → "Unklar"
     established  → "Gesichert"
     unverified   → "Ungeprüft"

3. Adhoc-Export: Neueste Entwicklungen statt Executive Summary
   Bei Live-Monitoring-Lagen ist die generische Executive Summary
   weniger aussagekräftig als die kompakten "Neueste Entwicklungen"-
   Bullets. Endpoint nutzt jetzt:
     - adhoc + latest_developments vorhanden → latest_developments
       (Markdown -> HTML konvertiert)
     - adhoc + leer → cached/generierte Executive Summary (Fallback)
     - research → unverändert Executive Summary

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 23:32:36 +02:00
3 geänderte Dateien mit 26 neuen und 7 gelöschten Zeilen

Datei anzeigen

@@ -11,4 +11,8 @@ python-multipart
aiosmtplib aiosmtplib
geonamescache>=2.0 geonamescache>=2.0
telethon telethon
# Bericht-Export (PDF via WeasyPrint + DOCX via python-docx)
Jinja2>=3.1
weasyprint>=68.0
python-docx>=1.2
pikepdf>=9.0 pikepdf>=9.0

Datei anzeigen

@@ -26,10 +26,15 @@ LOGO_PATH = Path(__file__).parent / "static" / "favicon.svg"
FC_STATUS_LABELS = { FC_STATUS_LABELS = {
"confirmed": "Bestätigt", # 1:1 vom Monitor-Frontend (components.js) — konsistent zum UI.
"unconfirmed": "Unbestätigt", "confirmed": "Bestätigt",
"disputed": "Umstritten", "unconfirmed": "Unbestätigt",
"false": "Falsch", "contradicted": "Widerlegt",
"developing": "Unklar",
"established": "Gesichert",
"disputed": "Umstritten",
"unverified": "Ungeprüft",
"false": "Falsch", # Legacy-Fallback
} }
@@ -709,7 +714,7 @@ async def generate_pdf(
), ),
lagebild_timestamp=(incident.get("updated_at") or "")[:16].replace("T", " "), lagebild_timestamp=(incident.get("updated_at") or "")[:16].replace("T", " "),
sources=_prepare_sources(incident)[:30] if scope == "report" else _prepare_sources(incident), sources=_prepare_sources(incident)[:30] if scope == "report" else _prepare_sources(incident),
fact_checks=_prepare_fact_checks(fact_checks[:20] if scope == "report" else fact_checks), fact_checks=_prepare_fact_checks(fact_checks),
source_stats=_prepare_source_stats(articles)[:20] if scope == "report" else _prepare_source_stats(articles), source_stats=_prepare_source_stats(articles)[:20] if scope == "report" else _prepare_source_stats(articles),
timeline=_prepare_timeline(articles) if scope == "full" else [], timeline=_prepare_timeline(articles) if scope == "full" else [],
articles=articles if scope == "full" else [], articles=articles if scope == "full" else [],

Datei anzeigen

@@ -1165,8 +1165,18 @@ async def export_incident(
) )
snapshots = [dict(r) for r in await cursor.fetchall()] snapshots = [dict(r) for r in await cursor.fetchall()]
# Executive Summary (KI-generiert, gecacht) # Zusammenfassung fuer den Export:
exec_summary = incident.get("executive_summary") # - Bei Adhoc-Lagen primaer "Neueste Entwicklungen" (latest_developments) als Markdown-Bullets,
# weil Live-Monitoring von Aktualitaet lebt.
# - Fallback (oder bei Research): Executive Summary (KI-generiert, gecacht).
is_adhoc = (incident.get("type") or "adhoc") != "research"
latest_dev = (incident.get("latest_developments") or "").strip()
exec_summary = None
if is_adhoc and latest_dev:
from report_generator import _markdown_to_html as _md_to_html
exec_summary = _md_to_html(latest_dev)
if not exec_summary:
exec_summary = incident.get("executive_summary")
if not exec_summary: if not exec_summary:
summary_text = incident.get("summary") or "" summary_text = incident.get("summary") or ""
exec_summary = await generate_executive_summary(summary_text) exec_summary = await generate_executive_summary(summary_text)