Spaces:
Sleeping
Sleeping
samsadar236
feat: deploy ControlPlane.ai — updated backend, frontend redesign, Responsible AI Gate
54f341c Download scripts/pregrade.py from samruddhisadar/gradeops: direct link, hf CLI and curl.
- Browser
- Download file 4.44 kB
-
https://huggingface.co/spaces/samruddhisadar/gradeops/resolve/main/scripts/pregrade.py
- Command line
-
hf download hf://spaces/samruddhisadar/gradeops/scripts/pregrade.py
-
curl -L -o pregrade.py https://huggingface.co/spaces/samruddhisadar/gradeops/resolve/main/scripts/pregrade.py
4.44 kB
| """Pre-grade the demo set into the database (T4.1), via the real API. | |
| Why HTTP and not direct DB writes: this drives the same endpoints the app | |
| already uses (POST /api/exams, /api/rubrics, /api/papers/upload), so the | |
| resulting gradeops.db is exactly what the app produces, with no assumptions | |
| about internal ORM constructors. Run it once against a locally-running | |
| instance the night before the demo, then bake the produced gradeops.db into | |
| the image (see the Dockerfile note at the bottom). | |
| This needs the app running and the grading keys set (GOOGLE_API_KEY / GROQ_API_KEY), | |
| so it is not run in CI. | |
| Manifest (JSON): | |
| { | |
| "session_id": "public", | |
| "exam_title": "Demo Midterm", | |
| "rubrics": [ | |
| {"title": "Q1", "question_text": "...", "max_marks": 3.0, | |
| "course_instructions": "...", | |
| "criteria": [{"name": "...", "points": 1.0, "conditions": "..."}]} | |
| ], | |
| "papers": [ | |
| {"file": "data/demo/paper1.pdf", "rubric_index": 0, "student_anon_id": "STU-001"} | |
| ] | |
| } | |
| Usage: | |
| # 1. start the app locally with keys set, then: | |
| python scripts/pregrade.py --manifest data/demo/manifest.json --base http://localhost:8000 | |
| # 2. bake the produced gradeops.db into the image (see note below) | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import json | |
| import sys | |
| from pathlib import Path | |
| try: | |
| import requests | |
| except ImportError: | |
| print("pip install requests", file=sys.stderr) | |
| raise | |
| def _post_json(base: str, path: str, body: dict, headers: dict | None = None) -> dict: | |
| r = requests.post(f"{base}{path}", json=body, headers=headers or {}, timeout=120) | |
| r.raise_for_status() | |
| return r.json() | |
| def create_exam(base: str, title: str, session_id: str) -> int: | |
| out = _post_json(base, "/api/exams", {"title": title}, {"X-Session-Id": session_id}) | |
| print(f" exam #{out['id']} '{out['title']}'") | |
| return out["id"] | |
| def create_rubric(base: str, exam_id: int, rubric: dict) -> int: | |
| body = { | |
| "exam_id": exam_id, | |
| "title": rubric["title"], | |
| "question_text": rubric["question_text"], | |
| "max_marks": float(rubric["max_marks"]), | |
| "course_instructions": rubric.get("course_instructions", ""), | |
| "criteria": rubric["criteria"], | |
| } | |
| out = _post_json(base, "/api/rubrics", body) | |
| print(f" rubric #{out['id']} '{out['title']}' ({out['version']})") | |
| return out["id"] | |
| def upload_paper(base: str, exam_id: int, rubric_id: int, file_path: str, | |
| student_anon_id: str | None) -> dict: | |
| p = Path(file_path) | |
| if not p.exists(): | |
| raise FileNotFoundError(f"paper file not found: {file_path}") | |
| data = {"exam_id": str(exam_id), "rubric_id": str(rubric_id)} | |
| if student_anon_id: | |
| data["student_anon_id"] = student_anon_id | |
| with p.open("rb") as fh: | |
| files = {"file": (p.name, fh)} | |
| r = requests.post(f"{base}/api/papers/upload", data=data, files=files, timeout=1800) | |
| r.raise_for_status() | |
| out = r.json() | |
| print(f" paper #{out['paper_id']} ({out['student_anon_id']}): " | |
| f"{len(out['crop_ids'])} crop(s) graded") | |
| return out | |
| def main() -> None: | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--manifest", required=True) | |
| ap.add_argument("--base", default="http://localhost:8000") | |
| args = ap.parse_args() | |
| manifest = json.loads(Path(args.manifest).read_text(encoding="utf-8")) | |
| session_id = manifest.get("session_id", "public") | |
| print(f"pre-grading against {args.base} (session '{session_id}')") | |
| exam_id = create_exam(args.base, manifest["exam_title"], session_id) | |
| rubric_ids = [create_rubric(args.base, exam_id, r) for r in manifest["rubrics"]] | |
| total_crops = 0 | |
| for paper in manifest["papers"]: | |
| rid = rubric_ids[int(paper.get("rubric_index", 0))] | |
| out = upload_paper(args.base, exam_id, rid, paper["file"], | |
| paper.get("student_anon_id")) | |
| total_crops += len(out["crop_ids"]) | |
| print(f"\ndone: exam #{exam_id}, {len(rubric_ids)} rubric(s), {total_crops} crop(s) graded.") | |
| print("The app's gradeops.db is now populated. Bake it into the image:") | |
| print(" Dockerfile: COPY gradeops.db /app/gradeops.db") | |
| print(" and make sure DATABASE_URL points at that path (sqlite:////app/gradeops.db).") | |
| print("The live demo then reads from the DB with no LLM call, and survives restarts.") | |
| if __name__ == "__main__": | |
| main() | |