年运附表补上整宫、Tripataki 和特殊点公式轨迹。黄经沿用已算好的星盘,不改原有 Saham 数值。
Co-Authored-By: Grok (agent loop) Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Grok (agent loop)
Cursor
parent
6b906f85c4
commit
9b2e6aa0b4
@@ -0,0 +1,73 @@
|
||||
"""Whole-sign houses for an annual chart that is already computed."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
|
||||
SIGNS = (
|
||||
"Aries", "Taurus", "Gemini", "Cancer", "Leo", "Virgo",
|
||||
"Libra", "Scorpio", "Sagittarius", "Capricorn", "Aquarius", "Pisces",
|
||||
)
|
||||
SIGN_LORDS = {
|
||||
"Aries": "Mars", "Taurus": "Venus", "Gemini": "Mercury", "Cancer": "Moon",
|
||||
"Leo": "Sun", "Virgo": "Mercury", "Libra": "Venus", "Scorpio": "Mars",
|
||||
"Sagittarius": "Jupiter", "Capricorn": "Saturn", "Aquarius": "Saturn", "Pisces": "Jupiter",
|
||||
}
|
||||
|
||||
|
||||
def _longitude(value: Any) -> float | None:
|
||||
if isinstance(value, bool) or not isinstance(value, (int, float)):
|
||||
return None
|
||||
return float(value) % 360.0
|
||||
|
||||
|
||||
def build_annual_whole_sign_houses(chart: dict | None) -> dict[str, Any]:
|
||||
"""Twelve whole-sign houses from the annual ascendant already on the chart."""
|
||||
chart = chart if isinstance(chart, dict) else {}
|
||||
ascendant = chart.get("ascendant") if isinstance(chart.get("ascendant"), dict) else {}
|
||||
planets = chart.get("planets") if isinstance(chart.get("planets"), dict) else {}
|
||||
asc_lon = _longitude(ascendant.get("degree_raw"))
|
||||
if asc_lon is None:
|
||||
asc_lon = _longitude(ascendant.get("lon") if ascendant.get("lon") is not None else ascendant.get("degree"))
|
||||
if asc_lon is None:
|
||||
return {
|
||||
"schema": "jyotish.annual_whole_sign_houses.v1",
|
||||
"status": "blocked",
|
||||
"reason": "annual_ascendant_longitude_missing",
|
||||
"houses": [],
|
||||
"source_longitudes": {},
|
||||
}
|
||||
asc_index = int(asc_lon // 30.0) % 12
|
||||
placed: dict[int, list[str]] = {index: [] for index in range(12)}
|
||||
source_longitudes = {}
|
||||
for name in ("Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn", "Rahu", "Ketu"):
|
||||
data = planets.get(name)
|
||||
if not isinstance(data, dict):
|
||||
continue
|
||||
longitude = _longitude(data.get("degree_raw"))
|
||||
if longitude is None:
|
||||
longitude = _longitude(data.get("degree"))
|
||||
if longitude is None:
|
||||
continue
|
||||
if name in ("Sun", "Moon") and data.get("degree_raw") is not None and not isinstance(data.get("degree_raw"), bool):
|
||||
source_longitudes[name] = float(data["degree_raw"]) % 360.0
|
||||
placed[int(longitude // 30.0) % 12].append(name)
|
||||
houses = []
|
||||
for house in range(1, 13):
|
||||
sign_index = (asc_index + house - 1) % 12
|
||||
sign = SIGNS[sign_index]
|
||||
houses.append({
|
||||
"house": house,
|
||||
"sign": sign,
|
||||
"lord": SIGN_LORDS[sign],
|
||||
"occupants": placed[sign_index],
|
||||
"cusp_longitude": sign_index * 30.0,
|
||||
})
|
||||
return {
|
||||
"schema": "jyotish.annual_whole_sign_houses.v1",
|
||||
"status": "partial_verified",
|
||||
"house_system": "whole_sign",
|
||||
"houses": houses,
|
||||
"source_longitudes": source_longitudes,
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
"""Formula traces for Sahams that were already calculated.
|
||||
|
||||
The trace copies the stored longitude. It does not replace it.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
|
||||
# (result key, day (p1, p2), night (p1, p2) or None when day and night match)
|
||||
# _saham(p1, p2) = Asc + p2 - p1.
|
||||
_LOCAL = (
|
||||
("karya_saham", ("Moon", "Mars"), ("Mars", "Moon")),
|
||||
("vivah_saham", ("Mars", "Venus"), None),
|
||||
("rajya_saham", ("Jupiter", "Sun"), None),
|
||||
("shatru_saham", ("Saturn", "Mars"), None),
|
||||
("labha_saham", ("Moon", "Jupiter"), None),
|
||||
("parakrama_saham", ("Sun", "Mars"), None),
|
||||
("putra_saham", ("Moon", "Jupiter"), None),
|
||||
("jnana_saham", ("Mercury", "Jupiter"), None),
|
||||
("raja_saham", ("Moon", "Sun"), None),
|
||||
("yasha_saham", ("Sun", "Jupiter"), None),
|
||||
("karma_saham", ("Mars", "Saturn"), None),
|
||||
("bandhu_saham", ("Mercury", "Mars"), None),
|
||||
("matri_saham", ("Venus", "Moon"), None),
|
||||
("pitri_saham", ("Saturn", "Sun"), None),
|
||||
("janma_saham", ("Sun", "Asc"), None),
|
||||
("mrityu_saham", ("Mars", "Saturn"), None),
|
||||
("rogha_saham", ("Saturn", "Mercury"), None),
|
||||
("aarogya_saham", ("Saturn", "Jupiter"), None),
|
||||
("bhraatri_saham", ("Moon", "Mars"), None),
|
||||
("ghataka_saham", ("Mars", "Rahu"), None),
|
||||
("paradesa_saham", ("Moon", "Saturn"), None),
|
||||
("parabharya_saham", ("Mars", "Venus"), None),
|
||||
("dhan_saham", ("Venus", "Jupiter"), None),
|
||||
("maya_saham", ("Ketu", "Rahu"), None),
|
||||
("moksha_saham", ("Jupiter", "Ketu"), None),
|
||||
("buddha_saham", ("Jupiter", "Mercury"), None),
|
||||
("shastra_saham", ("Ketu", "Mars"), None),
|
||||
("kala_saham", ("Sun", "Saturn"), None),
|
||||
("shakti_saham", ("Moon", "Venus"), None),
|
||||
("bhrigu_saham", ("Jupiter", "Venus"), None),
|
||||
("sundara_saham", ("Mercury", "Venus"), None),
|
||||
("jnati_saham", ("Saturn", "Mars"), None),
|
||||
("artha_saham", ("Venus", "Sun"), None),
|
||||
("dharma_saham", ("Saturn", "Jupiter"), None),
|
||||
("sangrama_saham", ("Rahu", "Mars"), None),
|
||||
)
|
||||
|
||||
|
||||
def _rule_text(meta: dict) -> str:
|
||||
operands = meta.get("formula_operands") or ()
|
||||
text = " + ".join(str(part).replace("_", " ") for part in operands) if operands else str(meta.get("rule_name") or "rule")
|
||||
if meta.get("zodiacal_order_exception_applied"):
|
||||
text += " (+30 deg)"
|
||||
return text
|
||||
|
||||
|
||||
def attach_formula_traces(
|
||||
results: dict[str, Any],
|
||||
*,
|
||||
is_day: bool,
|
||||
formula_meta: dict[str, dict] | None = None,
|
||||
) -> list[dict]:
|
||||
"""Add ``formula_traces`` without changing any existing Saham longitude."""
|
||||
formula_meta = formula_meta or {}
|
||||
traces = []
|
||||
punya = formula_meta.get("punya_saham")
|
||||
if punya and isinstance(results.get("punya_saham"), dict):
|
||||
traces.append({
|
||||
"name": results["punya_saham"].get("name") or "Punya Saham",
|
||||
"key": "punya_saham",
|
||||
"rule": _rule_text(punya),
|
||||
"phase": "day" if is_day else "night",
|
||||
"longitude": results["punya_saham"].get("longitude"),
|
||||
})
|
||||
for key, day_pair, night_pair in _LOCAL:
|
||||
item = results.get(key)
|
||||
if not isinstance(item, dict) or not isinstance(item.get("longitude"), (int, float)):
|
||||
continue
|
||||
meta = formula_meta.get(key)
|
||||
if meta:
|
||||
rule = _rule_text(meta)
|
||||
else:
|
||||
pair = day_pair if is_day or night_pair is None else night_pair
|
||||
rule = f"Asc + {pair[1]} - {pair[0]}"
|
||||
traces.append({
|
||||
"name": item.get("name") or key,
|
||||
"key": key,
|
||||
"rule": rule,
|
||||
"phase": "day" if is_day else "night",
|
||||
"longitude": item.get("longitude"),
|
||||
})
|
||||
results["formula_traces"] = traces
|
||||
return traces
|
||||
@@ -0,0 +1,104 @@
|
||||
"""Tripataki placement grid and Vedha rows from an annual chart.
|
||||
|
||||
Longitudes are the ones already on our chart. This module does not call an
|
||||
ephemeris and does not import PyJHora.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
|
||||
SIGNS = (
|
||||
"Aries", "Taurus", "Gemini", "Cancer", "Leo", "Virgo",
|
||||
"Libra", "Scorpio", "Sagittarius", "Capricorn", "Aquarius", "Pisces",
|
||||
)
|
||||
VEDHA_TARGETS = {
|
||||
"Moon": ("Sun", "Mars", "Mercury", "Venus", "Saturn"),
|
||||
"Lagna": ("Jupiter", "Ketu"),
|
||||
"Sun": ("Moon", "Mars", "Mercury", "Venus", "Saturn"),
|
||||
"Mars": ("Sun", "Moon", "Mercury", "Venus", "Saturn"),
|
||||
"Mercury": ("Sun", "Moon", "Mars", "Venus", "Saturn"),
|
||||
"Jupiter": ("Ketu",),
|
||||
"Venus": ("Sun", "Moon", "Mars", "Mercury", "Saturn"),
|
||||
"Saturn": ("Sun", "Moon", "Mars", "Mercury", "Venus"),
|
||||
}
|
||||
|
||||
|
||||
def build_tripataki_chakra(
|
||||
planet_longitudes: dict[str, Any],
|
||||
ascendant_longitude: float | int | None,
|
||||
) -> dict[str, Any]:
|
||||
if not isinstance(planet_longitudes, dict):
|
||||
return _blocked("annual_planet_longitudes_missing")
|
||||
try:
|
||||
if isinstance(ascendant_longitude, bool):
|
||||
raise TypeError
|
||||
ascendant = float(ascendant_longitude) % 360
|
||||
except (TypeError, ValueError):
|
||||
return _blocked("annual_ascendant_longitude_missing")
|
||||
|
||||
placements = [_placement("Lagna", ascendant, is_lagna=True)]
|
||||
for planet in ("Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn", "Rahu", "Ketu"):
|
||||
try:
|
||||
raw = planet_longitudes[planet]
|
||||
if isinstance(raw, bool):
|
||||
raise TypeError
|
||||
placements.append(_placement(planet, float(raw) % 360))
|
||||
except (KeyError, TypeError, ValueError):
|
||||
continue
|
||||
|
||||
sign_cells = []
|
||||
for sign_index, sign in enumerate(SIGNS):
|
||||
members = [row["body"] for row in placements if row["sign_index"] == sign_index]
|
||||
sign_cells.append({"sign_index": sign_index, "sign": sign, "bodies": members})
|
||||
|
||||
available = {row["body"] for row in placements}
|
||||
vedha_rows = []
|
||||
for target, sources in VEDHA_TARGETS.items():
|
||||
ready_sources = [source for source in sources if source in available]
|
||||
missing_sources = [source for source in sources if source not in available]
|
||||
vedha_rows.append({
|
||||
"target": target,
|
||||
"sources": list(sources),
|
||||
"available_sources": ready_sources,
|
||||
"missing_sources": missing_sources,
|
||||
"status": "partial_verified" if target in available and not missing_sources else "blocked",
|
||||
})
|
||||
return {
|
||||
"schema": "pl9.tripataki_chakra.v1",
|
||||
"status": "partial_verified" if len(placements) >= 8 else "blocked",
|
||||
"reason": None if len(placements) >= 8 else "fewer_than_eight_bodies",
|
||||
"placements": placements,
|
||||
"sign_cells": sign_cells,
|
||||
"vedha_rows": vedha_rows,
|
||||
"source_longitudes": {
|
||||
name: next(row["longitude"] for row in placements if row["body"] == name)
|
||||
for name in ("Sun", "Moon")
|
||||
if any(row["body"] == name for row in placements)
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _placement(body: str, longitude: float, *, is_lagna: bool = False) -> dict[str, Any]:
|
||||
sign_index = int(longitude // 30) % 12
|
||||
return {
|
||||
"body": body,
|
||||
"longitude": longitude,
|
||||
"sign_index": sign_index,
|
||||
"sign": SIGNS[sign_index],
|
||||
"degree_in_sign": longitude % 30,
|
||||
"is_lagna": is_lagna,
|
||||
}
|
||||
|
||||
|
||||
def _blocked(reason: str) -> dict[str, Any]:
|
||||
return {
|
||||
"schema": "pl9.tripataki_chakra.v1",
|
||||
"status": "blocked",
|
||||
"reason": reason,
|
||||
"placements": [],
|
||||
"sign_cells": [],
|
||||
"vedha_rows": [],
|
||||
"source_longitudes": {},
|
||||
}
|
||||
@@ -65,6 +65,8 @@ def build_annual_tajika_pack(
|
||||
"tajika_named_yogas": _tajika_named_yogas_field(solar_report),
|
||||
"tajika_strength": _tajika_strength_field(solar_report if isinstance(solar_report, dict) else {}),
|
||||
"sahams": sahams,
|
||||
"annual_houses": solar_report.get("annual_houses") if isinstance(solar_report, dict) else None,
|
||||
"tripataki_chakra": solar_report.get("tripataki_chakra") if isinstance(solar_report, dict) else None,
|
||||
"mudda_dasha": mudda_dasha,
|
||||
"patyayini_dasha": patyayini_dasha,
|
||||
"monthly_windows": _monthly_windows(mudda_dasha),
|
||||
|
||||
@@ -2619,12 +2619,20 @@ def render_pl9_parity_markdown(packet: dict) -> str:
|
||||
tripataki_placements = _list(tripataki.get('placements'))
|
||||
tripataki_vedha = _list(tripataki.get('vedha_rows'))
|
||||
if tripataki_placements:
|
||||
lines.extend([
|
||||
'### Tripataki Chakra 年盘落点',
|
||||
'',
|
||||
'| Body | Sign | Degree | Longitude |',
|
||||
'|------|------|--------|-----------|',
|
||||
])
|
||||
if _lang == 'en':
|
||||
lines.extend([
|
||||
'### Tripataki Chakra placements',
|
||||
'',
|
||||
'| Body | Sign | Degree | Longitude |',
|
||||
'|------|------|--------|-----------|',
|
||||
])
|
||||
else:
|
||||
lines.extend([
|
||||
'### Tripataki Chakra 年盘落点',
|
||||
'',
|
||||
'| 星体 | 星座 | 落座度数 | 黄经 |',
|
||||
'|------|------|----------|------|',
|
||||
])
|
||||
for row in tripataki_placements:
|
||||
if not isinstance(row, dict):
|
||||
continue
|
||||
@@ -2634,15 +2642,17 @@ def render_pl9_parity_markdown(packet: dict) -> str:
|
||||
)
|
||||
lines.append('')
|
||||
if tripataki_vedha:
|
||||
lines.extend([
|
||||
'| Target | Vedha sources |',
|
||||
'|--------|---------------|',
|
||||
])
|
||||
if _lang == 'en':
|
||||
lines.extend(['| Target | Vedha sources |', '|--------|---------------|'])
|
||||
joiner = ', '
|
||||
else:
|
||||
lines.extend(['| 目标 | Vedha 来源 |', '|------|-------------|'])
|
||||
joiner = '、'
|
||||
for row in tripataki_vedha:
|
||||
if not isinstance(row, dict):
|
||||
continue
|
||||
sources = row.get('sources') if isinstance(row.get('sources'), list) else []
|
||||
lines.append(f"| {_cell(row.get('target'))} | {_cell('、'.join(map(str, sources)))} |")
|
||||
lines.append(f"| {_cell(_token(row.get('target')))} | {_cell(joiner.join(_token(item) for item in sources))} |")
|
||||
lines.append('')
|
||||
monthly_pack = _dict(annual.get('monthly_chart_pack'))
|
||||
monthly_rows = _list(monthly_pack.get('rows'))
|
||||
|
||||
@@ -166,9 +166,12 @@ SECTIONS: tuple[tuple[str, str], ...] = (
|
||||
("Current Dasha Convergence", "当前多系统收敛"),
|
||||
("Chara Dasha Period Durations", "Chara 大运时长"),
|
||||
("Narayana Method Comparison", "Narayana 口径对照"),
|
||||
("Annual Return House Framework", "年运整宫框架"),
|
||||
("Annual Return Calculation Contract", "年运返照计算约定"),
|
||||
("Tajika Aspect and Yoga Candidates", "Tajika 相位与瑜伽候选"),
|
||||
("Tripataki Chakra Detail", "Tripataki 轮盘明细"),
|
||||
("Annual Tajika Strength", "年度 Tajika 力量"),
|
||||
("Annual Saham Formula Trace", "年度特殊点公式轨迹"),
|
||||
("Shadbala Subcomponent", "六维力量分项"),
|
||||
("Shadbala Result", "六维力量结果"),
|
||||
("House Components and Physical Coordinates", "宫位分量与坐标"),
|
||||
@@ -202,6 +205,7 @@ SECTIONS: tuple[tuple[str, str], ...] = (
|
||||
("Pancha Pakshi", "五鸟活动"),
|
||||
("Natal Vivah Saham", "本命 Vivah Saham"),
|
||||
("Natal Saham Formula Basis", "本命特殊点公式依据"),
|
||||
("Natal Saham Formula Trace", "本命特殊点公式轨迹"),
|
||||
("Arudha / UL / A10", "Arudha、Upapada 与 A10"),
|
||||
("Jaimini Calculation Details", "Jaimini 计算细节"),
|
||||
("Graha Pada", "Graha Pada"),
|
||||
@@ -225,10 +229,6 @@ SECTIONS: tuple[tuple[str, str], ...] = (
|
||||
)
|
||||
|
||||
FORBIDDEN_TITLES = (
|
||||
"Annual Return House Framework",
|
||||
"Tripataki Chakra Detail",
|
||||
"Annual Saham Formula Trace",
|
||||
"Natal Saham Formula Trace",
|
||||
"Annual Chart Numeric Data",
|
||||
"Bhava Bala Relative Score Components",
|
||||
"Score Extremes",
|
||||
@@ -850,6 +850,102 @@ def _narayana(packet: dict, language: str) -> str:
|
||||
])
|
||||
|
||||
|
||||
def _pack_data(field: Any) -> Any:
|
||||
if isinstance(field, dict) and "data" in field and isinstance(field.get("data"), (dict, list)):
|
||||
return field["data"]
|
||||
return field
|
||||
|
||||
|
||||
def _occupants_cell(names: Any, language: str) -> str:
|
||||
if isinstance(names, list) and names:
|
||||
return planet_list(names, language) or ("无" if language == "zh" else "None")
|
||||
if isinstance(names, list):
|
||||
return "无" if language == "zh" else "None"
|
||||
return names if isinstance(names, str) else ("无" if language == "zh" else "None")
|
||||
|
||||
|
||||
def _phase_word(phase: Any, language: str) -> str | None:
|
||||
if phase == "day":
|
||||
return "日间" if language == "zh" else "Day"
|
||||
if phase == "night":
|
||||
return "夜间" if language == "zh" else "Night"
|
||||
return None
|
||||
|
||||
|
||||
def _annual_houses(packet: dict, language: str) -> str:
|
||||
pack = _first(packet, ("timing_and_predictive_systems", "annual_tajika_pack")) or {}
|
||||
data = _pack_data(pack.get("annual_houses") if isinstance(pack, dict) else None)
|
||||
houses = data.get("houses") if isinstance(data, dict) else None
|
||||
rows = []
|
||||
for item in houses or []:
|
||||
if not isinstance(item, dict):
|
||||
continue
|
||||
rows.append({
|
||||
"house": item.get("house"),
|
||||
"sign": item.get("sign"),
|
||||
"lord": item.get("lord"),
|
||||
"occupant": _occupants_cell(item.get("occupants"), language),
|
||||
})
|
||||
return _rows_from(rows, language, [("house", "text"), ("sign", "sign"), ("lord", "planet"), ("occupant", "text")])
|
||||
|
||||
|
||||
def _tripataki(packet: dict, language: str) -> str:
|
||||
pack = _first(packet, ("timing_and_predictive_systems", "annual_tajika_pack")) or {}
|
||||
data = _pack_data(pack.get("tripataki_chakra") if isinstance(pack, dict) else None)
|
||||
if not isinstance(data, dict):
|
||||
return _blank(language, ["point", "sign", "degree", "longitude"])
|
||||
placements = []
|
||||
for item in data.get("placements") or []:
|
||||
if isinstance(item, dict):
|
||||
placements.append({
|
||||
"point": item.get("body"),
|
||||
"sign": item.get("sign"),
|
||||
"degree": None if item.get("degree_in_sign") is None else round(float(item["degree_in_sign"]), 4),
|
||||
"longitude": None if item.get("longitude") is None else round(float(item["longitude"]), 4),
|
||||
})
|
||||
vedha = []
|
||||
for item in data.get("vedha_rows") or []:
|
||||
if isinstance(item, dict):
|
||||
vedha.append({
|
||||
"target": item.get("target"),
|
||||
"planet": item.get("available_sources") or item.get("sources"),
|
||||
"status": item.get("status"),
|
||||
})
|
||||
parts = [
|
||||
_rows_from(placements, language, [("point", "text"), ("sign", "sign"), ("degree", "text"), ("longitude", "text")]),
|
||||
_rows_from(vedha, language, [("target", "planet"), ("planet", "planets"), ("status", "text")]),
|
||||
]
|
||||
return "\n\n".join(parts)
|
||||
|
||||
|
||||
def _trace_table(traces: Any, language: str) -> str:
|
||||
rows = []
|
||||
if isinstance(traces, list):
|
||||
for item in traces:
|
||||
if not isinstance(item, dict):
|
||||
continue
|
||||
rows.append({
|
||||
"name": item.get("name"),
|
||||
"rule": item.get("rule"),
|
||||
"phase": _phase_word(item.get("phase"), language),
|
||||
"longitude": item.get("longitude"),
|
||||
})
|
||||
return _rows_from(rows, language, [("name", "text"), ("rule", "text"), ("phase", "text"), ("longitude", "text")])
|
||||
|
||||
|
||||
def _annual_saham_trace(packet: dict, language: str) -> str:
|
||||
pack = _first(packet, ("timing_and_predictive_systems", "annual_tajika_pack")) or {}
|
||||
sahams = _pack_data(pack.get("sahams") if isinstance(pack, dict) else None)
|
||||
traces = sahams.get("formula_traces") if isinstance(sahams, dict) else None
|
||||
return _trace_table(traces, language)
|
||||
|
||||
|
||||
def _natal_saham_trace(packet: dict, language: str) -> str:
|
||||
module = _first(packet, ("advanced_systems", "sahams")) or {}
|
||||
traces = module.get("formula_traces") if isinstance(module, dict) else None
|
||||
return _trace_table(traces, language)
|
||||
|
||||
|
||||
def _annual(packet: dict, language: str) -> str:
|
||||
pack = _first(packet, ("timing_and_predictive_systems", "annual_tajika_pack")) or {}
|
||||
solar = pack.get("solar_return") if isinstance(pack, dict) else {}
|
||||
@@ -2398,9 +2494,12 @@ _BUILDERS = {
|
||||
"Current Dasha Convergence": _convergence,
|
||||
"Chara Dasha Period Durations": _chara,
|
||||
"Narayana Method Comparison": _narayana,
|
||||
"Annual Return Calculation Contract": _annual,
|
||||
"Tajika Aspect and Yoga Candidates": _tajika_candidates,
|
||||
"Annual Tajika Strength": _tajika_strength,
|
||||
"Annual Return House Framework": _annual_houses,
|
||||
"Annual Return Calculation Contract": _annual,
|
||||
"Tajika Aspect and Yoga Candidates": _tajika_candidates,
|
||||
"Tripataki Chakra Detail": _tripataki,
|
||||
"Annual Tajika Strength": _tajika_strength,
|
||||
"Annual Saham Formula Trace": _annual_saham_trace,
|
||||
}
|
||||
|
||||
|
||||
@@ -2408,11 +2507,11 @@ def _chapter_sections() -> list[list[str]]:
|
||||
order = [title for title, _zh in SECTIONS]
|
||||
groups = [
|
||||
order[:14],
|
||||
order[14:17],
|
||||
order[17:32],
|
||||
order[32:43],
|
||||
order[43:59],
|
||||
order[59:],
|
||||
order[14:20],
|
||||
order[20:35],
|
||||
order[35:46],
|
||||
order[46:63],
|
||||
order[63:],
|
||||
]
|
||||
return groups
|
||||
|
||||
@@ -2455,6 +2554,7 @@ def _render_named(packet: dict, language: str, title: str) -> str:
|
||||
"Pancha Pakshi": lambda: _missing_module(language, ["name", "value", "status"]),
|
||||
"Natal Vivah Saham": lambda: _vivah(packet, language),
|
||||
"Natal Saham Formula Basis": lambda: _saham_basis(packet, language),
|
||||
"Natal Saham Formula Trace": lambda: _natal_saham_trace(packet, language),
|
||||
"Arudha / UL / A10": lambda: _special_points(packet, language),
|
||||
"Jaimini Calculation Details": lambda: _jaimini_details(packet, language),
|
||||
"Graha Pada": lambda: _graha_pada(packet, language),
|
||||
|
||||
@@ -539,6 +539,20 @@ def solar_return_full_report(
|
||||
'age': sr['age'],
|
||||
}
|
||||
planet_lons = sr['planet_lons']
|
||||
try:
|
||||
from annual_native.annual_houses import build_annual_whole_sign_houses
|
||||
from annual_native.tripataki_chakra import build_tripataki_chakra
|
||||
except ImportError:
|
||||
from scripts.annual_native.annual_houses import build_annual_whole_sign_houses
|
||||
from scripts.annual_native.tripataki_chakra import build_tripataki_chakra
|
||||
annual_chart = sr.get('chart') if isinstance(sr.get('chart'), dict) else {}
|
||||
result['annual_houses'] = build_annual_whole_sign_houses(annual_chart)
|
||||
raw_longitudes = {}
|
||||
for name, data in (annual_chart.get('planets') or {}).items():
|
||||
if isinstance(data, dict) and isinstance(data.get('degree_raw'), (int, float)) and not isinstance(data.get('degree_raw'), bool):
|
||||
raw_longitudes[name] = data['degree_raw']
|
||||
ascendant = annual_chart.get('ascendant') if isinstance(annual_chart.get('ascendant'), dict) else {}
|
||||
result['tripataki_chakra'] = build_tripataki_chakra(raw_longitudes, ascendant.get('degree_raw'))
|
||||
sr_planets = sr.get('chart', {}).get('planets', {})
|
||||
tajika_planets = {
|
||||
pn: {
|
||||
|
||||
@@ -1793,6 +1793,27 @@ def calc_all_sahams(planet_lons: Dict[str, float],
|
||||
sangrama_lon = _saham(rahu_lon, mars_lon)
|
||||
results['sangrama_saham'] = _saham_dict(sangrama_lon, 'Sangrama Saham', '战斗点——竞争、挑战、胜利')
|
||||
|
||||
formula_meta: Dict[str, Dict] = {}
|
||||
for result_key, rule_name in (
|
||||
('punya_saham', 'Punya_Saham'),
|
||||
('yasha_saham', 'Yashas_Saham'),
|
||||
('karma_saham', 'Karma_Saham'),
|
||||
):
|
||||
try:
|
||||
traced = _formula_saham_trace(rule_name, planet_lons, asc_lon, is_day, computed_formula_sahams)
|
||||
except KeyError:
|
||||
continue
|
||||
formula_meta[result_key] = {
|
||||
'rule_name': traced.get('rule_name'),
|
||||
'formula_operands': traced.get('formula_operands'),
|
||||
'formula_variant': traced.get('formula_variant'),
|
||||
'zodiacal_order_exception_applied': traced.get('zodiacal_order_exception_applied'),
|
||||
}
|
||||
try:
|
||||
from annual_native.saham_traces import attach_formula_traces
|
||||
except ImportError:
|
||||
from scripts.annual_native.saham_traces import attach_formula_traces
|
||||
attach_formula_traces(results, is_day=is_day, formula_meta=formula_meta)
|
||||
return results
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user