Skip to content

ma3u/hackathon-spark

Repository files navigation

🎙️ graph-protokoll — vom Sitzungsmitschnitt zum prüfbaren Protokoll-Graphen

SPARK-Hackathon Challenge 2 „Da geht noch mehr!" — Prototyp. Eine neue Verwaltungs-/Parlamentsleistung jenseits von Planungs- und Genehmigungsverfahren: Aus dem Audiomitschnitt einer Gremiensitzung (Gemeinderat, Ausschuss, Bundestag, Anhörung) entsteht automatisch ein strukturiertes, durchsuchbares, rechtssicher belegbares Protokoll als Knowledge Graph mit GraphRAG — inklusive Faktencheck politischer Aussagen.

GraphRAG Faktencheck Szenarien DSGVO License

🏛️ Für die Jury — graph-protokoll in 60 Sekunden

Problem. Parlaments- und Gremienprotokolle sind lange, unstrukturierte Textmassen. Wer wissen will „Welcher Beschluss mit welchem Ergebnis?", „Wer war befangen — nach welcher Norm?" oder „Stimmt diese Zahl?", sucht sich tot. Suchen allein reicht nicht — man muss Zusammenhänge sehen und jede Aussage belegen können.

Warum wir SPARK weiterdenken. Das BMDS-Referenzprojekt SPARK beschleunigt Planungs- und Genehmigungsverfahren mit KI über Dokumente + Vektorsuche. Challenge 2 fragt „Da geht noch mehr!". Wir übertragen die KI-Bausteine auf eine neue Leistung — das Protokoll selbst — und ergänzen SPARK um zwei Bausteine, die es nicht hat: Sprache/Video als Eingabe und einen Wissensgraph mit Faktencheck und lückenloser Quelle.

Warum dieser Use Case. Bundestags-Plenarprotokolle sind öffentlich/gemeinfrei, hochrelevant und mehrhop-strukturiert (Antrag→Abstimmung→Beschluss; Person→Befangenheit→Norm). Genau dort schlägt ein Knowledge Graph die reine Volltext-/Vektorsuche.

Die Lösung. Aus einem Audio-/Video-Mitschnitt oder dem amtlichen XML entsteht automatisch ein durchsuchbarer, rechtssicher belegbarer Wissensgraph mit Faktencheck — jede Aussage ist per Klick im Video an der richtigen Sekunde nachprüfbar. 81 echte Bundestagssitzungen sind geladen; KI-Faktencheck-Vorschläge sind als solche markiert und werden von Menschen freigegeben (kein Urteil per Knopfdruck).

3D-Wissensgraph je Sitzung Aggregat-Dashboard (alle Sitzungen) Eingebetteter Video-Beleg
3D-Wissensgraph Aggregat-Dashboard Video-Beleg
Personen · Reden · Beschlüsse · Saalreaktionen · Faktenchecks — farbig nach Bedeutung; Knoten anklicken zeigt den Faktencheck rechts Themen, Redezeit, Faktencheck-Bilanz, Schlagabtausch & Fun Facts über alle Sitzungen Klick auf einen Faktencheck → Rede im Video, Start an der belegten Sekunde

▶ Live ausprobieren: https://ma3u.github.io/hackathon-spark/ — Sitzung wählen, Knoten anklicken, Quelle umschalten (🟢 amtlich ↔ 🎬 YouTube), 📈 Gesamt-Dashboard öffnen. Ohne Login.

Technische Details, Architektur, Datenquellen und Reproduktion: weiter unten ↓


Aktueller Stand (2026-06-11) — echte Daten. Alle 81 WP21-Plenarprotokolle + WP20/214 sind in Neo4j geladen (~136 k Knoten / ~361 k Beziehungen). Die Pages-App bietet 82 reale Sitzungen zur Auswahl mit Quellen-Umschalter 🟢 Offiziell (amtliches XML + Mediathek-Video-Deeplink je Rede) ↔ 🎬 YouTube (Gesamtmitschnitt, Zeit-Deeplinks). Faktencheck über reale Reden via In-Kontext-LLM- Extraktion → variierte Verdikte (bestätigt/teilweise/irreführend/falsch/unbelegt) als KI-Vorschlag mit Disclaimer; optional Retrieval-Grounding (DIP-API + Wikipedia) mit echter Quelle. Inkrementeller Import: python scripts/sync_sessions.py --all --load. Fortschritt/Plan: docs/challenge-plan.md. Live: https://ma3u.github.io/hackathon-spark/

