kundali-chart-mcp 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -0
- package/azure-function/function_app.py +93 -0
- package/azure-function/host.json +15 -0
- package/azure-function/kundali_bridge.py +952 -0
- package/azure-function/python/kundali_lib/__init__.py +1 -0
- package/azure-function/python/kundali_lib/__pycache__/__init__.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/__pycache__/ephemeris.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/__pycache__/geocoder.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/__pycache__/vedicastro_bridge.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/ephemeris.py +30 -0
- package/azure-function/python/kundali_lib/geocoder.py +82 -0
- package/azure-function/python/kundali_lib/vedic/__init__.py +1 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/__init__.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/arishta.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/ashtakavarga.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/avasthas.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/ayanamsa.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/bhava_chalit.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/char_dasha.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/chart.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/chart_types.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/compatibility.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/constants.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/dasha_extended.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/dasha_systems.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/doshas.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/gandanta.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/gochara.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/hora.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/houses.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/jaimini.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/kalachakra.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/kartari.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/kurmachakra.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/lunar_return.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/muhurta.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/nabhasha.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/nakshatra_details.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/panchanga.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/planets.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/shadbala.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/special_conditions.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/sudarshana.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/tajaka.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/upagrahas.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/varshaphal.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/yogas.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/__pycache__/zodiac.cpython-313.pyc +0 -0
- package/azure-function/python/kundali_lib/vedic/arishta.py +465 -0
- package/azure-function/python/kundali_lib/vedic/ashtakavarga.py +213 -0
- package/azure-function/python/kundali_lib/vedic/avasthas.py +292 -0
- package/azure-function/python/kundali_lib/vedic/ayanamsa.py +106 -0
- package/azure-function/python/kundali_lib/vedic/bhava_chalit.py +137 -0
- package/azure-function/python/kundali_lib/vedic/char_dasha.py +308 -0
- package/azure-function/python/kundali_lib/vedic/chart.py +126 -0
- package/azure-function/python/kundali_lib/vedic/chart_types.py +338 -0
- package/azure-function/python/kundali_lib/vedic/compatibility.py +705 -0
- package/azure-function/python/kundali_lib/vedic/constants.py +108 -0
- package/azure-function/python/kundali_lib/vedic/dasha_extended.py +262 -0
- package/azure-function/python/kundali_lib/vedic/dasha_systems.py +439 -0
- package/azure-function/python/kundali_lib/vedic/doshas.py +453 -0
- package/azure-function/python/kundali_lib/vedic/gandanta.py +213 -0
- package/azure-function/python/kundali_lib/vedic/gochara.py +277 -0
- package/azure-function/python/kundali_lib/vedic/hora.py +263 -0
- package/azure-function/python/kundali_lib/vedic/houses.py +30 -0
- package/azure-function/python/kundali_lib/vedic/jaimini.py +361 -0
- package/azure-function/python/kundali_lib/vedic/kalachakra.py +226 -0
- package/azure-function/python/kundali_lib/vedic/kartari.py +243 -0
- package/azure-function/python/kundali_lib/vedic/kurmachakra.py +383 -0
- package/azure-function/python/kundali_lib/vedic/lunar_return.py +402 -0
- package/azure-function/python/kundali_lib/vedic/muhurta.py +414 -0
- package/azure-function/python/kundali_lib/vedic/nabhasha.py +349 -0
- package/azure-function/python/kundali_lib/vedic/nakshatra_details.py +945 -0
- package/azure-function/python/kundali_lib/vedic/panchanga.py +297 -0
- package/azure-function/python/kundali_lib/vedic/planets.py +55 -0
- package/azure-function/python/kundali_lib/vedic/shadbala.py +500 -0
- package/azure-function/python/kundali_lib/vedic/special_conditions.py +319 -0
- package/azure-function/python/kundali_lib/vedic/sudarshana.py +232 -0
- package/azure-function/python/kundali_lib/vedic/tajaka.py +482 -0
- package/azure-function/python/kundali_lib/vedic/upagrahas.py +229 -0
- package/azure-function/python/kundali_lib/vedic/varshaphal.py +185 -0
- package/azure-function/python/kundali_lib/vedic/yogas.py +935 -0
- package/azure-function/python/kundali_lib/vedic/zodiac.py +42 -0
- package/azure-function/python/kundali_lib/vedicastro_bridge.py +198 -0
- package/azure-function/requirements.txt +9 -0
- package/index.js +747 -0
- package/kundali-chart-mcp.js +159 -0
- package/kundali_bridge.py +952 -0
- package/package.json +41 -0
- package/python/kundali_lib/__init__.py +1 -0
- package/python/kundali_lib/__pycache__/__init__.cpython-313.pyc +0 -0
- package/python/kundali_lib/__pycache__/ephemeris.cpython-313.pyc +0 -0
- package/python/kundali_lib/__pycache__/geocoder.cpython-313.pyc +0 -0
- package/python/kundali_lib/__pycache__/vedicastro_bridge.cpython-313.pyc +0 -0
- package/python/kundali_lib/ephemeris.py +30 -0
- package/python/kundali_lib/geocoder.py +82 -0
- package/python/kundali_lib/vedic/__init__.py +1 -0
- package/python/kundali_lib/vedic/__pycache__/__init__.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/arishta.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/ashtakavarga.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/avasthas.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/ayanamsa.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/bhava_chalit.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/char_dasha.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/chart.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/chart_types.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/compatibility.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/constants.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/dasha_extended.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/dasha_systems.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/doshas.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/gandanta.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/gochara.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/hora.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/houses.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/jaimini.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/kalachakra.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/kartari.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/kurmachakra.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/lunar_return.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/muhurta.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/nabhasha.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/nakshatra_details.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/panchanga.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/planets.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/shadbala.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/special_conditions.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/sudarshana.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/tajaka.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/upagrahas.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/varshaphal.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/yogas.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/__pycache__/zodiac.cpython-313.pyc +0 -0
- package/python/kundali_lib/vedic/arishta.py +465 -0
- package/python/kundali_lib/vedic/ashtakavarga.py +213 -0
- package/python/kundali_lib/vedic/avasthas.py +292 -0
- package/python/kundali_lib/vedic/ayanamsa.py +106 -0
- package/python/kundali_lib/vedic/bhava_chalit.py +137 -0
- package/python/kundali_lib/vedic/char_dasha.py +308 -0
- package/python/kundali_lib/vedic/chart.py +126 -0
- package/python/kundali_lib/vedic/chart_types.py +338 -0
- package/python/kundali_lib/vedic/compatibility.py +705 -0
- package/python/kundali_lib/vedic/constants.py +108 -0
- package/python/kundali_lib/vedic/dasha_extended.py +262 -0
- package/python/kundali_lib/vedic/dasha_systems.py +439 -0
- package/python/kundali_lib/vedic/doshas.py +453 -0
- package/python/kundali_lib/vedic/gandanta.py +213 -0
- package/python/kundali_lib/vedic/gochara.py +277 -0
- package/python/kundali_lib/vedic/hora.py +263 -0
- package/python/kundali_lib/vedic/houses.py +30 -0
- package/python/kundali_lib/vedic/jaimini.py +361 -0
- package/python/kundali_lib/vedic/kalachakra.py +226 -0
- package/python/kundali_lib/vedic/kartari.py +243 -0
- package/python/kundali_lib/vedic/kurmachakra.py +383 -0
- package/python/kundali_lib/vedic/lunar_return.py +402 -0
- package/python/kundali_lib/vedic/muhurta.py +414 -0
- package/python/kundali_lib/vedic/nabhasha.py +349 -0
- package/python/kundali_lib/vedic/nakshatra_details.py +945 -0
- package/python/kundali_lib/vedic/panchanga.py +297 -0
- package/python/kundali_lib/vedic/planets.py +55 -0
- package/python/kundali_lib/vedic/shadbala.py +500 -0
- package/python/kundali_lib/vedic/special_conditions.py +319 -0
- package/python/kundali_lib/vedic/sudarshana.py +232 -0
- package/python/kundali_lib/vedic/tajaka.py +482 -0
- package/python/kundali_lib/vedic/upagrahas.py +229 -0
- package/python/kundali_lib/vedic/varshaphal.py +185 -0
- package/python/kundali_lib/vedic/yogas.py +935 -0
- package/python/kundali_lib/vedic/zodiac.py +42 -0
- package/python/kundali_lib/vedicastro_bridge.py +198 -0
- package/remote-server.js +590 -0
- package/requirements.txt +8 -0
- package/setup.sh +218 -0
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
"""Nabhasha Yogas: special yogas based on overall chart patterns and planetary distributions."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from kundali_lib.vedic.constants import RASHIS
|
|
6
|
+
|
|
7
|
+
# ---------------------------------------------------------------------------
|
|
8
|
+
# Reference data
|
|
9
|
+
# ---------------------------------------------------------------------------
|
|
10
|
+
|
|
11
|
+
MOVABLE_SIGNS = {"Aries", "Cancer", "Libra", "Capricorn"}
|
|
12
|
+
FIXED_SIGNS = {"Taurus", "Leo", "Scorpio", "Aquarius"}
|
|
13
|
+
DUAL_SIGNS = {"Gemini", "Virgo", "Sagittarius", "Pisces"}
|
|
14
|
+
|
|
15
|
+
KENDRA_HOUSES = {1, 4, 7, 10}
|
|
16
|
+
APOKLIMA_HOUSES = {3, 6, 9, 12}
|
|
17
|
+
|
|
18
|
+
BENEFIC_PLANETS = {"Moon", "Mercury", "Jupiter", "Venus"}
|
|
19
|
+
MALEFIC_PLANETS = {"Sun", "Mars", "Saturn", "Rahu", "Ketu"}
|
|
20
|
+
|
|
21
|
+
# ---------------------------------------------------------------------------
|
|
22
|
+
# Ashrayas
|
|
23
|
+
# ---------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
ASHRAYAS: dict[str, dict] = {
|
|
26
|
+
"Rajju": {
|
|
27
|
+
"condition": "All planets in movable signs (Aries, Cancer, Libra, Capricorn)",
|
|
28
|
+
"effect": "Person travels frequently, unsettled",
|
|
29
|
+
},
|
|
30
|
+
"Musala": {
|
|
31
|
+
"condition": "All planets in fixed signs (Taurus, Leo, Scorpio, Aquarius)",
|
|
32
|
+
"effect": "Determined, stubborn, famous",
|
|
33
|
+
},
|
|
34
|
+
"Nala": {
|
|
35
|
+
"condition": "All planets in dual/common signs (Gemini, Virgo, Sagittarius, Pisces)",
|
|
36
|
+
"effect": "Skilled in arts, skilled in work with hands",
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# ---------------------------------------------------------------------------
|
|
41
|
+
# Dala
|
|
42
|
+
# ---------------------------------------------------------------------------
|
|
43
|
+
|
|
44
|
+
DALA: dict[str, dict] = {
|
|
45
|
+
"Mala": {
|
|
46
|
+
"condition": "Benefics (Moon, Mercury, Jupiter, Venus) all in kendras (1,4,7,10)",
|
|
47
|
+
"effect": "Happiness, wealth, honour",
|
|
48
|
+
},
|
|
49
|
+
"Sarpa": {
|
|
50
|
+
"condition": "Only malefics (Sun, Mars, Saturn, Rahu, Ketu) in kendras",
|
|
51
|
+
"effect": "Wicked, poor, dependent",
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# ---------------------------------------------------------------------------
|
|
56
|
+
# Akriti patterns (simplified — primary 10)
|
|
57
|
+
# ---------------------------------------------------------------------------
|
|
58
|
+
|
|
59
|
+
AKRITI_YOGAS: dict[int, dict] = {
|
|
60
|
+
2: {
|
|
61
|
+
"name": "Gada",
|
|
62
|
+
"description": "Planets in two adjacent houses",
|
|
63
|
+
"effect": "Wealthy, skilled",
|
|
64
|
+
},
|
|
65
|
+
3: {
|
|
66
|
+
"name": "Shakata",
|
|
67
|
+
"description": "Planets in houses 1 and 7",
|
|
68
|
+
"effect": "Variable fortune",
|
|
69
|
+
},
|
|
70
|
+
4: {
|
|
71
|
+
"name": "Vihaga",
|
|
72
|
+
"description": "Planets in houses 4 and 10",
|
|
73
|
+
"effect": "Messenger, traveller",
|
|
74
|
+
},
|
|
75
|
+
5: {
|
|
76
|
+
"name": "Shringataka",
|
|
77
|
+
"description": "Planets in trikonas (1,5,9)",
|
|
78
|
+
"effect": "Pleasure seeker",
|
|
79
|
+
},
|
|
80
|
+
6: {
|
|
81
|
+
"name": "Hala",
|
|
82
|
+
"description": "Planets in consecutive houses",
|
|
83
|
+
"effect": "Farmer, works hard",
|
|
84
|
+
},
|
|
85
|
+
7: {
|
|
86
|
+
"name": "Vajra",
|
|
87
|
+
"description": "Benefics in 1 and 7, malefics in 4 and 10",
|
|
88
|
+
"effect": "Rich, happy in youth and old age",
|
|
89
|
+
},
|
|
90
|
+
8: {
|
|
91
|
+
"name": "Yava",
|
|
92
|
+
"description": "Benefics in 1 and 7, malefics in 4 and 10 (reverse of Vajra)",
|
|
93
|
+
"effect": "Rich in middle age",
|
|
94
|
+
},
|
|
95
|
+
9: {
|
|
96
|
+
"name": "Kamala",
|
|
97
|
+
"description": "Planets in all 4 kendras",
|
|
98
|
+
"effect": "Virtuous, wealthy, famous",
|
|
99
|
+
},
|
|
100
|
+
10: {
|
|
101
|
+
"name": "Vapi",
|
|
102
|
+
"description": "All planets in Apoklimas (3,6,9,12)",
|
|
103
|
+
"effect": "Wealthy but hidden",
|
|
104
|
+
},
|
|
105
|
+
18: {
|
|
106
|
+
"name": "Ardha Chandra",
|
|
107
|
+
"description": "Planets in 7 consecutive houses",
|
|
108
|
+
"effect": "Commander",
|
|
109
|
+
},
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
# ---------------------------------------------------------------------------
|
|
114
|
+
# Internal helpers
|
|
115
|
+
# ---------------------------------------------------------------------------
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _sign_type(rashi: str) -> str:
|
|
119
|
+
if rashi in MOVABLE_SIGNS:
|
|
120
|
+
return "movable"
|
|
121
|
+
if rashi in FIXED_SIGNS:
|
|
122
|
+
return "fixed"
|
|
123
|
+
return "dual"
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _occupied_houses(planetary_positions: list[dict]) -> list[int]:
|
|
127
|
+
"""Return sorted list of houses that have at least one planet."""
|
|
128
|
+
seen: set[int] = set()
|
|
129
|
+
for p in planetary_positions:
|
|
130
|
+
h = p.get("house", 0)
|
|
131
|
+
if 1 <= h <= 12:
|
|
132
|
+
seen.add(h)
|
|
133
|
+
return sorted(seen)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _houses_are_consecutive(houses: list[int], span: int) -> bool:
|
|
137
|
+
"""True if all houses lie within a consecutive arc of ``span`` houses."""
|
|
138
|
+
if not houses:
|
|
139
|
+
return False
|
|
140
|
+
for start in range(1, 13):
|
|
141
|
+
arc = set((start + i - 1) % 12 + 1 for i in range(span))
|
|
142
|
+
if set(houses).issubset(arc):
|
|
143
|
+
return True
|
|
144
|
+
return False
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
# ---------------------------------------------------------------------------
|
|
148
|
+
# Yoga checkers
|
|
149
|
+
# ---------------------------------------------------------------------------
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _check_ashrayas(planetary_positions: list[dict]) -> str | None:
|
|
153
|
+
"""Return the name of the Ashrayas yoga present, or None."""
|
|
154
|
+
rashis = [p.get("rashi", "") for p in planetary_positions]
|
|
155
|
+
types = [_sign_type(r) for r in rashis if r]
|
|
156
|
+
if not types:
|
|
157
|
+
return None
|
|
158
|
+
if all(t == "movable" for t in types):
|
|
159
|
+
return "Rajju"
|
|
160
|
+
if all(t == "fixed" for t in types):
|
|
161
|
+
return "Musala"
|
|
162
|
+
if all(t == "dual" for t in types):
|
|
163
|
+
return "Nala"
|
|
164
|
+
return None
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def _check_dala(planetary_positions: list[dict]) -> str | None:
|
|
168
|
+
"""Return 'Mala', 'Sarpa', or None."""
|
|
169
|
+
kendra_planets = [
|
|
170
|
+
p for p in planetary_positions if p.get("house", 0) in KENDRA_HOUSES
|
|
171
|
+
]
|
|
172
|
+
if not kendra_planets:
|
|
173
|
+
return None
|
|
174
|
+
|
|
175
|
+
kendra_names = {p["name"] for p in kendra_planets}
|
|
176
|
+
|
|
177
|
+
# Mala: all 4 benefics in kendras
|
|
178
|
+
benefics_in_kendra = BENEFIC_PLANETS.intersection(kendra_names)
|
|
179
|
+
if benefics_in_kendra == BENEFIC_PLANETS:
|
|
180
|
+
return "Mala"
|
|
181
|
+
|
|
182
|
+
# Sarpa: only malefics in kendras (no benefic in kendra at all)
|
|
183
|
+
if not kendra_names.intersection(BENEFIC_PLANETS) and kendra_names:
|
|
184
|
+
return "Sarpa"
|
|
185
|
+
|
|
186
|
+
return None
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _check_akriti(occupied: list[int], planetary_positions: list[dict]) -> dict | None:
|
|
190
|
+
"""Return the Akriti yoga dict or None based on occupied house patterns."""
|
|
191
|
+
occ_set = set(occupied)
|
|
192
|
+
n = len(occ_set)
|
|
193
|
+
|
|
194
|
+
# Kamala: planets in all 4 kendras
|
|
195
|
+
if KENDRA_HOUSES.issubset(occ_set):
|
|
196
|
+
return AKRITI_YOGAS[9]
|
|
197
|
+
|
|
198
|
+
# Vapi: all in Apoklimas
|
|
199
|
+
if occ_set and occ_set.issubset(APOKLIMA_HOUSES):
|
|
200
|
+
return AKRITI_YOGAS[10]
|
|
201
|
+
|
|
202
|
+
# Ardha Chandra: planets in 7 consecutive houses
|
|
203
|
+
if _houses_are_consecutive(occupied, 7) and 5 <= n <= 8:
|
|
204
|
+
return AKRITI_YOGAS[18]
|
|
205
|
+
|
|
206
|
+
# Shringataka: only trikonas occupied
|
|
207
|
+
if occ_set and occ_set.issubset({1, 5, 9}):
|
|
208
|
+
return AKRITI_YOGAS[5]
|
|
209
|
+
|
|
210
|
+
# Vihaga: only 4 and 10 occupied
|
|
211
|
+
if occ_set and occ_set.issubset({4, 10}):
|
|
212
|
+
return AKRITI_YOGAS[4]
|
|
213
|
+
|
|
214
|
+
# Shakata: only 1 and 7 occupied
|
|
215
|
+
if occ_set and occ_set.issubset({1, 7}):
|
|
216
|
+
return AKRITI_YOGAS[3]
|
|
217
|
+
|
|
218
|
+
# Gada: two adjacent houses occupied only
|
|
219
|
+
if n == 2 and len(occupied) == 2:
|
|
220
|
+
diff = abs(occupied[0] - occupied[1])
|
|
221
|
+
if diff == 1 or diff == 11:
|
|
222
|
+
return AKRITI_YOGAS[2]
|
|
223
|
+
|
|
224
|
+
# Hala: all in 6 consecutive houses
|
|
225
|
+
if _houses_are_consecutive(occupied, 6) and n <= 7:
|
|
226
|
+
return AKRITI_YOGAS[6]
|
|
227
|
+
|
|
228
|
+
# Vajra / Yava (both use houses 1, 4, 7, 10)
|
|
229
|
+
if occ_set and occ_set.issubset({1, 4, 7, 10}):
|
|
230
|
+
benefics = {
|
|
231
|
+
p["name"] for p in planetary_positions if p["name"] in BENEFIC_PLANETS
|
|
232
|
+
}
|
|
233
|
+
malefics = {
|
|
234
|
+
p["name"] for p in planetary_positions if p["name"] in MALEFIC_PLANETS
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
def _in_house(names: set, houses: set) -> bool:
|
|
238
|
+
return all(
|
|
239
|
+
any(
|
|
240
|
+
p["name"] in names and p.get("house", 0) in houses
|
|
241
|
+
for p in planetary_positions
|
|
242
|
+
)
|
|
243
|
+
for _ in [1]
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
benefic_houses = {
|
|
247
|
+
p.get("house", 0)
|
|
248
|
+
for p in planetary_positions
|
|
249
|
+
if p["name"] in BENEFIC_PLANETS
|
|
250
|
+
}
|
|
251
|
+
malefic_houses = {
|
|
252
|
+
p.get("house", 0)
|
|
253
|
+
for p in planetary_positions
|
|
254
|
+
if p["name"] in MALEFIC_PLANETS
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if benefic_houses.issubset({1, 7}) and malefic_houses.issubset({4, 10}):
|
|
258
|
+
return AKRITI_YOGAS[7] # Vajra
|
|
259
|
+
if benefic_houses.issubset({4, 10}) and malefic_houses.issubset({1, 7}):
|
|
260
|
+
return AKRITI_YOGAS[8] # Yava
|
|
261
|
+
|
|
262
|
+
return None
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
# ---------------------------------------------------------------------------
|
|
266
|
+
# Public API
|
|
267
|
+
# ---------------------------------------------------------------------------
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def get_nabhasha_yogas(planetary_positions: list[dict]) -> dict:
|
|
271
|
+
"""Identify Nabhasha Yogas from a chart's planetary positions.
|
|
272
|
+
|
|
273
|
+
Args:
|
|
274
|
+
planetary_positions: List of planet dicts as produced by ``build_chart()``
|
|
275
|
+
(each dict must have ``name``, ``rashi``, and ``house``).
|
|
276
|
+
|
|
277
|
+
Returns:
|
|
278
|
+
dict with Ashrayas, Dala, Akriti yogas found, along with supporting
|
|
279
|
+
statistics and a plain-language summary.
|
|
280
|
+
"""
|
|
281
|
+
occupied = _occupied_houses(planetary_positions)
|
|
282
|
+
|
|
283
|
+
# ── Sign-type counts ──────────────────────────────────────────────────────
|
|
284
|
+
type_counts: dict[str, int] = {"movable": 0, "fixed": 0, "dual": 0}
|
|
285
|
+
for p in planetary_positions:
|
|
286
|
+
r = p.get("rashi", "")
|
|
287
|
+
if r:
|
|
288
|
+
type_counts[_sign_type(r)] += 1
|
|
289
|
+
|
|
290
|
+
# ── Yoga checks ───────────────────────────────────────────────────────────
|
|
291
|
+
ashrayas_name = _check_ashrayas(planetary_positions)
|
|
292
|
+
dala_name = _check_dala(planetary_positions)
|
|
293
|
+
akriti_data = _check_akriti(occupied, planetary_positions)
|
|
294
|
+
|
|
295
|
+
yogas_present: list[dict] = []
|
|
296
|
+
|
|
297
|
+
if ashrayas_name:
|
|
298
|
+
info = ASHRAYAS[ashrayas_name]
|
|
299
|
+
yogas_present.append(
|
|
300
|
+
{
|
|
301
|
+
"name": ashrayas_name,
|
|
302
|
+
"category": "Ashrayas",
|
|
303
|
+
"description": info["condition"],
|
|
304
|
+
"effect": info["effect"],
|
|
305
|
+
}
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
if dala_name:
|
|
309
|
+
info = DALA[dala_name]
|
|
310
|
+
yogas_present.append(
|
|
311
|
+
{
|
|
312
|
+
"name": dala_name,
|
|
313
|
+
"category": "Dala",
|
|
314
|
+
"description": info["condition"],
|
|
315
|
+
"effect": info["effect"],
|
|
316
|
+
}
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
if akriti_data:
|
|
320
|
+
yogas_present.append(
|
|
321
|
+
{
|
|
322
|
+
"name": akriti_data["name"],
|
|
323
|
+
"category": "Akriti",
|
|
324
|
+
"description": akriti_data["description"],
|
|
325
|
+
"effect": akriti_data["effect"],
|
|
326
|
+
}
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
# ── Summary ───────────────────────────────────────────────────────────────
|
|
330
|
+
if yogas_present:
|
|
331
|
+
names = ", ".join(y["name"] for y in yogas_present)
|
|
332
|
+
summary = f"Nabhasha yogas present: {names}. Planets occupy houses: {occupied}."
|
|
333
|
+
else:
|
|
334
|
+
summary = (
|
|
335
|
+
f"No primary Nabhasha yoga detected. "
|
|
336
|
+
f"Planets occupy houses: {occupied}. "
|
|
337
|
+
f"Sign distribution — movable: {type_counts['movable']}, "
|
|
338
|
+
f"fixed: {type_counts['fixed']}, dual: {type_counts['dual']}."
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
return {
|
|
342
|
+
"ashrayas_yoga": ashrayas_name,
|
|
343
|
+
"dala_yoga": dala_name,
|
|
344
|
+
"akriti_yoga": akriti_data["name"] if akriti_data else None,
|
|
345
|
+
"occupied_houses": occupied,
|
|
346
|
+
"occupied_signs_type": type_counts,
|
|
347
|
+
"yogas_present": yogas_present,
|
|
348
|
+
"summary": summary,
|
|
349
|
+
}
|