Spaces:
Running
Running
| """ | |
| Google Gemini MCP Integration | |
| Natural language conversations about Hellenistic astrology | |
| """ | |
| import json | |
| from typing import Dict, List, Optional | |
| import os | |
| try: | |
| import google.generativeai as genai | |
| GEMINI_AVAILABLE = True | |
| except ImportError: | |
| GEMINI_AVAILABLE = False | |
| class GeminiMCP: | |
| """MCP Server for Google Gemini AI conversations about Hellenistic astrology""" | |
| def __init__(self, api_key: Optional[str] = None): | |
| """ | |
| Initialize Gemini MCP server | |
| Args: | |
| api_key: Google AI API key (or set GOOGLE_API_KEY environment variable) | |
| """ | |
| self.api_key = api_key or os.getenv("GOOGLE_API_KEY") | |
| self.model_name = "gemini-pro" | |
| self.conversation_history = [] | |
| if GEMINI_AVAILABLE and self.api_key: | |
| genai.configure(api_key=self.api_key) | |
| self.model = genai.GenerativeModel(self.model_name) | |
| self.chat = None | |
| self.is_configured = True | |
| else: | |
| self.model = None | |
| self.chat = None | |
| self.is_configured = False | |
| # Hellenistic astrology system prompt | |
| self.system_prompt = """You are an expert in Hellenistic astrology (1st-7th century CE). | |
| You specialize in: | |
| - Essential dignities (domicile, exaltation, triplicity, bound, decan) | |
| - Sect (day/night charts and benefic/malefic teams) | |
| - Whole Sign houses (traditional house system) | |
| - Traditional aspects with orbs | |
| - Lots/Parts (Fortune, Spirit, Eros, etc.) | |
| - Time-lord techniques (profections, zodiacal releasing, firdaria) | |
| - Classical texts (Vettius Valens, Ptolemy, Dorotheus, Paulus Alexandrinus) | |
| **Teaching Style:** | |
| - Explain concepts clearly for beginners | |
| - Reference primary sources when relevant | |
| - Distinguish traditional vs. modern techniques | |
| - Use examples from classical texts | |
| - Be precise about technical terminology | |
| **Always:** | |
| - Cite sources (ancient or modern) | |
| - Explain "why" behind techniques, not just "what" | |
| - Connect theory to practical interpretation | |
| - Note when techniques vary between authors | |
| - Encourage further study of primary texts | |
| **Never:** | |
| - Make predictions without chart data | |
| - Mix modern psychological astrology with traditional | |
| - Oversimplify complex techniques | |
| - Claim certainty about contested interpretations""" | |
| def ask_question( | |
| self, | |
| question: str, | |
| include_sources: bool = True | |
| ) -> Dict: | |
| """ | |
| Ask a question about Hellenistic astrology | |
| Args: | |
| question: User's question | |
| include_sources: Whether to request source citations | |
| Returns: | |
| AI response with explanation and sources | |
| """ | |
| if not self.is_configured: | |
| return { | |
| "error": "Gemini not configured", | |
| "message": "Please set GOOGLE_API_KEY environment variable or provide API key", | |
| "fallback": self._get_fallback_response(question) | |
| } | |
| try: | |
| # Start new chat if needed | |
| if not self.chat: | |
| self.chat = self.model.start_chat(history=[]) | |
| # Send system prompt as first message | |
| self.chat.send_message(self.system_prompt) | |
| # Add instruction for sources if requested | |
| if include_sources: | |
| full_question = f"{question}\n\n(Please include relevant classical sources in your answer.)" | |
| else: | |
| full_question = question | |
| # Send question | |
| response = self.chat.send_message(full_question) | |
| return { | |
| "question": question, | |
| "answer": response.text, | |
| "model": self.model_name, | |
| "conversation_turn": len(self.conversation_history) + 1, | |
| "source": "Google Gemini via HERMES MCP" | |
| } | |
| except Exception as e: | |
| return { | |
| "error": f"Gemini API error: {str(e)}", | |
| "question": question, | |
| "fallback": self._get_fallback_response(question) | |
| } | |
| def _get_fallback_response(self, question: str) -> str: | |
| """ | |
| Provide fallback responses when Gemini unavailable | |
| Returns basic information about common topics | |
| """ | |
| fallback_db = { | |
| "dignit": """**Essential Dignities** measure planetary strength by zodiacal position. | |
| The five levels are: | |
| 1. **Domicile** (+5): Planet in its home sign (e.g., Sun in Leo) | |
| 2. **Exaltation** (+4): Planet in its exaltation (e.g., Sun in Aries) | |
| 3. **Triplicity** (+3): Planet ruling the element | |
| 4. **Bound/Term** (+2): Planet ruling degree ranges within signs | |
| 5. **Decan/Face** (+1): Planet ruling 10-degree sections | |
| **Debilities** are opposites: | |
| - **Detriment** (-5): Opposite of domicile (e.g., Sun in Aquarius) | |
| - **Fall** (-4): Opposite of exaltation (e.g., Sun in Libra) | |
| *Source: Ptolemy's Tetrabiblos, Vettius Valens*""", | |
| "sect": """**Sect** divides charts into day and night teams. | |
| **Day Chart** (Sun above horizon): | |
| - Sun, Jupiter, Saturn = Day team (stronger) | |
| - Moon, Venus, Mars = Night team (weaker) | |
| - Jupiter = benefic, Saturn = malefic (but of the day team) | |
| **Night Chart** (Sun below horizon): | |
| - Moon, Venus, Mars = Night team (stronger) | |
| - Sun, Jupiter, Saturn = Day team (weaker) | |
| - Venus = benefic, Mars = malefic (but of the night team) | |
| Planets in-sect function better than out-of-sect planets. | |
| *Source: Vettius Valens, Anthology Book II*""", | |
| "profection": """**Annual Profections** move the Ascendant forward one house per year. | |
| **How it works:** | |
| 1. Start at Ascendant (age 0-1) | |
| 2. Move to 2nd house (age 1-2) | |
| 3. Continue advancing one house per year | |
| 4. At age 12, return to Ascendant (12-year cycle) | |
| The **profected house** shows the year's themes. | |
| The **ruler** of that house becomes **Lord of the Year**. | |
| Example: Age 35 profects to the 12th house (35 % 12 = 11, +1 = 12th). | |
| *Source: Vettius Valens, Paulus Alexandrinus*""", | |
| "whole sign": """**Whole Sign Houses** assign entire signs to houses. | |
| **How it works:** | |
| 1. Ascendant sign = entire 1st house (0-30°) | |
| 2. Next sign = entire 2nd house | |
| 3. Continue through all 12 signs | |
| This is the **original Hellenistic house system** (1st-7th century). | |
| **Benefits:** | |
| - Simple and clear | |
| - Each house is exactly 30° | |
| - Easy to determine house rulers | |
| - Used by Vettius Valens, Dorotheus | |
| Modern systems (Placidus, Koch) came later (16th-18th century). | |
| *Source: Chris Brennan, Hellenistic Astrology (2017)*""" | |
| } | |
| # Check for keywords | |
| question_lower = question.lower() | |
| for keyword, response in fallback_db.items(): | |
| if keyword in question_lower: | |
| return response | |
| # Default response | |
| return """**API Key Required** | |
| For AI-powered conversations, set your Google AI API key: | |
| ```python | |
| export GOOGLE_API_KEY="your-key-here" | |
| ``` | |
| Get a free API key at: https://makersuite.google.com/app/apikey | |
| **Meanwhile, try these resources:** | |
| - Chris Brennan: "Hellenistic Astrology: The Study of Fate and Fortune" (2017) | |
| - Vettius Valens: "Anthology" (Project Hindsight translation) | |
| - Demetra George: "Ancient Astrology in Theory and Practice" (2019) | |
| **Or ask specific questions like:** | |
| - "What are essential dignities?" | |
| - "How does sect work?" | |
| - "What are annual profections?" | |
| - "What are Whole Sign houses?" """ | |
| def explain_technique( | |
| self, | |
| technique: str, | |
| level: str = "beginner" | |
| ) -> Dict: | |
| """ | |
| Get detailed explanation of a traditional technique | |
| Args: | |
| technique: Name of technique (dignities, profections, lots, etc.) | |
| level: Explanation level (beginner, intermediate, advanced) | |
| Returns: | |
| Structured explanation tailored to level | |
| """ | |
| levels_prompt = { | |
| "beginner": "Explain this as if teaching someone new to astrology. Use simple language and clear examples.", | |
| "intermediate": "Provide a comprehensive explanation with examples and source citations.", | |
| "advanced": "Give an in-depth technical explanation including variant methods across classical authors." | |
| } | |
| question = f"""Please explain the technique of {technique} in Hellenistic astrology. | |
| Level: {levels_prompt.get(level, levels_prompt['beginner'])} | |
| Include: | |
| 1. What it is and why it's used | |
| 2. How to calculate or apply it | |
| 3. An example | |
| 4. Classical sources | |
| 5. Common mistakes to avoid""" | |
| return self.ask_question(question, include_sources=True) | |
| def interpret_placement( | |
| self, | |
| planet: str, | |
| sign: str, | |
| house: int, | |
| aspects: Optional[List[str]] = None, | |
| is_day_chart: bool = True | |
| ) -> Dict: | |
| """ | |
| Get AI interpretation of a planetary placement | |
| Args: | |
| planet: Planet name | |
| sign: Zodiac sign | |
| house: House number (1-12) | |
| aspects: List of aspects (e.g., ["square Mars", "trine Jupiter"]) | |
| is_day_chart: Whether it's a day chart (for sect analysis) | |
| Returns: | |
| Detailed interpretation using Hellenistic principles | |
| """ | |
| aspect_text = f"\nAspects: {', '.join(aspects)}" if aspects else "" | |
| chart_type = "day chart" if is_day_chart else "night chart" | |
| question = f"""Interpret this planetary placement using Hellenistic astrology: | |
| **Planet:** {planet} | |
| **Sign:** {sign} | |
| **House:** {house} | |
| **Chart Type:** {chart_type}{aspect_text} | |
| Please analyze: | |
| 1. Essential dignity (domicile, exaltation, detriment, fall) | |
| 2. Sect condition (in-sect or out-of-sect) | |
| 3. House signification | |
| 4. Aspects and their influence | |
| 5. Overall interpretation | |
| Use traditional Hellenistic principles and cite classical sources where relevant.""" | |
| return self.ask_question(question, include_sources=True) | |
| def compare_techniques( | |
| self, | |
| technique1: str, | |
| technique2: str | |
| ) -> Dict: | |
| """ | |
| Compare two astrological techniques | |
| Args: | |
| technique1: First technique | |
| technique2: Second technique | |
| Returns: | |
| Comparison with similarities, differences, and when to use each | |
| """ | |
| question = f"""Compare these two techniques in Hellenistic astrology: | |
| 1. {technique1} | |
| 2. {technique2} | |
| Please explain: | |
| - What each technique does | |
| - Similarities and differences | |
| - Historical origins | |
| - When to use each one | |
| - How they complement each other | |
| Include classical sources where relevant.""" | |
| return self.ask_question(question, include_sources=True) | |
| def reset_conversation(self): | |
| """Reset conversation history and start fresh""" | |
| self.conversation_history = [] | |
| if self.chat: | |
| self.chat = None | |
| return {"status": "Conversation reset", "ready": True} | |
| def get_mcp_tools() -> List[Dict]: | |
| """Return list of available Gemini MCP tools""" | |
| return [ | |
| { | |
| "name": "ask_question", | |
| "description": "Ask any question about Hellenistic astrology", | |
| "parameters": { | |
| "question": "string (your question)", | |
| "include_sources": "boolean (optional, default True)" | |
| }, | |
| "returns": "AI-generated answer with classical sources" | |
| }, | |
| { | |
| "name": "explain_technique", | |
| "description": "Get detailed explanation of a traditional technique", | |
| "parameters": { | |
| "technique": "string (dignities, profections, lots, etc.)", | |
| "level": "string (beginner, intermediate, advanced)" | |
| }, | |
| "returns": "Structured explanation tailored to experience level" | |
| }, | |
| { | |
| "name": "interpret_placement", | |
| "description": "Get interpretation of a planetary placement", | |
| "parameters": { | |
| "planet": "string", | |
| "sign": "string", | |
| "house": "integer (1-12)", | |
| "aspects": "list of strings (optional)", | |
| "is_day_chart": "boolean (optional, default True)" | |
| }, | |
| "returns": "Hellenistic interpretation with sect and dignity analysis" | |
| }, | |
| { | |
| "name": "compare_techniques", | |
| "description": "Compare two astrological techniques", | |
| "parameters": { | |
| "technique1": "string", | |
| "technique2": "string" | |
| }, | |
| "returns": "Comparison with when to use each" | |
| }, | |
| { | |
| "name": "reset_conversation", | |
| "description": "Reset conversation history", | |
| "parameters": {}, | |
| "returns": "Confirmation of reset" | |
| } | |
| ] | |
| # Main entry point | |
| if __name__ == "__main__": | |
| import sys | |
| if len(sys.argv) > 1 and sys.argv[1] == "tools": | |
| print(json.dumps(get_mcp_tools(), indent=2)) | |
| else: | |
| print("=" * 70) | |
| print("Google Gemini MCP Server") | |
| print("Natural Language Hellenistic Astrology Conversations") | |
| print("=" * 70) | |
| print("\nAvailable Tools:") | |
| print(json.dumps(get_mcp_tools(), indent=2)) | |
| # Test example | |
| print("\n" + "=" * 70) | |
| print("TEST: Ask Question (Fallback Mode)") | |
| print("=" * 70) | |
| server = GeminiMCP() | |
| result = server.ask_question("What are essential dignities?") | |
| print(json.dumps(result, indent=2)) | |
| if not GEMINI_AVAILABLE: | |
| print("\n⚠️ Note: google-generativeai package not installed") | |
| print(" Install with: pip install google-generativeai") | |
| if not server.api_key: | |
| print("\n⚠️ Note: GOOGLE_API_KEY not set") | |
| print(" Get free API key: https://makersuite.google.com/app/apikey") | |
| print(" Set with: export GOOGLE_API_KEY='your-key'") | |