Export: Zusammenfassung-Sektion, Checkbox-Auswahl, neue Reihenfolge

Research-Briefings:
- Neue Sektion ZUSAMMENFASSUNG mit Bullet-Points als erstes Element
- UEBERBLICK entfernt, durch ZUSAMMENFASSUNG ersetzt
- Inkrementelles Briefing ebenfalls angepasst

Export-System:
- Zusammenfassung wird direkt aus dem Bericht extrahiert (kein
  separater KI-Aufruf mehr fuer Research-Lagen)
- Reihenfolge: Zusammenfassung > Recherchebericht > Faktencheck > Quellen > Timeline
- Sections-basiert statt scope-basiert (rueckwaertskompatibel)
- Checkbox-Dialog statt Radio-Buttons im Frontend
- Bereiche: Zusammenfassung, Recherchebericht, Faktencheck, Quellen, Timeline, Karte
- PDF und DOCX Templates angepasst
- Backend akzeptiert sections-Parameter (kommagetrennt)
Dieser Commit ist enthalten in:
claude-dev
2026-04-11 20:56:04 +00:00
Ursprung 89cc920bdc
Commit fa12d4cfd6
7 geänderte Dateien mit 188 neuen und 66 gelöschten Zeilen

Datei anzeigen

@@ -713,12 +713,21 @@ async def export_incident(
incident_id: int,
format: str = Query("pdf", pattern="^(pdf|docx)$"),
scope: str = Query("report", pattern="^(summary|report|full)$"),
sections: str = Query(None),
current_user: dict = Depends(get_current_user),
db: aiosqlite.Connection = Depends(db_dependency),
):
"""Lage als PDF oder Word exportieren."""
from report_generator import generate_pdf, generate_docx, generate_executive_summary
# Sections aus Komma-getrenntem String parsen
VALID_SECTIONS = {"zusammenfassung", "bericht", "faktencheck", "quellen", "timeline", "karte"}
sections_set = None
if sections:
sections_set = {s.strip() for s in sections.split(",") if s.strip() in VALID_SECTIONS}
if not sections_set:
sections_set = None
tenant_id = current_user.get("tenant_id")
row = await _check_incident_access(db, incident_id, current_user["id"], tenant_id)
incident = dict(row)
@@ -765,18 +774,28 @@ async def export_incident(
date_str = datetime.now(TIMEZONE).strftime("%Y%m%d")
slug = _slugify(incident["title"])
scope_labels = {"summary": "executive_summary", "report": "lagebericht", "full": "vollstaendig"}
# Wenn sections explizit angegeben, passenden Label waehlen
if sections_set:
if sections_set == {"zusammenfassung"}:
scope_labels_key = "executive_summary"
elif "timeline" in sections_set:
scope_labels_key = "vollstaendig"
else:
scope_labels_key = "lagebericht"
else:
scope_labels_key = scope_labels.get(scope, "lagebericht")
if format == "pdf":
pdf_bytes = await generate_pdf(incident, articles, fact_checks, snapshots, scope, creator, exec_summary)
filename = f"{slug}_{scope_labels[scope]}_{date_str}.pdf"
pdf_bytes = await generate_pdf(incident, articles, fact_checks, snapshots, scope, creator, exec_summary, sections=sections_set)
filename = f"{slug}_{scope_labels_key}_{date_str}.pdf"
return StreamingResponse(
io.BytesIO(pdf_bytes),
media_type="application/pdf",
headers={"Content-Disposition": f'attachment; filename="{filename}"'},
)
else:
docx_bytes = await generate_docx(incident, articles, fact_checks, snapshots, scope, creator, exec_summary)
filename = f"{slug}_{scope_labels[scope]}_{date_str}.docx"
docx_bytes = await generate_docx(incident, articles, fact_checks, snapshots, scope, creator, exec_summary, sections=sections_set)
filename = f"{slug}_{scope_labels_key}_{date_str}.docx"
return StreamingResponse(
io.BytesIO(docx_bytes),
media_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document",