The foundation of the Professional Astrology Consultant is its ability to calculate precise birth charts, determine planetary positions, and analyze astrological aspects for comprehensive personality and life guidance:
import ephem
import google.generativeai as genai
import datetime
from typing import Dict, List, Tuple
import math
class AstrologyCalculator:
"""
Professional astrology calculation engine that computes birth charts,
planetary positions, and astrological aspects for comprehensive readings.
"""
def __init__(self, api_key: str):
genai.configure(api_key=api_key)
self.astro_ai = genai.GenerativeModel('gemini-pro')
self.zodiac_signs = {
'Aries': {'element': 'Fire', 'quality': 'Cardinal', 'ruler': 'Mars', 'degree_range': (0, 30)},
'Taurus': {'element': 'Earth', 'quality': 'Fixed', 'ruler': 'Venus', 'degree_range': (30, 60)},
'Gemini': {'element': 'Air', 'quality': 'Mutable', 'ruler': 'Mercury', 'degree_range': (60, 90)},
'Cancer': {'element': 'Water', 'quality': 'Cardinal', 'ruler': 'Moon', 'degree_range': (90, 120)},
'Leo': {'element': 'Fire', 'quality': 'Fixed', 'ruler': 'Sun', 'degree_range': (120, 150)},
'Virgo': {'element': 'Earth', 'quality': 'Mutable', 'ruler': 'Mercury', 'degree_range': (150, 180)}
}
self.houses = {
1: {'name': 'Self & Identity', 'keywords': ['personality', 'appearance', 'first impressions']},
2: {'name': 'Money & Values', 'keywords': ['finances', 'possessions', 'self-worth']},
3: {'name': 'Communication', 'keywords': ['siblings', 'short trips', 'learning']},
4: {'name': 'Home & Family', 'keywords': ['roots', 'mother', 'real estate']},
5: {'name': 'Creativity & Romance', 'keywords': ['children', 'art', 'pleasure']},
7: {'name': 'Partnerships', 'keywords': ['marriage', 'business partners', 'open enemies']},
10: {'name': 'Career & Reputation', 'keywords': ['profession', 'public image', 'father']}
}
self.aspects = {
'conjunction': {'degrees': 0, 'orb': 8, 'nature': 'neutral', 'strength': 'major'},
'opposition': {'degrees': 180, 'orb': 8, 'nature': 'challenging', 'strength': 'major'},
'trine': {'degrees': 120, 'orb': 8, 'nature': 'harmonious', 'strength': 'major'},
'square': {'degrees': 90, 'orb': 8, 'nature': 'challenging', 'strength': 'major'},
'sextile': {'degrees': 60, 'orb': 6, 'nature': 'harmonious', 'strength': 'minor'}
}
def calculate_birth_chart(self, birth_date: datetime.datetime,
birth_time: datetime.time,
birth_location: Tuple[float, float]) -> Dict:
"""
Calculate complete birth chart with planetary positions and house cusps.
Args:
birth_date: Date of birth
birth_time: Exact time of birth
birth_location: (latitude, longitude) of birth location
Returns:
Dictionary containing complete astrological chart data
"""
birth_datetime = datetime.datetime.combine(birth_date, birth_time)
planetary_positions = self._calculate_planetary_positions(birth_datetime)
house_cusps = self._calculate_house_cusps(birth_datetime, birth_location)
zodiac_placements = self._determine_zodiac_placements(planetary_positions)
aspects = self._calculate_planetary_aspects(planetary_positions)
planet_house_positions = self._calculate_planet_houses(
planetary_positions, house_cusps
)
chart_analysis = await self._generate_chart_analysis(
zodiac_placements, aspects, planet_house_positions
)
return {
'birth_info': {
'date_time': birth_datetime.isoformat(),
'location': birth_location
},
'planetary_positions': planetary_positions,
'zodiac_placements': zodiac_placements,
'house_cusps': house_cusps,
'planet_houses': planet_house_positions,
'aspects': aspects,
'chart_analysis': chart_analysis,
'chart_summary': self._generate_chart_summary(zodiac_placements, aspects)
}
def _calculate_planetary_positions(self, birth_datetime: datetime.datetime) -> Dict:
"""
Calculate precise astronomical positions of planets at birth time.
Uses PyEphem for accurate celestial mechanics calculations.
"""
observer = ephem.Observer()
observer.date = birth_datetime
planetary_positions = {}
planets = {
'Sun': ephem.Sun(),
'Moon': ephem.Moon(),
'Mercury': ephem.Mercury(),
'Venus': ephem.Venus(),
'Mars': ephem.Mars(),
'Jupiter': ephem.Jupiter(),
'Saturn': ephem.Saturn(),
'Uranus': ephem.Uranus(),
'Neptune': ephem.Neptune(),
'Pluto': ephem.Pluto()
}
for planet_name, planet_obj in planets.items():
planet_obj.compute(observer)
ecliptic_longitude = math.degrees(planet_obj.hlong)
planetary_positions[planet_name] = {
'longitude': ecliptic_longitude,
'latitude': math.degrees(planet_obj.hlat),
'distance': planet_obj.earth_distance,
'speed': self._calculate_planetary_speed(planet_obj, observer),
'retrograde': self._is_retrograde(planet_obj, observer)
}
return planetary_positions
def _determine_zodiac_placements(self, planetary_positions: Dict) -> Dict:
"""
Determine which zodiac sign each planet occupies and calculate degrees.
Provides detailed placement information for astrological interpretation.
"""
zodiac_placements = {}
for planet, position_data in planetary_positions.items():
longitude = position_data['longitude']
normalized_longitude = longitude % 360
sign_index = int(normalized_longitude // 30)
degree_in_sign = normalized_longitude % 30
zodiac_sign_names = list(self.zodiac_signs.keys())
sign_name = zodiac_sign_names[sign_index]
zodiac_placements[planet] = {
'sign': sign_name,
'degree': degree_in_sign,
'element': self.zodiac_signs[sign_name]['element'],
'quality': self.zodiac_signs[sign_name]['quality'],
'ruling_planet': self.zodiac_signs[sign_name]['ruler'],
'retrograde': position_data['retrograde'],
'placement_strength': self._calculate_placement_strength(planet, sign_name)
}
return zodiac_placements
def _calculate_planetary_aspects(self, planetary_positions: Dict) -> List[Dict]:
"""
Calculate major and minor aspects between planets in the birth chart.
Identifies harmonious and challenging planetary relationships.
"""
aspects = []
planet_names = list(planetary_positions.keys())
for i in range(len(planet_names)):
for j in range(i + 1, len(planet_names)):
planet1 = planet_names[i]
planet2 = planet_names[j]
lon1 = planetary_positions[planet1]['longitude'] % 360
lon2 = planetary_positions[planet2]['longitude'] % 360
separation = abs(lon1 - lon2)
if separation > 180:
separation = 360 - separation
for aspect_name, aspect_data in self.aspects.items():
target_angle = aspect_data['degrees']
orb = aspect_data['orb']
if abs(separation - target_angle) <= orb:
aspects.append({
'planet1': planet1,
'planet2': planet2,
'aspect': aspect_name,
'exact_angle': separation,
'orb_difference': abs(separation - target_angle),
'nature': aspect_data['nature'],
'strength': aspect_data['strength'],
'interpretation': self._interpret_aspect(planet1, planet2, aspect_name)
})
return sorted(aspects, key=lambda x: (x['strength'] == 'major', -x['orb_difference']), reverse=True)