Dep-freie Demo-Szenarien (fiktiv, für CI/offline): Gemeinderat und Bundestag (fiktive Plenardebatte) — laufen ohne pip/GPU/Netz und treiben den CI-Smoke-Test; in der Web-Oberfläche werden nur reale Sitzungen gezeigt. SPARK-Nutzung, Echtdaten-Wege und die Faktencheck-Grenzen: docs/spark-und-echtdaten.md. Analyse der Bundestags-Protokollierung & des Faktenchecks: docs/bundestag-protokollierung-analyse.md.


Schnellstart (läuft ohne GPU, Modelle oder Netz)

python3 run_demo.py                      # beide Szenarien
python3 run_demo.py --scenario bundestag # nur Bundestag + Faktencheck

Die Demo verarbeitet zwei mitgelieferte, fiktive Mitschnitte (Gemeinderat Musterbach; fiktive Bundestags-Plenardebatte), baut je einen Graphen und beantwortet GraphRAG-Fragen — jede Antwort mit Audio-Zeitstempel als Beleg. Pro Szenario landen Artefakte in output/ (SPARK-Datenformat) und in web/data/ (für GitHub Pages):

Datei (<scenario> = gemeinderat | bundestag) Zweck
<scenario>_graph_data.json Graph ({metadata, nodes, relationships})
<scenario>_nodes.csv / _relationships.csv Neo4j-Bulk-Import
<scenario>_neo4j_import.cypher Idempotenter MERGE-Import

Echtes Audio:

pip install -r requirements.txt
python3 run_demo.py --audio pfad/zur/sitzung.mp3

Wie analysiert man Audio? (die Pipeline)

  🎙️ Audio (mp3/wav)
        │
        ▼
  ┌─────────────┐   faster-whisper large-v3, language="de", word_timestamps,
  │  ASR        │   VAD-Filter (Stille/Applaus raus)            → Wörter + Zeiten
  └─────────────┘   pipeline/asr.py
        │
        ▼
  ┌─────────────┐   pyannote/speaker-diarization-3.1
  │ Diarisierung│   "wer spricht wann?"                          → Sprecher-Turns
  └─────────────┘   pipeline/diarize.py
        │
        ▼
  ┌─────────────┐   WhisperX forced alignment: jedes Wort dem
  │ Alignment   │   überlappenden Sprecher-Turn zuordnen, zu     → Utterances
  └─────────────┘   Redebeiträgen bündeln   pipeline/align.py    (Sprecher+Text+Zeit)
        │           Sprecher-Label → Person via Enrollment/Rednerliste
        ▼
  ┌─────────────┐   Lokales LLM (vLLM/Ollama), JSON-Schema-Constraint:
  │ Extraktion  │   TOPs · Anträge · Abstimmungen · Beschlüsse · → Protocol
  └─────────────┘   Befangenheiten · Aufgaben   pipeline/extract.py
        │           jede Aussage trägt ihre Quell-Segment-Indizes
        ▼
  ┌─────────────┐   Vier-Schichten-Ontologie + Provenienzkanten
  │ Graph       │   pipeline/graph_build.py                      → Neo4j-Graph
  └─────────────┘
        │
        ▼
  ┌─────────────┐   Mehrhop-Abfragen mit Audio-Beleg
  │ GraphRAG    │   pipeline/graphrag.py                         → Antworten + Zitate
  └─────────────┘

