From f471586f33b95f1918d043869aaa57876b93831f Mon Sep 17 00:00:00 2001 From: Dotty Dotter Date: Thu, 7 May 2026 11:01:18 +0200 Subject: [PATCH] =?UTF-8?q?feat(v3):=20Themen,=20Kernpunkte,=20Schwerpunkt?= =?UTF-8?q?,=20Konfidenz,=20fehlende=20Programme,=20Wahlperiode=20+=20?= =?UTF-8?q?=C3=84hnliche=20Antr=C3=A4ge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DB-Felder die bisher in der UI fehlten, jetzt in v3 sichtbar: - _row_to_detail() liefert themen, kernpunkte, schwerpunkt, link, konfidenz, fehlende_programme, wahlperiode an's Frontend. - _wahlperiode_silent() leitet die WP aus datum+bundesland ab via wahlperioden.wahlperiode_for() — silent-fail bei Lookup-Fehler. v3-Template: - Wahlperiode in der Antrag-ID-Zeile ("18. Wahlperiode") - Themen-Chips als Reihe unter byline - Kernforderungen als Bullet-Liste in der Zusammenfassungs-Sektion - Konfidenz-Pille (hoch/mittel/niedrig) neben der Empfehlung - Schwerpunkt-Felder (Top-Matrix-Cells) als Chips über der Matrix - Disclaimer "fehlende Programme" am Programm-Treue-Block - Original-PDF-Link im Aktions-Block - Ähnliche Anträge als eigener Block, geladen via JS aus /api/assessment/similar (Re-Use des bestehenden Endpoints aus #108) Co-Authored-By: Claude Opus 4.7 (1M context) --- app/main.py | 20 +++ app/static/v3/v3.css | 137 ++++++++++++++++++++ app/templates/v3/screens/antrag_detail.html | 88 ++++++++++++- 3 files changed, 240 insertions(+), 5 deletions(-) diff --git a/app/main.py b/app/main.py index d5e84a3..b416e6f 100644 --- a/app/main.py +++ b/app/main.py @@ -623,11 +623,31 @@ def _row_to_detail(row): "share_threads": row.get("share_threads"), "share_twitter": row.get("share_twitter"), "share_mastodon": row.get("share_mastodon"), + # Zusatzfelder fuer v3 (Bürger:innen-Modus): Themen-Tags, + # Kernforderungen, Top-Matrix-Felder, Original-PDF-Link, + # Bewertungs-Konfidenz, fehlende Programme, Wahlperiode. + "themen": row.get("themen") or [], + "kernpunkte": row.get("antrag_kernpunkte") or [], + "schwerpunkt": row.get("gwoe_schwerpunkt") or [], + "link": row.get("link") or "", + "konfidenz": row.get("konfidenz") or "", + "fehlende_programme": row.get("fehlende_programme") or [], + "wahlperiode": _wahlperiode_silent(row.get("datum", ""), row.get("bundesland", "")), # Roher ISO-Zeitstempel für OG-Cache-Key (#141) "updated_at_raw": row.get("updated_at", ""), } +def _wahlperiode_silent(datum: str, bundesland: str) -> str: + """Liefert die Wahlperiode zum Datum/Bundesland, oder leerer String wenn + das Lookup fehlschlaegt — UI-only, soll keinen Render-Fail ausloesen.""" + try: + from .wahlperioden import wahlperiode_for + return wahlperiode_for(datum, bundesland) or "" + except Exception: + return "" + + @app.post("/analyze") @limiter.limit("10/minute") async def start_analysis( diff --git a/app/static/v3/v3.css b/app/static/v3/v3.css index d060e13..39c4b69 100644 --- a/app/static/v3/v3.css +++ b/app/static/v3/v3.css @@ -637,3 +637,140 @@ .v3-empfehlung { font-size: 18px; } .v3-userrow { flex-direction: column; align-items: flex-start; } } + +/* ── Themen-Chips unter byline ───────────────────────────────────── */ +.v3-themen { + display: flex; + flex-wrap: wrap; + gap: 5px; + margin-top: 10px; +} +.v3-theme-chip { + font-family: var(--font-mono); + font-size: 11px; + padding: 2px 8px; + border: 1px solid var(--hairline); + border-radius: 2px; + background: var(--paper); + color: var(--ecg-dark); +} + +/* ── Kernpunkte-Liste in Zusammenfassung ─────────────────────────── */ +.v3-kernpunkte { + margin-top: 14px; + padding-top: 12px; + border-top: 1px dashed var(--hairline); +} +.v3-kernpunkte-label { + font-family: var(--font-mono); + font-size: 10px; + text-transform: uppercase; + letter-spacing: 0.07em; + color: var(--ecg-dark); + opacity: 0.6; + margin-bottom: 6px; +} +.v3-kernpunkte-list { + margin: 0; + padding-left: 18px; +} +.v3-kernpunkte-list li { + font-size: 13.5px; + line-height: 1.55; + margin-bottom: 4px; +} + +/* ── Konfidenz-Pille bei Empfehlung ──────────────────────────────── */ +.v3-empfehlung-wrap { + display: flex; + flex-direction: column; + gap: 4px; + flex: 1 1 auto; + min-width: 0; +} +.v3-konfidenz { + display: inline-block; + font-family: var(--font-mono); + font-size: 10px; + text-transform: uppercase; + letter-spacing: 0.05em; + padding: 1px 6px; + border-radius: 2px; + align-self: flex-start; +} +.v3-konfidenz-hoch { background: rgba(45, 164, 78, 0.12); color: #1a7f37; } +.v3-konfidenz-mittel { background: rgba(110, 119, 129, 0.12); color: #57606a; } +.v3-konfidenz-niedrig { background: rgba(207, 34, 46, 0.10); color: #a40e26; } + +/* ── Schwerpunkt-Felder vor Matrix ───────────────────────────────── */ +.v3-schwerpunkt { + margin-bottom: 10px; + font-family: var(--font-mono); + font-size: 11px; + color: var(--ecg-dark); + display: flex; + align-items: baseline; + gap: 6px; + flex-wrap: wrap; +} +.v3-schwerpunkt-label { + text-transform: uppercase; + letter-spacing: 0.07em; + opacity: 0.6; +} +.v3-schwerpunkt-chip { + padding: 1px 7px; + background: var(--ecg-blue); + color: #fff; + border-radius: 2px; + font-weight: 700; +} + +/* ── Disclaimer (fehlende Programme) ─────────────────────────────── */ +.v3-disclaimer { + margin-bottom: 12px; + padding: 8px 12px; + background: rgba(247, 148, 29, 0.08); + border-left: 3px solid #bf6c10; + border-radius: 2px; + font-size: 12.5px; + line-height: 1.55; + color: var(--ecg-dark); +} + +/* ── Ähnliche Anträge ────────────────────────────────────────────── */ +.v3-similar-item { + display: block; + padding: 10px 12px; + margin-bottom: 6px; + border: 1px solid var(--hairline); + border-radius: 3px; + background: var(--paper); + color: var(--ecg-dark); + text-decoration: none; +} +.v3-similar-item:hover { + border-color: var(--ecg-blue); + background: var(--surface); +} +.v3-similar-meta { + font-family: var(--font-mono); + font-size: 10px; + text-transform: uppercase; + letter-spacing: 0.05em; + color: var(--ecg-dark); + opacity: 0.65; + margin-bottom: 3px; +} +.v3-similar-title { + font-size: 13.5px; + line-height: 1.4; + font-weight: 600; + color: var(--ecg-dark); + margin-bottom: 3px; +} +.v3-similar-score { + font-family: var(--font-mono); + font-size: 11px; + color: var(--ecg-blue); +} diff --git a/app/templates/v3/screens/antrag_detail.html b/app/templates/v3/screens/antrag_detail.html index e0872db..99a6685 100644 --- a/app/templates/v3/screens/antrag_detail.html +++ b/app/templates/v3/screens/antrag_detail.html @@ -53,6 +53,7 @@ {{ antrag.bundesland | default("") }} {% if antrag.drucksache %} · Drs. {{ antrag.drucksache }}{% endif %} {% if antrag.typ %} · {{ antrag.typ }}{% endif %} + {% if antrag.wahlperiode %} · {{ antrag.wahlperiode }}. Wahlperiode{% endif %} {% if antrag.datum %} · eingebracht {{ antrag.datum }}{% endif %}

