6f87b2b323
Jedyne wymaganie Must bez implementacji. Nowy zodiac.py + wpiecie w horoskop: - zodiac.py: ayanamsy (Lahiri, Fagan-Bradley, Krishnamurti) modelem ayan(jd)=ayan0+B*x+C*x^2 (wspolna precesja, rozna stala) — skalibrowanym do Swiss Ephemeris jako WYROCZNI: zgodnosc do ~0,02" w latach 1900-2100. Draconic = wzgledem wzla wznoszacego (wzel = 0 Barana). RA: konwersja ekliptyka->rownik (to_equatorial) na przyszly widok rownikowy. - chart.py: build_chart(..., zodiac): offset jednolicie przesuwa etykiety znakow/dlugosci obiektow, osi, cusps i Lots; DOMY licza sie po dlugosci tropikalnej (geometria niezmiennicza wzgledem obrotu -> numery domow bez zmian). Domyslnie tropical -> sciezka i wyniki bez zmian. - main.py: /chart/positions przyjmuje `zodiac`; bledny -> 422. - prezentacja: dropdown „Zodiak" + pokazanie ayanamshy w wynikach. Testy (14): ayanamsy vs wyrocznia swisseph (<0.1"), julian_day, draconic (wzel=0 Barana), niezmienniczosc domow, RA w punktach charakterystycznych, odrzucenie bledow. Cala logika: 99 passed, 1 skipped. Zweryfikowane e2e w przegladarce (horoskop syderyczny Lahiri: Slonce Aries 16°34', ayan 23.6382). RA jako osobny widok zodiaku (per-obiekt, z szerokoscia) — do osobnego PR. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
75 lines
2.9 KiB
Python
75 lines
2.9 KiB
Python
"""Klient HTTP do warstwy logicznej.
|
|
|
|
Jedyny punkt styku prezentacji w dół. Przekazuje dane z formularza i odbiera
|
|
opracowane wyniki. Prezentacja nie sięga bezpośrednio do bazy ani do silnika.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
import httpx
|
|
|
|
from app.config import settings
|
|
|
|
|
|
class LogicClient:
|
|
def __init__(self, base_url: str | None = None) -> None:
|
|
self.base_url = (base_url or settings.logic_url).rstrip("/")
|
|
|
|
def query(self, query: str, field: str, exact: bool, limit: int) -> dict[str, Any]:
|
|
payload = {"query": query, "field": field, "exact": exact, "limit": limit}
|
|
with httpx.Client(timeout=settings.http_timeout) as client:
|
|
r = client.post(f"{self.base_url}/api/query", json=payload)
|
|
r.raise_for_status()
|
|
return r.json()
|
|
|
|
def positions(
|
|
self,
|
|
when_utc_iso: str,
|
|
lat: float,
|
|
lon: float,
|
|
objects: list[str] | None = None,
|
|
house_system: str = "whole_sign",
|
|
stations: bool = False,
|
|
zodiac: str = "tropical",
|
|
) -> dict[str, Any]:
|
|
"""Pełny horoskop dla danego momentu — woła logic /chart/positions."""
|
|
payload = {
|
|
"when_utc": when_utc_iso,
|
|
"lat": lat,
|
|
"lon": lon,
|
|
"objects": objects,
|
|
"house_system": house_system,
|
|
"stations": stations,
|
|
"zodiac": zodiac,
|
|
}
|
|
# stacje wymagają root-findów — dłuższy timeout
|
|
with httpx.Client(timeout=max(settings.http_timeout, 60.0) if stations else settings.http_timeout) as client:
|
|
r = client.post(f"{self.base_url}/chart/positions", json=payload)
|
|
r.raise_for_status()
|
|
return r.json()
|
|
|
|
def report(
|
|
self, when_utc_iso: str, lat: float, lon: float, limit: int = 5000, group: bool = False
|
|
) -> dict[str, Any]:
|
|
"""Sygnifikatory z obliczeń szukane w bazie — woła logic /chart/report."""
|
|
payload = {"when_utc": when_utc_iso, "lat": lat, "lon": lon, "limit": limit, "group": group}
|
|
with httpx.Client(timeout=max(settings.http_timeout, 30.0)) as client:
|
|
r = client.post(f"{self.base_url}/chart/report", json=payload)
|
|
r.raise_for_status()
|
|
return r.json()
|
|
|
|
def timeline(
|
|
self, when_utc_iso: str, lat: float, lon: float,
|
|
from_date: str, to_date: str, interpret: bool = True,
|
|
) -> dict[str, Any]:
|
|
"""Oś czasu z technik (+interpretacje z bazy) — woła logic /chart/timeline."""
|
|
payload = {
|
|
"when_utc": when_utc_iso, "lat": lat, "lon": lon,
|
|
"from_date": from_date, "to_date": to_date, "interpret": interpret,
|
|
}
|
|
with httpx.Client(timeout=max(settings.http_timeout, 60.0)) as client:
|
|
r = client.post(f"{self.base_url}/chart/timeline", json=payload)
|
|
r.raise_for_status()
|
|
return r.json()
|