PSP.cz Analyzer¶
Czech Parliamentary Voting Analyzer — an OSINT tool that downloads, parses, and visualizes open voting data from the Czech Chamber of Deputies.
Built with FastAPI, Polars, and HTMX.
Features¶
- Party Loyalty — rebellion rates: how often each MP votes against their party's majority
- Attendance — participation rates with breakdowns (active, passive, absent, excused)
- Most Active MPs — ranked by raw vote count (YES + NO + ABSTAIN)
- Voting Similarity — cross-party alliances via cosine similarity + PCA visualization
- Votes Browser — searchable, paginated list of all parliamentary votes with detail views
- Chart Endpoints — server-rendered PNG charts (seaborn/matplotlib)
- Multi-period Support — covers all 10 electoral periods (1993 to present)
- Tisk Pipeline — background processing that downloads parliamentary print PDFs, extracts text, and classifies topics
- AI Summaries — optional LLM-based bilingual (Czech + English) summarization and topic classification via Ollama
- i18n — full Czech/English UI localization with a header language switcher
- Docker — containerized deployment with docker-compose
- Documentation — project docs on GitHub
Quick Start¶
Requires Python >= 3.12 and uv.
# Install dependencies
uv sync
# (Optional) Copy and edit environment variables
cp .env.example .env
# Run the dev server (with hot reload)
uv run python -m pspcz_analyzer.main
The app starts on http://localhost:8000. On first launch it downloads ~50 MB of open data from psp.cz and caches it locally as Parquet files.
Configuration¶
All configuration is via environment variables loaded from .env by python-dotenv:
| Variable | Default | Description |
|---|---|---|
PSPCZ_CACHE_DIR |
~/.cache/pspcz-analyzer/psp |
Data cache directory |
PSPCZ_DEV |
1 |
1 for hot reload, 0 for production |
PORT |
8000 |
Server port (used by both local dev and Docker) |
OLLAMA_BASE_URL |
http://localhost:11434 |
Ollama API endpoint |
OLLAMA_API_KEY |
(empty) | Bearer token for remote HTTPS Ollama |
OLLAMA_MODEL |
qwen3:8b |
Model for classification and summarization |
See .env.example for a documented template.
Docker¶
The app runs at http://localhost:8000 (or the port set by PORT). Data cache is persisted via a bind mount at ./cache-data/. Configure OLLAMA_BASE_URL and OLLAMA_API_KEY in .env to connect to your Ollama instance on the local network.
Tech Stack¶
| Layer | Technology |
|---|---|
| Web framework | FastAPI + Uvicorn |
| Templating | Jinja2 + i18n extension |
| Frontend interactivity | HTMX |
| CSS | Pico CSS (institutional light theme) |
| Localization | Dict-based i18n (Czech + English) |
| Data processing | Polars |
| Charts | Seaborn + Matplotlib |
| PDF extraction | PyMuPDF |
| HTML scraping | BeautifulSoup4 |
| LLM integration | Ollama (optional, bilingual) |
| Documentation | GitHub + MkDocs |
| HTTP client | httpx |
| Configuration | python-dotenv |
| Testing | pytest + pytest-cov |
| Linting & formatting | Ruff |
| Type checking | Pyright |
| Containerization | Docker + docker-compose |
| CI/CD | GitHub Actions |
| Package manager | uv |
Data Source¶
All data comes from the psp.cz open data portal. Files are pipe-delimited UNL format, Windows-1250 encoded. The app downloads and caches them automatically on first access.
Cached data is stored at ~/.cache/pspcz-analyzer/psp/ (override with PSPCZ_CACHE_DIR).
License¶
Educational / OSINT project. Parliamentary data is public domain per Czech law.