Drei Audio-spezifische Knackpunkte (Hackathon-relevant):

  1. Diarisierung ≠ Identifikation. pyannote liefert anonyme Labels (SPEAKER_00…). Die Zuordnung zu echten Personen kommt aus einem Voice-Enrollment beim Namensaufruf oder aus der Rednerliste — gekapselt in speaker_map. Stimmprofile sind biometrische Daten (Art. 9 DSGVO): Embeddings nur mit Rechtsgrundlage speichern, sonst pro Sitzung verwerfen.
  2. Provenienz bis zur Sekunde. Jeder extrahierte Beschluss/jede Abstimmung verweist per BELEGT_DURCH auf das Transkriptsegment mit start_sec/end_sec. Im Streit­fall ist die Aussage per Klick im Audio nachhörbar — das macht aus einer KI-Zusammenfassung ein justiziables Protokoll.
  3. On-prem statt Cloud. Whisper + pyannote + lokales LLM laufen vollständig im Behördennetz. Keine Sitzungsstimmen verlassen das Haus.

Warum GraphRAG statt Vektor-RAG?

Protokollfragen sind mehrhop und strukturiert — genau dort versagt ein Embedding-Index über Textchunks:

Frage Graph-Traversierung
„Welche Beschlüsse mit welchem Ergebnis?" Beschluss ←FUEHRT_ZU← Abstimmung (Ja/Nein/Enthaltung)
„Wie war die Abstimmung zum Bücherbus?" TOP →ENTSCHIEDEN_DURCH→ Abstimmung →…→ Beschluss
„Wer war befangen — nach welcher Norm?" Person →BEFANGEN_BEI→ TOP, Person →BEFANGENHEIT_NACH→ Norm §18
„Welche Aufgabe, wer zuständig, welche Frist?" Beschluss →ERZEUGT_AUFGABE→ Aufgabe
„Beleg im Audio?" * →BELEGT_DURCH→ Transkriptsegment.start_sec

Beispielausgabe (gekürzt):

❓ Welche Beschlüsse wurden gefasst?
📋 • Beschluss 2026-014: Online-Terminsystem … — Abstimmung 7:0:1 (angenommen)
     ↳ Audiobeleg [01:44] Dr. Petra Hoffmann: „Damit ist Beschluss 2026-014 gefasst…"
   • Beschluss 2026-015: Anschaffung Bücherbus … — Abstimmung 5:2:0 (angenommen)
     ↳ Audiobeleg [03:56] Dr. Petra Hoffmann: „Beschluss 2026-015: Die Anschaffung…"

Vier-Schichten-Ontologie (wie in den Schwester-Prototypen)

Schicht Knotentypen Beispiel
L1 Normativ Norm GemO §37 (Beschlussfähigkeit), §18 (Befangenheit)
L2 Zeitlich Sitzung, Fristen an Aufgabe Sitzung 12.05.2026; Frist 09.06.2026
L3 Prozedural Tagesordnungspunkt → Antrag → Abstimmung → Beschluss → Aufgabe TOP 3 → Antrag → 5:2:0 → Beschluss 2026-015
L4 Fallbezug Person, Fraktion, Redebeitrag Klaus Brandt (GRÜN-Liste), Redebeitrag zu TOP 2
L4 Fallbezug Aussage (prüfbare Behauptung), Frage „über 150.000 Ladepunkte"
+ Faktencheck Faktencheck (Verdikt), Quelle irreführend · Ladesäulenregister
+ Provenienz Transkriptsegment Segment [03:56], start_sec, audio_file

Faktencheck (Bundestag-Szenario)

Prüfbare Aussagen aus Reden → Verdikt + Quelle + Audio-Beleg. Konzept, Verdikt-Skala und Grenzen: docs/bundestag-protokollierung-analyse.md.

🔎 Faktencheck der Reden:
• [irreführend] „über 150.000 öffentliche Ladepunkte" — Stefan Möller
    belegt: ~121.000 · Quelle: Ladesäulenregister (Stand 2026-04)   ↳ [00:18]
• [falsch]      „seit 2021 nicht erhöht" — Dr. Lena Vossberg
    mehr als verdoppelt (50.000 → 121.000)                          ↳ [00:47]
• [unbelegt]    „über 40 % der Ladesäulen defekt" — keine Evidenz   ↳ [01:44]

Graph: Aussage →GEPRUEFT_ALS→ Faktencheck →BELEGT_MIT→ Quelle (+ BELEGT_DURCH → Transkriptsegment).


GitHub Pages (interaktiver 3D-Graph + Faktencheck-Panel)

