GWÖ-Antragsprüfer: Automatische Gemeinwohl-Bilanzierung von Parlamentsanträgen nach der GWÖ-Matrix 2.0
Go to file
Dotty Dotter b76c08d92e Sub-D Citation-Test: PDF-Bindestrich + Token-Resolver + Anker-Match
Erster Live-Run von Sub-Issue D gegen die Prod-DB im Container hat 15 von
39 Citation-Tests fehlschlagen lassen. Detail-Analyse: 12 davon waren
Test-False-Positives (zwei Schichten von Brittleness im Test selbst), 3
sind echte LLM-Halluzinationen.

Drei Härtungen am Test-Resolver, damit er nur noch echte Halluzinationen
fängt:

1. **PDF-Bindestrich-Bridging in `_normalize`**:
   PyMuPDF zerlegt Wörter über Zeilenumbrüche mit `-\n`. Nach unserer
   Whitespace-Normalisierung wird daraus `- `, sodass aus
   "Investitionsoffensive" im LLM-Snippet das PDF "investiti- onsoffensive"
   gegenübersteht. Neue Regex `_RE_HYPHEN_BREAK` bridged das in einem
   Konvergenz-Loop, damit auch mehrere aufeinanderfolgende Wort-Wraps
   sauber verschmelzen.

2. **Token-Coverage-Resolver in `_resolve_quelle_to_programm_id`**:
   Zwei-stufig — erst die alte strict-substring-Strategie (deckt
   Adapter-konformes LLM-Output), dann ein Token-Coverage-Fallback. Der
   zerlegt jeden PROGRAMME-Namen in (Partei + Bundesland + Jahr) mit
   Aliasen (GRÜNE/Bündnis 90, LSA/Sachsen-Anhalt, …) und akzeptiert
   eine Quelle, wenn alle drei Tokens in irgendeiner Reihenfolge in der
   Quelle vorkommen. Fängt damit z.B. "Landtagswahlprogramm 2021 BÜNDNIS
   90/DIE GRÜNEN Sachsen-Anhalt" → `gruene-lsa-2021`, ohne dass die LLM
   den exakten Adapter-Label-Wortlaut treffen muss.

3. **Anker-Match-Fallback in `_is_substring`**:
   Ein 200-Zeichen-Snippet, das nur in einem Wort kürzt, scheitert sonst
   am Volltext-Substring-Check. Neuer Anker-Match zerlegt den Snippet
   in 5-Wort-Sequenzen und akzeptiert, wenn mindestens eine wortwörtlich
   im Seitentext steht. Erfundene Snippets haben keine 5-Wort-Sequenz,
   die wortwörtlich im PDF steht — die false-negative-Rate für echte
   Halluzinationen bleibt damit bei 0.

Live-Run nach dem Patch: **15 → 3 Failures** (39 Cases, 24 → 36 grüne).
Die verbleibenden 3 sind echte LLM-Bugs:

- 18/9605 NRW GRÜNE S.58 ('Wahlalter auf 16/14 absenken') — Snippet
  und PDF-Seite zeigen komplett andere Themen, das LLM hat die Seite
  oder den Snippet erfunden
- 18/18100 NRW B90/Grüne S.36 (Grundsatzprogramm 2020, Plattform-
  Regulierung)
- 8/6645 LSA SPD S.37 ('Wir Sozialdemokratinnen ächten ...') — PDF
  S.37 enthält dort Zweitstudiengebühren-Text

Diese drei werden als separates LLM-Bug-Issue erfasst.

13 Helper-Unit-Tests bleiben grün.

