import json import re from typing import Any def normalize_answer(raw: str, item_type: int | None) -> str: if not raw: return "" s = raw.strip().upper() if item_type == 288: letters = re.findall(r"[A-Z]", s.replace(",", "")) return "".join(sorted(set(letters))) return s.replace(",", "").strip() def normalize_reference(ref: str, item_type: int | None) -> str: if not ref: return "" s = ref.strip().upper() if item_type == 288: letters = re.findall(r"[A-Z]", s) return "".join(sorted(set(letters))) return s def get_correct_mark(answer_rules: str | None, default: float = 1.0) -> float: if not answer_rules: return default try: rules = json.loads(answer_rules) return float(rules.get("correctMark", default)) except (json.JSONDecodeError, TypeError, ValueError): return default def grade_item( user_answer: str, reference_answer: str, answer_rules: str | None, item_type: int | None, max_score: float | None, ) -> tuple[bool, float]: ua = normalize_answer(user_answer, item_type) ra = normalize_reference(reference_answer, item_type) if not ra and answer_rules: try: rules = json.loads(answer_rules) ra = normalize_reference(str(rules.get("reference", "")), item_type) except json.JSONDecodeError: pass mark = get_correct_mark(answer_rules, max_score or 1.0) ok = ua == ra and bool(ra) return ok, (mark if ok else 0.0) def answers_json_to_map(answers_json: str) -> dict[str, str]: try: arr = json.loads(answers_json) except json.JSONDecodeError: return {} out: dict[str, str] = {} if isinstance(arr, list): for item in arr: if isinstance(item, dict): iid = item.get("itemId") or item.get("item_id") ans = item.get("answer", "") if iid: out[str(iid)] = str(ans) if ans is not None else "" return out