GWÖ-Antragsprüfer: Automatische Gemeinwohl-Bilanzierung von Parlamentsanträgen nach der GWÖ-Matrix 2.0
Go to file
Dotty Dotter c7242f8413 Add PortalaAdapter for PADOKA / Sachsen-Anhalt (#2)
Adds a clean-room PortalaAdapter that talks to the eUI/portala framework
behind PADOKA (Landtag Sachsen-Anhalt). Same engine powers Berlin's
PARDOK; the same adapter will serve issue #3 once activated for BE.

Reverse-engineering notes
- The "PADOKA = StarWeb" assumption from issue #1 / dokukratie's st.yml
  is outdated. The Sachsen-Anhalt portal was migrated to the same
  eUI/portala SPA framework Berlin uses. The legacy starweb URL returns
  503; the new entry point is /portal/browse.tt.html.
- Search workflow is two-stage:
  1. POST /portal/browse.tt.json with a JSON action body containing an
     Elasticsearch-style query tree under search.json. Returns a
     report_id plus hit count.
  2. POST /portal/report.tt.html with {report_id, start, chunksize}
     returns the HTML hit list. Each record carries a Perl Data::Dumper
     block in a <pre> tag with the canonical metadata.
- The query schema (sources, search.lines, search.json tree, report
  block) is taken from dokukratie/scrapers/portala.query.json (GPL-3.0)
  — only structure/selectors are reused, no Python code is ported.
- DB id is "lsa.lissh"; the server validates this and rejects unknown
  interfaces with an explicit errormsg.
- PDFs live under /files/drs/wp{N}/drs/d{nr}{xxx}.pdf and are served
  directly without any session cookie.

What the adapter does
- search() builds a date-window query (last ~24 months) for "Antrag"
  document type and returns the most recent hits. The user's free-text
  query is applied as a client-side title/Urheber filter (no fulltext
  search server-side yet — see "Limitations" below).
- Hits are parsed from the Perl record dumps in the report HTML:
  - WEV06.main → title (Perl \x{xx} hex escapes decoded)
  - WEV32.5   → relative PDF path
  - WEV32.main → "Antrag <Urheber> <DD.MM.YYYY> Drucksache <b>X/YYYY</b>"
- Fraktion strings are normalised to canonical codes (CDU, SPD, GRÜNE,
  FDP, AfD, LINKE, Landesregierung).
- get_document() looks up a single Drucksache by re-running the search.
- download_text() fetches the PDF and extracts text via PyMuPDF.
- bundeslaender.py: LSA's doku_system corrected from "StarWeb" to
  "PARDOK", anmerkung updated with the migration story.

Limitations (deliberate, MVP)
- No server-side full-text search. The portala framework's sf index
  names for LSA full-text content are not yet known; tree mutations
  with sf=alAB return 0 hits. Client-side filter is "good enough" for
  the next ~24 months of Anträge (≈few hundred per WP).
- LSA is still aktiv=False in bundeslaender.py — the adapter is dormant
  in production until issue #2's wahlprogramm ingest and frontend
  activation land.

Verified live against padoka.landtag.sachsen-anhalt.de:
- search(query="", limit=5) returned 5 current Anträge from März 2026
  (LINKE + GRÜNE) with correct dates, fractions, titles and PDF URLs.
- download_text("8/6790") returned 5051 chars of real Antragstext
  ("ICE-Halt für Salzwedel dauerhaft erhalten").

Refs #2.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 21:50:23 +02:00
app Add PortalaAdapter for PADOKA / Sachsen-Anhalt (#2) 2026-04-07 21:50:23 +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
README.md Initial commit: GWÖ-Antragsprüfer v1.0 2026-03-28 22:30:24 +01:00
requirements.txt Initial commit: GWÖ-Antragsprüfer v1.0 2026-03-28 22:30:24 +01: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