Spaces:
Sleeping
Sleeping
File size: 3,512 Bytes
2aabc58 3475963 2aabc58 23b513a 086c738 23b513a 2aabc58 23b513a 2aabc58 23b513a 2aabc58 23b513a 042edfb 2aabc58 042edfb 2aabc58 042edfb 2aabc58 3475963 23b513a 3475963 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | """Constants and helpers for the intake form schema."""
import hashlib
import json
from typing import Literal, TypedDict, List
DESIGN_ELEMENTS: List[str] = [
"Hypotheses/Endpoints",
"Multiplicity control",
"Sample size and power",
"Interim analyses",
"Others",
]
QUESTION_TYPES: List[str] = [
"extraction_only",
"derivation_required",
]
QuestionType = Literal["extraction_only", "derivation_required", ""]
Status = Literal["pending", "reviewed", "needs_fix"]
VALID_STATUSES: List[str] = ["pending", "reviewed", "needs_fix"]
# Each criterion's importance (replaces the old numeric "points").
IMPORTANCE_OPTIONS: List[str] = ["High", "Medium", "Low"]
class Criterion(TypedDict):
criterion: str
importance: str
class Rubric(TypedDict):
# A dimension block; holds one or more criteria.
artifact: str
dimension: str
criteria: List[Criterion]
class Question(TypedDict):
id: str
design_element: str
design_element_other: str
question: str
question_type: str
rubrics: List[Rubric]
def dimensions_for_type(qt: str):
"""Fixed (artifact, dimension) blocks for a question type, each with the
number of criterion rows to show by default. The user fills in one or more
criteria under each; the first is primary, extras are optional."""
if qt == "extraction_only":
return [{"artifact": "output.json", "dimension": "", "default_criteria": 1}]
if qt == "derivation_required":
return [
{"artifact": "output.json", "dimension": "Inputs used", "default_criteria": 1},
{"artifact": "output.json", "dimension": "Calculated value", "default_criteria": 1},
{"artifact": "output.json", "dimension": "Method", "default_criteria": 3},
]
return []
def blank_question(qid: str) -> Question:
return {
"id": qid,
"design_element": "",
"design_element_other": "",
"question": "",
"question_type": "",
"rubrics": [],
}
def next_question_id(existing: List[Question]) -> str:
nums = []
for q in existing:
qid = q.get("id", "")
if qid.startswith("P-"):
try:
nums.append(int(qid[2:]))
except ValueError:
pass
return f"P-{(max(nums) + 1 if nums else 1):03d}"
def question_content_hash(q: dict) -> str:
"""Stable hash of a question's *content* (excludes its id).
Used to detect whether a question was edited since it was reviewed: if the
current content hash differs from the hash stored on a review, that review
no longer applies to the current content.
"""
canonical = {
"design_element": q.get("design_element", ""),
"design_element_other": q.get("design_element_other", ""),
"question": q.get("question", ""),
"question_type": q.get("question_type", ""),
"rubrics": [
{
"artifact": r.get("artifact", ""),
"dimension": r.get("dimension", ""),
"criteria": [
{
"criterion": c.get("criterion", ""),
"importance": c.get("importance", ""),
}
for c in (r.get("criteria") or [])
],
}
for r in (q.get("rubrics") or [])
],
}
blob = json.dumps(canonical, sort_keys=True, ensure_ascii=False)
return hashlib.sha1(blob.encode("utf-8")).hexdigest()
|