"""Most: policzony horoskop → tokeny sygnifikatorów → wyszukiwanie w bazie. Pierwsza wersja (LOG-16/18/19 w zalążku): z pozycji obiektów generujemy tokeny w składni bazy (np. Słońce w Byku → planeta `[Su`, znak `[Tau`), pytamy warstwę danych o rekordy zawierające token planety, a następnie zawężamy do tych, które wspominają też jej znak („planeta w swoim znaku"). To realizuje przepływ „wynik obliczeń szukany w pliku". Format skrótów odczytany z realnej bazy (Encyclopaedia of Medical Astrology): planety `[Su`,`[Mo`,…; znaki `[Ari`,`[Tau`,…; np. `[Su affl. in [Vir`. """ from __future__ import annotations from typing import Any, Protocol from app.engine.formats import SIGN_ABBR, sign_index PLANET_ABBR = { "Sun": "Su", "Moon": "Mo", "Mercury": "Me", "Venus": "Ve", "Mars": "Ma", "Jupiter": "Ju", "Saturn": "Sa", "Uranus": "Ur", "Neptune": "Ne", "Pluto": "Pl", } class DataSource(Protocol): def search( self, key: str, value: str, exact: bool, limit: int, fields: list[str] | None = None ) -> dict[str, Any]: ... def _effect(row: dict) -> str: for col in ("actioneffect", "topicresult", "bodypart"): v = row.get(col) if v and str(v).strip().lower() not in ("", "nan"): return str(v).strip() return "" def _is_noise(sig: str, effect: str) -> bool: s = sig.strip().lower() return ( not effect or s.startswith("significator") or "header" in s or s in ("x", "x?", "nan") ) def build_report(positions, data: DataSource, per_object_limit: int = 60) -> dict: """Dla każdego obiektu: wyszukaj sygnifikatory planety i zawęź do jej znaku.""" items: list[dict] = [] provider = None for p in positions: if p.name not in PLANET_ABBR: continue planet_tok = "[" + PLANET_ABBR[p.name] sign_tok = "[" + SIGN_ABBR[sign_index(p.longitude)] raw = data.search( key="significator", value=planet_tok, exact=False, limit=per_object_limit, fields=["significator", "actioneffect", "topicresult", "bodypart"], ) provider = raw.get("provider", provider) rows = raw.get("rows", []) samples: list[dict] = [] for r in rows: sig = str(r.get("significator") or "") if sign_tok.lower() not in sig.lower(): continue eff = _effect(r) if _is_noise(sig, eff): continue samples.append({"significator": sig.strip(), "effect": eff}) items.append({ "object": p.name, "sign": p.sign, "direction": p.direction, "planet_token": planet_tok, "sign_token": sign_tok, "planet_total": raw.get("total", 0), "in_sign_count": len(samples), "samples": samples[:5], }) return {"provider": provider, "objects": items}