Routes¶
All routes accept a period query parameter (default: 10, the current electoral period). Changing the period loads data for that period on demand.
All page and API routes respect the current UI language (set via the lang cookie). Chart labels and vote outcome labels are localized.
Page Routes¶
Full HTML pages rendered with Jinja2. Defined in pspcz_analyzer/routes/pages.py.
| Method | Path | Description |
|---|---|---|
| GET | / |
Dashboard — overview stats for the selected period |
| GET | /loyalty |
Party loyalty analysis page |
| GET | /attendance |
Attendance analysis page (includes vote breakdown + activity ranking) |
| GET | /similarity |
Cross-party voting similarity page |
| GET | /votes |
Votes browser (searchable, paginated) |
| GET | /votes/{vote_id} |
Single vote detail — per-party and per-MP breakdown |
| GET | /laws |
Laws browser — filterable list of parliamentary bills |
| GET | /laws/{ct} |
Law detail — bill sponsors, status, legislative history |
| GET | /amendments |
Amendment voting — third-reading amendment analysis overview |
| GET | /amendments/{schuze}/{bod} |
Amendment detail — per-amendment votes, coalitions, AI summary |
| GET | /set-lang/{lang} |
Set UI language (cs or en) via cookie and redirect back |
API Routes (HTMX Partials)¶
Return HTML fragments for dynamic table updates. Split across domain modules mounted under /api:
- routes/voting.py — loyalty, attendance, similarity, votes
- routes/amendments.py — amendment bills, coalitions
- routes/tisk.py — tisk text, evolution, related bills
- routes/feedback.py — user feedback
- routes/health.py — health checks, LLM diagnostics
- routes/utils.py — shared utilities (validate_period, _safe_url)
GET /api/loyalty¶
| Param | Type | Default | Description |
|---|---|---|---|
period |
int | 10 | Electoral period |
top |
int | 30 | Number of MPs to show |
party |
string | "" |
Filter by party code (e.g. ODS, ANO) |
GET /api/attendance¶
| Param | Type | Default | Description |
|---|---|---|---|
period |
int | 10 | Electoral period |
top |
int | 30 | Number of MPs to show |
sort |
string | worst |
Sort order: worst, best, most_active, least_active, most_yes, most_no, most_abstained, most_passive, most_absent, most_excused |
party |
string | "" |
Filter by party code (e.g. ODS, ANO) |
GET /api/similarity¶
| Param | Type | Default | Description |
|---|---|---|---|
period |
int | 10 | Electoral period |
top |
int | 20 | Number of cross-party pairs |
GET /api/votes¶
| Param | Type | Default | Description |
|---|---|---|---|
period |
int | 10 | Electoral period |
search |
string | "" |
Full-text search on vote descriptions |
outcome |
string | "" |
Filter: A (passed), R (rejected), or empty for all |
topic |
string | "" |
Filter by topic label (from keyword or LLM classification) |
page |
int | 1 | Page number |
GET /api/tisk-text¶
Returns extracted PDF text for a parliamentary print as an HTML fragment (for lazy-loading via HTMX on vote detail pages).
| Param | Type | Default | Description |
|---|---|---|---|
period |
int | 10 | Electoral period |
ct |
int | 0 | Print number (cislo tisku) |
GET /api/tisk-evolution¶
Returns the legislative evolution view for a parliamentary print, including sub-versions and LLM-generated diff summaries (bilingual — displays English when lang=en).
| Param | Type | Default | Description |
|---|---|---|---|
period |
int | 10 | Electoral period |
ct |
int | (required) | Print number |
GET /api/related-bills¶
Returns related bills for a parliamentary print, discovered via zakon.cz cross-references.
| Param | Type | Default | Description |
|---|---|---|---|
idsb |
int | (required) | Bill identifier from zakon.cz |
Rate limit: 5/minute.
POST /api/feedback¶
Submit user feedback as a GitHub Issue (requires GITHUB_FEEDBACK_ENABLED=1).
| Param | Type | Default | Description |
|---|---|---|---|
title |
string | (required) | Feedback title |
body |
string | (required) | Feedback body text |
vote_id |
string | "" |
Related vote ID |
period |
string | "" |
Related electoral period |
page_url |
string | "" |
URL of the page where feedback was submitted |
Rate limit: 3/hour.
GET /api/llm/health¶
Returns LLM availability status as JSON.
Response:
{ "available": true, "provider": "ollama", "base_url": "http://localhost:11434", "model": "qwen3:8b" }
Rate limit: 10/minute.
GET /api/llm/smoke-test¶
Concurrent bilingual generation test. Fires two parallel LLM calls and measures wall-clock time.
Response:
{
"success": true,
"provider": "ollama",
"model": "qwen3:8b",
"duration_seconds": 4.2,
"summary_cs": "...",
"summary_en": "..."
}
Returns 503 if LLM is down, 502 on generation failure.
Rate limit: 2/minute.
GET /api/health¶
Health check endpoint returning JSON.
Response:
GET /api/laws¶
Returns an HTMX partial with filtered laws list.
| Parameter | Type | Default | Description |
|---|---|---|---|
period |
int | latest | Electoral period |
page |
int | 1 | Page number |
q |
str | — | Full-text search query |
topic |
str | — | Filter by topic classification |
status |
str | — | Filter by legislative status |
GET /api/amendments¶
Returns an HTMX partial with amendment bills for a period.
| Parameter | Type | Default | Description |
|---|---|---|---|
period |
int | latest | Electoral period |
page |
int | 1 | Page number |
GET /api/amendment-coalitions¶
Returns coalition analysis for a specific amendment vote.
| Parameter | Type | Default | Description |
|---|---|---|---|
period |
int | required | Electoral period |
schuze |
int | required | Session number |
bod |
int | required | Agenda point number |
Admin Routes (Port 8001)¶
The admin backend runs on a separate port (default 8001) with IP whitelist + password authentication.
Authentication¶
| Route | Method | Description |
|---|---|---|
/admin/login |
GET | Login page |
/admin/login |
POST | Authenticate (username + bcrypt password) |
/admin/logout |
POST | Clear session cookie |
Admin Pages¶
| Route | Description |
|---|---|
/admin/ |
Dashboard — system overview, cache size, LLM info |
/admin/pipelines |
Pipeline management — start, stop, monitor |
/admin/config |
Runtime config editor — LLM settings, toggles |
Admin API¶
| Route | Method | Description |
|---|---|---|
/admin/api/pipeline/start |
POST | Start a pipeline (type + period via form) |
/admin/api/pipeline/stop |
POST | Stop the currently running pipeline |
/admin/api/pipeline/cancel/{period} |
POST | Cancel a single period's pipeline |
/admin/api/pipeline/remove/{period} |
POST | Remove a pending period from the queue |
/admin/api/pipeline/status |
GET | Current pipeline status as JSON |
/admin/api/pipeline/history |
GET | Recent pipeline run history |
/admin/api/pipeline/logs |
GET | SSE endpoint for real-time log streaming |
/admin/api/config |
GET | Read runtime config (secrets masked) |
/admin/api/config |
POST | Update runtime config |
/admin/api/refresh |
POST | Trigger manual data refresh |
/admin/api/health |
GET | Admin backend health check |
/admin/partials/pipeline-status |
GET | HTMX partial for pipeline progress polling |
Chart Routes¶
Return PNG images via StreamingResponse. Defined in pspcz_analyzer/routes/charts.py. Mounted under /charts.
| Method | Path | Params | Description |
|---|---|---|---|
| GET | /charts/loyalty.png |
period, top=20 |
Horizontal bar chart — rebellion rates (coolwarm palette) |
| GET | /charts/attendance.png |
period, top=20 |
Horizontal bar chart — worst attendance (RdYlGn palette) |
| GET | /charts/similarity.png |
period |
PCA scatter plot — MPs colored by party (husl palette) |
All charts render at 150 DPI with a light background (#FFFFFF with #F7F7F7 plot area). Labels and titles are localized based on the current UI language.
OpenAPI¶
The full OpenAPI schema is available at /openapi.json. Default Swagger UI and ReDoc are disabled. The nav bar links to the GitHub repository for documentation.
Rate Limiting¶
Per-endpoint rate limits (via slowapi/limits):
| Endpoint | Limit |
|---|---|
| Page routes (incl. laws, amendments) | 60/minute |
Analysis APIs (/api/loyalty, etc.) |
15/minute |
/api/related-bills |
5/minute |
/api/feedback |
3/hour |
/api/llm/health |
10/minute |
/api/llm/smoke-test |
2/minute |
| Chart routes | 30/minute |
| Admin API routes | No limit (auth-protected) |