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,439 @@
|
|
|
1
|
+
"""Additional Dasha systems: Ashtottari, Sookshma (4th level), Prana (5th level)."""
|
|
2
|
+
|
|
3
|
+
from datetime import datetime, timedelta
|
|
4
|
+
|
|
5
|
+
from kundali_lib.vedic.dasha_extended import (
|
|
6
|
+
NAKSHATRA_TO_DASHA_LORD,
|
|
7
|
+
VIMSHOTTARI_SEQUENCE,
|
|
8
|
+
VIMSHOTTARI_TOTAL,
|
|
9
|
+
VIMSHOTTARI_YEARS,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
# ── Ashtottari constants ─────────────────────────────────────────────────────
|
|
13
|
+
|
|
14
|
+
ASHTOTTARI_SEQUENCE = [
|
|
15
|
+
"Sun",
|
|
16
|
+
"Moon",
|
|
17
|
+
"Mars",
|
|
18
|
+
"Mercury",
|
|
19
|
+
"Saturn",
|
|
20
|
+
"Jupiter",
|
|
21
|
+
"Rahu",
|
|
22
|
+
"Venus",
|
|
23
|
+
]
|
|
24
|
+
ASHTOTTARI_YEARS: dict[str, int] = {
|
|
25
|
+
"Sun": 6,
|
|
26
|
+
"Moon": 15,
|
|
27
|
+
"Mars": 8,
|
|
28
|
+
"Mercury": 17,
|
|
29
|
+
"Saturn": 10,
|
|
30
|
+
"Jupiter": 19,
|
|
31
|
+
"Rahu": 12,
|
|
32
|
+
"Venus": 21,
|
|
33
|
+
}
|
|
34
|
+
ASHTOTTARI_TOTAL = 108
|
|
35
|
+
|
|
36
|
+
# Birth nakshatra → Ashtottari starting dasha
|
|
37
|
+
NAKSHATRA_ASHTOTTARI: dict[str, str] = {
|
|
38
|
+
"Ashwini": "Sun",
|
|
39
|
+
"Bharani": "Moon",
|
|
40
|
+
"Krittika": "Mars",
|
|
41
|
+
"Rohini": "Mercury",
|
|
42
|
+
"Mrigashira": "Saturn",
|
|
43
|
+
"Ardra": "Jupiter",
|
|
44
|
+
"Punarvasu": "Rahu",
|
|
45
|
+
"Pushya": "Venus",
|
|
46
|
+
"Ashlesha": "Sun",
|
|
47
|
+
"Magha": "Moon",
|
|
48
|
+
"Purva Phalguni": "Mars",
|
|
49
|
+
"Uttara Phalguni": "Mercury",
|
|
50
|
+
"Hasta": "Saturn",
|
|
51
|
+
"Chitra": "Jupiter",
|
|
52
|
+
"Swati": "Rahu",
|
|
53
|
+
"Vishakha": "Venus",
|
|
54
|
+
"Anuradha": "Sun",
|
|
55
|
+
"Jyeshtha": "Moon",
|
|
56
|
+
"Mula": "Mars",
|
|
57
|
+
"Purva Ashadha": "Mercury",
|
|
58
|
+
"Uttara Ashadha": "Saturn",
|
|
59
|
+
"Shravana": "Jupiter",
|
|
60
|
+
"Dhanishta": "Rahu",
|
|
61
|
+
"Shatabhisha": "Venus",
|
|
62
|
+
"Purva Bhadrapada": "Sun",
|
|
63
|
+
"Uttara Bhadrapada": "Moon",
|
|
64
|
+
"Revati": "Mars",
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
_NAKSHATRA_SPAN = 360.0 / 27.0
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# ── Private helpers ──────────────────────────────────────────────────────────
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _rotated(seq: list, start: str) -> list:
|
|
74
|
+
"""Return seq rotated so it begins at start."""
|
|
75
|
+
idx = seq.index(start)
|
|
76
|
+
return seq[idx:] + seq[:idx]
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _iter_pds(ad_lord: str, ad_start: datetime, ad_years: float):
|
|
80
|
+
"""Yield (pd_lord, pd_start, pd_years) for each of the 9 PDs in one AD."""
|
|
81
|
+
pd_cursor = ad_start
|
|
82
|
+
for pd_lord in _rotated(VIMSHOTTARI_SEQUENCE, ad_lord):
|
|
83
|
+
pd_y = (VIMSHOTTARI_YEARS[pd_lord] / VIMSHOTTARI_TOTAL) * ad_years
|
|
84
|
+
pd_end = pd_cursor + timedelta(days=pd_y * 365.25)
|
|
85
|
+
yield pd_lord, pd_cursor, pd_y
|
|
86
|
+
pd_cursor = pd_end
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _iter_sds(pd_lord: str, pd_start: datetime, pd_years: float):
|
|
90
|
+
"""Yield (sd_lord, sd_start, sd_end) for each of the 9 SDs in one PD.
|
|
91
|
+
|
|
92
|
+
SD duration = (sd_years / 120) * pd_duration_years.
|
|
93
|
+
"""
|
|
94
|
+
sd_cursor = pd_start
|
|
95
|
+
for sd_lord in _rotated(VIMSHOTTARI_SEQUENCE, pd_lord):
|
|
96
|
+
sd_y = (VIMSHOTTARI_YEARS[sd_lord] / VIMSHOTTARI_TOTAL) * pd_years
|
|
97
|
+
sd_days = sd_y * 365.25
|
|
98
|
+
sd_end = sd_cursor + timedelta(days=sd_days)
|
|
99
|
+
yield sd_lord, sd_cursor, sd_end, sd_y
|
|
100
|
+
sd_cursor = sd_end
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _iter_prds(sd_lord: str, sd_start: datetime, sd_years: float):
|
|
104
|
+
"""Yield (prd_lord, prd_start, prd_end, prd_days) for each PRD in one SD.
|
|
105
|
+
|
|
106
|
+
PRD duration = (prd_years / 120) * sd_duration_years.
|
|
107
|
+
"""
|
|
108
|
+
prd_cursor = sd_start
|
|
109
|
+
for prd_lord in _rotated(VIMSHOTTARI_SEQUENCE, sd_lord):
|
|
110
|
+
prd_y = (VIMSHOTTARI_YEARS[prd_lord] / VIMSHOTTARI_TOTAL) * sd_years
|
|
111
|
+
prd_days = prd_y * 365.25
|
|
112
|
+
prd_end = prd_cursor + timedelta(days=prd_days)
|
|
113
|
+
yield prd_lord, prd_cursor, prd_end, prd_days
|
|
114
|
+
prd_cursor = prd_end
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _find_periods(
|
|
118
|
+
birth_dt: datetime,
|
|
119
|
+
moon_longitude: float,
|
|
120
|
+
moon_nakshatra: str,
|
|
121
|
+
now: datetime,
|
|
122
|
+
) -> dict | None:
|
|
123
|
+
"""Drill down MD → AD → PD and return context for current periods.
|
|
124
|
+
|
|
125
|
+
Returns a dict with keys: md_lord, ad_lord, ad_start, ad_years,
|
|
126
|
+
pd_lord, pd_start, pd_years — or None if not found within the 120-year span.
|
|
127
|
+
"""
|
|
128
|
+
birth_dasha_lord = NAKSHATRA_TO_DASHA_LORD[moon_nakshatra]
|
|
129
|
+
fraction_elapsed = (moon_longitude % _NAKSHATRA_SPAN) / _NAKSHATRA_SPAN
|
|
130
|
+
|
|
131
|
+
md0_years = VIMSHOTTARI_YEARS[birth_dasha_lord]
|
|
132
|
+
md_cursor = birth_dt - timedelta(days=fraction_elapsed * md0_years * 365.25)
|
|
133
|
+
|
|
134
|
+
for md_lord in _rotated(VIMSHOTTARI_SEQUENCE, birth_dasha_lord):
|
|
135
|
+
md_years = VIMSHOTTARI_YEARS[md_lord]
|
|
136
|
+
md_start = md_cursor
|
|
137
|
+
md_end = md_start + timedelta(days=md_years * 365.25)
|
|
138
|
+
md_cursor = md_end
|
|
139
|
+
|
|
140
|
+
if not (md_start <= now < md_end):
|
|
141
|
+
continue
|
|
142
|
+
|
|
143
|
+
# Found the current MD — drill into ADs
|
|
144
|
+
ad_cursor = md_start
|
|
145
|
+
for ad_lord in _rotated(VIMSHOTTARI_SEQUENCE, md_lord):
|
|
146
|
+
ad_years = (VIMSHOTTARI_YEARS[ad_lord] / VIMSHOTTARI_TOTAL) * md_years
|
|
147
|
+
ad_start = ad_cursor
|
|
148
|
+
ad_end = ad_start + timedelta(days=ad_years * 365.25)
|
|
149
|
+
ad_cursor = ad_end
|
|
150
|
+
|
|
151
|
+
if not (ad_start <= now < ad_end):
|
|
152
|
+
continue
|
|
153
|
+
|
|
154
|
+
# Found the current AD — drill into PDs
|
|
155
|
+
pd_cursor = ad_start
|
|
156
|
+
for pd_lord in _rotated(VIMSHOTTARI_SEQUENCE, ad_lord):
|
|
157
|
+
pd_years = (VIMSHOTTARI_YEARS[pd_lord] / VIMSHOTTARI_TOTAL) * ad_years
|
|
158
|
+
pd_start = pd_cursor
|
|
159
|
+
pd_end = pd_start + timedelta(days=pd_years * 365.25)
|
|
160
|
+
pd_cursor = pd_end
|
|
161
|
+
|
|
162
|
+
if pd_start <= now < pd_end:
|
|
163
|
+
return {
|
|
164
|
+
"md_lord": md_lord,
|
|
165
|
+
"ad_lord": ad_lord,
|
|
166
|
+
"ad_start": ad_start,
|
|
167
|
+
"ad_years": ad_years,
|
|
168
|
+
"pd_lord": pd_lord,
|
|
169
|
+
"pd_start": pd_start,
|
|
170
|
+
"pd_years": pd_years,
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return None
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
# ── Ashtottari Dasha ─────────────────────────────────────────────────────────
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def get_ashtottari_dasha(
|
|
180
|
+
birth_dt: datetime,
|
|
181
|
+
moon_longitude: float,
|
|
182
|
+
moon_nakshatra: str,
|
|
183
|
+
) -> dict:
|
|
184
|
+
"""Calculate Ashtottari Dasha (108-year cycle).
|
|
185
|
+
|
|
186
|
+
Applicable when Rahu occupies certain positions; can be calculated for all charts.
|
|
187
|
+
Antardasha duration = (ad_years / 108) * md_years.
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
birth_dt: Naive local birth datetime.
|
|
191
|
+
moon_longitude: Sidereal Moon longitude in degrees (0–360).
|
|
192
|
+
moon_nakshatra: Name of the birth nakshatra (e.g. "Ashwini").
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
dict with ``system``, ``total_years``, ``birth_dasha_lord``, and ``mahadashas``.
|
|
196
|
+
"""
|
|
197
|
+
birth_dasha_lord = NAKSHATRA_ASHTOTTARI[moon_nakshatra]
|
|
198
|
+
fraction_elapsed = (moon_longitude % _NAKSHATRA_SPAN) / _NAKSHATRA_SPAN
|
|
199
|
+
|
|
200
|
+
result_mds: dict = {}
|
|
201
|
+
md_cursor: datetime | None = None
|
|
202
|
+
|
|
203
|
+
for i, md_lord in enumerate(_rotated(ASHTOTTARI_SEQUENCE, birth_dasha_lord)):
|
|
204
|
+
md_full_years = ASHTOTTARI_YEARS[md_lord]
|
|
205
|
+
md_full_days = md_full_years * 365.25
|
|
206
|
+
|
|
207
|
+
if i == 0:
|
|
208
|
+
elapsed_days = fraction_elapsed * md_full_days
|
|
209
|
+
md_start = birth_dt - timedelta(days=elapsed_days)
|
|
210
|
+
display_duration = round((1.0 - fraction_elapsed) * md_full_years, 4)
|
|
211
|
+
else:
|
|
212
|
+
md_start = md_cursor # type: ignore[assignment]
|
|
213
|
+
display_duration = float(md_full_years)
|
|
214
|
+
|
|
215
|
+
md_end = md_start + timedelta(days=md_full_days)
|
|
216
|
+
md_cursor = md_end
|
|
217
|
+
|
|
218
|
+
# ── Antardasha sequence starts from this MD lord ─────────────────
|
|
219
|
+
result_ads: dict = {}
|
|
220
|
+
ad_cursor = md_start
|
|
221
|
+
|
|
222
|
+
for ad_lord in _rotated(ASHTOTTARI_SEQUENCE, md_lord):
|
|
223
|
+
ad_years = (ASHTOTTARI_YEARS[ad_lord] / ASHTOTTARI_TOTAL) * md_full_years
|
|
224
|
+
ad_days = ad_years * 365.25
|
|
225
|
+
ad_end = ad_cursor + timedelta(days=ad_days)
|
|
226
|
+
|
|
227
|
+
result_ads[ad_lord] = {
|
|
228
|
+
"start": ad_cursor.strftime("%d-%m-%Y"),
|
|
229
|
+
"end": ad_end.strftime("%d-%m-%Y"),
|
|
230
|
+
"duration_days": round(ad_days, 2),
|
|
231
|
+
}
|
|
232
|
+
ad_cursor = ad_end
|
|
233
|
+
|
|
234
|
+
result_mds[md_lord] = {
|
|
235
|
+
"start": md_start.strftime("%d-%m-%Y"),
|
|
236
|
+
"end": md_end.strftime("%d-%m-%Y"),
|
|
237
|
+
"duration_years": display_duration,
|
|
238
|
+
"antardashas": result_ads,
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return {
|
|
242
|
+
"system": "Ashtottari",
|
|
243
|
+
"total_years": ASHTOTTARI_TOTAL,
|
|
244
|
+
"birth_dasha_lord": birth_dasha_lord,
|
|
245
|
+
"mahadashas": result_mds,
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
# ── Sookshma Dasha (4th level) ────────────────────────────────────────────────
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def get_sookshma_dasha(
|
|
253
|
+
birth_dt: datetime,
|
|
254
|
+
moon_longitude: float,
|
|
255
|
+
moon_nakshatra: str,
|
|
256
|
+
) -> dict:
|
|
257
|
+
"""Generate 4 levels of Vimshottari (MD → AD → PD → SD) and return the current state.
|
|
258
|
+
|
|
259
|
+
Finds the running period at all 4 levels (as of now) and returns the current
|
|
260
|
+
Sookshma Dasha plus the next 5 upcoming Sookshma periods.
|
|
261
|
+
|
|
262
|
+
SD duration = (sd_planet_years / 120) * pd_duration_years.
|
|
263
|
+
|
|
264
|
+
Args:
|
|
265
|
+
birth_dt: Naive local birth datetime.
|
|
266
|
+
moon_longitude: Sidereal Moon longitude in degrees (0–360).
|
|
267
|
+
moon_nakshatra: Name of the birth nakshatra.
|
|
268
|
+
|
|
269
|
+
Returns:
|
|
270
|
+
dict with current MD/AD/PD/SD labels, current SD start/end, and
|
|
271
|
+
``upcoming_sookshma`` (list of next 5 SD periods).
|
|
272
|
+
"""
|
|
273
|
+
now = datetime.now()
|
|
274
|
+
ctx = _find_periods(birth_dt, moon_longitude, moon_nakshatra, now)
|
|
275
|
+
|
|
276
|
+
if ctx is None:
|
|
277
|
+
return {"error": "Could not determine current dasha period."}
|
|
278
|
+
|
|
279
|
+
current_sd_lord: str | None = None
|
|
280
|
+
current_sd_start: datetime | None = None
|
|
281
|
+
current_sd_end: datetime | None = None
|
|
282
|
+
upcoming: list = []
|
|
283
|
+
found = False
|
|
284
|
+
|
|
285
|
+
for pd_lord, pd_start, pd_years in _iter_pds(
|
|
286
|
+
ctx["ad_lord"], ctx["ad_start"], ctx["ad_years"]
|
|
287
|
+
):
|
|
288
|
+
# Skip PDs that ended before the current PD began
|
|
289
|
+
pd_end = pd_start + timedelta(days=pd_years * 365.25)
|
|
290
|
+
if pd_end <= ctx["pd_start"]:
|
|
291
|
+
continue
|
|
292
|
+
|
|
293
|
+
for sd_lord, sd_start, sd_end, _sd_y in _iter_sds(pd_lord, pd_start, pd_years):
|
|
294
|
+
if sd_start <= now < sd_end:
|
|
295
|
+
current_sd_lord = sd_lord
|
|
296
|
+
current_sd_start = sd_start
|
|
297
|
+
current_sd_end = sd_end
|
|
298
|
+
found = True
|
|
299
|
+
elif found and len(upcoming) < 5:
|
|
300
|
+
upcoming.append(
|
|
301
|
+
{
|
|
302
|
+
"planet": sd_lord,
|
|
303
|
+
"start": sd_start.strftime("%d-%m-%Y"),
|
|
304
|
+
"end": sd_end.strftime("%d-%m-%Y"),
|
|
305
|
+
}
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
if found and len(upcoming) >= 5:
|
|
309
|
+
break
|
|
310
|
+
|
|
311
|
+
return {
|
|
312
|
+
"current_mahadasha": ctx["md_lord"],
|
|
313
|
+
"current_antardasha": ctx["ad_lord"],
|
|
314
|
+
"current_pratyantar": ctx["pd_lord"],
|
|
315
|
+
"current_sookshma": current_sd_lord or "Unknown",
|
|
316
|
+
"current_sookshma_start": (
|
|
317
|
+
current_sd_start.strftime("%d-%m-%Y") if current_sd_start else ""
|
|
318
|
+
),
|
|
319
|
+
"current_sookshma_end": (
|
|
320
|
+
current_sd_end.strftime("%d-%m-%Y") if current_sd_end else ""
|
|
321
|
+
),
|
|
322
|
+
"upcoming_sookshma": upcoming,
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
# ── Prana Dasha (5th level) ───────────────────────────────────────────────────
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def get_prana_dasha(
|
|
330
|
+
birth_dt: datetime,
|
|
331
|
+
moon_longitude: float,
|
|
332
|
+
moon_nakshatra: str,
|
|
333
|
+
) -> dict:
|
|
334
|
+
"""Generate 5 levels of Vimshottari (MD → AD → PD → SD → PRD) and return the current state.
|
|
335
|
+
|
|
336
|
+
Finds the running period at all 5 levels (as of now) and returns the current
|
|
337
|
+
Prana Dasha plus the next 5 upcoming Prana periods.
|
|
338
|
+
|
|
339
|
+
PRD duration = (prd_planet_years / 120) * sd_duration_years.
|
|
340
|
+
|
|
341
|
+
Args:
|
|
342
|
+
birth_dt: Naive local birth datetime.
|
|
343
|
+
moon_longitude: Sidereal Moon longitude in degrees (0–360).
|
|
344
|
+
moon_nakshatra: Name of the birth nakshatra.
|
|
345
|
+
|
|
346
|
+
Returns:
|
|
347
|
+
dict with current MD/AD/PD/SD/PRD labels, current PRD start/end/duration_days,
|
|
348
|
+
and ``upcoming_prana`` (list of next 5 PRD periods).
|
|
349
|
+
"""
|
|
350
|
+
now = datetime.now()
|
|
351
|
+
ctx = _find_periods(birth_dt, moon_longitude, moon_nakshatra, now)
|
|
352
|
+
|
|
353
|
+
if ctx is None:
|
|
354
|
+
return {"error": "Could not determine current dasha period."}
|
|
355
|
+
|
|
356
|
+
current_sd_lord: str | None = None
|
|
357
|
+
current_prd_lord: str | None = None
|
|
358
|
+
current_prd_start: datetime | None = None
|
|
359
|
+
current_prd_end: datetime | None = None
|
|
360
|
+
current_prd_days: float | None = None
|
|
361
|
+
upcoming: list = []
|
|
362
|
+
found_sd = False
|
|
363
|
+
found_prd = False
|
|
364
|
+
|
|
365
|
+
for pd_lord, pd_start, pd_years in _iter_pds(
|
|
366
|
+
ctx["ad_lord"], ctx["ad_start"], ctx["ad_years"]
|
|
367
|
+
):
|
|
368
|
+
pd_end = pd_start + timedelta(days=pd_years * 365.25)
|
|
369
|
+
if pd_end <= ctx["pd_start"]:
|
|
370
|
+
continue
|
|
371
|
+
|
|
372
|
+
for sd_lord, sd_start, sd_end, sd_y in _iter_sds(pd_lord, pd_start, pd_years):
|
|
373
|
+
# Skip SDs that ended before the current PD began
|
|
374
|
+
if sd_end <= ctx["pd_start"]:
|
|
375
|
+
continue
|
|
376
|
+
|
|
377
|
+
if sd_start <= now < sd_end and not found_sd:
|
|
378
|
+
current_sd_lord = sd_lord
|
|
379
|
+
found_sd = True
|
|
380
|
+
|
|
381
|
+
# Drill into PRDs within this SD
|
|
382
|
+
for prd_lord, prd_start, prd_end, prd_days in _iter_prds(
|
|
383
|
+
sd_lord, sd_start, sd_y
|
|
384
|
+
):
|
|
385
|
+
if prd_start <= now < prd_end:
|
|
386
|
+
current_prd_lord = prd_lord
|
|
387
|
+
current_prd_start = prd_start
|
|
388
|
+
current_prd_end = prd_end
|
|
389
|
+
current_prd_days = prd_days
|
|
390
|
+
found_prd = True
|
|
391
|
+
elif found_prd and len(upcoming) < 5:
|
|
392
|
+
upcoming.append(
|
|
393
|
+
{
|
|
394
|
+
"planet": prd_lord,
|
|
395
|
+
"start": prd_start.strftime("%d-%m-%Y"),
|
|
396
|
+
"end": prd_end.strftime("%d-%m-%Y"),
|
|
397
|
+
}
|
|
398
|
+
)
|
|
399
|
+
if found_prd and len(upcoming) >= 5:
|
|
400
|
+
break
|
|
401
|
+
|
|
402
|
+
elif found_prd and len(upcoming) < 5:
|
|
403
|
+
# Collect PRDs from subsequent SDs to fill up upcoming list
|
|
404
|
+
for prd_lord, prd_start, prd_end, _prd_days in _iter_prds(
|
|
405
|
+
sd_lord, sd_start, sd_y
|
|
406
|
+
):
|
|
407
|
+
upcoming.append(
|
|
408
|
+
{
|
|
409
|
+
"planet": prd_lord,
|
|
410
|
+
"start": prd_start.strftime("%d-%m-%Y"),
|
|
411
|
+
"end": prd_end.strftime("%d-%m-%Y"),
|
|
412
|
+
}
|
|
413
|
+
)
|
|
414
|
+
if len(upcoming) >= 5:
|
|
415
|
+
break
|
|
416
|
+
|
|
417
|
+
if found_prd and len(upcoming) >= 5:
|
|
418
|
+
break
|
|
419
|
+
|
|
420
|
+
if found_prd and len(upcoming) >= 5:
|
|
421
|
+
break
|
|
422
|
+
|
|
423
|
+
return {
|
|
424
|
+
"current_mahadasha": ctx["md_lord"],
|
|
425
|
+
"current_antardasha": ctx["ad_lord"],
|
|
426
|
+
"current_pratyantar": ctx["pd_lord"],
|
|
427
|
+
"current_sookshma": current_sd_lord or "Unknown",
|
|
428
|
+
"current_prana": current_prd_lord or "Unknown",
|
|
429
|
+
"current_prana_start": (
|
|
430
|
+
current_prd_start.strftime("%d-%m-%Y") if current_prd_start else ""
|
|
431
|
+
),
|
|
432
|
+
"current_prana_end": (
|
|
433
|
+
current_prd_end.strftime("%d-%m-%Y") if current_prd_end else ""
|
|
434
|
+
),
|
|
435
|
+
"current_prana_duration_days": round(current_prd_days, 2)
|
|
436
|
+
if current_prd_days
|
|
437
|
+
else 0.0,
|
|
438
|
+
"upcoming_prana": upcoming,
|
|
439
|
+
}
|