Parcourir la source

houses parameter added

Lukas Goldschmidt il y a 1 mois
Parent
commit
c8efe6b406
1 fichiers modifiés avec 62 ajouts et 1 suppressions
  1. 62 1
      src/ephemeris_mcp/server.py

+ 62 - 1
src/ephemeris_mcp/server.py

@@ -69,6 +69,13 @@ def _parse_date(date_str: str) -> float:
     return julday(dt.year, dt.month, dt.day, 12.0)
 
 
+def _sign_name(lon: float) -> str:
+    signs = ["Aries","Taurus","Gemini","Cancer","Leo","Virgo","Libra","Scorpio","Sagittarius","Capricorn","Aquarius","Pisces"]
+    return signs[int(lon / 30) % 12]
+
+def _sign_abbr(lon: float) -> str:
+    return _sign_name(lon)[:3]
+
 def _utc_date_from_datetime(dt_str: str | None) -> str:
     """Convert an ISO datetime string to a UTC date string."""
     if dt_str is None:
@@ -373,6 +380,7 @@ def get_sky_state(
     lon: float | None = None,
     elevation: float = 0.0,
     geocentric: bool = True,
+    house_system: str | None = None,
 ) -> dict:
     """
     Return a consolidated raw sky-state snapshot for downstream chart engines.
@@ -380,6 +388,23 @@ def get_sky_state(
     This stays purely descriptive: it combines the core astronomical outputs
     already exposed elsewhere in the server without adding signs, houses, or
     interpretation.
+
+    Args:
+        datetime: ISO 8601 datetime (UTC). Defaults to now.
+        lat: Observer latitude in decimal degrees.
+        lon: Observer longitude in decimal degrees.
+        elevation: Observer elevation in meters.
+        geocentric: If True, return geocentric positions instead of topocentric.
+        house_system: Optional house system code. When provided, includes house
+            cusps and angles in the response. Supported codes:
+            'P' = Placidus, 'K' = Koch, 'E' = Equal, 'W' = Whole Sign,
+            'A' = Alcabitius, 'C' = Campanus, 'M' = Morinus, 'R' = Porphyry,
+            'T' = Polich/Page, 'U' = Krusinski-Pisa, 'V' = Vehlow Equal,
+            'X' = Meridian, 'Y' = Horizontal, 'H' = Azimuthal, 'B' = Alcabitius,
+            'O' = Equal/MC, 'F' = Carter poli-eq, 'D' = Equal from 15° Aries,
+            'G' = Gauquelin sectors, 'I' = Sunshine, 'J' = Sunshine alt,
+            'L' = Pullen SD, 'N' = Equal/1, 'Q' = Pullen SR, 'S' = Sripati,
+            'Z' = APC houses.
     """
     lat, lon = _default_location(lat, lon)
     date = _utc_date_from_datetime(datetime)
@@ -387,13 +412,14 @@ def get_sky_state(
 
     ck = cache_key(
         "get_sky_state",
-        cache_version=1,
+        cache_version=2,
         datetime=datetime or "now",
         date=date,
         elevation=elevation,
         geocentric=geocentric,
         lat=lat,
         lon=lon,
+        house_system=house_system,
     )
     cached = cache.get(ck)
     if cached:
@@ -405,6 +431,7 @@ def get_sky_state(
                 "lon": lon,
                 "elevation": elevation,
                 "geocentric": geocentric,
+                "house_system": house_system,
             },
             **cached,
         }
@@ -428,6 +455,7 @@ def get_sky_state(
             "lon": lon,
             "elevation": elevation,
             "geocentric": geocentric,
+            "house_system": house_system,
         },
         "timestamp_utc": datetime or __import__("datetime").datetime.now(timezone.utc).isoformat(),
         "julian_day": round(jd, 6),
@@ -436,6 +464,38 @@ def get_sky_state(
         "lunar_state": lunar_state,
         "sidereal_time": sidereal_time,
     }
+
+    # Compute house cusps when requested
+    if house_system is not None:
+        hs_code = house_system.upper().encode()
+        try:
+            cusps, ascmc = swe.houses(jd, lat, lon, hs_code)
+            houses = []
+            for i in range(12):
+                houses.append({
+                    "house": i + 1,
+                    "absolute_lon": cusps[i],
+                    "sign": _sign_name(cusps[i]),
+                    "abbreviation": _sign_abbr(cusps[i]),
+                    "degree": cusps[i] % 30.0,
+                })
+            result["houses"] = {
+                "system": house_system.upper(),
+                "cusps": houses,
+                "ascendant": ascmc[0],
+                "midheaven": ascmc[1],
+                "descendant": ascmc[0] + 180.0 if ascmc[0] < 180.0 else ascmc[0] - 180.0,
+                "imum_coeli": ascmc[1] + 180.0 if ascmc[1] < 180.0 else ascmc[1] - 180.0,
+                "armc": ascmc[2] if len(ascmc) > 2 else None,
+                "equatorial_ascendant": ascmc[3] if len(ascmc) > 3 else None,
+                "vertex": ascmc[4] if len(ascmc) > 4 else None,
+                "co_ascendant": ascmc[5] if len(ascmc) > 5 else None,
+                "polar_ascendant": ascmc[6] if len(ascmc) > 6 else None,
+            }
+        except Exception as exc:
+            logger.warning(f"house calculation failed for system {house_system!r}: {exc}")
+            result["houses"] = {"system": house_system.upper(), "error": str(exc)}
+
     cache.set(
         ck,
         {
@@ -445,6 +505,7 @@ def get_sky_state(
             "solar_events": solar_events,
             "lunar_state": lunar_state,
             "sidereal_time": sidereal_time,
+            "houses": result.get("houses"),
         },
         config.CACHE_SKY,
     )