Spaces:
Running
Running
| import gradio as gr | |
| import os | |
| from datetime import datetime | |
| import json | |
| # Import local modules | |
| try: | |
| from voice_agent import AstrologyVoiceAgent | |
| VOICE_AVAILABLE = True | |
| except ImportError: | |
| VOICE_AVAILABLE = False | |
| print("Voice agent not available - install elevenlabs package") | |
| # Initialize with sponsor APIs (will be configured with environment variables) | |
| OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "") | |
| ANTHROPIC_API_KEY = os.getenv("ANTHROPIC_API_KEY", "") | |
| ELEVENLABS_API_KEY = os.getenv("ELEVENLABS_API_KEY", "") | |
| GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY", "") | |
| # Initialize voice agent if available | |
| voice_agent = AstrologyVoiceAgent(agent_type="teaching") if VOICE_AVAILABLE and ELEVENLABS_API_KEY else None | |
| # Essential Dignities Tables | |
| DOMICILE_RULERS = { | |
| "Aries": "Mars", "Taurus": "Venus", "Gemini": "Mercury", | |
| "Cancer": "Moon", "Leo": "Sun", "Virgo": "Mercury", | |
| "Libra": "Venus", "Scorpio": "Mars", "Sagittarius": "Jupiter", | |
| "Capricorn": "Saturn", "Aquarius": "Saturn", "Pisces": "Jupiter" | |
| } | |
| EXALTATIONS = { | |
| "Aries": "Sun", "Taurus": "Moon", "Gemini": None, | |
| "Cancer": "Jupiter", "Leo": None, "Virgo": "Mercury", | |
| "Libra": "Saturn", "Scorpio": None, "Sagittarius": None, | |
| "Capricorn": "Mars", "Aquarius": None, "Pisces": "Venus" | |
| } | |
| # Detriments (opposite sign of domicile rulership) | |
| DETRIMENTS = { | |
| "Sun": ["Aquarius"], | |
| "Moon": ["Capricorn"], | |
| "Mercury": ["Sagittarius", "Pisces"], | |
| "Venus": ["Aries", "Scorpio"], | |
| "Mars": ["Taurus", "Libra"], | |
| "Jupiter": ["Gemini", "Virgo"], | |
| "Saturn": ["Cancer", "Leo"] | |
| } | |
| # Falls (opposite sign of exaltation) | |
| FALLS = { | |
| "Sun": ["Libra"], | |
| "Moon": ["Scorpio"], | |
| "Mercury": ["Pisces"], | |
| "Venus": ["Virgo"], | |
| "Mars": ["Cancer"], | |
| "Jupiter": ["Capricorn"], | |
| "Saturn": ["Aries"] | |
| } | |
| TRIPLICITIES = { | |
| "Fire": {"day": "Sun", "night": "Jupiter", "participating": "Saturn"}, | |
| "Earth": {"day": "Venus", "night": "Moon", "participating": "Mars"}, | |
| "Air": {"day": "Saturn", "night": "Mercury", "participating": "Jupiter"}, | |
| "Water": {"day": "Venus", "night": "Mars", "participating": "Moon"} | |
| } | |
| SIGN_TRIPLICITIES = { | |
| "Aries": "Fire", "Leo": "Fire", "Sagittarius": "Fire", | |
| "Taurus": "Earth", "Virgo": "Earth", "Capricorn": "Earth", | |
| "Gemini": "Air", "Libra": "Air", "Aquarius": "Air", | |
| "Cancer": "Water", "Scorpio": "Water", "Pisces": "Water" | |
| } | |
| # Egyptian Bounds (Terms) | |
| EGYPTIAN_BOUNDS = { | |
| "Aries": [(0, 6, "Jupiter"), (6, 12, "Venus"), (12, 20, "Mercury"), (20, 25, "Mars"), (25, 30, "Saturn")], | |
| "Taurus": [(0, 8, "Venus"), (8, 14, "Mercury"), (14, 22, "Jupiter"), (22, 27, "Saturn"), (27, 30, "Mars")], | |
| "Gemini": [(0, 6, "Mercury"), (6, 12, "Jupiter"), (12, 17, "Venus"), (17, 24, "Mars"), (24, 30, "Saturn")], | |
| "Cancer": [(0, 7, "Mars"), (7, 13, "Venus"), (13, 19, "Mercury"), (19, 26, "Jupiter"), (26, 30, "Saturn")], | |
| "Leo": [(0, 6, "Jupiter"), (6, 11, "Venus"), (11, 18, "Saturn"), (18, 24, "Mercury"), (24, 30, "Mars")], | |
| "Virgo": [(0, 7, "Mercury"), (7, 17, "Venus"), (17, 21, "Jupiter"), (21, 28, "Mars"), (28, 30, "Saturn")], | |
| "Libra": [(0, 6, "Saturn"), (6, 14, "Mercury"), (14, 21, "Jupiter"), (21, 28, "Venus"), (28, 30, "Mars")], | |
| "Scorpio": [(0, 7, "Mars"), (7, 11, "Venus"), (11, 19, "Mercury"), (19, 24, "Jupiter"), (24, 30, "Saturn")], | |
| "Sagittarius": [(0, 12, "Jupiter"), (12, 17, "Venus"), (17, 21, "Mercury"), (21, 26, "Saturn"), (26, 30, "Mars")], | |
| "Capricorn": [(0, 7, "Mercury"), (7, 14, "Jupiter"), (14, 22, "Venus"), (22, 26, "Saturn"), (26, 30, "Mars")], | |
| "Aquarius": [(0, 7, "Mercury"), (7, 13, "Venus"), (13, 20, "Jupiter"), (20, 25, "Mars"), (25, 30, "Saturn")], | |
| "Pisces": [(0, 12, "Venus"), (12, 16, "Jupiter"), (16, 19, "Mercury"), (19, 28, "Mars"), (28, 30, "Saturn")] | |
| } | |
| # Decans (Faces) | |
| DECANS = { | |
| "Aries": [(0, 10, "Mars"), (10, 20, "Sun"), (20, 30, "Venus")], | |
| "Taurus": [(0, 10, "Mercury"), (10, 20, "Moon"), (20, 30, "Saturn")], | |
| "Gemini": [(0, 10, "Jupiter"), (10, 20, "Mars"), (20, 30, "Sun")], | |
| "Cancer": [(0, 10, "Venus"), (10, 20, "Mercury"), (20, 30, "Moon")], | |
| "Leo": [(0, 10, "Saturn"), (10, 20, "Jupiter"), (20, 30, "Mars")], | |
| "Virgo": [(0, 10, "Sun"), (10, 20, "Venus"), (20, 30, "Mercury")], | |
| "Libra": [(0, 10, "Moon"), (10, 20, "Saturn"), (20, 30, "Jupiter")], | |
| "Scorpio": [(0, 10, "Mars"), (10, 20, "Sun"), (20, 30, "Venus")], | |
| "Sagittarius": [(0, 10, "Mercury"), (10, 20, "Moon"), (20, 30, "Saturn")], | |
| "Capricorn": [(0, 10, "Jupiter"), (10, 20, "Mars"), (20, 30, "Sun")], | |
| "Aquarius": [(0, 10, "Venus"), (10, 20, "Mercury"), (20, 30, "Moon")], | |
| "Pisces": [(0, 10, "Saturn"), (10, 20, "Jupiter"), (20, 30, "Mars")] | |
| } | |
| # Zodiacal Releasing | |
| ZODIACAL_RELEASING_ORDER = [ | |
| "Cancer", "Leo", "Virgo", "Libra", "Scorpio", "Sagittarius", | |
| "Capricorn", "Aquarius", "Pisces", "Aries", "Taurus", "Gemini" | |
| ] | |
| SIGN_YEARS = { | |
| "Cancer": 25, "Leo": 19, "Virgo": 20, "Libra": 8, "Scorpio": 15, | |
| "Sagittarius": 12, "Capricorn": 27, "Aquarius": 30, "Pisces": 12, | |
| "Aries": 15, "Taurus": 8, "Gemini": 20 | |
| } | |
| def calculate_profections(birth_year: int, target_year: int) -> str: | |
| """Calculate annual profections from Ascendant""" | |
| age = target_year - birth_year | |
| profected_house = (age % 12) + 1 | |
| house_meanings = { | |
| 1: "Self, body, vitality, life direction", | |
| 2: "Resources, money, possessions, values", | |
| 3: "Siblings, communication, short journeys, learning", | |
| 4: "Home, family, parents, foundations, endings", | |
| 5: "Children, creativity, pleasure, speculation", | |
| 6: "Health, work, service, daily routines, pets", | |
| 7: "Partnership, marriage, open enemies, contracts", | |
| 8: "Death, transformation, shared resources, inheritance", | |
| 9: "Higher learning, travel, philosophy, religion", | |
| 10: "Career, reputation, authority, public life", | |
| 11: "Friends, groups, hopes, wishes, benefactors", | |
| 12: "Hidden matters, spirituality, isolation, undoing" | |
| } | |
| return f"""## Annual Profections | |
| **Birth Year:** {birth_year} | |
| **Target Year:** {target_year} | |
| **Age:** {age} | |
| ### Profected House: {profected_house}th House | |
| **Significations:** {house_meanings[profected_house]} | |
| ### Lord of the Year: | |
| The ruler of your natal {profected_house}th house becomes your "Lord of the Year" for age {age}. | |
| **How to use this:** | |
| 1. Identify which sign is on the cusp of your natal {profected_house}th house | |
| 2. The ruler of that sign is activated for this entire year | |
| 3. Pay attention to: | |
| - Transits to the Lord of the Year | |
| - The condition of the Lord in your natal chart | |
| - Any planets in your natal {profected_house}th house (also activated) | |
| **Technique from:** Vettius Valens (*Anthology*, Book 4) and Paulus Alexandrinus | |
| ### How Profections Work: | |
| Each year of life corresponds to one house, counted from the Ascendant: | |
| - Age 0-11 months: 1st house | |
| - Age 1: 2nd house | |
| - Age 12: Returns to 1st house (first profection return) | |
| - Age {age}: {profected_house}th house | |
| Every 12 years, you return to the same house, creating profection return years. | |
| """ | |
| def assess_planetary_dignity(planet: str, sign: str, is_day_chart: bool) -> str: | |
| """Assess a planet's essential dignity in a given sign""" | |
| dignity_score = 0 | |
| dignities = [] | |
| debilities = [] | |
| # Check domicile (+5) | |
| if DOMICILE_RULERS.get(sign) == planet: | |
| dignity_score += 5 | |
| dignities.append("Domicile (+5)") | |
| # Check exaltation (+4) | |
| if EXALTATIONS.get(sign) == planet: | |
| dignity_score += 4 | |
| dignities.append("Exaltation (+4)") | |
| # Check triplicity (+3) | |
| triplicity = SIGN_TRIPLICITIES.get(sign) | |
| if triplicity: | |
| triplicity_rulers = TRIPLICITIES[triplicity] | |
| if is_day_chart and triplicity_rulers["day"] == planet: | |
| dignity_score += 3 | |
| dignities.append("Triplicity Ruler - Day (+3)") | |
| elif not is_day_chart and triplicity_rulers["night"] == planet: | |
| dignity_score += 3 | |
| dignities.append("Triplicity Ruler - Night (+3)") | |
| elif triplicity_rulers["participating"] == planet: | |
| dignity_score += 3 | |
| dignities.append("Triplicity Ruler - Participating (+3)") | |
| # Check detriment (-5) | |
| if sign in DETRIMENTS.get(planet, []): | |
| dignity_score -= 5 | |
| debilities.append("Detriment (-5)") | |
| # Check fall (-4) | |
| if sign in FALLS.get(planet, []): | |
| dignity_score -= 4 | |
| debilities.append("Fall (-4)") | |
| # Determine condition based on score | |
| if dignity_score <= -4: | |
| condition = "Debilitated" | |
| elif dignity_score < 0: | |
| condition = "Weak" | |
| elif dignity_score == 0: | |
| condition = "Peregrine (no essential dignity)" | |
| elif dignity_score <= 3: | |
| condition = "Minor Dignity" | |
| else: | |
| condition = "Strong" | |
| chart_type = "Day Chart" if is_day_chart else "Night Chart" | |
| # Format as readable text | |
| result = f"""## Essential Dignity Analysis | |
| **Planet:** {planet} | |
| **Sign:** {sign} | |
| **Chart Type:** {chart_type} | |
| ### Dignity Assessment: | |
| """ | |
| if dignities: | |
| for dignity in dignities: | |
| result += f"β {dignity}\n" | |
| else: | |
| result += "β No major dignities\n" | |
| if debilities: | |
| result += "\n### Debilities:\n" | |
| for debility in debilities: | |
| result += f"β {debility}\n" | |
| result += f""" | |
| **Total Dignity Score:** {dignity_score} points | |
| **Planetary Condition:** {condition} | |
| ### Interpretation: | |
| """ | |
| if dignity_score <= -5: | |
| result += f"{planet} is severely debilitated in {sign}, being in detriment. The planet struggles to express its nature and may act contrary to its essential significations." | |
| elif dignity_score == -4: | |
| result += f"{planet} is in fall in {sign}, a position of weakness. The planet cannot act with full strength and may produce difficult outcomes." | |
| elif dignity_score < 0: | |
| result += f"{planet} is weakened in {sign} with mixed conditions. The debilities outweigh any minor dignities present." | |
| elif dignity_score == 0: | |
| result += f"{planet} is peregrine in {sign}, having no essential dignity. The planet is like a stranger in a foreign land, neither particularly strong nor weak, but without support." | |
| elif dignity_score <= 3: | |
| result += f"{planet} has minor dignity in {sign}. The planet has some support but is not at full strength." | |
| elif dignity_score >= 5: | |
| result += f"{planet} is very well-placed in {sign}, having its domicile or maximum dignity. The planet can act with full strength and autonomy." | |
| else: | |
| result += f"{planet} is strong in {sign}, with significant essential dignity. The planet functions well and can express its significations effectively." | |
| return result | |
| def calculate_lots(asc_degree: float, sun_degree: float, moon_degree: float, is_day_chart: bool) -> str: | |
| """Calculate traditional Hellenistic lots (Fortuna and Spirit)""" | |
| if is_day_chart: | |
| # Lot of Fortune (day): Asc + Moon - Sun | |
| fortune = (asc_degree + moon_degree - sun_degree) % 360 | |
| else: | |
| # Lot of Fortune (night): Asc + Sun - Moon | |
| fortune = (asc_degree + sun_degree - moon_degree) % 360 | |
| if is_day_chart: | |
| # Lot of Spirit (day): Asc + Sun - Moon | |
| spirit = (asc_degree + sun_degree - moon_degree) % 360 | |
| else: | |
| # Lot of Spirit (night): Asc + Moon - Sun | |
| spirit = (asc_degree + moon_degree - sun_degree) % 360 | |
| # Convert to sign and degree | |
| def deg_to_sign(deg): | |
| signs = ["Aries", "Taurus", "Gemini", "Cancer", "Leo", "Virgo", | |
| "Libra", "Scorpio", "Sagittarius", "Capricorn", "Aquarius", "Pisces"] | |
| sign_num = int(deg // 30) | |
| sign_deg = deg % 30 | |
| return signs[sign_num], round(sign_deg, 2) | |
| chart_type = "Day Chart" if is_day_chart else "Night Chart" | |
| fortune_sign, fortune_deg = deg_to_sign(fortune) | |
| spirit_sign, spirit_deg = deg_to_sign(spirit) | |
| formula_fortune = "Asc + Moon - Sun" if is_day_chart else "Asc + Sun - Moon" | |
| formula_spirit = "Asc + Sun - Moon" if is_day_chart else "Asc + Moon - Sun" | |
| result = f"""## Traditional Hellenistic Lots | |
| **Chart Type:** {chart_type} | |
| ### Lot of Fortune (Fortuna) | |
| **Position:** {fortune_deg}Β° {fortune_sign} ({round(fortune, 2)}Β° absolute) | |
| **Formula ({chart_type}):** {formula_fortune} | |
| **Signifies:** Material fortune, body, health, general life circumstances | |
| ### Lot of Spirit | |
| **Position:** {spirit_deg}Β° {spirit_sign} ({round(spirit, 2)}Β° absolute) | |
| **Formula ({chart_type}):** {formula_spirit} | |
| **Signifies:** Spirit, reputation, career, action in the world | |
| ### Notes: | |
| - Lot formulas reverse for day vs night charts (sect consideration) | |
| - In {chart_type.lower()}, Fortune = {formula_fortune} | |
| - Fortune is used for Zodiacal Releasing of general life topics | |
| - Spirit is used for Zodiacal Releasing of career and reputation | |
| """ | |
| return result | |
| def get_bound_ruler(sign: str, degree: float) -> str: | |
| """Get the Egyptian bound (term) ruler for a planet's position""" | |
| if sign not in EGYPTIAN_BOUNDS: | |
| return f"β Error: Invalid sign '{sign}'" | |
| bounds = EGYPTIAN_BOUNDS[sign] | |
| for start, end, ruler in bounds: | |
| if start <= degree < end: | |
| return f"""## Egyptian Bounds (Terms) | |
| **Position:** {degree}Β° {sign} | |
| ### Bound Ruler: {ruler} | |
| **Range:** {start}Β°-{end}Β° of {sign} | |
| **Dignity Points:** +2 | |
| ### All Bounds in {sign}: | |
| """+ "\n".join([f"- {s}Β°-{e}Β°: {r}" for s, e, r in bounds]) + f""" | |
| ### Significance: | |
| The Egyptian bounds divide each sign into 5 unequal sections, each ruled by a different planet. A planet in its own bound gains +2 dignity points. Bounds are used in time-lord techniques and provide refined dignity assessment. | |
| """ | |
| return f"β Error: Degree {degree} is out of range (must be 0-30)" | |
| def get_decan_ruler(sign: str, degree: float) -> str: | |
| """Get the decan (face) ruler for a planet's position""" | |
| if sign not in DECANS: | |
| return f"β Error: Invalid sign '{sign}'" | |
| decans = DECANS[sign] | |
| for start, end, ruler in decans: | |
| if start <= degree < end: | |
| decan_num = (start // 10) + 1 | |
| return f"""## Decans (Faces) | |
| **Position:** {degree}Β° {sign} | |
| ### Decan Ruler: {ruler} | |
| **Decan:** {decan_num} of 3 ({start}Β°-{end}Β°) | |
| **Dignity Points:** +1 | |
| ### All Decans in {sign}: | |
| - 1st Decan (0Β°-10Β°): {decans[0][2]} | |
| - 2nd Decan (10Β°-20Β°): {decans[1][2]} | |
| - 3rd Decan (20Β°-30Β°): {decans[2][2]} | |
| ### Significance: | |
| Decans (also called "faces") divide each sign into three equal 10Β° sections. Each decan is ruled by a planet following the Chaldean order. A planet in its own decan gains +1 dignity point. | |
| """ | |
| return f"β Error: Degree {degree} is out of range (must be 0-30)" | |
| def calculate_zodiacal_releasing(starting_sign: str, birth_year: int, target_year: int = None) -> str: | |
| """Calculate Zodiacal Releasing periods (simplified version)""" | |
| if starting_sign not in ZODIACAL_RELEASING_ORDER: | |
| return f"β Error: Invalid starting sign '{starting_sign}'" | |
| if target_year is None: | |
| target_year = datetime.now().year | |
| age = target_year - birth_year | |
| current_index = ZODIACAL_RELEASING_ORDER.index(starting_sign) | |
| accumulated_years = 0 | |
| result = f"""## Zodiacal Releasing (Loosing of the Bond) | |
| **Starting Sign:** {starting_sign} (from Lot of Fortune or Spirit) | |
| **Birth Year:** {birth_year} | |
| **Current Year:** {target_year} | |
| **Current Age:** {age} | |
| ### Major Periods: | |
| """ | |
| # Calculate first 8 periods for display | |
| for i in range(8): | |
| sign = ZODIACAL_RELEASING_ORDER[(current_index + i) % 12] | |
| period_years = SIGN_YEARS[sign] | |
| start_age = int(accumulated_years) | |
| end_age = int(accumulated_years + period_years) | |
| is_current = start_age <= age < end_age | |
| marker = " β **CURRENT PERIOD**" if is_current else "" | |
| result += f"{i+1}. **{sign}** - Ages {start_age}-{end_age} ({period_years} years){marker}\n" | |
| accumulated_years += period_years | |
| result += f""" | |
| ### About Zodiacal Releasing: | |
| From Vettius Valens' *Anthology*, this sophisticated timing technique uses a fixed planetary order through the zodiac signs. Each sign grants a specific number of years: | |
| **Sign Years:** | |
| - Cancer: 25 | Leo: 19 | Virgo: 20 | Libra: 8 | |
| - Scorpio: 15 | Sagittarius: 12 | Capricorn: 27 | Aquarius: 30 | |
| - Pisces: 12 | Aries: 15 | Taurus: 8 | Gemini: 20 | |
| This is a simplified view showing major periods. Full ZR includes minor and sub-minor divisions for precise timing. | |
| """ | |
| return result | |
| def research_hellenistic_topic(query: str) -> str: | |
| """Research assistant for Hellenistic astrology topics""" | |
| topics = { | |
| "sect": """Sect Theory (Hairesis) | |
| According to Vettius Valens (Anthology, Book III), sect distinguishes between day and night charts: | |
| **Day Chart (Diurnal)**: Sun above horizon at birth | |
| - Benefics: Jupiter, Saturn (traditionally) | |
| - Malefics: Mars more difficult than Saturn | |
| - Solar sect planets: Sun, Jupiter, Saturn | |
| **Night Chart (Nocturnal)**: Sun below horizon at birth | |
| - Benefics: Venus, Moon | |
| - Malefics: Saturn more difficult than Mars | |
| - Lunar sect planets: Moon, Venus, Mars | |
| **Practical Application**: | |
| Ptolemy (Tetrabiblos, Book III) emphasizes that planets in their proper sect are strengthened, while planets contrary to sect are weakened. A day chart with Jupiter angular is far more favorable than Saturn in the same position. | |
| **Source Differences**: | |
| - Valens: More emphasis on sect in time-lord systems | |
| - Ptolemy: More theoretical, applies to natal interpretation | |
| - Dorotheus: Less explicit about sect distinctions | |
| """, | |
| "profections": """Annual Profections (Epembasis) | |
| The technique advances one house per year of life from the Ascendant. | |
| **Method** (from Valens, Anthology Book IV): | |
| 1. Count age in complete years | |
| 2. Each year = one house from Ascendant | |
| 3. The profected house's ruler becomes the "Lord of the Year" | |
| **Example**: | |
| - Age 0-11 months: 1st house | |
| - Age 1: 2nd house | |
| - Age 12: Returns to 1st house (first return) | |
| - Age 25: 2nd house (third time) | |
| **Application**: | |
| The Lord of the Year is activated. Transits to that planet are significant. The house profected to shows the area of life emphasis. | |
| **Paulus Alexandrinus** adds that planets in the profected house are also activated that year. | |
| """, | |
| "bounds": """Egyptian Bounds (Terms) | |
| Each sign is divided into five unequal sections, each ruled by a planet. | |
| **Ptolemy vs Egyptian System**: | |
| Ptolemy (Tetrabiblos I.21) presents his own system, but most practitioners use the older Egyptian bounds found in Valens. | |
| **Significance** (per Valens): | |
| - Bounds = +2 dignity points | |
| - Show more refined planet influence within a sign | |
| - Used in time-lord distributions | |
| **Example - Aries** (Egyptian): | |
| - 0-6Β°: Jupiter | |
| - 6-12Β°: Venus | |
| - 12-20Β°: Mercury | |
| - 20-25Β°: Mars | |
| - 25-30Β°: Saturn | |
| """, | |
| "zodiacal releasing": """Zodiacal Releasing (Aphesis) | |
| From Vettius Valens (Anthology, Book IV), this is the most sophisticated Hellenistic time-lord technique. | |
| **Basic Method**: | |
| 1. Start from Spirit (day) or Fortune (night) lot | |
| 2. Each sign has a planetary ruler and period length | |
| 3. Periods subdivide into smaller periods | |
| 4. Loosing of the bond = major life transitions | |
| **Period Lengths** (years per sign): | |
| - Aries/Scorpio (Mars): 15 years | |
| - Taurus/Libra (Venus): 8 years | |
| - Gemini/Virgo (Mercury): 20 years | |
| - Cancer (Moon): 25 years | |
| - Leo (Sun): 19 years | |
| - Sagittarius/Pisces (Jupiter): 12 years | |
| - Capricorn/Aquarius (Saturn): 30 years | |
| **Peak Periods**: | |
| When the releasing reaches the natal position of the Lot, or angular houses (1st, 10th, 7th, 4th). | |
| **Valens' Example**: | |
| In Anthology IV, Valens demonstrates using ZR to time major career events, marriages, and deaths. The technique requires understanding both general and specific periods. | |
| **Modern Application**: | |
| Chris Brennan's work has revived this technique. Look for "loosing of the bond" (when releasing completes a full cycle) as major turning points. | |
| """ | |
| } | |
| # Simple keyword matching | |
| query_lower = query.lower() | |
| for keyword, content in topics.items(): | |
| if keyword in query_lower: | |
| return content | |
| # If no match, try using Gemini API | |
| if GOOGLE_API_KEY: | |
| try: | |
| import google.generativeai as genai | |
| genai.configure(api_key=GOOGLE_API_KEY) | |
| model = genai.GenerativeModel('gemini-2.5-flash') | |
| # Create a specialized prompt for Hellenistic astrology | |
| prompt = f"""You are an expert in Hellenistic astrology (1st-7th century CE). | |
| Answer this question with references to classical sources when possible: | |
| Question: {query} | |
| Please include citations from: | |
| - Vettius Valens (Anthology) | |
| - Claudius Ptolemy (Tetrabiblos) | |
| - Dorotheus of Sidon (Carmen Astrologicum) | |
| - Paulus Alexandrinus | |
| - Or other relevant ancient sources | |
| Provide a clear, educational response suitable for students of traditional astrology.""" | |
| response = model.generate_content(prompt) | |
| return f"""## {query} | |
| {response.text} | |
| --- | |
| *Response generated by Google Gemini AI with classical astrology context* | |
| """ | |
| except ImportError: | |
| pass # Fall through to fallback | |
| except Exception as e: | |
| return f"""## Error using AI research | |
| {str(e)} | |
| Please check your GOOGLE_API_KEY environment variable. | |
| **Fallback**: Try asking about "sect", "profections", "bounds", or "zodiacal releasing" for built-in content. | |
| """ | |
| # Fallback if no API key or error | |
| return f"""## Research Query: "{query}" | |
| **Available built-in topics** (instant responses): | |
| - "sect" or "sect theory" | |
| - "profections" or "annual profections" | |
| - "bounds" or "egyptian bounds" | |
| - "zodiacal releasing" | |
| **For other topics**, please set the GOOGLE_API_KEY environment variable to enable AI-powered research through ancient texts. | |
| **To set up**: | |
| 1. Get a free API key from: https://ai.google.dev/ | |
| 2. Add to HuggingFace Space secrets: `GOOGLE_API_KEY=your_key_here` | |
| 3. Restart the Space | |
| **Classical Sources Available via AI**: | |
| - Vettius Valens (Anthology) | |
| - Ptolemy (Tetrabiblos) | |
| - Dorotheus (Carmen Astrologicum) | |
| - Paulus Alexandrinus | |
| - Modern synthesizers: Chris Brennan, Demetra George, Robert Schmidt | |
| """ | |
| # Gradio Interface | |
| def create_demo(): | |
| with gr.Blocks( | |
| theme=gr.themes.Soft(primary_hue="purple", secondary_hue="blue"), | |
| title="HERMES - Hellenistic Astrology Research Assistant", | |
| css=""" | |
| .purple-banner { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| padding: 2rem; | |
| border-radius: 10px; | |
| color: white; | |
| text-align: center; | |
| margin-bottom: 2rem; | |
| box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
| } | |
| .purple-banner h1 { | |
| margin: 0 0 0.5rem 0; | |
| font-size: 2.5rem; | |
| font-weight: 700; | |
| } | |
| .purple-banner p { | |
| margin: 0; | |
| font-size: 1.2rem; | |
| opacity: 0.95; | |
| } | |
| .banner-badges { | |
| margin-top: 1rem; | |
| display: flex; | |
| gap: 1rem; | |
| justify-content: center; | |
| flex-wrap: wrap; | |
| } | |
| .banner-badge { | |
| background: rgba(255, 255, 255, 0.2); | |
| padding: 0.5rem 1rem; | |
| border-radius: 20px; | |
| font-size: 0.9rem; | |
| backdrop-filter: blur(10px); | |
| } | |
| """ | |
| ) as demo: | |
| gr.HTML(""" | |
| <div class="purple-banner"> | |
| <h1>ποΈ HERMES - Hellenistic Ephemeris Research & MCP Educational System</h1> | |
| <p>Ancient Wisdom Meets Modern AI Through the Model Context Protocol</p> | |
| <div class="banner-badges"> | |
| <span class="banner-badge">π 4 MCP Servers Integrated</span> | |
| <span class="banner-badge">π MCP Birthday Hackathon</span> | |
| <span class="banner-badge">π 2000+ Years of Wisdom</span> | |
| <span class="banner-badge">β¨ 10,000+ Students</span> | |
| </div> | |
| </div> | |
| """) | |
| gr.Markdown(""" | |
| ## β¨ What is HERMES? | |
| An interactive research and teaching tool for traditional Hellenistic astrology, combining 2000-year-old techniques | |
| from ancient Greek and Roman astrologers with modern AI agents and the Model Context Protocol (MCP). | |
| ## β¨ What You Can Do Here: | |
| ### π Chart Calculations | |
| - **Essential Dignities** - Assess planetary strength through domicile, exaltation, and triplicity | |
| - **Traditional Lots** - Calculate the Lots of Fortune and Spirit with proper sect consideration | |
| - **Egyptian Bounds** - Determine bound (term) rulers for refined dignity assessment | |
| - **Decans (Faces)** - Find decan rulers following the Chaldean order | |
| ### β±οΈ Time-Lord Techniques | |
| - **Annual Profections** - Discover your Lord of the Year for any age | |
| - **Zodiacal Releasing** - Explore major life periods from Vettius Valens' system | |
| ### π Learn Traditional Astrology | |
| - **Text-Based Teaching** - AI-powered explanations of Hellenistic techniques | |
| - **Source Research** - Educational content citing ancient texts | |
| - **Study Resources** - Curated books, courses, and free learning materials | |
| ### π External Integrations | |
| - **Modal Serverless** - 6 MCP functions deployed for calculations | |
| - **Astro.com MCP** - Classical Hellenistic chart generation | |
| - **Local Fallback** - All calculations available offline | |
| ### ποΈ Built on Ancient Foundations | |
| All techniques are drawn from authentic Hellenistic sources (1st-7th century CE), | |
| not modern psychological astrology. We preserve the traditional methods exactly as | |
| taught by Valens, Ptolemy, and Dorotheus. | |
| --- | |
| **Built for the MCP 1st Birthday Hackathon** | Powered by OpenAI, Anthropic, ElevenLabs & Modal | |
| """) | |
| with gr.Tab("π MCP Integrations"): | |
| gr.Markdown(""" | |
| # π Model Context Protocol (MCP) Integration Showcase | |
| HERMES demonstrates the power of MCP by integrating **4 different calculation backends**: | |
| 1. π **Local MCP** - Core features running locally | |
| 2. βοΈ **Modal Serverless** - Cloud-deployed time-lord calculations | |
| 3. π **Astro.com** - Classical Hellenistic chart generation | |
| 4. π€ **Google Gemini AI** - Natural language astrology conversations | |
| ### Why MCP Matters for HERMES | |
| The Model Context Protocol allows HERMES to: | |
| - **Scale**: Offload heavy calculations to cloud (Modal) | |
| - **Integrate**: Connect to third-party services (Astro.com) | |
| - **Converse**: Use AI for educational explanations (Gemini) | |
| - **Fallback**: Gracefully degrade when services unavailable | |
| - **Extend**: Easy to add new calculation sources | |
| """) | |
| gr.Markdown("---") | |
| # MCP Server 1: Local HERMES | |
| with gr.Accordion("π Local HERMES MCP Server", open=True): | |
| gr.Markdown(""" | |
| ### Local MCP Server | |
| Runs **directly on your machine** with instant responses. | |
| **Features:** | |
| - Essential Dignities (5-level system) | |
| - Annual Profections | |
| - Lot of Fortune calculations | |
| - Educational explanations | |
| **Status**: β Always Available (no internet required) | |
| """) | |
| with gr.Row(): | |
| with gr.Column(): | |
| gr.Markdown("#### Test Essential Dignity") | |
| local_planet = gr.Dropdown( | |
| choices=["Sun", "Moon", "Mercury", "Venus", "Mars", "Jupiter", "Saturn"], | |
| label="Planet", | |
| value="Venus" | |
| ) | |
| local_sign = gr.Dropdown( | |
| choices=["Aries", "Taurus", "Gemini", "Cancer", "Leo", "Virgo", | |
| "Libra", "Scorpio", "Sagittarius", "Capricorn", "Aquarius", "Pisces"], | |
| label="Sign", | |
| value="Aries" | |
| ) | |
| local_degree = gr.Number(label="Degree (0-30)", value=8.5, precision=1) | |
| local_is_day = gr.Checkbox(label="Day Chart", value=True) | |
| local_dignity_btn = gr.Button("π Calculate via Local MCP", variant="primary") | |
| with gr.Column(): | |
| local_output = gr.Textbox( | |
| label="Local MCP Result", | |
| lines=15, | |
| show_copy_button=True | |
| ) | |
| def test_local_mcp(planet, sign, degree, is_day): | |
| """Test local MCP server""" | |
| try: | |
| from hermes_local_mcp import HermesLocalMCP | |
| server = HermesLocalMCP() | |
| result = server.calculate_essential_dignity(planet, sign, degree, is_day) | |
| output = f"""## β Local MCP Response | |
| **Server**: {result.get('source', 'Local MCP')} | |
| **Planet**: {result['planet']} at {result['degree']}Β° {result['sign']} | |
| **Chart Type**: {result['chart_type']} | |
| ### Dignity Assessment: | |
| **Score**: {result['dignity_score']} points | |
| **Condition**: {result['condition']} | |
| ### Dignities: | |
| {chr(10).join(f'β {d}' for d in result['dignities']) if result['dignities'] else 'β No major dignities'} | |
| ### Debilities: | |
| {chr(10).join(f'β {d}' for d in result['debilities']) if result['debilities'] else 'β No debilities'} | |
| ### Interpretation: | |
| {result['interpretation']} | |
| --- | |
| *Via: Local HERMES MCP Server (instant response, no internet required)* | |
| """ | |
| return output | |
| except Exception as e: | |
| return f"β Error: {str(e)}" | |
| local_dignity_btn.click( | |
| fn=test_local_mcp, | |
| inputs=[local_planet, local_sign, local_degree, local_is_day], | |
| outputs=local_output | |
| ) | |
| gr.Markdown("---") | |
| # MCP Server 2: Modal Serverless | |
| with gr.Accordion("βοΈ Modal Serverless MCP", open=False): | |
| gr.Markdown(""" | |
| ### Modal Serverless MCP | |
| **Cloud-deployed** calculation functions on Modal infrastructure. | |
| **Features:** | |
| - Zodiacal Releasing | |
| - Firdaria | |
| - Bounds & Decans | |
| - Essential Dignities (cloud version) | |
| - Fixed Stars | |
| **Status**: β Deployed at modal.com | |
| **Endpoint**: `modal app list` to view deployment | |
| **Benefits:** | |
| - Zero local compute overhead | |
| - Scales automatically | |
| - Same API as local MCP | |
| - Graceful fallback to local | |
| **Test it:** Use the Time Lords tab - calculations run on Modal! | |
| """) | |
| gr.Code(""" | |
| # Example: Using Modal MCP from Python | |
| from modal import Function | |
| # Call serverless function | |
| result = Function.lookup("hermes-mcp", "calculate_zodiacal_releasing").remote( | |
| birth_date="1990-01-15", | |
| birth_time="12:00" | |
| ) | |
| print(result) # Returns ZR periods from cloud | |
| """, language="python") | |
| gr.Markdown("---") | |
| # MCP Server 3: Astro.com Integration | |
| with gr.Accordion("π Astro.com (AstroDienst) MCP", open=False): | |
| gr.Markdown(""" | |
| ### Astro.com Classical Chart Generator | |
| Generate **classical Hellenistic charts** using Astro.com infrastructure. | |
| **Features:** | |
| - Whole Sign house system | |
| - Traditional aspects | |
| - Chart URL generation | |
| - Hellenistic interpretation guides | |
| **Status**: π‘ Proof-of-concept (URL generation) | |
| """) | |
| with gr.Row(): | |
| with gr.Column(): | |
| gr.Markdown("#### Chart Request") | |
| astro_date = gr.Textbox(label="Birth Date (DD.MM.YYYY)", value="15.01.1990") | |
| astro_time = gr.Textbox(label="Birth Time (HH:MM)", value="12:00") | |
| astro_city = gr.Textbox(label="City", value="New York") | |
| astro_country = gr.Textbox(label="Country", value="USA") | |
| astro_house_system = gr.Dropdown( | |
| choices=[ | |
| ("Whole Sign (Hellenistic)", "W"), | |
| ("Placidus", "P"), | |
| ("Koch", "K"), | |
| ("Equal House", "E") | |
| ], | |
| label="House System", | |
| value="W" | |
| ) | |
| astro_btn = gr.Button("π Generate Chart via Astro.com MCP", variant="primary") | |
| with gr.Column(): | |
| astro_output = gr.Textbox( | |
| label="Astro.com MCP Result", | |
| lines=15, | |
| show_copy_button=True | |
| ) | |
| def test_astrodienst_mcp(date, time, city, country, house_system): | |
| """Test Astro.com MCP""" | |
| try: | |
| from astrodienst_mcp import AstroDienstMCP | |
| server = AstroDienstMCP() | |
| result = server.generate_chart(date, time, city, country, house_system) | |
| output = f"""## π Astro.com MCP Response | |
| **Service**: {result['service']} | |
| **Birth Data**: {result['birth_date']} at {result['birth_time']} | |
| **Location**: {result['location']} | |
| **House System**: {result['house_system']} | |
| ### Chart URL: | |
| {result['chart_url']} | |
| ### Instructions: | |
| {chr(10).join(f"{i}. {inst}" for i, inst in enumerate(result['instructions'], 1))} | |
| ### Hellenistic Features: | |
| - Whole Sign Houses: {'β Yes' if result['hellenistic_features']['whole_sign_houses'] else 'β No'} | |
| - Traditional Aspects: {'β Included' if result['hellenistic_features']['traditional_aspects'] else 'β No'} | |
| - Sect Awareness: {result['hellenistic_features']['sect_aware']} | |
| - Essential Dignities: {result['hellenistic_features']['essential_dignities']} | |
| ### Note: | |
| {result['note']} | |
| --- | |
| *Via: AstroDienst MCP Integration* | |
| """ | |
| return output | |
| except Exception as e: | |
| return f"β Error: {str(e)}" | |
| astro_btn.click( | |
| fn=test_astrodienst_mcp, | |
| inputs=[astro_date, astro_time, astro_city, astro_country, astro_house_system], | |
| outputs=astro_output | |
| ) | |
| gr.Markdown("---") | |
| # MCP Server 4: Google Gemini AI | |
| with gr.Accordion("π€ Google Gemini AI MCP", open=True): | |
| gr.Markdown(""" | |
| ### Natural Language Astrology Conversations | |
| Ask questions about Hellenistic astrology in **plain English**. | |
| Powered by Google Gemini AI with specialized knowledge of traditional techniques. | |
| **Features:** | |
| - Explain techniques (dignities, profections, etc.) | |
| - Interpret placements | |
| - Answer questions with sources | |
| - Compare different methods | |
| - Educational, not predictive | |
| **Status**: π Requires GOOGLE_API_KEY (free at makersuite.google.com) | |
| """) | |
| with gr.Row(): | |
| with gr.Column(): | |
| gr.Markdown("#### Ask a Question") | |
| gemini_api_key = gr.Textbox( | |
| label="Google Gemini API Key (Optional)", | |
| placeholder="Enter your API key or leave blank for fallback responses", | |
| type="password", | |
| info="Get free key at: https://makersuite.google.com/app/apikey" | |
| ) | |
| gemini_question = gr.Textbox( | |
| label="Your Question", | |
| placeholder="What are essential dignities in Hellenistic astrology?", | |
| lines=3 | |
| ) | |
| gemini_btn = gr.Button("π€ Ask Gemini via MCP", variant="primary") | |
| gr.Markdown("**Example questions:**") | |
| gr.Markdown(""" | |
| - What are essential dignities? | |
| - How does sect work in Hellenistic astrology? | |
| - Explain annual profections step by step | |
| - What are Whole Sign houses? | |
| - Compare profections vs zodiacal releasing | |
| """) | |
| with gr.Column(): | |
| gemini_output = gr.Textbox( | |
| label="Gemini AI Response", | |
| lines=20, | |
| show_copy_button=True | |
| ) | |
| def test_gemini_mcp(api_key, question): | |
| """Test Gemini MCP""" | |
| try: | |
| import os | |
| from gemini_mcp import GeminiMCP | |
| # Temporarily set API key if provided | |
| original_key = os.environ.get('GOOGLE_API_KEY') | |
| if api_key and api_key.strip(): | |
| os.environ['GOOGLE_API_KEY'] = api_key.strip() | |
| server = GeminiMCP() | |
| result = server.ask_question(question, include_sources=True) | |
| # Restore original key | |
| if original_key: | |
| os.environ['GOOGLE_API_KEY'] = original_key | |
| elif api_key and api_key.strip(): | |
| del os.environ['GOOGLE_API_KEY'] | |
| if "error" in result: | |
| return f"""## β οΈ API Key Required | |
| {result.get('message', 'Gemini API not configured')} | |
| ### Fallback Response: | |
| {result.get('fallback', 'No fallback available')} | |
| --- | |
| **To enable full Gemini AI:** | |
| 1. Get free API key: https://makersuite.google.com/app/apikey | |
| 2. Set environment variable: `GOOGLE_API_KEY=your-key` | |
| 3. Restart application | |
| **Or use the fallback responses above for common questions.** | |
| """ | |
| output = f"""## π€ Gemini AI Response (via MCP) | |
| **Question**: {result['question']} | |
| **Model**: {result.get('model', 'gemini-pro')} | |
| **Conversation Turn**: {result.get('conversation_turn', 1)} | |
| --- | |
| {result['answer']} | |
| --- | |
| *Via: Google Gemini MCP Server* | |
| *Source: {result['source']}* | |
| """ | |
| return output | |
| except Exception as e: | |
| return f"β Error: {str(e)}" | |
| gemini_btn.click( | |
| fn=test_gemini_mcp, | |
| inputs=[gemini_api_key, gemini_question], | |
| outputs=gemini_output | |
| ) | |
| gr.Markdown("---") | |
| # MCP Architecture Diagram | |
| gr.Markdown(""" | |
| ## ποΈ HERMES MCP Architecture | |
| ``` | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β HERMES Application β | |
| β (Gradio UI) β | |
| βββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββ | |
| β | |
| βββββββββββββββ΄ββββββββββββββ | |
| β MCP Protocol Layer β | |
| β (Unified Interface) β | |
| βββββββββββββββ¬ββββββββββββββ | |
| β | |
| βββββββββββββββββββββββΌββββββββββββββββββββββ¬ββββββββββββββββββ | |
| β β β β | |
| βββββΌβββββ ββββββββββΌβββββββββ βββββββΌβββββββ ββββββΌββββββ | |
| β Local β β Modal Serverless β β Astro.com β β Gemini β | |
| β MCP β β MCP β β MCP β β AI MCP β | |
| ββββββββββ ββββββββββββββββββββ ββββββββββββββ ββββββββββββ | |
| β β β β | |
| β β β β | |
| Fast & Scalable Cloud Classical Chart AI-Powered | |
| Reliable Calculations Generation Teaching | |
| ``` | |
| ### Key Benefits: | |
| 1. **Modularity**: Each MCP server is independent | |
| 2. **Scalability**: Cloud functions handle heavy computation | |
| 3. **Resilience**: Automatic fallback if services unavailable | |
| 4. **Extensibility**: Easy to add new data sources | |
| 5. **Interoperability**: Standard protocol across all backends | |
| ### MCP Configuration | |
| All servers configured in `.mcp_config.json`: | |
| """) | |
| gr.Code("""{ | |
| "mcpServers": { | |
| "hermes-local": "Local calculations", | |
| "hermes-modal": "Modal serverless", | |
| "astrodienst": "Astro.com charts", | |
| "gemini": "AI conversations" | |
| }, | |
| "settings": { | |
| "default_server": "hermes-local", | |
| "fallback_chain": ["hermes-modal", "hermes-local"] | |
| } | |
| }""", language="json") | |
| gr.Markdown(""" | |
| ### Try It Yourself | |
| 1. **Test each MCP server** using the accordions above | |
| 2. **Compare performance** between local and cloud | |
| 3. **See fallback behavior** when services unavailable | |
| 4. **Check the code** in `hermes_local_mcp.py`, `astrodienst_mcp.py`, `gemini_mcp.py` | |
| ### For Hackathon Judges | |
| HERMES demonstrates **MCP's value** by: | |
| - β Integrating 4 different calculation backends | |
| - β Showing graceful fallback (Modal β Local) | |
| - β Connecting to external services (Astro.com) | |
| - β Using AI for education (Gemini) | |
| - β Maintaining consistent interface across all backends | |
| This architecture makes ancient astrology accessible through modern protocols! | |
| """) | |
| with gr.Tab("π Chart Analysis"): | |
| gr.Markdown("### Essential Dignity Calculator") | |
| with gr.Row(): | |
| planet_input = gr.Dropdown( | |
| choices=["Sun", "Moon", "Mercury", "Venus", "Mars", "Jupiter", "Saturn"], | |
| label="Planet", | |
| value="Sun" | |
| ) | |
| sign_input = gr.Dropdown( | |
| choices=list(DOMICILE_RULERS.keys()), | |
| label="Sign", | |
| value="Aries" | |
| ) | |
| sect_input = gr.Checkbox(label="Day Chart (uncheck for Night Chart)", value=True) | |
| dignity_btn = gr.Button("Assess Planetary Condition", variant="primary") | |
| dignity_output = gr.Markdown(label="Dignity Analysis") | |
| dignity_btn.click( | |
| fn=assess_planetary_dignity, | |
| inputs=[planet_input, sign_input, sect_input], | |
| outputs=dignity_output | |
| ) | |
| gr.Markdown("### Lot Calculator") | |
| with gr.Row(): | |
| asc_deg = gr.Number(label="Ascendant (degrees 0-360)", value=0) | |
| sun_deg = gr.Number(label="Sun (degrees 0-360)", value=45) | |
| moon_deg = gr.Number(label="Moon (degrees 0-360)", value=180) | |
| lot_sect = gr.Checkbox(label="Day Chart", value=True) | |
| lot_btn = gr.Button("Calculate Lots", variant="primary") | |
| lot_output = gr.Markdown(label="Traditional Lots") | |
| lot_btn.click( | |
| fn=calculate_lots, | |
| inputs=[asc_deg, sun_deg, moon_deg, lot_sect], | |
| outputs=lot_output | |
| ) | |
| with gr.Tab("π Source Research"): | |
| gr.Markdown(""" | |
| ### Hellenistic Astrology Knowledge Base | |
| Ask about traditional techniques and get answers citing ancient sources. | |
| """) | |
| research_query = gr.Textbox( | |
| label="Research Question", | |
| placeholder="e.g., 'Explain sect theory' or 'What are profections?' or 'Describe Egyptian bounds'", | |
| lines=2 | |
| ) | |
| research_btn = gr.Button("Search Ancient Sources", variant="primary") | |
| research_output = gr.Textbox(label="Research Results", lines=20) | |
| research_btn.click( | |
| fn=research_hellenistic_topic, | |
| inputs=research_query, | |
| outputs=research_output | |
| ) | |
| gr.Markdown(""" | |
| **Sources Referenced:** | |
| - Vettius Valens (*Anthology*) | |
| - Ptolemy (*Tetrabiblos*) | |
| - Dorotheus of Sidon (*Carmen Astrologicum*) | |
| - Paulus Alexandrinus | |
| - Modern: Chris Brennan, Demetra George, Robert Schmidt | |
| """) | |
| with gr.Tab("β±οΈ Time-Lord Systems"): | |
| gr.Markdown("### Annual Profections Calculator") | |
| with gr.Row(): | |
| birth_year_input = gr.Number(label="Birth Year", value=1990) | |
| target_year_input = gr.Number(label="Target Year", value=2025) | |
| profection_btn = gr.Button("Calculate Profections", variant="primary") | |
| profection_output = gr.Markdown(label="Profection Results") | |
| profection_btn.click( | |
| fn=calculate_profections, | |
| inputs=[birth_year_input, target_year_input], | |
| outputs=profection_output | |
| ) | |
| with gr.Tab("π― Bounds & Decans"): | |
| gr.Markdown(""" | |
| ### Egyptian Bounds (Terms) & Decans (Faces) | |
| Calculate the sub-rulerships within each sign for refined essential dignity assessment. | |
| """) | |
| with gr.Row(): | |
| bound_sign = gr.Dropdown( | |
| choices=list(DOMICILE_RULERS.keys()), | |
| label="Sign", | |
| value="Aries" | |
| ) | |
| bound_degree = gr.Number(label="Degree (0-30)", value=15, minimum=0, maximum=30) | |
| with gr.Row(): | |
| bound_btn = gr.Button("Get Bound Ruler", variant="primary") | |
| decan_btn = gr.Button("Get Decan Ruler", variant="secondary") | |
| bound_output = gr.Markdown(label="Results") | |
| bound_btn.click( | |
| fn=get_bound_ruler, | |
| inputs=[bound_sign, bound_degree], | |
| outputs=bound_output | |
| ) | |
| decan_btn.click( | |
| fn=get_decan_ruler, | |
| inputs=[bound_sign, bound_degree], | |
| outputs=bound_output | |
| ) | |
| gr.Markdown(""" | |
| **About Bounds & Decans:** | |
| - **Egyptian Bounds** (Terms): Each sign divided into 5 unequal sections ruled by planets (+2 dignity points) | |
| - **Decans** (Faces): Each sign divided into 3 equal 10Β° sections (+1 dignity point) | |
| These sub-rulers provide more refined assessment of planetary condition and are used in advanced time-lord techniques. | |
| Source: Vettius Valens, Ptolemy (though he presents his own bounds system) | |
| """) | |
| with gr.Tab("π Zodiacal Releasing"): | |
| gr.Markdown(""" | |
| ### Zodiacal Releasing (Loosing of the Bond) | |
| Advanced time-lord system from Vettius Valens using the Lot of Fortune or Spirit. | |
| """) | |
| with gr.Row(): | |
| zr_starting_sign = gr.Dropdown( | |
| choices=ZODIACAL_RELEASING_ORDER, | |
| label="Starting Sign (where Lot of Fortune/Spirit falls)", | |
| value="Cancer" | |
| ) | |
| with gr.Row(): | |
| zr_birth_year = gr.Number(label="Birth Year", value=1990) | |
| zr_target_year = gr.Number(label="Target Year (optional)", value=2025) | |
| zr_btn = gr.Button("Calculate Zodiacal Releasing Periods", variant="primary") | |
| zr_output = gr.Markdown(label="ZR Periods") | |
| zr_btn.click( | |
| fn=calculate_zodiacal_releasing, | |
| inputs=[zr_starting_sign, zr_birth_year, zr_target_year], | |
| outputs=zr_output | |
| ) | |
| with gr.Tab("π Learning Center"): | |
| gr.Markdown(""" | |
| ### Interactive Voice Teaching | |
| Learn Hellenistic astrology techniques with AI-powered voice explanations. | |
| """) | |
| if voice_agent and ELEVENLABS_API_KEY: | |
| gr.Markdown(""" | |
| β οΈ **Voice Feature Status**: ElevenLabs audio requires a paid subscription when running on HuggingFace Spaces (free tier blocked due to proxy detection). | |
| Text explanations are fully available below! For voice audio, consider running HERMES locally. | |
| """) | |
| technique_choice = gr.Dropdown( | |
| choices=["Annual Profections", "Sect Theory", "Zodiacal Releasing", | |
| "Essential Dignities", "Lots (Fortune & Spirit)", "Bounds & Decans"], | |
| label="Choose a Technique to Learn", | |
| value="Annual Profections" | |
| ) | |
| teach_btn = gr.Button("π Get Text Explanation", variant="primary") | |
| text_output = gr.Textbox( | |
| label="Text Explanation", | |
| lines=20, | |
| max_lines=30, | |
| show_copy_button=True, | |
| container=True | |
| ) | |
| def get_teaching_explanation(technique): | |
| """Get text explanation (audio disabled due to ElevenLabs free tier restrictions on HF Spaces)""" | |
| technique_map = { | |
| "Annual Profections": "annual_profections", | |
| "Sect Theory": "sect_theory", | |
| "Zodiacal Releasing": "zodiacal_releasing" | |
| } | |
| key = technique_map.get(technique, technique.lower().replace(" ", "_")) | |
| text = voice_agent.explain_technique(key) | |
| return text | |
| teach_btn.click( | |
| fn=get_teaching_explanation, | |
| inputs=technique_choice, | |
| outputs=text_output | |
| ) | |
| else: | |
| gr.Markdown("β οΈ Voice teaching requires ELEVENLABS_API_KEY to be set in environment") | |
| gr.Markdown("Add the API key in HuggingFace Space Settings β Repository Secrets") | |
| gr.Markdown(""" | |
| --- | |
| ### π Educational Resources | |
| **Recommended Books:** | |
| - **Chris Brennan** - [*Hellenistic Astrology: The Study of Fate and Fortune*](https://www.hellenisticastrology.com/book/) | |
| - Comprehensive modern treatment of traditional techniques | |
| - Available at: https://www.hellenisticastrology.com | |
| - **Demetra George** - *Ancient Astrology in Theory and Practice* (2 volumes) | |
| - **Vettius Valens** - *The Anthology* (Project Hindsight translation) | |
| - **Claudius Ptolemy** - *Tetrabiblos* (Schmidt translation) | |
| **Online Resources:** | |
| - [The Astrology Podcast](https://theastrologypodcast.com) by Chris Brennan | |
| - [Hellenistic Astrology Website](https://www.hellenisticastrology.com) - Courses, articles, chart examples | |
| - [Project Hindsight](http://www.projecthindsight.com) - Ancient text translations | |
| **Free Learning:** | |
| - Chris Brennan's YouTube channel - Technique tutorials and demonstrations | |
| - [Astrology Podcast Episodes on Hellenistic Techniques](https://theastrologypodcast.com/hellenistic-astrology/) | |
| **Study Path:** | |
| 1. Start with essential dignities and sect | |
| 2. Learn the lot calculations (Fortune, Spirit) | |
| 3. Master annual profections for yearly forecasting | |
| 4. Progress to zodiacal releasing for life periods | |
| 5. Explore bounds, decans, and advanced timing | |
| """) | |
| with gr.Tab("βΉοΈ About"): | |
| gr.Markdown(""" | |
| ## About HERMES | |
| **Hellenistic Ephemeris Research & MCP Educational System** | |
| ### Purpose | |
| HERMES is a research and teaching tool for traditional Hellenistic astrology, bridging | |
| 2000-year-old wisdom with modern AI technology. | |
| ### Technical Stack | |
| - **Agent Framework**: OpenAI GPT-4 + Anthropic Claude | |
| - **Teaching**: Text-based AI explanations | |
| - **MCP Server**: Python + Modal (serverless) β **DEPLOYED** | |
| - **UI**: Gradio 5.49+ on HuggingFace Spaces | |
| - **Ephemeris**: Swiss Ephemeris (pyswisseph) | |
| ### MCP Server Features (Modal Serverless) | |
| The HERMES MCP server is deployed on Modal with 6 serverless functions: | |
| - `calculate_zodiacal_releasing` - Time-lord periods from Vettius Valens | |
| - `calculate_firdaria` - Persian time-lord system | |
| - `get_bound_ruler` - Egyptian bounds (terms) | |
| - `get_decan_ruler` - Decans (faces) | |
| - `calculate_full_dignities` - Complete essential dignity analysis | |
| - `find_fixed_stars` - Fixed star conjunction database | |
| **Live at**: `modal.com/apps/aamanlamba/hermes-astrology-mcp` | |
| ### Interactive Features | |
| - Essential dignity calculations (domicile, exaltation, triplicity, bounds, decans) | |
| - Time-lord systems (annual profections, zodiacal releasing) | |
| - Traditional lot calculations (Fortune, Spirit with sect consideration) | |
| - Source research with citations to ancient texts | |
| - AI-powered teaching explanations | |
| ### Educational Use Cases | |
| 1. **Students**: Interactive learning of complex traditional techniques | |
| 2. **Researchers**: Rapid comparison across source texts and translations | |
| 3. **Practitioners**: Chart analysis using authentic Hellenistic methods | |
| ### Built For | |
| MCP 1st Birthday Hackathon (Nov 14-30, 2025) | |
| ### Author | |
| Created by an astrology author and strategy consultant | |
| ### Credits & Acknowledgments | |
| **Hackathon Sponsors:** | |
| - Anthropic, OpenAI, ElevenLabs, Modal, HuggingFace | |
| **Ancient Sources:** | |
| - Vettius Valens (*Anthology*, 2nd century CE) | |
| - Claudius Ptolemy (*Tetrabiblos*, 2nd century CE) | |
| - Dorotheus of Sidon (*Carmen Astrologicum*, 1st century CE) | |
| - Firmicus Maternus, Paulus Alexandrinus, Rhetorius | |
| **Modern Teachers & Resources:** | |
| - **Chris Brennan** - [*Hellenistic Astrology: The Study of Fate and Fortune*](https://www.hellenisticastrology.com/book/) | |
| - The definitive modern text on Hellenistic astrology | |
| - Host of [The Astrology Podcast](https://theastrologypodcast.com) | |
| - Courses and resources at [HellenisticAstrology.com](https://www.hellenisticastrology.com) | |
| - **Demetra George** - Traditional astrology teacher and author | |
| - **Robert Schmidt** - Project Hindsight founder, translator of ancient texts | |
| Special thanks to Chris Brennan for preserving and teaching these ancient techniques to modern practitioners. | |
| --- | |
| ## π Primary Ancient Sources | |
| All techniques in HERMES are based on authentic ancient texts: | |
| ### Hellenistic Era (1st-7th century CE) | |
| - **Vettius Valens** (*Anthology*, 2nd century CE) - Our primary source for profections, zodiacal releasing, and lots | |
| - **Claudius Ptolemy** (*Tetrabiblos*, 2nd century CE) - Theoretical foundations of essential dignities and sect | |
| - **Dorotheus of Sidon** (*Carmen Astrologicum*, 1st century CE) - Early treatment of time-lord techniques | |
| - **Paulus Alexandrinus** (*Introductory Matters*, 4th century CE) - Teaching manual with profections | |
| - **Firmicus Maternus** (*Mathesis*, 4th century CE) - Late Hellenistic synthesis | |
| - **Rhetorius of Egypt** (6th-7th century CE) - Compilation and commentary on earlier authors | |
| ### Modern Translations & Commentary | |
| - **Robert Schmidt** - Project Hindsight translations from Greek and Latin | |
| - **Chris Brennan** - *Hellenistic Astrology: The Study of Fate and Fortune* (2017) - Comprehensive modern synthesis | |
| - **Demetra George** - *Ancient Astrology in Theory and Practice* (2019) - Practical application guide | |
| ### Technique Sources | |
| - **Domicile, Exaltation, Triplicity** β Ptolemy (*Tetrabiblos* I.17-21), Valens (*Anthology* passim) | |
| - **Egyptian Bounds** β Preserved in Valens and Paulus (distinct from Ptolemy's system) | |
| - **Decans (Faces)** β Attributed to Egyptian sources, preserved by Hellenistic authors | |
| - **Lots (Fortune, Spirit)** β Valens (*Anthology* III, IV), Paulus (*Introductory Matters*) | |
| - **Annual Profections** β Valens (*Anthology* IV), Paulus (*Introductory Matters* 23) | |
| - **Zodiacal Releasing** β Valens (*Anthology* IV.4-11) - detailed treatment of "Loosing of the Bond" | |
| - **Sect Theory** β Valens (*Anthology* III.2), Ptolemy (*Tetrabiblos* III.2) | |
| ### Why These Sources Matter | |
| Unlike modern psychological astrology, Hellenistic astrology is a **reconstructed tradition** based on | |
| ancient texts that were lost for centuries. Thanks to Project Hindsight (1990s-2000s) and modern scholars, | |
| we can now practice astrology as the Greeks and Romans did - with time-lord techniques, essential dignities, | |
| and a focus on prediction rather than personality. | |
| HERMES aims to make these authentic ancient techniques accessible through modern AI technology. | |
| --- | |
| *Built with β€οΈ for traditional astrology and the MCP Birthday Hackathon* | |
| *"The stars incline, they do not compel" - Traditional maxim* | |
| """) | |
| return demo | |
| # Launch the app | |
| if __name__ == "__main__": | |
| demo = create_demo() | |
| demo.launch() | |