"""사주 + 궁합 응답 JSON 검증.""" VALID_CONFIDENCE = {"high", "medium", "low"} SAJU_ITEM_KEYS = { "기질", "오행밸런스", "지지상호작용", "신살영향", "재물운", "직업적성", "애정운", "건강운", "현재대운", "올해세운", "인생황금기", "종합조언", } def validate_saju_interpretation(parsed: dict) -> tuple[bool, str]: if not isinstance(parsed, dict): return False, "응답이 dict가 아님" for k in ("items", "summary", "advice", "confidence"): if k not in parsed: return False, f"필수 필드 누락: {k}" if parsed.get("confidence") not in VALID_CONFIDENCE: return False, f"confidence 값 비정상: {parsed.get('confidence')}" items = parsed["items"] if not isinstance(items, list): return False, "items가 list 아님" if len(items) != 12: return False, f"items는 12개 필요 (현재 {len(items)})" seen_keys = set() for i, it in enumerate(items): if not isinstance(it, dict): return False, f"items[{i}] dict 아님" for k in ("key", "title", "content", "evidence"): if k not in it: return False, f"items[{i}].{k} 누락" if it["key"] not in SAJU_ITEM_KEYS: return False, f"items[{i}].key 비정상: {it['key']}" if it["key"] in seen_keys: return False, f"items[{i}].key 중복: {it['key']}" seen_keys.add(it["key"]) ev = it["evidence"] if not isinstance(ev, dict) or "saju_element" not in ev or "reasoning" not in ev: return False, f"items[{i}].evidence 형식 오류" if not ev.get("saju_element", "").strip() or not ev.get("reasoning", "").strip(): return False, f"items[{i}].evidence 빈 문자열" return True, "" def validate_compat_interpretation(parsed: dict) -> tuple[bool, str]: if not isinstance(parsed, dict): return False, "응답이 dict가 아님" for k in ("summary", "strengths", "challenges", "advice", "confidence"): if k not in parsed: return False, f"필수 필드 누락: {k}" if parsed.get("confidence") not in VALID_CONFIDENCE: return False, f"confidence 값 비정상: {parsed.get('confidence')}" for k in ("strengths", "challenges"): v = parsed[k] if not isinstance(v, list) or not v: return False, f"{k}는 비어있지 않은 list 필요" for i, item in enumerate(v): if not isinstance(item, dict) or "title" not in item or "explanation" not in item or "evidence" not in item: return False, f"{k}[{i}] 형식 오류" return True, ""