web/index.html ist eine statische Single-File-App (3d-force-graph via CDN), die web/data/<scenario>.json lädt — Szenario-Umschalter, Detail-Panel, Faktencheck-Liste, Audio-Deep-Links auf Transkriptsegment.

Lokal starten (nur Python-Stdlib, kein Build-Schritt):

python3 run_demo.py --no-queries        # web/data/*.json (neu) erzeugen — bei stale Daten
python3 -m http.server -d web 8000      # statischen Server starten
# → Browser öffnen: http://localhost:8000   ·   Stoppen: Strg-C

Der Server liefert nur die statischen Dateien aus web/ aus (kein Backend). Sind die Daten im UI veraltet oder leer, zuerst run_demo.py --no-queries laufen lassen, dann neu laden.

Deploy: Der Workflow .github/workflows/pages.yml baut die Daten und publiziert web/ automatisch. Eigenständiges Repo + Pages mit einem Befehl:

./scripts/publish-to-github.sh hackathon-spark   # braucht `gh auth login`
# → https://ma3u.github.io/hackathon-spark/

Amtliches Plenarprotokoll → Neo4j → GraphRAG → Dashboard

Echte Bundestagsdaten brauchen kein Audio: das amtliche Plenarprotokoll-XML (DTD dbtplenarprotokoll, ab WP19) wird direkt geparst — inklusive der <kommentar>-Saalreaktionen (Beifall/Zwischenruf/Lachen/Widerspruch = Jubel/Buhrufe, amtlich annotiert). Mitgeliefert ist eine echte Sitzung (data/real/plenarprotokoll-20-214.xml, gemeinfrei) — Szenario „Bundestag (echt)".

# Echtes mitgeliefertes Protokoll (ohne Faktencheck über reale Personen):
python ingest_bundestag.py --xml data/real/plenarprotokoll-20-214.xml \
    --name bundestag_real --no-factcheck

# Eigene Sitzung ziehen + verarbeiten:
# 1) Offizielle Quellen einer Sitzung ziehen (auf deiner Maschine):
./scripts/fetch-session.sh 21 81            # Open-Data-XML + DIP-API + YouTube-Audio
# 2) Parsen → Graph + Faktencheck + Dashboard, dry-run Neo4j:
python ingest_bundestag.py --xml data/incoming/21-081/21081.xml
# 3) Neo4j starten und echt laden:
docker compose -f docker-compose.neo4j.yml up -d
python ingest_bundestag.py --xml data/incoming/21-081/21081.xml --load

Neo4j-Import (pipeline/neo4j_loader.py): idempotente, parametrisierte MERGE über den offiziellen neo4j-Driver (kein String-Interpolieren).

Neo4j-GraphRAG (pipeline/neo4j_graphrag.py): die offizielle neo4j-graphrag-Bibliothek mit Text2Cypher — natürliche Frage → schema-gestützter Cypher → Neo4j → Antwort (LLM on-prem via Ollama/vLLM). Faktencheck-Fragen liefern per Few-Shot immer Verdikt + Quelle.

python -m pipeline.neo4j_graphrag "Welche Aussagen sind falsch — mit Quelle?"

