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,500 @@
|
|
|
1
|
+
"""Shadbala: six-fold planetary strength calculation."""
|
|
2
|
+
|
|
3
|
+
import math
|
|
4
|
+
|
|
5
|
+
# ---------------------------------------------------------------------------
|
|
6
|
+
# Constant tables
|
|
7
|
+
# ---------------------------------------------------------------------------
|
|
8
|
+
|
|
9
|
+
PLANETS = ["Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn"]
|
|
10
|
+
|
|
11
|
+
# Absolute sidereal longitudes for exaltation / debilitation
|
|
12
|
+
EXALTATION_DEG = {
|
|
13
|
+
"Sun": 10,
|
|
14
|
+
"Moon": 33,
|
|
15
|
+
"Mars": 298,
|
|
16
|
+
"Mercury": 165,
|
|
17
|
+
"Jupiter": 95,
|
|
18
|
+
"Venus": 357,
|
|
19
|
+
"Saturn": 200,
|
|
20
|
+
}
|
|
21
|
+
DEBILITATION_DEG = {
|
|
22
|
+
"Sun": 190,
|
|
23
|
+
"Moon": 213,
|
|
24
|
+
"Mars": 118,
|
|
25
|
+
"Mercury": 345,
|
|
26
|
+
"Jupiter": 275,
|
|
27
|
+
"Venus": 177,
|
|
28
|
+
"Saturn": 20,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
OWN_SIGNS = {
|
|
32
|
+
"Sun": ["Leo"],
|
|
33
|
+
"Moon": ["Cancer"],
|
|
34
|
+
"Mars": ["Aries", "Scorpio"],
|
|
35
|
+
"Mercury": ["Gemini", "Virgo"],
|
|
36
|
+
"Jupiter": ["Sagittarius", "Pisces"],
|
|
37
|
+
"Venus": ["Taurus", "Libra"],
|
|
38
|
+
"Saturn": ["Capricorn", "Aquarius"],
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
MOOLATRIKONA = {
|
|
42
|
+
"Sun": "Leo",
|
|
43
|
+
"Moon": "Taurus",
|
|
44
|
+
"Mars": "Aries",
|
|
45
|
+
"Mercury": "Virgo",
|
|
46
|
+
"Jupiter": "Sagittarius",
|
|
47
|
+
"Venus": "Libra",
|
|
48
|
+
"Saturn": "Aquarius",
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
# Rashi index → name
|
|
52
|
+
RASHIS = [
|
|
53
|
+
"Aries",
|
|
54
|
+
"Taurus",
|
|
55
|
+
"Gemini",
|
|
56
|
+
"Cancer",
|
|
57
|
+
"Leo",
|
|
58
|
+
"Virgo",
|
|
59
|
+
"Libra",
|
|
60
|
+
"Scorpio",
|
|
61
|
+
"Sagittarius",
|
|
62
|
+
"Capricorn",
|
|
63
|
+
"Aquarius",
|
|
64
|
+
"Pisces",
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
# Navamsha sign lookup: given absolute longitude, return D9 rashi name
|
|
68
|
+
# Each rashi (30°) is divided into 9 navamshas of 3°20' each.
|
|
69
|
+
# The 108 navamshas cycle through the 12 rashis starting from Aries for
|
|
70
|
+
# fire signs, Cancer for earth, Libra for air, Capricorn for water.
|
|
71
|
+
_NAVAMSHA_START = {
|
|
72
|
+
0: 0,
|
|
73
|
+
1: 9,
|
|
74
|
+
2: 6,
|
|
75
|
+
3: 3,
|
|
76
|
+
4: 0,
|
|
77
|
+
5: 9,
|
|
78
|
+
6: 6,
|
|
79
|
+
7: 3,
|
|
80
|
+
8: 0,
|
|
81
|
+
9: 9,
|
|
82
|
+
10: 6,
|
|
83
|
+
11: 3,
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _navamsha_rashi(lon: float) -> str:
|
|
88
|
+
"""Return navamsha (D9) sign for a given sidereal longitude."""
|
|
89
|
+
lon = lon % 360
|
|
90
|
+
rashi_idx = int(lon / 30)
|
|
91
|
+
degree_in_sign = lon - rashi_idx * 30
|
|
92
|
+
navamsha_num = int(degree_in_sign / (10 / 3)) # 0-8
|
|
93
|
+
navamsha_num = min(navamsha_num, 8)
|
|
94
|
+
start = _NAVAMSHA_START[rashi_idx]
|
|
95
|
+
d9_rashi_idx = (start + navamsha_num) % 12
|
|
96
|
+
return RASHIS[d9_rashi_idx]
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
# Planetary relationships (for saptavargaja — simplified to friend/enemy/neutral)
|
|
100
|
+
FRIENDS = {
|
|
101
|
+
"Sun": ["Moon", "Mars", "Jupiter"],
|
|
102
|
+
"Moon": ["Sun", "Mercury"],
|
|
103
|
+
"Mars": ["Sun", "Moon", "Jupiter"],
|
|
104
|
+
"Mercury": ["Sun", "Venus"],
|
|
105
|
+
"Jupiter": ["Sun", "Moon", "Mars"],
|
|
106
|
+
"Venus": ["Mercury", "Saturn"],
|
|
107
|
+
"Saturn": ["Mercury", "Venus"],
|
|
108
|
+
}
|
|
109
|
+
ENEMIES = {
|
|
110
|
+
"Sun": ["Venus", "Saturn"],
|
|
111
|
+
"Moon": ["None"],
|
|
112
|
+
"Mars": ["Mercury"],
|
|
113
|
+
"Mercury": ["Moon"],
|
|
114
|
+
"Jupiter": ["Mercury", "Venus"],
|
|
115
|
+
"Venus": ["Sun", "Moon"],
|
|
116
|
+
"Saturn": ["Sun", "Moon", "Mars"],
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
# Sign rulerships (lord → sign index list)
|
|
120
|
+
_SIGN_LORDS = {
|
|
121
|
+
"Aries": "Mars",
|
|
122
|
+
"Taurus": "Venus",
|
|
123
|
+
"Gemini": "Mercury",
|
|
124
|
+
"Cancer": "Moon",
|
|
125
|
+
"Leo": "Sun",
|
|
126
|
+
"Virgo": "Mercury",
|
|
127
|
+
"Libra": "Venus",
|
|
128
|
+
"Scorpio": "Mars",
|
|
129
|
+
"Sagittarius": "Jupiter",
|
|
130
|
+
"Capricorn": "Saturn",
|
|
131
|
+
"Aquarius": "Saturn",
|
|
132
|
+
"Pisces": "Jupiter",
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
# Exaltation sign names
|
|
136
|
+
_EXALT_SIGN = {p: RASHIS[int(EXALTATION_DEG[p] / 30)] for p in PLANETS}
|
|
137
|
+
|
|
138
|
+
# Best house for Dig Bala
|
|
139
|
+
DIG_BALA_BEST_HOUSE = {
|
|
140
|
+
"Sun": 10,
|
|
141
|
+
"Moon": 4,
|
|
142
|
+
"Mars": 10,
|
|
143
|
+
"Mercury": 1,
|
|
144
|
+
"Jupiter": 1,
|
|
145
|
+
"Venus": 4,
|
|
146
|
+
"Saturn": 7,
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
# Natural (Naisargika) Bala in Shashtiamsas
|
|
150
|
+
NAISARGIKA_BALA = {
|
|
151
|
+
"Sun": 60.0,
|
|
152
|
+
"Moon": 51.43,
|
|
153
|
+
"Mars": 17.14,
|
|
154
|
+
"Mercury": 25.71,
|
|
155
|
+
"Jupiter": 34.29,
|
|
156
|
+
"Venus": 42.86,
|
|
157
|
+
"Saturn": 8.57,
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
# Mean daily motion in degrees
|
|
161
|
+
MEAN_MOTION = {
|
|
162
|
+
"Sun": 1.0,
|
|
163
|
+
"Moon": 13.0,
|
|
164
|
+
"Mars": 0.524,
|
|
165
|
+
"Mercury": 1.383,
|
|
166
|
+
"Jupiter": 0.083,
|
|
167
|
+
"Venus": 1.2,
|
|
168
|
+
"Saturn": 0.033,
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
# Required Rupas (minimum for "Strong" classification)
|
|
172
|
+
REQUIRED_RUPAS = {
|
|
173
|
+
"Sun": 6.5,
|
|
174
|
+
"Moon": 6.0,
|
|
175
|
+
"Mars": 5.0,
|
|
176
|
+
"Mercury": 7.0,
|
|
177
|
+
"Jupiter": 6.5,
|
|
178
|
+
"Venus": 5.5,
|
|
179
|
+
"Saturn": 5.0,
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
# Natural benefics / malefics
|
|
183
|
+
NATURAL_BENEFICS = {"Moon", "Mercury", "Jupiter", "Venus"}
|
|
184
|
+
NATURAL_MALEFICS = {"Sun", "Mars", "Saturn", "Rahu", "Ketu"}
|
|
185
|
+
|
|
186
|
+
# ---------------------------------------------------------------------------
|
|
187
|
+
# Sthana Bala components
|
|
188
|
+
# ---------------------------------------------------------------------------
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _uchcha_bala(planet: str, lon: float) -> float:
|
|
192
|
+
"""Exaltation strength (0-60 Shashtiamsas)."""
|
|
193
|
+
debil = DEBILITATION_DEG[planet]
|
|
194
|
+
diff = abs(lon - debil) % 360
|
|
195
|
+
if diff > 180:
|
|
196
|
+
diff = 360 - diff
|
|
197
|
+
return min(60.0, diff / 3.0)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def _saptavargaja_bala(planet: str, lon: float) -> float:
|
|
201
|
+
"""
|
|
202
|
+
Simplified Saptavargaja Bala using D1 and D9 only.
|
|
203
|
+
Returns combined score (max ~40 per chart = 80 total).
|
|
204
|
+
"""
|
|
205
|
+
total = 0.0
|
|
206
|
+
for rashi in [RASHIS[int(lon / 30) % 12], _navamsha_rashi(lon)]:
|
|
207
|
+
lord = _SIGN_LORDS.get(rashi, "")
|
|
208
|
+
exalt_sign = _EXALT_SIGN.get(planet, "")
|
|
209
|
+
if rashi == exalt_sign:
|
|
210
|
+
total += 20.0
|
|
211
|
+
elif rashi in OWN_SIGNS.get(planet, []):
|
|
212
|
+
total += 15.0
|
|
213
|
+
elif rashi == MOOLATRIKONA.get(planet, ""):
|
|
214
|
+
total += 15.0
|
|
215
|
+
elif lord in FRIENDS.get(planet, []):
|
|
216
|
+
total += 10.0
|
|
217
|
+
elif lord in ENEMIES.get(planet, []):
|
|
218
|
+
total += 3.75
|
|
219
|
+
else:
|
|
220
|
+
total += 7.5
|
|
221
|
+
return total
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _ojhayugma_bala(planet: str, lon: float) -> float:
|
|
225
|
+
"""Odd/Even sign strength (0 or 15 Shashtiamsas)."""
|
|
226
|
+
rashi_idx = int(lon / 30) % 12
|
|
227
|
+
is_odd = rashi_idx % 2 == 0 # Aries=0 is odd, Taurus=1 is even, etc.
|
|
228
|
+
male_planets = {"Sun", "Mars", "Jupiter"}
|
|
229
|
+
female_planets = {"Moon", "Venus"}
|
|
230
|
+
if planet in male_planets and is_odd:
|
|
231
|
+
return 15.0
|
|
232
|
+
if planet in female_planets and not is_odd:
|
|
233
|
+
return 15.0
|
|
234
|
+
if planet == "Saturn":
|
|
235
|
+
return 15.0 # simplified
|
|
236
|
+
return 0.0
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def _kendradi_bala(house: int) -> float:
|
|
240
|
+
"""Angular/succedent/cadent house strength."""
|
|
241
|
+
if house in (1, 4, 7, 10):
|
|
242
|
+
return 60.0
|
|
243
|
+
if house in (2, 5, 8, 11):
|
|
244
|
+
return 30.0
|
|
245
|
+
return 15.0
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def _drekkana_bala(planet: str, lon: float) -> float:
|
|
249
|
+
"""Decanate (drekkana) strength (0 or 15 Shashtiamsas)."""
|
|
250
|
+
degree_in_sign = lon % 30
|
|
251
|
+
male_planets = {"Sun", "Mars", "Jupiter"}
|
|
252
|
+
female_planets = {"Moon", "Venus"}
|
|
253
|
+
if planet in male_planets and degree_in_sign < 10:
|
|
254
|
+
return 15.0
|
|
255
|
+
if planet in female_planets and degree_in_sign >= 20:
|
|
256
|
+
return 15.0
|
|
257
|
+
if planet == "Mercury" and 10 <= degree_in_sign < 20:
|
|
258
|
+
return 15.0
|
|
259
|
+
return 0.0
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def _sthana_bala(planet: str, lon: float, house: int) -> float:
|
|
263
|
+
"""Total positional strength."""
|
|
264
|
+
return (
|
|
265
|
+
_uchcha_bala(planet, lon)
|
|
266
|
+
+ _saptavargaja_bala(planet, lon)
|
|
267
|
+
+ _ojhayugma_bala(planet, lon)
|
|
268
|
+
+ _kendradi_bala(house)
|
|
269
|
+
+ _drekkana_bala(planet, lon)
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
# ---------------------------------------------------------------------------
|
|
274
|
+
# Dig Bala
|
|
275
|
+
# ---------------------------------------------------------------------------
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def _dig_bala(planet: str, house: int) -> float:
|
|
279
|
+
"""Directional strength (0-60 Shashtiamsas)."""
|
|
280
|
+
best = DIG_BALA_BEST_HOUSE[planet]
|
|
281
|
+
# Minimum circular distance in houses (1-12 circle)
|
|
282
|
+
dist = abs(house - best)
|
|
283
|
+
dist = min(dist, 12 - dist)
|
|
284
|
+
# Convert house distance to degrees (1 house = 30°), normalize to 0-60
|
|
285
|
+
angular_dist_deg = dist * 30 # 0-180
|
|
286
|
+
return max(0.0, 60.0 - (angular_dist_deg * 60.0 / 180.0))
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
# ---------------------------------------------------------------------------
|
|
290
|
+
# Kala Bala (temporal strength)
|
|
291
|
+
# ---------------------------------------------------------------------------
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def _nathonnatha_bala(planet: str, jd: float) -> float:
|
|
295
|
+
"""Day/night strength based on Julian Day fraction."""
|
|
296
|
+
# JD fraction: 0.5 = noon UT; <0.5 or >0.5 used to approximate day/night.
|
|
297
|
+
# Simplified: treat JD fraction 0.25–0.75 as daytime.
|
|
298
|
+
frac = jd % 1.0
|
|
299
|
+
is_daytime = 0.25 <= frac < 0.75
|
|
300
|
+
diurnal = {"Sun", "Venus", "Jupiter"}
|
|
301
|
+
nocturnal = {"Moon", "Mars", "Saturn"}
|
|
302
|
+
if planet == "Mercury":
|
|
303
|
+
return 30.0
|
|
304
|
+
if planet in diurnal:
|
|
305
|
+
return 30.0 if is_daytime else 0.0
|
|
306
|
+
if planet in nocturnal:
|
|
307
|
+
return 30.0 if not is_daytime else 0.0
|
|
308
|
+
return 15.0
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def _paksha_bala(planet: str, sun_lon: float, moon_lon: float) -> float:
|
|
312
|
+
"""Lunar phase (Paksha) strength."""
|
|
313
|
+
diff = (moon_lon - sun_lon) % 360
|
|
314
|
+
benefics = {"Moon", "Mercury", "Jupiter", "Venus"}
|
|
315
|
+
if planet in benefics:
|
|
316
|
+
return min(60.0, diff / 6.0)
|
|
317
|
+
else:
|
|
318
|
+
return min(60.0, (360.0 - diff) / 6.0)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def _kala_bala(planet: str, jd: float, sun_lon: float, moon_lon: float) -> float:
|
|
322
|
+
"""Combined temporal strength (Nathonnatha + Paksha)."""
|
|
323
|
+
return _nathonnatha_bala(planet, jd) + _paksha_bala(planet, sun_lon, moon_lon)
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
# ---------------------------------------------------------------------------
|
|
327
|
+
# Chesta Bala (motional strength)
|
|
328
|
+
# ---------------------------------------------------------------------------
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def _chesta_bala(planet: str, speed: float) -> float:
|
|
332
|
+
"""Motional strength based on longitudinal speed."""
|
|
333
|
+
if planet == "Moon":
|
|
334
|
+
# Moon chesta bala = similar to paksha bala for simplicity; return 30
|
|
335
|
+
return 30.0
|
|
336
|
+
mean = MEAN_MOTION.get(planet, 1.0)
|
|
337
|
+
if speed < 0: # retrograde
|
|
338
|
+
return 60.0
|
|
339
|
+
if speed == 0:
|
|
340
|
+
return 60.0
|
|
341
|
+
if speed <= mean:
|
|
342
|
+
# Slower than mean → stronger (approaching retrogression)
|
|
343
|
+
ratio = speed / mean
|
|
344
|
+
return max(0.0, 60.0 * (1.0 - ratio * 0.5))
|
|
345
|
+
else:
|
|
346
|
+
# Faster than mean
|
|
347
|
+
return 45.0
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
# ---------------------------------------------------------------------------
|
|
351
|
+
# Drik Bala (aspectual strength)
|
|
352
|
+
# ---------------------------------------------------------------------------
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
def _drik_bala(planet: str, all_positions: list) -> float:
|
|
356
|
+
"""
|
|
357
|
+
Simplified aspectual strength.
|
|
358
|
+
Full aspect = planets in 7th house from each other (opposition).
|
|
359
|
+
Conjunction = same house.
|
|
360
|
+
Each benefic aspect: +15, each malefic aspect: -15. Cap at ±60.
|
|
361
|
+
"""
|
|
362
|
+
target = next((p for p in all_positions if p["name"] == planet), None)
|
|
363
|
+
if target is None:
|
|
364
|
+
return 0.0
|
|
365
|
+
|
|
366
|
+
target_house = target["house"]
|
|
367
|
+
score = 0.0
|
|
368
|
+
|
|
369
|
+
for p in all_positions:
|
|
370
|
+
if p["name"] == planet:
|
|
371
|
+
continue
|
|
372
|
+
p_name = p["name"]
|
|
373
|
+
p_house = p["house"]
|
|
374
|
+
|
|
375
|
+
# Check if p aspects target: conjunction or 7th house opposition
|
|
376
|
+
diff = abs(p_house - target_house)
|
|
377
|
+
is_aspecting = (diff == 0) or (diff == 6)
|
|
378
|
+
|
|
379
|
+
if is_aspecting:
|
|
380
|
+
if p_name in NATURAL_BENEFICS:
|
|
381
|
+
score += 15.0
|
|
382
|
+
elif p_name in NATURAL_MALEFICS:
|
|
383
|
+
score -= 15.0
|
|
384
|
+
|
|
385
|
+
return max(-60.0, min(60.0, score))
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
# ---------------------------------------------------------------------------
|
|
389
|
+
# Ishta / Kashta Phala
|
|
390
|
+
# ---------------------------------------------------------------------------
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
def _ishta_kashta(chesta: float, uchcha: float) -> tuple:
|
|
394
|
+
"""
|
|
395
|
+
Ishta Phala (benefic strength) and Kashta Phala (malefic strength).
|
|
396
|
+
Ishta = sqrt(uchcha_bala * chesta_bala)
|
|
397
|
+
Kashta = sqrt((60 - uchcha_bala) * (60 - chesta_bala))
|
|
398
|
+
"""
|
|
399
|
+
uchcha_norm = min(60.0, max(0.0, uchcha))
|
|
400
|
+
chesta_norm = min(60.0, max(0.0, chesta))
|
|
401
|
+
ishta = math.sqrt(uchcha_norm * chesta_norm)
|
|
402
|
+
kashta = math.sqrt((60.0 - uchcha_norm) * (60.0 - chesta_norm))
|
|
403
|
+
return round(ishta, 2), round(kashta, 2)
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
# ---------------------------------------------------------------------------
|
|
407
|
+
# Main entry point
|
|
408
|
+
# ---------------------------------------------------------------------------
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
def get_shadbala(base_chart: dict) -> dict:
|
|
412
|
+
"""
|
|
413
|
+
Calculate Shadbala (six-fold planetary strength) for all seven classical planets.
|
|
414
|
+
|
|
415
|
+
Parameters
|
|
416
|
+
----------
|
|
417
|
+
base_chart : dict
|
|
418
|
+
Output of ``build_chart()``. Must contain:
|
|
419
|
+
- ``planetary_positions``: list of planet dicts (see module docstring).
|
|
420
|
+
- ``julian_day``: float (JD at birth moment).
|
|
421
|
+
|
|
422
|
+
Returns
|
|
423
|
+
-------
|
|
424
|
+
dict
|
|
425
|
+
``planets`` mapping each planet name to its strength breakdown,
|
|
426
|
+
plus a ``summary`` string.
|
|
427
|
+
"""
|
|
428
|
+
positions: list = base_chart.get("planetary_positions", [])
|
|
429
|
+
jd: float = base_chart.get("julian_day", 0.0)
|
|
430
|
+
|
|
431
|
+
# Build quick lookup
|
|
432
|
+
pos_map = {p["name"]: p for p in positions}
|
|
433
|
+
|
|
434
|
+
sun_lon = pos_map.get("Sun", {}).get("longitude", 0.0)
|
|
435
|
+
moon_lon = pos_map.get("Moon", {}).get("longitude", 0.0)
|
|
436
|
+
|
|
437
|
+
results = {}
|
|
438
|
+
|
|
439
|
+
for planet in PLANETS:
|
|
440
|
+
p = pos_map.get(planet)
|
|
441
|
+
if p is None:
|
|
442
|
+
continue
|
|
443
|
+
|
|
444
|
+
lon = p["longitude"]
|
|
445
|
+
house = p["house"]
|
|
446
|
+
speed = p.get("speed_longitude", 0.0)
|
|
447
|
+
is_retro = p.get("is_retrograde", False)
|
|
448
|
+
if is_retro:
|
|
449
|
+
speed = -abs(speed)
|
|
450
|
+
|
|
451
|
+
# --- Six strengths ---
|
|
452
|
+
sthana = _sthana_bala(planet, lon, house)
|
|
453
|
+
dig = _dig_bala(planet, house)
|
|
454
|
+
kala = _kala_bala(planet, jd, sun_lon, moon_lon)
|
|
455
|
+
chesta = _chesta_bala(planet, speed)
|
|
456
|
+
naisargika = NAISARGIKA_BALA[planet]
|
|
457
|
+
drik = _drik_bala(planet, positions)
|
|
458
|
+
|
|
459
|
+
total = sthana + dig + kala + chesta + naisargika + drik
|
|
460
|
+
total_rupas = round(total / 60.0, 3)
|
|
461
|
+
required = REQUIRED_RUPAS[planet]
|
|
462
|
+
|
|
463
|
+
uchcha = _uchcha_bala(planet, lon)
|
|
464
|
+
ishta, kashta = _ishta_kashta(chesta, uchcha)
|
|
465
|
+
|
|
466
|
+
if total_rupas >= required * 1.2:
|
|
467
|
+
grade = "Strong"
|
|
468
|
+
elif total_rupas >= required * 0.8:
|
|
469
|
+
grade = "Average"
|
|
470
|
+
else:
|
|
471
|
+
grade = "Weak"
|
|
472
|
+
|
|
473
|
+
results[planet] = {
|
|
474
|
+
"sthana_bala": round(sthana, 2),
|
|
475
|
+
"dig_bala": round(dig, 2),
|
|
476
|
+
"kala_bala": round(kala, 2),
|
|
477
|
+
"chesta_bala": round(chesta, 2),
|
|
478
|
+
"naisargika_bala": round(naisargika, 2),
|
|
479
|
+
"drik_bala": round(drik, 2),
|
|
480
|
+
"total_shadbala": round(total, 2),
|
|
481
|
+
"total_rupas": total_rupas,
|
|
482
|
+
"required_rupas": required,
|
|
483
|
+
"ishta_phala": ishta,
|
|
484
|
+
"kashta_phala": kashta,
|
|
485
|
+
"strength_grade": grade,
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
# Build summary
|
|
489
|
+
strong = [p for p, v in results.items() if v["strength_grade"] == "Strong"]
|
|
490
|
+
weak = [p for p, v in results.items() if v["strength_grade"] == "Weak"]
|
|
491
|
+
summary_parts = []
|
|
492
|
+
if strong:
|
|
493
|
+
summary_parts.append(f"Strong planets: {', '.join(strong)}.")
|
|
494
|
+
if weak:
|
|
495
|
+
summary_parts.append(f"Weak planets: {', '.join(weak)}.")
|
|
496
|
+
if not summary_parts:
|
|
497
|
+
summary_parts.append("All planets are of average strength.")
|
|
498
|
+
summary = " ".join(summary_parts)
|
|
499
|
+
|
|
500
|
+
return {"planets": results, "summary": summary}
|