"""Shared response-parsing helpers for LLM providers.""" from __future__ import annotations import json import re from physcom.models.domain import MetricBound def parse_verdict(text: str) -> bool: """Extract VERDICT: PLAUSIBLE/IMPLAUSIBLE from response; default to True.""" m = re.search(r"VERDICT:\s*(PLAUSIBLE|IMPLAUSIBLE)", text, re.IGNORECASE) if m: return m.group(1).upper() == "PLAUSIBLE" return True def parse_rating(text: str) -> str | None: """Extract RATING: LOW/MEDIUM/HIGH from response; None if absent (older reviews saved before this existed, or a malformed response).""" m = re.search(r"RATING:\s*(LOW|MEDIUM|HIGH)", text, re.IGNORECASE) return m.group(1).upper() if m else None def parse_metric_json(text: str, metrics: list[MetricBound]) -> dict[str, float]: """Strip markdown fences and parse JSON; fall back to each metric's own norm_min/norm_max midpoint on error — a flat constant like 0.5 is guaranteed wrong-magnitude for at least some metrics regardless of unit. """ names = {mb.metric_name for mb in metrics} text = re.sub(r"```(?:json)?\s*", "", text).strip().rstrip("`").strip() try: data = json.loads(text) return {k: float(v) for k, v in data.items() if k in names} except (json.JSONDecodeError, ValueError, TypeError): return {mb.metric_name: (mb.norm_min + mb.norm_max) / 2 for mb in metrics}