Dashboard pro Sitzung (pipeline/dashboard.pyweb/data/*_dashboard.json, im Pages-UI über „📊 Dashboard"): Top-Themen nach Redevolumen, Sprachanteil pro Fraktion, positives/negatives Feedback je Thema und je Fraktion (aus den Saalreaktionen), Faktencheck-Bilanz.

Barrierefreiheit (blinde/sehbehinderte Menschen) (pipeline/accessible.py, Pages „♿ Vorlesefassung"): lineare, screen-reader-/TTS-taugliche Textfassung der Sitzung — inkl. verbalisierter Saalreaktionen (Beifall = Zustimmung, Widerspruch/Buhrufe = Ablehnung) und Faktencheck mit Quellen.

Gap-Analyse Protokoll ↔ Video (compare_protocol_video.py, pipeline/gap_analysis.py): WER, Saalreaktions-Recall, Sprecher-/Inhalts-Lücken gegen den amtlichen Goldstandard. Methodik: docs/test-protokoll-vs-video.md.

Doku: Quellen docs/quellen.md · Plan/Fortschritt docs/challenge-plan.md · Fragen an den Bundestag docs/fragen-bundestag.md.

Datenquellen → Graph (Mapping & „landed"-Status)

Welche Quelle erzeugt welche Graph-Elemente — und ist sie tatsächlich geladen? Status: ✅ geladen · ⚠️ funktionsfähig, (noch) nicht in Neo4j · ⬜ offen. Die landed-Spalte wird von der E2E-Test-Suite (s. u.) automatisch geprüft.

Zwei klar getrennte, quellenmarkierte Graphen pro Sitzung (metadata.herkunft, metadata.quelle_url): herkunft=youtube (yt_<wp>_<nr>, Zeit-Deeplinks) vs. herkunft=amtlich (amt_<wp>_<nr>). Person/Fraktion bleiben global → derselbe Mensch in beiden Graphen. Inkrementeller Import + Status: scripts/sync_sessions.py.

# Quelle Format Loader / Modul Erzeugte Knoten (Auswahl) Art landed
1 Amtliches Plenarprotokoll — ALLE WP21-Sitzungen (dserver.bundestag.de/btp/21/21NNN.xml, DTD dbtplenarprotokoll) XML sync_sessions --officialbundestag_xmlgraph_buildneo4j_loader (amt_-Namespace) Sitzung, Tagesordnungspunkt, Person, Fraktion, Redebeitrag, Aussage, AkustischesEreignis, Transkriptsegment echt ✅ alle verfügbaren WP21-Sitzungen in Neo4j; Dashboards je Sitzung auf Pages
2 Inhaltsverzeichnis (im selben XML) XML bundestag_xml._ivz_titles TOP-Titel (Property) echt
3 Anlagen „zu Protokoll gegebene Reden" / §31-GO (im selben XML) XML bundestag_xml (anlagen) Redebeitrag (schriftlich=true) echt
4 YouTube-Gesamtmitschnitte (@bundestag/streams, Auto-Untertitel) VTT sync_sessions --youtubesubtitles.youtube_segmentsgraph_build (yt_-Namespace) Sitzung, Transkriptsegment (mit Startsekunde → Deeplink), Aussage, Faktencheck, Quelle echt ✅ Sitzung 79 + 81 in Neo4j + Pages (Graph, Dashboard, HTML-Protokoll)
5 Diarisierte Audio-Mitschnitte JSON asr/align/extractgraph_build + Beschluss, Abstimmung, Antrag, Befangenheit, Aufgabe fiktiv ✅ Pages-Demo (gemeinderat/bundestag)
6 Sound-Event-Detection (PANNs/AudioSet) JSON/Audio pipeline/sound_events.py AkustischesEreignis (herkunft=audio-SED) fiktiv (Sample) ✅ Pages-Demo
7 LLM-Faktencheck (Azure Mistral-Large-3) — reale Inhalte REST factcheck.factcheck_with_llm / factcheck_transcript_llm Faktencheck, Quelle (+ metadata.factcheck_disclaimer) echt ✅ KI-Vorschlag (ungeprüft) mit Disclaimer auf YT- + amtl. Sitzungen
8 Evidenz-Korpus (Faktencheck) JSON pipeline/factcheck.factcheck_rule_based Faktencheck, Quelle fiktiv ✅ nur fiktive Demo-Szenarien (dep-frei, CI)
9 Gap-Analyse YouTube ↔ amtlich sync_sessions --gapgap_analysis — (web/data/gap_<wp>_<nr>.json: WER, Reaktions-Recall) echt ✅ Sitzung 79 + 81
10 DIP-API (Vorgänge/Drucksachen/Metadaten) REST/JSON scripts/fetch-session.sh (Key) — (nur Fetch/Metadaten) echt ⬜ noch nicht in den Graph importiert
11 Embeddings (Azure text-embedding-3-large) Vektor scripts/vector_search.py Transkriptsegment.embedding + Vektor-Index echt ✅ in Neo4j
# Inkrementell ALLE noch nicht importierten Sitzungen laden (überspringt Vorhandenes):
python scripts/sync_sessions.py --youtube --load              # neue YouTube-Gesamtmitschnitte
python scripts/sync_sessions.py --official --from 1 --to 81 --load   # alle amtlichen WP21-XML
python scripts/sync_sessions.py --gap                         # Lückenanalyse YT ↔ amtlich

SPARK: Was wir nutzen — und was wir erweitern

Das offizielle BMDS SPARK Workflow wurde lokal geklont und untersucht. Wichtig zur Einordnung: graph-protokoll hat keine Code-Abhängigkeit zu SPARK — wir teilen Mission, Lizenz und Bausteinkonzept, nicht Quellcode. (Das „SPARK-Datenformat" der Schwester-Prototypen graph-insurance/-investigation/-eAkte stammt aus dem eigenen Prototypen-Ökosystem github.com/ma3u, nicht aus SPARK selbst.)

Was wir aus SPARK übernehmen (konzeptionell):

SPARK Workflow (BMDS) Übernahme in graph-protokoll
Challenge 2 „Da geht noch mehr" — neue Leistung jenseits Planung/Genehmigung Gremien-/Plenarprotokoll-Analyse als neue Verwaltungsleistung
Lizenz EUPL-1.2, Public Money – Public Code gleiche Lizenz/Haltung
On-prem-LLM über OpenAI-kompatiblen Endpoint (LiteLLM/vLLM) gleiches Muster (Ollama/vLLM oder Azure AI Foundry über .env)
Modul Inhaltsextraktion aus Antragsunterlagen analog pipeline/extract.py / bundestag_xml.py
Vollständigkeits-/Plausibilitätsprüfung analog Faktencheck/Qualitätsprüfung

Wo wir SPARK erweitern (Bausteine, die SPARK Workflow nicht hat — SPARK nutzt Temporal + FastAPI + Qdrant/Vektor-RAG, keinen Graph):

Fähigkeit SPARK graph-protokoll (Erweiterung)
Eingabe Dokumente (PDF/DOCX) Audio/ASR, amtliches Plenarprotokoll-XML, YouTube-Untertitel
Retrieval Vektor-RAG (Qdrant) Knowledge Graph (Neo4j) + GraphRAG/Text2Cypher
Analytik Graph Data Science (PageRank, Louvain, Degree)
Provenienz Dokumentbezug Audio-Sekunde / Segment (BELEGT_DURCH)
Bewertung formale/Plausibilitätsprüfung Faktencheck mit Quellen (fiktiv; reale Personen ohne Auto-Verdikt)
Mehrkanal-RAG Haystack/Neo4j (Volltext-RAG) + Text2Cypher nebeneinander

Ausführliche Analyse (mit den real ausgeführten Schritten): docs/spark-und-echtdaten.md.

GenAI-Stack: GraphRAG · GDS · Haystack (Mistral-Large-3 vs. Kimi-K2.6)

Für Genauigkeit & Performance auf den echten Sitzungen (siehe docs/neo4j-echtsitzungen.md) kommen drei Neo4j-GenAI-Bausteine zum Einsatz. LLM-Zugang on-prem-fähig über .env (OpenAI-kompatibel; hier Azure AI Foundry: Mistral-Large-3 + Kimi-K2.6). Setup: .venv/bin/pip install -r requirements-genai.txt, cp .env.example .env (Werte eintragen), Neo4j auf 7475/7688 starten + load_real_sessions.py.

Baustein Bibliothek Skript Zweck
GraphRAG (Text2Cypher) neo4j-graphrag scripts/graphrag_compare.py NL-Frage → Cypher → Antwort; Modellvergleich Mistral vs. Kimi
Graph Data Science graphdatascience scripts/gds_analysis.py PageRank/Louvain/Degree über den Mitsprache-Graph
Haystack ↔ Neo4j neo4j-haystack scripts/haystack_neo4j.py Volltext-RAG über die Reden + Azure-Generator
Vektor-/Semantik-Suche neo4j-graphrag VectorCypherRetriever scripts/vector_search.py Embeddings (Azure text-embedding-3-large, 3072d) → nativer Neo4j-Vektor-Index → Bedeutungsähnlichkeit

Damit stehen drei komplementäre Retrieval-Wege über denselben Graphen: strukturiert (Text2Cypher), stichwortbasiert (Haystack-Volltext) und semantisch (Vektor). Das Embedding-Modell gab es im Azure-Resource noch nicht — es wurde per az cognitiveservices account deployment create bereitgestellt (Mistral-Embed ist dort nicht im Katalog → text-embedding-3-large, multilingual).

.venv/bin/python scripts/graphrag_compare.py   # Mistral-Large-3 vs. Kimi-K2.6, Cypher + Antwort
.venv/bin/python scripts/gds_analysis.py       # zentrale Sprecher, Communities
.venv/bin/python scripts/haystack_neo4j.py "Was wurde zur Energie gesagt?"
.venv/bin/python scripts/vector_search.py "Was wurde zur Rente gesagt?"  # semantisch (Embeddings)

Beobachtung Modellvergleich: Beide erzeugen valides Cypher; Mistral-Large-3 ist schneller (~2–4 s), Kimi-K2.6 ist ein Reasoning-Modell (langsamer, braucht mehr max_tokens) und war bei der Synthese komplexer Ranglisten teils präziser. Beleg/Details: docs/neo4j-echtsitzungen.md.

E2E-Tests (200+ reale Fälle)

tests/ enthält eine End-to-End-Suite mit ~250 realen Testfällen (pytest) gegen die echten, in Neo4j geladenen Sitzungen — positiv (System tut das Richtige) und negativ (ungültige Eingaben werden abgewehrt, nicht vorhandene Daten liefern leer). Sie prüft u. a. die landed-Spalte der Mapping-Tabelle.

.venv/bin/pip install -r requirements-test.txt
NEO4J_URI=bolt://localhost:7688 .venv/bin/python -m pytest tests/ -q     # → 251 passed
Gruppe Beispiele ~Fälle
✅ positiv — Quellen gelandet jeder Knotentyp vorhanden; je Sitzung Reden/Saalreaktionen/TOPs = Parser-Zahl ~70
✅ positiv — Provenienz & Personen 50 echte Redner:innen als Person-Knoten; 30× „jeder Redebeitrag ist BELEGT_DURCH" ~80
✅ positiv — Embeddings/Index 449 Vektoren, Dimension 3072, Vektor-Index ONLINE ~20
❌ negativ — Sicherheit _SAFE weist 25 unsichere Label/Injection-Strings ab; Namespacing kollisionsfrei ~35
❌ negativ — Invarianten 0 Faktencheck/Quelle/GEPRUEFT_ALS über reale Personen ~6
❌ negativ — Robustheit/Absenz malformed XML → sauberer ParseError; 25 nicht vorhandene Namen/Begriffe → leer ~35

Projektstruktur

graph-protokoll/
├── run_demo.py                 # Audio-Demo (Gemeinderat + Bundestag)
├── ingest_bundestag.py         # amtliches Plenarprotokoll-XML → Graph → Neo4j
├── pipeline/
│   ├── asr.py / diarize.py / align.py   # Audio → sprecher-attribuierte Utterances
│   ├── bundestag_xml.py        # Parser für amtliches dbtplenarprotokoll-XML (+ Saalreaktionen)
│   ├── extract.py              # Regel-/LLM-Extraktion (TOPs, Beschlüsse, Aussagen, Fragen)
│   ├── factcheck.py            # Aussagen → Verdikt + Quelle (immer)
│   ├── graph_build.py          # Protokoll → 5-Schichten-Graph (SPARK-Format)
│   ├── export.py               # JSON / CSV / Neo4j-Cypher
│   ├── neo4j_loader.py         # idempotenter, parametrisierter Import nach Neo4j
│   ├── neo4j_graphrag.py       # Neo4j-GraphRAG (Text2Cypher) — NL-Fragen über den Graphen
│   ├── dashboard.py            # Sitzungs-Kennzahlen (Themen, Sprachanteil, Feedback)
│   └── graphrag.py             # Offline-Demo-Router (ohne Neo4j/LLM)
├── docker-compose.neo4j.yml    # lokales Neo4j 5 für Import + GraphRAG
├── scripts/fetch-session.sh    # offizielle Sitzungsquellen ziehen (Open Data/DIP/YouTube)
├── data/sample/                # fiktive, diarisierte Mitschnitte
├── data/evidence/              # fiktive Evidenzbasis für den Faktencheck
├── web/                        # statische GitHub-Pages-App (+ web/data/*.json)
├── docs/                       # Bundestag-Protokollierung & Faktencheck-Analyse
├── scripts/publish-to-github.sh
├── .github/workflows/pages.yml
├── output/                     # generierte Graph-Artefakte
├── requirements.txt            # nur Produktivpfad (Demo braucht keine Deps)
├── publiccode.yml              # Public-Money-Public-Code-Metadaten (EUPL-1.2)
└── LICENSE                     # EUPL-1.2 (Volltext via publish-Skript)

Demo-Daten

  • data/sample/ — frei erfunden: Gemeinde Musterbach, fiktive Abgeordnete/Fraktionen, fiktive Statistiken/Quellen. Keine realen Personen, Organisationen, Sitzungen oder Zitate. Der Faktencheck läuft nur hier (gegen den fiktiven data/evidence/evidenz.json) und demonstriert den Mechanismus, nicht reale Politik.
  • data/real/ — echt: amtliches Plenarprotokoll WP20/214 (gemeinfrei, § 5 UrhG). Daraus entsteht das Szenario „Bundestag (echt)" mit Graph, Saalreaktionen, Dashboard und Vorlesefassung — ohne Faktencheck-Verdikte über reale Personen (--no-factcheck). Einordnung & weitere Echtdaten-Wege (YouTube-Untertitel, eigene Sitzungen): docs/spark-und-echtdaten.md.

🤖 Agentic-AI-Kontroll-Stack (Claude Code)

Dieses Repo ist als Claude-Code-natives Agentic-AI-Projekt aufgesetzt (Agentic-Init-Prompt). Bootstrap + Selbstprüfung idempotent:

bash scripts/agentic-init.sh          # fehlende Tools installieren + Stack prüfen
bash scripts/agentic-init.sh --check  # nur prüfen, nichts installieren
Baustein Inhalt
CLAUDE.md schlank + cachebar; Details on-demand via @.claude/rules/*-Imports
.claude/settings.json + hooks/guard.sh Permissions (allow/ask/deny) + PreToolUse-Guard: blockt root/home-Wipes·Force-Push, fragt bei rm -rf·reset --hard·Infra-Teardown·Secret-Reads
.claude/rules/ (3) code-style · testing · api-conventions (importierte Konventionen)
.claude/commands/ (4) /review · /fix-issue · /deploy-check · /plan
.claude/agents/ (6) architect · implementer · reviewer · tester · security-test · compliance-reviewer (Modell + Effort je Rolle)
.claude/skills/ (5) audio-transcription · bundestag-ingestion · fact-checking · graphrag-queries · knowledge-graph
docs/adr/ (17) ADRs (Nygard, immutabel) + Index; Strukturentscheidungen verlinken docs/diagrams/ (Mermaid)
docs/planning/ future → current → done, gespiegelt aus docs/challenge-plan.md
docs/knowledge/ (31) OKF-v0.1-Wissensbasis — ein Konzept pro Datei (datamodels · services · apis · runbooks · decisions), progressive Disclosure

Token-Disziplin (lokal, nur Dev — nie in CI). RTK (Rust Token Killer, Input-Seite, PreToolUse-Hook) komprimiert Tool-Ausgaben vor dem Kontext — in dieser Session gemessen 88,6 % Ersparnis (≈ 589,6 k Tokens über 373 Befehle, rtk gain). caveman (Output-Seite, Claude-Code-Skill) strippt Prosa (~65 %; Code/Commands bleiben exakt). Beide stapeln mit dem Opus-4.8-Prompt-Caching auf der stabilen CLAUDE.md. Entscheidungen zum Design-System: ADR-0016.

Lizenz

EUPL-1.2 — wie die BMDS-Referenzlösung SPARK Workflow, im Sinne von „Public Money – Public Code". Die LICENSE enthält die offizielle EUPL-Notice; den autoritativen Volltext zieht scripts/publish-to-github.sh beim Veröffentlichen (oder manuell von https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12).

About

SPARK Challenge 2 — Audiomitschnitt → Protokoll-Knowledge-Graph + Faktencheck (GraphRAG, lokal/DSGVO)

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors