Update app.py
Browse files
app.py
CHANGED
@@ -22,7 +22,7 @@ ZODIAC_SIGNS = [
|
|
22 |
("Pisces", 330, 360),
|
23 |
]
|
24 |
|
25 |
-
# Moon phase boundaries (0° to 360° phase angle)
|
26 |
MOON_PHASES = [
|
27 |
("New Moon", 0, 45),
|
28 |
("Waxing Crescent", 45, 90),
|
@@ -34,36 +34,100 @@ MOON_PHASES = [
|
|
34 |
("Waning Crescent", 315, 360),
|
35 |
]
|
36 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
@tool
|
38 |
def get_moon_info(date_time: str) -> dict:
|
39 |
"""
|
40 |
-
Returns Moon's Zodiac position
|
41 |
|
42 |
Args:
|
43 |
date_time (str): ISO 8601 formatted datetime (YYYY-MM-DDTHH:MM:SS)
|
44 |
|
45 |
Returns:
|
46 |
-
dict: {
|
47 |
-
|
|
|
|
|
|
|
|
|
|
|
48 |
"""
|
49 |
try:
|
|
|
50 |
user_time = datetime.datetime.strptime(date_time, "%Y-%m-%dT%H:%M:%S")
|
51 |
user_time = pytz.utc.localize(user_time)
|
52 |
|
|
|
53 |
planets = load('de421.bsp')
|
54 |
ts = load.timescale()
|
55 |
t = ts.from_datetime(user_time)
|
56 |
|
|
|
57 |
earth = planets['earth']
|
58 |
moon = planets['moon']
|
59 |
sun = planets['sun']
|
60 |
|
61 |
-
# Calculate ecliptic longitude
|
62 |
astrometric = earth.at(t).observe(moon)
|
63 |
_, _, ecliptic_lon = astrometric.ecliptic_latlon()
|
64 |
lon_deg = ecliptic_lon.degrees % 360
|
65 |
|
66 |
-
# Calculate phase angle
|
67 |
phase_angle = earth.at(t).observe(moon).apparent().phase_angle(sun).degrees
|
68 |
|
69 |
# Determine Zodiac sign and position
|
@@ -75,21 +139,46 @@ def get_moon_info(date_time: str) -> dict:
|
|
75 |
position_degrees = lon_deg - start
|
76 |
break
|
77 |
|
78 |
-
# Format position to degrees
|
79 |
degrees = int(position_degrees)
|
80 |
minutes = int((position_degrees % 1) * 60)
|
81 |
position_str = f"{zodiac_sign} {degrees}°{minutes:02}'"
|
82 |
|
83 |
-
# Determine phase
|
84 |
moon_phase = "Unknown"
|
85 |
for phase, start, end in MOON_PHASES:
|
86 |
if start <= phase_angle < end:
|
87 |
moon_phase = phase
|
88 |
break
|
89 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
return {
|
91 |
"zodiac_position": position_str,
|
92 |
-
"moon_phase": moon_phase
|
|
|
|
|
|
|
93 |
}
|
94 |
|
95 |
except Exception as e:
|
|
|
22 |
("Pisces", 330, 360),
|
23 |
]
|
24 |
|
25 |
+
# Moon phase boundaries (0° to 360° phase angle) for display purposes
|
26 |
MOON_PHASES = [
|
27 |
("New Moon", 0, 45),
|
28 |
("Waxing Crescent", 45, 90),
|
|
|
34 |
("Waning Crescent", 315, 360),
|
35 |
]
|
36 |
|
37 |
+
# Fertility sign coefficients (applicable to all plants)
|
38 |
+
FERTILITY_SIGN_COEFFS = {
|
39 |
+
"Aries": 1,
|
40 |
+
"Taurus": 2,
|
41 |
+
"Gemini": 0,
|
42 |
+
"Cancer": 2,
|
43 |
+
"Leo": 1,
|
44 |
+
"Virgo": 0,
|
45 |
+
"Libra": 0.5,
|
46 |
+
"Scorpio": 1.5,
|
47 |
+
"Sagittarius": 1,
|
48 |
+
"Capricorn": 1,
|
49 |
+
"Aquarius": 0,
|
50 |
+
"Pisces": 2,
|
51 |
+
}
|
52 |
+
|
53 |
+
# Pruning sign coefficients (applicable to all plants)
|
54 |
+
PRUNING_SIGN_COEFFS = {
|
55 |
+
"Aries": 1,
|
56 |
+
"Taurus": 0,
|
57 |
+
"Gemini": 2,
|
58 |
+
"Cancer": 0,
|
59 |
+
"Leo": 1,
|
60 |
+
"Virgo": 2,
|
61 |
+
"Libra": 1.5,
|
62 |
+
"Scorpio": 0.5,
|
63 |
+
"Sagittarius": 1,
|
64 |
+
"Capricorn": 1,
|
65 |
+
"Aquarius": 2,
|
66 |
+
"Pisces": 0,
|
67 |
+
}
|
68 |
+
|
69 |
+
# Fertility phase coefficients for above-ground plants
|
70 |
+
FERTILITY_PHASE_COEFFS_ABOVE = {
|
71 |
+
"New Moon": 0,
|
72 |
+
"Waxing Moon": 1,
|
73 |
+
"Full Moon": 0,
|
74 |
+
"Waning Moon": 0.5,
|
75 |
+
}
|
76 |
+
|
77 |
+
# Fertility phase coefficients for root crops
|
78 |
+
FERTILITY_PHASE_COEFFS_ROOT = {
|
79 |
+
"New Moon": 0,
|
80 |
+
"Waxing Moon": 0.5,
|
81 |
+
"Full Moon": 0,
|
82 |
+
"Waning Moon": 1,
|
83 |
+
}
|
84 |
+
|
85 |
+
# Pruning phase coefficients
|
86 |
+
PRUNING_PHASE_COEFFS = {
|
87 |
+
"New Moon": 0,
|
88 |
+
"Waxing Moon": 1,
|
89 |
+
"Full Moon": 0,
|
90 |
+
"Waning Moon": 0.5,
|
91 |
+
}
|
92 |
+
|
93 |
@tool
|
94 |
def get_moon_info(date_time: str) -> dict:
|
95 |
"""
|
96 |
+
Returns Moon's Zodiac position, phase, and fertility and pruning indices for the given date/time.
|
97 |
|
98 |
Args:
|
99 |
date_time (str): ISO 8601 formatted datetime (YYYY-MM-DDTHH:MM:SS)
|
100 |
|
101 |
Returns:
|
102 |
+
dict: {
|
103 |
+
"zodiac_position": "Leo 15°30'",
|
104 |
+
"moon_phase": "Waxing Gibbous",
|
105 |
+
"fertility_above_ground": 2.0,
|
106 |
+
"fertility_root_crop": 1.5,
|
107 |
+
"pruning": 2.0
|
108 |
+
}
|
109 |
"""
|
110 |
try:
|
111 |
+
# Parse input datetime and localize to UTC
|
112 |
user_time = datetime.datetime.strptime(date_time, "%Y-%m-%dT%H:%M:%S")
|
113 |
user_time = pytz.utc.localize(user_time)
|
114 |
|
115 |
+
# Load ephemeris and timescale
|
116 |
planets = load('de421.bsp')
|
117 |
ts = load.timescale()
|
118 |
t = ts.from_datetime(user_time)
|
119 |
|
120 |
+
# Define celestial bodies
|
121 |
earth = planets['earth']
|
122 |
moon = planets['moon']
|
123 |
sun = planets['sun']
|
124 |
|
125 |
+
# Calculate Moon's ecliptic longitude
|
126 |
astrometric = earth.at(t).observe(moon)
|
127 |
_, _, ecliptic_lon = astrometric.ecliptic_latlon()
|
128 |
lon_deg = ecliptic_lon.degrees % 360
|
129 |
|
130 |
+
# Calculate phase angle (angle between Moon and Sun from Earth)
|
131 |
phase_angle = earth.at(t).observe(moon).apparent().phase_angle(sun).degrees
|
132 |
|
133 |
# Determine Zodiac sign and position
|
|
|
139 |
position_degrees = lon_deg - start
|
140 |
break
|
141 |
|
142 |
+
# Format position to degrees and minutes
|
143 |
degrees = int(position_degrees)
|
144 |
minutes = int((position_degrees % 1) * 60)
|
145 |
position_str = f"{zodiac_sign} {degrees}°{minutes:02}'"
|
146 |
|
147 |
+
# Determine moon phase for display
|
148 |
moon_phase = "Unknown"
|
149 |
for phase, start, end in MOON_PHASES:
|
150 |
if start <= phase_angle < end:
|
151 |
moon_phase = phase
|
152 |
break
|
153 |
|
154 |
+
# Determine phase category for indices with 15° orbis for New and Full Moon
|
155 |
+
if (phase_angle >= 345 or phase_angle < 15):
|
156 |
+
phase_category = "New Moon" # 345° to 15° (30° total orbis)
|
157 |
+
elif 15 <= phase_angle < 165:
|
158 |
+
phase_category = "Waxing Moon"
|
159 |
+
elif 165 <= phase_angle < 195:
|
160 |
+
phase_category = "Full Moon" # 165° to 195° (30° total orbis)
|
161 |
+
elif 195 <= phase_angle < 345:
|
162 |
+
phase_category = "Waning Moon"
|
163 |
+
else:
|
164 |
+
phase_category = "Unknown"
|
165 |
+
|
166 |
+
# Calculate fertility and pruning indices
|
167 |
+
if zodiac_sign in FERTILITY_SIGN_COEFFS and phase_category in FERTILITY_PHASE_COEFFS_ABOVE:
|
168 |
+
fertility_above_ground = FERTILITY_SIGN_COEFFS[zodiac_sign] + FERTILITY_PHASE_COEFFS_ABOVE[phase_category]
|
169 |
+
fertility_root_crop = FERTILITY_SIGN_COEFFS[zodiac_sign] + FERTILITY_PHASE_COEFFS_ROOT[phase_category]
|
170 |
+
pruning = PRUNING_SIGN_COEFFS[zodiac_sign] + PRUNING_PHASE_COEFFS[phase_category]
|
171 |
+
else:
|
172 |
+
fertility_above_ground = None
|
173 |
+
fertility_root_crop = None
|
174 |
+
pruning = None
|
175 |
+
|
176 |
return {
|
177 |
"zodiac_position": position_str,
|
178 |
+
"moon_phase": moon_phase,
|
179 |
+
"fertility_above_ground": fertility_above_ground,
|
180 |
+
"fertility_root_crop": fertility_root_crop,
|
181 |
+
"pruning": pruning
|
182 |
}
|
183 |
|
184 |
except Exception as e:
|