Spaces:
Paused
Paused
Download scripts/verify_provider.py from Syed-Hassan/obe-matrix: direct link, hf CLI and curl.
- Browser
- Download file 5.34 kB
-
https://huggingface.co/spaces/Syed-Hassan/obe-matrix/resolve/main/scripts/verify_provider.py
- Command line
-
hf download hf://spaces/Syed-Hassan/obe-matrix/scripts/verify_provider.py
-
curl -L -o verify_provider.py https://huggingface.co/spaces/Syed-Hassan/obe-matrix/resolve/main/scripts/verify_provider.py
5.34 kB
| """Check that the configured provider actually produces valid output. | |
| An HTTP 200 proves nothing — llama2 7b/13b returned 200s full of wrong field | |
| names, inline comments, and fractional weights. Only a real generation that | |
| validates against the Pydantic schema counts as working. | |
| Run before any deploy, and again after changing OBE_LLM_MODEL: | |
| python scripts/verify_provider.py | |
| Exits non-zero if any generation fails. | |
| """ | |
| import logging | |
| import os | |
| import sys | |
| import time | |
| sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) | |
| from obe.course_plo_prompt import build_course_plo_messages | |
| from obe.llm_client import ( | |
| generate_course_plo_mapping, | |
| generate_obe_matrix, | |
| generate_question_set, | |
| get_provider, | |
| ) | |
| from obe.prompt import build_messages | |
| from obe.question_prompt import build_question_messages | |
| from obe.schema import BLOOM_LABELS | |
| logging.basicConfig(level=logging.INFO, format="%(levelname)s %(name)s: %(message)s") | |
| CHAPTER = """ | |
| Memory is the process by which information is encoded, stored, and retrieved. | |
| Encoding converts sensory input into a form the brain can process. Storage | |
| maintains that information over time, across sensory, short-term, and long-term | |
| stores. Retrieval brings stored information back into awareness. The multi-store | |
| model distinguishes these stages, while the levels-of-processing framework | |
| argues that depth of processing at encoding predicts later recall better than | |
| time spent in any one store. Interference and decay both explain forgetting. | |
| """ | |
| PLOS = [ | |
| "PLO-01: Apply core psychological theories to explain human behaviour.", | |
| "PLO-02: Evaluate research evidence critically.", | |
| ] | |
| def _check(label: str, fn) -> tuple[bool, float]: | |
| print(f"\n-- {label} " + "-" * (56 - len(label))) | |
| start = time.perf_counter() | |
| try: | |
| result = fn() | |
| except Exception as exc: | |
| elapsed = time.perf_counter() - start | |
| print(f" FAIL ({elapsed:.1f}s): {type(exc).__name__}: {exc}") | |
| return False, elapsed | |
| elapsed = time.perf_counter() - start | |
| print(f" OK ({elapsed:.1f}s)") | |
| return True, elapsed | |
| def _obe(): | |
| matrix = generate_obe_matrix(build_messages("Cognitive Psychology", PLOS, CHAPTER)) | |
| assert matrix.clos, "no CLOs generated" | |
| first = matrix.clos[0] | |
| weights = first.assessment_weights | |
| total = weights.quiz + weights.assignment + weights.midterm + weights.final | |
| print(f" {len(matrix.clos)} CLOs; first at Bloom {first.bloom_level} " | |
| f"({first.bloom_label}); weights sum to {total:g}") | |
| print(f" CLO: {first.clo_text[:80]}") | |
| return matrix | |
| def _questions(): | |
| qs = generate_question_set( | |
| build_question_messages( | |
| clo_text="Explain how encoding depth affects long-term recall.", | |
| content_text=CHAPTER, | |
| bloom_level=2, | |
| bloom_label=BLOOM_LABELS[2], | |
| difficulty="Medium", | |
| question_type="MCQ (single correct)", | |
| question_count=3, | |
| option_count=4, | |
| ) | |
| ) | |
| assert qs.questions, "no questions generated" | |
| first = qs.questions[0] | |
| assert len(first.options) == 4, f"expected 4 options, got {len(first.options)}" | |
| print(f" {len(qs.questions)} questions; {len(first.options)} options on the first") | |
| print(f" Q: {first.question_text[:80]}") | |
| return qs | |
| def _mapping(): | |
| result = generate_course_plo_mapping( | |
| build_course_plo_messages( | |
| program="BS Psychology", | |
| course_batch=[ | |
| { | |
| "Code": "PSY-101", | |
| "Course Title": "Introduction to Psychology", | |
| "Objectives": "Survey of major areas of psychology.", | |
| "Cr. Hrs.": "3", | |
| }, | |
| { | |
| "Code": "PSY-201", | |
| "Course Title": "Research Methods I", | |
| "Objectives": "Design and evaluation of psychological research.", | |
| "Cr. Hrs.": "3", | |
| }, | |
| ], | |
| plo_list=[ | |
| {"PLO Code": "PLO-01", "PLO Text": PLOS[0]}, | |
| {"PLO Code": "PLO-02", "PLO Text": PLOS[1]}, | |
| ], | |
| ) | |
| ) | |
| assert result.mappings, "no mappings generated" | |
| codes = [m.course_code for m in result.mappings] | |
| print(f" {len(result.mappings)} courses mapped: {', '.join(codes)}") | |
| return result | |
| def main() -> int: | |
| provider = get_provider() | |
| print(f"Provider : {provider.name}") | |
| print(f"Model : {provider.model}") | |
| print(f"Schema : {provider.schema_mode.value}") | |
| print(f"Timeout : {provider.timeout}s") | |
| if provider.schema_mode.value != "native": | |
| print("\n NOTE: no constrained decoding for this model — output is not") | |
| print(" schema-guaranteed. The runner will fall back and repair, but") | |
| print(" a strict-capable model is safer for production.") | |
| results = [ | |
| _check("OBEMatrix", _obe), | |
| _check("QuestionSet", _questions), | |
| _check("CoursePLOMappingSet", _mapping), | |
| ] | |
| passed = sum(1 for ok, _ in results if ok) | |
| total_time = sum(t for _, t in results) | |
| print("\n" + "=" * 60) | |
| print(f"{passed}/{len(results)} passed in {total_time:.1f}s") | |
| return 0 if passed == len(results) else 1 | |
| if __name__ == "__main__": | |
| sys.exit(main()) | |