CivicAI i mypilawa.pl – AI w służbie danych samorządowych

Dane o tym, jak funkcjonuje gmina, są w Polsce formalnie publiczne, ale w praktyce rozproszone: umowy w Centralnym Rejestrze Umów, statystyki w GUS, dane budżetowe w Ministerstwie Finansów, uchwały i zarządzenia w Biuletynie Informacji Publicznej. Do tego dochodzą nagrania sesji rady, które mało kto ma czas obejrzeć w całości.
Ten projekt to połączenie inżynierii oprogramowania z AI, którego celem jest zebranie tych danych w jednym miejscu i podanie ich w formie zrozumiałej dla zwykłego mieszkańca. Pierwotnie miała to być prosta strona w Astro z bazą w plikach JSON dla miasta Piława Górna. Skończyło się na rozbudowanym systemie.
Dwa projekty w jednym
Całość składa się z dwóch wyraźnie rozdzielonych części:
- CivicAI – silnik i serce systemu: pobieranie danych, OCR, transkrypcja, streszczenia i uruchamianie pipeline'ów,
- mypilawa.pl – warstwa frontendowa, czyli strona, na której mieszkańcy czytają przetworzone informacje o swojej gminie.
Rozdzielenie ich było kluczowe: CivicAI nie jest związany z jedną gminą i można go zaadaptować do dowolnej gminy w Polsce, a mypilawa.pl jest pierwszą implementacją i poligonem doświadczalnym.
Źródła danych
System zbiera informacje z kilku niezależnych źródeł publicznych:
- Centralny Rejestr Umów,
- Główny Urząd Statystyczny,
- Ministerstwo Finansów,
- Biuletyn Informacji Publicznej miasta Piława Górna (uchwały, zarządzenia, interpelacje).
Każde źródło ma inny format, inną strukturę i inne problemy, dlatego pobieranie jest zorganizowane jako osobne pipeline'y, a nie jeden monolityczny skrypt.
Dokumenty prostym językiem
Uchwały, zarządzenia i interpelacje są pisane językiem prawniczo-urzędowym. Dla każdego takiego dokumentu modele LLM generują uproszczoną wersję, która wyjaśnia prostym językiem, o czym jest dokument i co faktycznie wnosi, tak by zrozumiał to każdy mieszkaniec, nie tylko prawnik czy urzędnik.
Uproszczona wersja jest uzupełnieniem oryginału, nie jego zamiennikiem. Streszczenia generowane przez LLM zawsze warto traktować jako warstwę pomocniczą nad dokumentem źródłowym.
Sesje rady miasta: od nagrania do podsumowania
Osobny pipeline pobiera nagrania z transmisji sesji rady miasta. Audio jest transkrybowane przez Whisper, a następnie transkrypt jest obrabiany i podsumowywany z użyciem AI. W efekcie kilkugodzinna sesja zamienia się w tekst, który można przeszukać i przeczytać w kilka minut.
OCR dwustopniowy
Wiele dokumentów publicznych to skany lub PDF-y o kiepskiej strukturze, więc potrzebny był OCR. Zamiast od razu używać LLM do wszystkiego, zastosowałem podejście dwustopniowe:
| Etap | Metoda | Kiedy używany |
|---|---|---|
| 1 | Deterministyczny kod w Pythonie, który pobiera całość tekstu dokumentu | Zawsze jako pierwszy krok |
| 2 | AI/LLM | Gdy wynik z etapu 1 jest niezadowalający |
Taki układ ogranicza użycie modeli do przypadków, w których naprawdę są potrzebne. Dzięki temu proste dokumenty przechodzą szybko i przewidywalnie, a LLM dostaje tylko te trudniejsze.
Runner pipeline'ów
W środku CivicAI działa prosty runner napisany w Pythonie, który uruchamia pipeline'y. Własne, lekkie rozwiązanie wystarczyło do orkiestracji pobierania, OCR-u, transkrypcji i generowania streszczeń, bez wprowadzania ciężkiej infrastruktury.
Ewolucja architektury
Projekt zaczynał jako statyczna strona w Astro, a źródłem danych były pliki JSON. To podejście pozwoliło szybko zweryfikować pomysł. Gdy zakres rósł o kolejne źródła, OCR, transkrypcję i streszczenia, całość przekształciła się w pełnoprawny, rozbudowany system z wydzielonym silnikiem danych.
- Prototyp: strona w Astro i dane w plikach JSON.
- Dodanie kolejnych źródeł publicznych i przetwarzania AI.
- Wydzielenie CivicAI jako niezależnego silnika z runnerem pipeline'ów.
- mypilawa.pl jako frontend korzystający z przetworzonych danych.
Adaptacja do innych gmin
Ponieważ logika przetwarzania jest oddzielona od konkretnego serwisu, CivicAI można zaadaptować do dowolnej gminy w Polsce. Przy kolejnej gminie zmienia się głównie konfiguracja źródeł, a mechanizmy OCR, streszczania i transkrypcji pozostają te same.