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
|