{{ antrag.title | default("Antrag") }}

@@ -64,13 +65,28 @@ {% if antrag.zitate_count %} · {{ antrag.zitate_count }} Zitat{{ "e" if antrag.zitate_count != 1 else "" }} verifiziert{% endif %} {% endif %} + {% if antrag.themen %} +
+ {% for t in antrag.themen %}{{ t }}{% endfor %} +
+ {% endif %} - {# 2 ── Zusammenfassung ───────────────────────────────────────────── #} - {% if antrag.zusammenfassung %} + {# 2 ── Zusammenfassung + Kernpunkte ─────────────────────────────── #} + {% if antrag.zusammenfassung or antrag.kernpunkte %}

Zusammenfassung

+ {% if antrag.zusammenfassung %}

{{ antrag.zusammenfassung }}

+ {% endif %} + {% if antrag.kernpunkte %} +
+
Kernforderungen
+
    + {% for kp in antrag.kernpunkte %}
  • {{ kp }}
  • {% endfor %} +
+
+ {% endif %}
{% endif %} @@ -82,9 +98,17 @@ {{ "%.1f"|format(s) }}/10 {% if antrag.verdict_title %} -
- {{ antrag.verdict_title }} +
+
+ {{ antrag.verdict_title }} +
+ {% if antrag.konfidenz %} + + Konfidenz: {{ antrag.konfidenz }} + + {% endif %}
{% endif %}
@@ -116,6 +140,12 @@ {% if antrag.matrix %}

Matrix 2.0 · 25 Felder

+ {% if antrag.schwerpunkt %} +
+ Schwerpunkt-Felder: + {% for f in antrag.schwerpunkt %}{{ f }}{% endfor %} +
+ {% endif %} {{ matrix_mini(antrag.matrix) }}
{% endif %} @@ -124,6 +154,12 @@ {% if antrag.fraktions_scores %}

Programm-Treue pro Fraktion

+ {% if antrag.fehlende_programme %} +
+ Hinweis: Für folgende Parteien lag kein Wahl-/Parteiprogramm vor — keine Treue-Bewertung möglich: + {{ antrag.fehlende_programme | join(", ") }}. +
+ {% endif %}
{% for fs in antrag.fraktions_scores %}
@@ -276,10 +312,21 @@ {# 9a Aktions-Links #}
PDF-Bericht + {% if antrag.link %} + Original-Antrag (Landtag) + {% endif %} JSON-Export Permalink
+ {# 9a' Ähnliche Anträge — per JS via /api/assessment/similar geladen #} +
+

Ähnliche Anträge

+
+ Lade … +
+
+ {# 9b Teilen #}

Teilen

@@ -453,5 +500,36 @@ bar.appendChild(pill); bar.appendChild(toggle); })(); + +/* Ähnliche Anträge: /api/assessment/similar?drucksache=…&top_k=5 */ +(async function () { + var box = document.getElementById('v3-similar-box'); + if (!box) return; + var drs = box.dataset.drucksache; + var list = document.getElementById('v3-similar-list'); + try { + var resp = await fetch('/api/assessment/similar?drucksache=' + encodeURIComponent(drs) + '&top_k=5'); + var data = await resp.json(); + var items = (data && data.results) || data || []; + if (!Array.isArray(items) || items.length === 0) { + list.innerHTML = 'Keine ähnlichen Anträge gefunden.'; + return; + } + list.innerHTML = items.map(function (it) { + var sim = (it.similarity != null) ? Math.round(it.similarity * 100) + '%' : ''; + var bl = it.bundesland || ''; + var drs = it.drucksache || ''; + var title = it.title || ''; + var score = (it.gwoe_score != null) ? it.gwoe_score.toFixed(1) : ''; + return '' + + '
' + bl + (drs ? ' · Drs. ' + drs : '') + (sim ? ' · ' + sim + ' ähnlich' : '') + '
' + + '
' + title + '
' + + (score ? '
Score ' + score + '/10
' : '') + + '
'; + }).join(''); + } catch (e) { + list.innerHTML = 'Konnte ähnliche Anträge nicht laden.'; + } +})(); {% endblock %}