"""Display-only Horary recast for birth-time rectification. If the user gives the time they first asked the question, recast a natal-like chart at that local datetime. Never score it. Never block propose or confirm. """ from __future__ import annotations import re from typing import Any from scripts.rectification.house_table import SIGNS_CN from scripts.rectification.kp_cusp_observation import observe_kp_cusps _CLOCK = re.compile(r"(?:[01]?\d|2[0-3]):[0-5]\d") def _question_clock(event: dict[str, Any]) -> str: summary = str(event.get("summary") or "") match = _CLOCK.search(summary) if match: hour, minute = match.group(0).split(":") return f"{int(hour):02d}:{int(minute):02d}" return "12:00" def build_horary_observation(request: dict[str, Any]) -> dict[str, Any]: events = [ event for event in (request.get("events") or []) if isinstance(event, dict) and event.get("event_kind") == "horary_query" ] if not events: return { "status": "skipped", "user_meaning": "没有第一次问起这件事的时间,占问观察未执行。", "unique_minute_claim": False, } try: lat = float(request["lat"]) lon = float(request["lon"]) tz = float(request["tz"]) except (KeyError, TypeError, ValueError): return { "status": "blocked", "user_meaning": "占问时间已记录,但观察盘未能重算。不计分,不挡提出门。", "unique_minute_claim": False, } event = events[0] date_text = str(event.get("date_start") or "")[:10] clock = _question_clock(event) try: year, month, day = (int(part) for part in date_text.split("-")) hour, minute = (int(part) for part in clock.split(":")) import domain_calculation_service chart = domain_calculation_service.compute_chart({ "year": year, "month": month, "day": day, "hour": hour, "minute": minute, "lat": float(request["lat"]), "lon": float(request["lon"]), "tz": float(request["tz"]), "ayanamsa": "raman", "node_mode": "mean", }) asc = chart.get("ascendant") or {} sign = str(asc.get("sign") or "") lagna = SIGNS_CN.get(sign, sign) birth_info = chart.get("birth_info") if isinstance(chart.get("birth_info"), dict) else {} kp = observe_kp_cusps(birth_info.get("julian_day"), float(request["lat"]), float(request["lon"])) angles = {} if kp.get("status") == "executed": for house in ("1", "4", "7", "10"): row = (kp.get("houses") or {}).get(house) or {} angles[house] = { "sub_lord": row.get("sub_lord"), "nakshatra_lord": row.get("nakshatra_lord"), } return { "status": "executed", "question_date": date_text, "question_time": clock, "lagna": lagna if lagna else None, "kp_angles": angles, "user_meaning": ( f"已按问起时间 {date_text} {clock} 重算占问盘作观察,不计分,不确认唯一分钟。" ), "unique_minute_claim": False, } except (TypeError, ValueError, KeyError, OverflowError, OSError): return { "status": "blocked", "question_date": date_text, "question_time": clock, "user_meaning": "占问时间已记录,但观察盘未能重算。不计分,不挡提出门。", "unique_minute_claim": False, }