Download mathly2/config.py from wzender/mathly: direct link, hf CLI and curl.
- Browser
- Download file 4 kB
-
https://huggingface.co/spaces/wzender/mathly/resolve/main/mathly2/config.py
- Command line
-
hf download hf://spaces/wzender/mathly/mathly2/config.py
-
curl -L -o config.py https://huggingface.co/spaces/wzender/mathly/resolve/main/mathly2/config.py
4 kB
| """Settings, read from the environment when the app is created.""" | |
| from __future__ import annotations | |
| import os | |
| import re | |
| from dataclasses import dataclass, field | |
| from pathlib import Path | |
| from dotenv import load_dotenv | |
| ENV_FILE = Path(__file__).parent / ".env" # this app's own settings, if it has any | |
| ROOT_ENV_FILE = Path(__file__).parent.parent / ".env" # the repository's .env, shared with mathly1 (same Supabase project) | |
| def _emails(name: str) -> frozenset[str]: | |
| return frozenset(re.split(r"[\s,;]+", os.environ.get(name, "").strip().lower())) - {""} | |
| class Settings: | |
| supabase_url: str = "" | |
| supabase_key: str = "" # publishable key, sent to the browser for Google sign-in | |
| supabase_secret: str = "" # secret key, server only | |
| teachers: frozenset[str] = field(default_factory=frozenset) | |
| developers: frozenset[str] = field(default_factory=frozenset) # the developer role comes only from here | |
| admins: frozenset[str] = field(default_factory=frozenset) # the first admins; others are given the role by an admin | |
| answer_bucket: str = "m2-answers" # the private bucket for answer pictures (not mathly1's) | |
| anthropic_key: str = "" # the AI is unavailable without it (a send fails with "missing key") | |
| math_model: str = "" # empty: the default model in ai.py | |
| gemini_key: str = "" # the AI review of the way in tests (boardreview.py); none without it | |
| gemini_model: str = "" # empty: the default (free tier) model in boardreview.py | |
| cache_seconds: float = 30 # how long slow-changing reads are remembered; 0 is off | |
| vapid_private_key: str = "" # the server's push key; push notifications are off without it | |
| vapid_subject: str = "" # a contact the push services may write to ("mailto:...") | |
| def supabase_on(self) -> bool: | |
| return bool(self.supabase_url and self.supabase_key and self.supabase_secret) | |
| def check(self) -> "Settings": | |
| """Either all three Supabase settings are set, or none (local development with the "dev only" sign-in). | |
| A half-configured server must not fall back to dev sign-in, which trusts any email address.""" | |
| given = [bool(self.supabase_url), bool(self.supabase_key), bool(self.supabase_secret)] | |
| if any(given) and not all(given): | |
| raise ValueError("Set all of SUPABASE_URL, SUPABASE_PUBLISHABLE_KEY and SUPABASE_SECRET_KEY, or none of them.") | |
| return self | |
| def load_settings(env_file: Path | None = None) -> Settings: | |
| """Settings from the environment. Files fill in what the environment does not set, in this order: mathly2/.env, then the | |
| repository's .env. A real environment variable always wins, so deployments are unaffected. Passing `env_file` reads only that file.""" | |
| for path in ([env_file] if env_file else [ENV_FILE, ROOT_ENV_FILE]): | |
| load_dotenv(path, override=False) | |
| env = lambda name: os.environ.get(name, "").strip() | |
| return Settings( | |
| supabase_url=env("SUPABASE_URL").rstrip("/"), | |
| supabase_key=env("SUPABASE_PUBLISHABLE_KEY"), | |
| supabase_secret=env("SUPABASE_SECRET_KEY"), | |
| teachers=_emails("TEACHER_EMAILS"), | |
| developers=_emails("DEVELOPER_EMAILS"), | |
| admins=_emails("ADMIN_EMAILS"), | |
| answer_bucket=env("MATHLY_M2_ANSWER_BUCKET") or "m2-answers", | |
| anthropic_key=env("ANTHROPIC_API_KEY"), | |
| math_model=env("MATH_MODEL"), | |
| gemini_key=env("GEMINI_API_KEY"), | |
| gemini_model=env("GEMINI_MODEL"), | |
| cache_seconds=float(env("MATHLY_CACHE_SECONDS") or 30), | |
| vapid_private_key=env("VAPID_PRIVATE_KEY"), | |
| vapid_subject=env("VAPID_SUBJECT"), | |
| ).check() | |