"""Per-user progress persistence backed by a Hugging Face Dataset. Layout in the dataset repo: progress/.json Each JSON document looks like: { "username": "ishaan", "level": 2, "xp": 145, "streak": 3, "best_streak": 11, "history": [], "updated_at": "2026-06-08T19:42:11Z" } Failure modes are silent — if HF_TOKEN is missing, or the dataset doesn't exist, or the network is flaky, load_progress returns the empty default and save_progress is a no-op. The practice loop keeps working; the user just loses cross-device sync. """ from __future__ import annotations import json import os import time from datetime import datetime, timezone DATASET_REPO = os.environ.get("PROGRESS_DATASET", "IndianChess/rivet-progress") HF_TOKEN = os.environ.get("HF_TOKEN", "") HISTORY_CAP = 50 # cap stored history to keep files small def _empty(username: str = "") -> dict: return { "username": username, "level": 0, "xp": 0, "streak": 0, "best_streak": 0, "history": [], "updated_at": None, } def _now() -> str: return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") def _user_path(username: str) -> str: safe = "".join(c if c.isalnum() or c in "-_" else "_" for c in username) return f"progress/{safe}.json" def _api(): """Lazy huggingface_hub HfApi handle. Returns None if no token.""" if not HF_TOKEN: return None try: from huggingface_hub import HfApi return HfApi(token=HF_TOKEN) except Exception as e: # noqa: BLE001 print(f"[progress] huggingface_hub unavailable: {e}") return None def load_progress(username: str | None) -> dict: """Fetch saved progress for a signed-in user. Returns the empty default if the user has no entry yet, or if the dataset can't be reached. Never raises. """ if not username: return _empty("") api = _api() if api is None: return _empty(username) try: from huggingface_hub import hf_hub_download path = hf_hub_download( repo_id=DATASET_REPO, filename=_user_path(username), repo_type="dataset", token=HF_TOKEN, ) with open(path) as f: data = json.load(f) if not isinstance(data, dict): return _empty(username) # Re-stamp username in case it was renamed / shared file data["username"] = username return {**_empty(username), **data} except Exception as e: # noqa: BLE001 - load failures are non-fatal # Most common: 404 (no entry yet). Don't spam logs on those. msg = str(e) if "404" not in msg and "EntryNotFound" not in msg: print(f"[progress] load failed for {username}: {e}") return _empty(username) def save_progress(username: str | None, payload: dict) -> bool: """Write the user's progress back to the dataset. Returns True on success, False if persistence is unavailable or the write failed. Never raises. """ if not username: return False api = _api() if api is None: return False doc = {**_empty(username), **payload, "username": username, "updated_at": _now()} history = doc.get("history") or [] if isinstance(history, list) and len(history) > HISTORY_CAP: doc["history"] = history[-HISTORY_CAP:] try: from huggingface_hub import CommitOperationAdd body = json.dumps(doc, ensure_ascii=False, indent=2).encode("utf-8") api.create_commit( repo_id=DATASET_REPO, repo_type="dataset", operations=[ CommitOperationAdd( path_in_repo=_user_path(username), path_or_fileobj=body, ) ], commit_message=f"progress: update {username} @ {int(time.time())}", ) return True except Exception as e: # noqa: BLE001 print(f"[progress] save failed for {username}: {e}") return False