Refs: #54, #59 (Sub-D Live-Verifikation)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 11:36:02 +02:00
app Phase E (substituted): Auswertungen-Drilldown-Modal (#59) 2026-04-09 11:30:10 +02:00
tests Sub-D Citation-Test: PDF-Bindestrich + Token-Resolver + Anker-Match 2026-04-09 11:36:02 +02:00
.dockerignore Initial commit: GWÖ-Antragsprüfer v1.0 2026-03-28 22:30:24 +01:00
.env.example Initial commit: GWÖ-Antragsprüfer v1.0 2026-03-28 22:30:24 +01:00
.gitignore Initial commit: GWÖ-Antragsprüfer v1.0 2026-03-28 22:30:24 +01:00
.tarignore Initial commit: GWÖ-Antragsprüfer v1.0 2026-03-28 22:30:24 +01:00
docker-compose.yml Initial commit: GWÖ-Antragsprüfer v1.0 2026-03-28 22:30:24 +01:00
Dockerfile Initial commit: GWÖ-Antragsprüfer v1.0 2026-03-28 22:30:24 +01:00
LICENSE Initial commit: GWÖ-Antragsprüfer v1.0 2026-03-28 22:30:24 +01:00
pytest.ini Add E2E functional acceptance test suite (#50, #51, #52, #53, #54) 2026-04-09 10:00:20 +02:00
README.md Initial commit: GWÖ-Antragsprüfer v1.0 2026-03-28 22:30:24 +01:00
requirements-dev.txt Add pytest suite + fix two regex bugs uncovered by it (#46) 2026-04-08 23:26:06 +02:00
requirements.txt Security hotfixes #1, #2, #6 from audit (#57) 2026-04-09 10:45:43 +02:00

GWÖ-Antragsprüfer

Automatische Gemeinwohl-Bilanzierung von Parlamentsanträgen nach der GWÖ-Matrix 2.0 für Gemeinden

Python FastAPI License

🎯 Was ist das?

Der GWÖ-Antragsprüfer analysiert Anträge aus Landesparlamenten (aktuell NRW) und bewertet sie nach den Kriterien der Gemeinwohl-Ökonomie (GWÖ):

  • GWÖ-Score (0-10): Wie gut entspricht der Antrag den GWÖ-Werten?
  • Matrix-Zuordnung: Welche Felder der GWÖ-Matrix werden adressiert?
  • Programmtreue: Passt der Antrag zu Wahl- und Parteiprogrammen?
  • Verbesserungsvorschläge: Konkrete Textänderungen mit GWÖ-Begründung

Features

  • 🔍 Landtag-Suche: Direkte Anbindung an OPAL (NRW Parlamentsdokumentation)
  • 📊 GWÖ-Matrix-Visualisierung: 5×5-Tabelle mit Bewertungssymbolen
  • 🏷️ Tag-Wolke: Filter nach Themen mit Multi-Select
  • 🎯 Partei-Filter: Durchschnittswerte pro Fraktion
  • 📄 PDF-Export: Professionelle Berichte im GWÖ-Design
  • 🔒 Security: CSP, CORS, Rate Limiting

🚀 Schnellstart

Voraussetzungen

  • Python 3.12+
  • Docker & Docker Compose
  • DashScope API-Key (Qwen LLM)

Installation

# Repository klonen
git clone https://github.com/tobiasroedel/gwoe-antragspruefer.git
cd gwoe-antragspruefer

# Environment-Variablen
cp .env.example .env
# DASHSCOPE_API_KEY eintragen

# Mit Docker starten
docker compose up -d

# Oder lokal entwickeln
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --reload

Die App läuft auf http://localhost:8000

📁 Projektstruktur

webapp/
├── app/
│   ├── main.py           # FastAPI-Endpoints
│   ├── analyzer.py       # LLM-Analyse-Logik
│   ├── database.py       # SQLite-Persistenz
│   ├── models.py         # Pydantic-Modelle
│   ├── parlamente.py     # Landtag-Adapter (OPAL)
│   ├── report.py         # PDF-Generierung
│   ├── config.py         # Settings
│   ├── kontext/          # GWÖ-Matrix, Wahlprogramme
│   ├── templates/        # Jinja2-HTML
│   └── static/           # CSS, JS, Assets
├── data/                 # SQLite-DBs (Volume)
├── reports/              # Generierte PDFs (Volume)
├── docker-compose.yml
├── Dockerfile
└── requirements.txt

🔧 Konfiguration

Environment-Variablen

Variable Beschreibung Default
DASHSCOPE_API_KEY Alibaba DashScope API-Key (required)
LLM_MODEL_DEFAULT Standard-Modell qwen-plus-latest
LLM_MODEL_PREMIUM Premium-Modell qwen-max

Unterstützte Bundesländer

Code Name Status
NRW Nordrhein-Westfalen Aktiv
BY Bayern 🔜 Geplant
BW Baden-Württemberg 🔜 Geplant

📊 API-Endpoints

Methode Pfad Beschreibung
GET / Web-UI
GET /api/assessments Alle Bewertungen
GET /api/assessment?drucksache=18/12345 Einzelne Bewertung
POST /api/analyze-drucksache Neue Analyse starten
GET /api/search?q=Klima Interne Suche
GET /api/search-landtag?q=Klima Landtag-Suche
GET /api/assessment/pdf?drucksache=18/12345 PDF-Download

🧠 GWÖ-Prompt (v5)

Der Analyse-Prompt basiert auf:

  • GWÖ-Matrix 2.0 für Gemeinden (Arbeitsbuch)
  • ECOnGOOD Corporate Design Manual 2024
  • Wahlprogramme der NRW-Landtagsparteien 2022

Ausgabe-Format:

  • GWÖ-Score mit Matrix-Feldern und Symbolen (++/+/○//)
  • Wahlprogramm- und Parteiprogrammtreue
  • Verbesserungsvorschläge im Redline-Format (Original → Vorschlag → Begründung)
  • Themen-Tags für Kategorisierung

🛠️ Entwicklung

# Tests ausführen
pytest

# Linting
ruff check app/

# Type-Checking
mypy app/

📝 Lizenz

MIT License - siehe LICENSE

🙏 Credits


Entwickelt von Tobias Rödel · tobiasroedel.de