import json import os import uuid from datetime import datetime, timezone from pathlib import Path def _token(): return os.getenv("HF_TOKEN", "") def _repo(): repo = os.getenv("HF_DATASET_REPO", "") if not repo: raise ValueError("HF_DATASET_REPO not set") return repo def _api(): from huggingface_hub import HfApi return HfApi(token=_token()) def append_exhibit(name, material, components, transformation_name, tagline, instructions, portrait_path, original_path=None) -> dict: api = _api() repo = _repo() exhibit_id = str(uuid.uuid4())[:8] timestamp = datetime.now(timezone.utc).isoformat() def _upload(local_path, remote_filename): if not local_path or not Path(local_path).exists(): return "" api.upload_file( path_or_fileobj=local_path, path_in_repo=remote_filename, repo_id=repo, repo_type="dataset", ) return f"https://huggingface.co/datasets/{repo}/resolve/main/{remote_filename}" portrait_url = _upload(portrait_path, f"portraits/{exhibit_id}.jpg") original_url = _upload(original_path, f"originals/{exhibit_id}.jpg") exhibit = { "id": exhibit_id, "timestamp": timestamp, "name": name, "material": material, "components": components if isinstance(components, list) else [components], "transformation_name": transformation_name, "tagline": tagline, "instructions": instructions, "portrait_url": portrait_url, "original_url": original_url, "likes": 0, } existing = _load_raw() existing.append(exhibit) jsonl = "\n".join(json.dumps(e) for e in existing) + "\n" api.upload_file( path_or_fileobj=jsonl.encode(), path_in_repo="exhibits.jsonl", repo_id=repo, repo_type="dataset", ) return exhibit def load_exhibits() -> list[dict]: return list(reversed(_load_raw())) def count_exhibits() -> int: return len(_load_raw()) def _load_raw() -> list[dict]: try: from huggingface_hub import hf_hub_download path = hf_hub_download( repo_id=_repo(), filename="exhibits.jsonl", repo_type="dataset", token=_token(), force_download=True, ) lines = Path(path).read_text().strip().splitlines() return [json.loads(l) for l in lines if l.strip()] except Exception: return []