hugging-science/request-moderator
0
1"""Submissions queue backed by the existing hugging-science/feedback HF Dataset.2 3`requests.jsonl` holds every non-"feedback" type (dataset/model/organization/4blog/challenge/collaboration); `feedback.jsonl` holds "feedback". Both are5written by the feedback-api Space's /submit endpoint. Ingestion happens6there, not here — this module only reads those files and updates a row's7status when the reviewer approves/rejects/acknowledges it.8"""9 10import json11import threading12from datetime import datetime, timezone13 14from huggingface_hub import HfApi15from huggingface_hub.utils import EntryNotFoundError16 17from about import DATASET_REPO, FEEDBACK_FILE, REQUESTS_FILE, TOKEN18 19_api = HfApi(token=TOKEN)20_lock = threading.Lock()21 22ALL_FILES = (REQUESTS_FILE, FEEDBACK_FILE)23 24 25def _now() -> str:26 return datetime.now(timezone.utc).isoformat()27 28 29def _read_file(filename: str) -> list[dict]:30 try:31 path = _api.hf_hub_download(32 repo_id=DATASET_REPO, repo_type="dataset", filename=filename33 )34 except EntryNotFoundError:35 return []36 with open(path, encoding="utf-8") as f:37 return [json.loads(line) for line in f if line.strip()]38 39 40def _write_file(filename: str, rows: list[dict]) -> None:41 content = "\n".join(json.dumps(row) for row in rows) + "\n"42 _api.upload_file(43 path_or_fileobj=content.encode("utf-8"),44 path_in_repo=filename,45 repo_id=DATASET_REPO,46 repo_type="dataset",47 commit_message="Update requests queue",48 )49 50 51def _read_all() -> list[dict]:52 return [row for filename in ALL_FILES for row in _read_file(filename)]53 54 55def list_submissions(status: str | None = None, type_: str | None = None) -> list[dict]:56 rows = _read_all()57 if status is not None:58 rows = [r for r in rows if r["status"] == status]59 if type_ is not None:60 rows = [r for r in rows if r["type"] == type_]61 return rows62 63 64def get_submission(submission_id: str) -> dict | None:65 for row in _read_all():66 if row["id"] == submission_id:67 return row68 return None69 70 71def _update_row(submission_id: str, mutate_fn) -> None:72 """Find `submission_id` in whichever file its type lives in, mutate it in73 place, and rewrite only that file."""74 with _lock:75 for filename in ALL_FILES:76 rows = _read_file(filename)77 for row in rows:78 if row["id"] == submission_id:79 mutate_fn(row)80 _write_file(filename, rows)81 return82 83 84def mark_approved(submission_id: str, pr_url: str) -> None:85 def mutate(row):86 row["status"] = "approved"87 row["reviewed_at"] = _now()88 row["pr_url"] = pr_url89 90 _update_row(submission_id, mutate)91 92 93def mark_acknowledged(submission_id: str) -> None:94 """For non-PR types (feedback, collaboration, challenge): close out a95 submission without opening a PR — e.g. once it's been read or the96 requester has been emailed."""97 98 def mutate(row):99 row["status"] = "acknowledged"100 row["reviewed_at"] = _now()101 102 _update_row(submission_id, mutate)103 104 105def mark_rejected(submission_id: str, reason: str | None) -> None:106 def mutate(row):107 row["status"] = "rejected"108 row["reviewed_at"] = _now()109 row["reject_reason"] = reason110 111 _update_row(submission_id, mutate)112 