"""Compact D1 house table for the public rectification surface. Sign names and occupants only. Longitudes, coordinates, scores and fingerprints stay out of this projection. """ from __future__ import annotations from typing import Any from scripts.jyotish_engine import SIGNS, SIGNS_CN PLANET_ORDER = ( "Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn", "Rahu", "Ketu", ) PLANET_ZH = { "Sun": "太阳", "Moon": "月亮", "Mars": "火星", "Mercury": "水星", "Jupiter": "木星", "Venus": "金星", "Saturn": "土星", "Rahu": "罗睺", "Ketu": "计都", } def _sign_cn(sign: str | None) -> str | None: if not isinstance(sign, str) or sign not in SIGNS_CN: return None return SIGNS_CN[sign] def _house_number(value: Any, sign: str | None, asc_idx: int | None) -> int | None: if isinstance(value, int) and 1 <= value <= 12: return value if not sign or sign not in SIGNS or asc_idx is None: return None return ((SIGNS.index(sign) - asc_idx) % 12) + 1 def compact_house_table(chart: Any, *, time: str) -> dict[str, Any] | None: if not isinstance(chart, dict) or not isinstance(time, str): return None ascendant = chart.get("ascendant") if isinstance(chart.get("ascendant"), dict) else {} lagna = _sign_cn(str(ascendant.get("sign") or "") or None) if not lagna: return None try: asc_idx = SIGNS.index(str(ascendant["sign"])) except (KeyError, ValueError): return None occupants: dict[int, list[str]] = {house: [] for house in range(1, 13)} planets = chart.get("planets") if isinstance(chart.get("planets"), dict) else {} for name in PLANET_ORDER: data = planets.get(name) if not isinstance(data, dict): continue house = _house_number(data.get("house"), str(data.get("sign") or "") or None, asc_idx) label = PLANET_ZH.get(name) if house is None or not label or label in occupants[house]: continue occupants[house].append(label) houses = [] for house in range(1, 13): sign = _sign_cn(SIGNS[(asc_idx + house - 1) % 12]) if not sign: return None houses.append({ "house": house, "sign": sign, "occupants": occupants[house], }) return { "time": time[:5], "lagna": lagna, "houses": houses, } def compact_house_table_from_contexts(contexts: Any, time: str | None) -> dict[str, Any] | None: if not isinstance(time, str) or not time or not isinstance(contexts, list): return None wanted = time[:5] for context in contexts: if not isinstance(context, dict): continue feature = context.get("feature") if isinstance(context.get("feature"), dict) else {} feature_time = feature.get("time") candidate_at = context.get("candidate_at") context_time = feature_time if isinstance(feature_time, str) else None if context_time is None and hasattr(candidate_at, "strftime"): context_time = candidate_at.strftime("%H:%M") if context_time != wanted: continue return compact_house_table(context.get("chart"), time=wanted) return None