Initial import of Politrack, a self-hosted service that tracks Austrian politicians from federal to municipal level - roles, votes, money flows, statements, meetings, social media and legal proceedings - with every claim linked to its sources. - backend: FastAPI + Postgres/pgvector; adapter framework (fetch -> parse -> load -> enrich) with robots.txt/TDM-aware fetching, a raw-response archive for reparsing, and a claim/evidence model with corroboration - sources: Parliament, Wikidata, EU Parliament/Commission, Council of Ministers, Rechnungshof party reports and donations, procurement, RTR media transparency, political ad libraries, WKStA, news feeds, Wikipedia edits, Bluesky, Mastodon, public Telegram channels, YouTube and X (official API) - web: Next.js frontend in German and English with typed API client - mcp: MCP server for AI agents and RAG - docs: architecture, data model, sources, legal notes, Unraid deployment and contributor guides; Docker Compose setup for Unraid Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
49 lines
1.7 KiB
Python
49 lines
1.7 KiB
Python
from functools import lru_cache
|
|
from pathlib import Path
|
|
|
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
|
|
|
|
class Settings(BaseSettings):
|
|
"""All settings come from environment variables prefixed POLITRACK_ (see .env.example)."""
|
|
|
|
model_config = SettingsConfigDict(env_prefix="POLITRACK_", env_file=".env", extra="ignore")
|
|
|
|
database_url: str = "postgresql://politrack:politrack@localhost:5432/politrack"
|
|
reader_password: str | None = None
|
|
|
|
# Crawling identity & politeness
|
|
user_agent: str = "PolitrackBot/0.2 (+https://github.com/your-user/politics-tracking; contact: admin@example.org)"
|
|
min_request_interval: float = 2.0
|
|
http_timeout: float = 60.0
|
|
|
|
# Raw archive (fetched responses, gzip, content-addressed)
|
|
raw_dir: Path = Path("/data/raw")
|
|
|
|
config_dir: Path = Path(__file__).resolve().parent.parent / "config"
|
|
|
|
# Parliament: legislative periods (GP) ingested in detail
|
|
parlament_periods: list[str] = ["XXVII", "XXVIII"]
|
|
|
|
# Embeddings via Ollama (optional)
|
|
ollama_url: str | None = None
|
|
embedding_model: str = "bge-m3"
|
|
|
|
# Optional credentials for sources that require them (adapters skip themselves when unset)
|
|
youtube_api_key: str | None = None
|
|
meta_ad_library_token: str | None = None
|
|
x_bearer_token: str | None = None
|
|
|
|
# Bulk sources: how far back to backfill on the first run
|
|
procurement_since: str = "2024-01-01"
|
|
ad_archive_since: str = "2023-01-01"
|
|
|
|
api_cors_origins: list[str] = ["http://localhost:3000"]
|
|
# Bearer token for moderation/admin endpoints. Empty = disabled (use the CLI).
|
|
admin_token: str | None = None
|
|
|
|
|
|
@lru_cache
|
|
def get_settings() -> Settings:
|
|
return Settings()
|