# Stemwijzer

A Dutch parliamentary voting compass that lets you vote on real Tweede Kamer motions and see which parties match your positions.

![Stemwijzer Explorer](docs/assets/stemwijzer-screenshot.png)

## What is Stemwijzer?

Stemwijzer ingests motions and voting records from the Dutch House of Representatives (Tweede Kamer), stores them in DuckDB, generates AI-powered explanations with an LLM, and presents a Streamlit UI where users can vote on real motions and explore party positions through SVD visualizations, trajectory analysis, and embedding-based similarity search.

## Features

- **Voting Compass** — Vote on real parliamentary motions and see which parties align with your choices
- **Explorer** — Interactive SVD visualizations, party trajectories over time, motion browser, and semantic search
- **Analytics** — SVD decomposition of voting patterns, UMAP projections, clustering, and drift analysis
- **LLM Enrichment** — Automatic generation of layman-friendly motion explanations using QWEN via OpenRouter

## Prerequisites

- Python >= 3.13
- [uv](https://docs.astral.sh/uv/) for dependency management
- (Optional) `OPENROUTER_API_KEY` for LLM enrichment

## Quickstart

```bash
# Clone and enter the repository
git clone <your-gitea-url>/sgeboers/stemwijzer.git
cd stemwijzer

# Install dependencies
uv sync

# Run the Streamlit app
uv run streamlit run Home.py

# Run the data pipeline (fetch motions, compute embeddings, etc.)
uv run python pipeline/run_pipeline.py

# Run tests
uv run pytest tests/ -q
```

The app will be available at http://localhost:8501.

## Project Structure

```
├── app.py              # Streamlit UI entrypoint
├── database.py         # DuckDB schema and queries
├── api_client.py       # Tweede Kamer OData API client
├── explorer.py         # Explorer page with SVD visualizations
├── pipeline/           # Data ingestion and analysis pipelines
├── analysis/           # SVD, clustering, trajectory modules
├── tests/              # pytest test suite
├── docs/               # Documentation, research, and plans
└── data/motions.db     # DuckDB database (~18 GB)
```

## Documentation

- **[ARCHITECTURE.md](ARCHITECTURE.md)** — Comprehensive architecture overview, tech stack, and contributor guidance
- **[CODE_STYLE.md](CODE_STYLE.md)** — Coding conventions, naming, typing, and testing standards
- **[docs/solutions/](docs/solutions/)** — Documented solutions to past bugs and best practices

## Tech Stack

- **Language:** Python 3.13+
- **Data:** DuckDB via ibis-framework
- **UI:** Streamlit + Plotly
- **ML/Analysis:** scipy, scikit-learn, umap-learn
- **LLM:** QWEN via OpenRouter (OpenAI-compatible)
- **Package Manager:** uv

## Deployment

See [docs/deployment/ansible-package-deploy.md](docs/deployment/ansible-package-deploy.md) for server deployment instructions using the Ansible package.

## License

[Your license here]
