aamanlamba commited on
Commit
bf79a43
Β·
verified Β·
1 Parent(s): 1c93f85

Upload folder using huggingface_hub

Browse files
Files changed (4) hide show
  1. .gitignore +12 -0
  2. README.md +10 -1
  3. app.py +230 -6
  4. requirements.txt +4 -3
.gitignore CHANGED
@@ -1,6 +1,18 @@
1
  deploy_to_hf.py
2
  .venv
 
 
3
  __pycache__/
 
 
 
 
 
 
 
 
 
 
4
  MANUAL_DEPLOYMENT.md
5
  DEPLOYMENT_CHECKLIST.md
6
  00_START_HERE.md
 
1
  deploy_to_hf.py
2
  .venv
3
+ .env
4
+ .python-version
5
  __pycache__/
6
+ *.pyc
7
+ *.pyo
8
+ *.pyd
9
+ .Python
10
+ *.so
11
+ *.egg
12
+ *.egg-info/
13
+ dist/
14
+ build/
15
+ .DS_Store
16
  MANUAL_DEPLOYMENT.md
17
  DEPLOYMENT_CHECKLIST.md
18
  00_START_HERE.md
README.md CHANGED
@@ -203,7 +203,9 @@ MCP 1st Birthday Hackathon organized by Gradio & HuggingFace (Nov 14-30, 2025)
203
 
204
  ## πŸ“Ή Demo Video
205
 
206
- *[Demo video will be added before Nov 30, 2025 submission deadline]*
 
 
207
 
208
  **Planned Contents** (3-4 minutes):
209
  1. Introduction to Hellenistic astrology and HERMES (30s)
@@ -212,6 +214,13 @@ MCP 1st Birthday Hackathon organized by Gradio & HuggingFace (Nov 14-30, 2025)
212
  4. Source research feature (45s)
213
  5. Real-world applications (30s)
214
 
 
 
 
 
 
 
 
215
  ## πŸ”§ Installation & Development
216
 
217
  ### Local Development
 
203
 
204
  ## πŸ“Ή Demo Video
205
 
206
+ **Video Link**: *[Will be added before Nov 30, 2025 submission deadline]*
207
+
208
+ **Social Media Post**: https://x.com/aamanlamba/status/1989639180960579874
209
 
210
  **Planned Contents** (3-4 minutes):
211
  1. Introduction to Hellenistic astrology and HERMES (30s)
 
214
  4. Source research feature (45s)
215
  5. Real-world applications (30s)
216
 
217
+ **Recording Guide**:
218
+ - Screen record the live HuggingFace Space
219
+ - Demonstrate each calculator with real examples
220
+ - Show source citations and educational content
221
+ - Highlight MCP architecture and tech stack
222
+ - Available at: https://huggingface.co/spaces/aamanlamba/hermes-astrology
223
+
224
  ## πŸ”§ Installation & Development
225
 
226
  ### Local Development
app.py CHANGED
@@ -3,11 +3,22 @@ import os
3
  from datetime import datetime
4
  import json
5
 
 
 
 
 
 
 
 
 
6
  # Initialize with sponsor APIs (will be configured with environment variables)
7
  OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "")
8
  ANTHROPIC_API_KEY = os.getenv("ANTHROPIC_API_KEY", "")
9
  ELEVENLABS_API_KEY = os.getenv("ELEVENLABS_API_KEY", "")
10
 
 
 
 
11
  # Essential Dignities Tables
12
  DOMICILE_RULERS = {
13
  "Aries": "Mars", "Taurus": "Venus", "Gemini": "Mercury",
@@ -37,6 +48,50 @@ SIGN_TRIPLICITIES = {
37
  "Cancer": "Water", "Scorpio": "Water", "Pisces": "Water"
38
  }
39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  def calculate_profections(birth_year: int, target_year: int) -> dict:
41
  """Calculate annual profections from Ascendant"""
42
  age = target_year - birth_year
@@ -90,27 +145,111 @@ def assess_planetary_dignity(planet: str, sign: str, is_day_chart: bool) -> dict
90
 
91
  def calculate_lots(asc_degree: float, sun_degree: float, moon_degree: float, is_day_chart: bool) -> dict:
92
  """Calculate traditional Hellenistic lots (Fortuna and Spirit)"""
93
-
94
  if is_day_chart:
95
  # Lot of Fortune (day): Asc + Moon - Sun
96
  fortune = (asc_degree + moon_degree - sun_degree) % 360
97
  else:
98
  # Lot of Fortune (night): Asc + Sun - Moon
99
  fortune = (asc_degree + sun_degree - moon_degree) % 360
100
-
101
  if is_day_chart:
102
  # Lot of Spirit (day): Asc + Sun - Moon
103
  spirit = (asc_degree + sun_degree - moon_degree) % 360
104
  else:
105
  # Lot of Spirit (night): Asc + Moon - Sun
106
  spirit = (asc_degree + moon_degree - sun_degree) % 360
107
-
 
 
 
 
 
 
 
 
108
  return {
109
- "Lot of Fortune": round(fortune, 2),
110
- "Lot of Spirit": round(spirit, 2),
111
  "chart_type": "Day Chart" if is_day_chart else "Night Chart"
112
  }
113
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  def research_hellenistic_topic(query: str) -> str:
115
  """Research assistant for Hellenistic astrology topics"""
116
  # This will integrate with OpenAI/Anthropic APIs
@@ -311,7 +450,92 @@ def create_demo():
311
 
312
  Used by Valens, Paulus Alexandrinus, and modern practitioners for annual forecasting.
313
  """)
314
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
315
  with gr.Tab("ℹ️ About"):
316
  gr.Markdown("""
317
  ## About HERMES
 
3
  from datetime import datetime
4
  import json
5
 
6
+ # Import local modules
7
+ try:
8
+ from voice_agent import AstrologyVoiceAgent
9
+ VOICE_AVAILABLE = True
10
+ except ImportError:
11
+ VOICE_AVAILABLE = False
12
+ print("Voice agent not available - install elevenlabs package")
13
+
14
  # Initialize with sponsor APIs (will be configured with environment variables)
15
  OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "")
16
  ANTHROPIC_API_KEY = os.getenv("ANTHROPIC_API_KEY", "")
17
  ELEVENLABS_API_KEY = os.getenv("ELEVENLABS_API_KEY", "")
18
 
19
+ # Initialize voice agent if available
20
+ voice_agent = AstrologyVoiceAgent(agent_type="teaching") if VOICE_AVAILABLE and ELEVENLABS_API_KEY else None
21
+
22
  # Essential Dignities Tables
23
  DOMICILE_RULERS = {
24
  "Aries": "Mars", "Taurus": "Venus", "Gemini": "Mercury",
 
48
  "Cancer": "Water", "Scorpio": "Water", "Pisces": "Water"
49
  }
50
 
51
+ # Egyptian Bounds (Terms)
52
+ EGYPTIAN_BOUNDS = {
53
+ "Aries": [(0, 6, "Jupiter"), (6, 12, "Venus"), (12, 20, "Mercury"), (20, 25, "Mars"), (25, 30, "Saturn")],
54
+ "Taurus": [(0, 8, "Venus"), (8, 14, "Mercury"), (14, 22, "Jupiter"), (22, 27, "Saturn"), (27, 30, "Mars")],
55
+ "Gemini": [(0, 6, "Mercury"), (6, 12, "Jupiter"), (12, 17, "Venus"), (17, 24, "Mars"), (24, 30, "Saturn")],
56
+ "Cancer": [(0, 7, "Mars"), (7, 13, "Venus"), (13, 19, "Mercury"), (19, 26, "Jupiter"), (26, 30, "Saturn")],
57
+ "Leo": [(0, 6, "Jupiter"), (6, 11, "Venus"), (11, 18, "Saturn"), (18, 24, "Mercury"), (24, 30, "Mars")],
58
+ "Virgo": [(0, 7, "Mercury"), (7, 17, "Venus"), (17, 21, "Jupiter"), (21, 28, "Mars"), (28, 30, "Saturn")],
59
+ "Libra": [(0, 6, "Saturn"), (6, 14, "Mercury"), (14, 21, "Jupiter"), (21, 28, "Venus"), (28, 30, "Mars")],
60
+ "Scorpio": [(0, 7, "Mars"), (7, 11, "Venus"), (11, 19, "Mercury"), (19, 24, "Jupiter"), (24, 30, "Saturn")],
61
+ "Sagittarius": [(0, 12, "Jupiter"), (12, 17, "Venus"), (17, 21, "Mercury"), (21, 26, "Saturn"), (26, 30, "Mars")],
62
+ "Capricorn": [(0, 7, "Mercury"), (7, 14, "Jupiter"), (14, 22, "Venus"), (22, 26, "Saturn"), (26, 30, "Mars")],
63
+ "Aquarius": [(0, 7, "Mercury"), (7, 13, "Venus"), (13, 20, "Jupiter"), (20, 25, "Mars"), (25, 30, "Saturn")],
64
+ "Pisces": [(0, 12, "Venus"), (12, 16, "Jupiter"), (16, 19, "Mercury"), (19, 28, "Mars"), (28, 30, "Saturn")]
65
+ }
66
+
67
+ # Decans (Faces)
68
+ DECANS = {
69
+ "Aries": [(0, 10, "Mars"), (10, 20, "Sun"), (20, 30, "Venus")],
70
+ "Taurus": [(0, 10, "Mercury"), (10, 20, "Moon"), (20, 30, "Saturn")],
71
+ "Gemini": [(0, 10, "Jupiter"), (10, 20, "Mars"), (20, 30, "Sun")],
72
+ "Cancer": [(0, 10, "Venus"), (10, 20, "Mercury"), (20, 30, "Moon")],
73
+ "Leo": [(0, 10, "Saturn"), (10, 20, "Jupiter"), (20, 30, "Mars")],
74
+ "Virgo": [(0, 10, "Sun"), (10, 20, "Venus"), (20, 30, "Mercury")],
75
+ "Libra": [(0, 10, "Moon"), (10, 20, "Saturn"), (20, 30, "Jupiter")],
76
+ "Scorpio": [(0, 10, "Mars"), (10, 20, "Sun"), (20, 30, "Venus")],
77
+ "Sagittarius": [(0, 10, "Mercury"), (10, 20, "Moon"), (20, 30, "Saturn")],
78
+ "Capricorn": [(0, 10, "Jupiter"), (10, 20, "Mars"), (20, 30, "Sun")],
79
+ "Aquarius": [(0, 10, "Venus"), (10, 20, "Mercury"), (20, 30, "Moon")],
80
+ "Pisces": [(0, 10, "Saturn"), (10, 20, "Jupiter"), (20, 30, "Mars")]
81
+ }
82
+
83
+ # Zodiacal Releasing
84
+ ZODIACAL_RELEASING_ORDER = [
85
+ "Cancer", "Leo", "Virgo", "Libra", "Scorpio", "Sagittarius",
86
+ "Capricorn", "Aquarius", "Pisces", "Aries", "Taurus", "Gemini"
87
+ ]
88
+
89
+ SIGN_YEARS = {
90
+ "Cancer": 25, "Leo": 19, "Virgo": 20, "Libra": 8, "Scorpio": 15,
91
+ "Sagittarius": 12, "Capricorn": 27, "Aquarius": 30, "Pisces": 12,
92
+ "Aries": 15, "Taurus": 8, "Gemini": 20
93
+ }
94
+
95
  def calculate_profections(birth_year: int, target_year: int) -> dict:
96
  """Calculate annual profections from Ascendant"""
97
  age = target_year - birth_year
 
145
 
146
  def calculate_lots(asc_degree: float, sun_degree: float, moon_degree: float, is_day_chart: bool) -> dict:
147
  """Calculate traditional Hellenistic lots (Fortuna and Spirit)"""
148
+
149
  if is_day_chart:
150
  # Lot of Fortune (day): Asc + Moon - Sun
151
  fortune = (asc_degree + moon_degree - sun_degree) % 360
152
  else:
153
  # Lot of Fortune (night): Asc + Sun - Moon
154
  fortune = (asc_degree + sun_degree - moon_degree) % 360
155
+
156
  if is_day_chart:
157
  # Lot of Spirit (day): Asc + Sun - Moon
158
  spirit = (asc_degree + sun_degree - moon_degree) % 360
159
  else:
160
  # Lot of Spirit (night): Asc + Moon - Sun
161
  spirit = (asc_degree + moon_degree - sun_degree) % 360
162
+
163
+ # Convert to sign and degree
164
+ def deg_to_sign(deg):
165
+ signs = ["Aries", "Taurus", "Gemini", "Cancer", "Leo", "Virgo",
166
+ "Libra", "Scorpio", "Sagittarius", "Capricorn", "Aquarius", "Pisces"]
167
+ sign_num = int(deg // 30)
168
+ sign_deg = deg % 30
169
+ return f"{round(sign_deg, 2)}Β° {signs[sign_num]}"
170
+
171
  return {
172
+ "Lot of Fortune": f"{round(fortune, 2)}Β° ({deg_to_sign(fortune)})",
173
+ "Lot of Spirit": f"{round(spirit, 2)}Β° ({deg_to_sign(spirit)})",
174
  "chart_type": "Day Chart" if is_day_chart else "Night Chart"
175
  }
176
 
177
+ def get_bound_ruler(sign: str, degree: float) -> dict:
178
+ """Get the Egyptian bound (term) ruler for a planet's position"""
179
+ if sign not in EGYPTIAN_BOUNDS:
180
+ return {"error": f"Invalid sign: {sign}"}
181
+
182
+ bounds = EGYPTIAN_BOUNDS[sign]
183
+ for start, end, ruler in bounds:
184
+ if start <= degree < end:
185
+ return {
186
+ "sign": sign,
187
+ "degree": degree,
188
+ "bound_ruler": ruler,
189
+ "bound_range": f"{start}-{end}Β°",
190
+ "dignity_points": 2
191
+ }
192
+
193
+ return {"error": "Degree out of range (0-30)"}
194
+
195
+ def get_decan_ruler(sign: str, degree: float) -> dict:
196
+ """Get the decan (face) ruler for a planet's position"""
197
+ if sign not in DECANS:
198
+ return {"error": f"Invalid sign: {sign}"}
199
+
200
+ decans = DECANS[sign]
201
+ for start, end, ruler in decans:
202
+ if start <= degree < end:
203
+ return {
204
+ "sign": sign,
205
+ "degree": degree,
206
+ "decan_ruler": ruler,
207
+ "decan_number": (start // 10) + 1,
208
+ "decan_range": f"{start}-{end}Β°",
209
+ "dignity_points": 1
210
+ }
211
+
212
+ return {"error": "Degree out of range (0-30)"}
213
+
214
+ def calculate_zodiacal_releasing(starting_sign: str, birth_year: int, target_year: int = None) -> dict:
215
+ """Calculate Zodiacal Releasing periods (simplified version)"""
216
+ if starting_sign not in ZODIACAL_RELEASING_ORDER:
217
+ return {"error": f"Invalid starting sign: {starting_sign}"}
218
+
219
+ if target_year is None:
220
+ target_year = datetime.now().year
221
+
222
+ age = target_year - birth_year
223
+ current_index = ZODIACAL_RELEASING_ORDER.index(starting_sign)
224
+ accumulated_years = 0
225
+ periods = []
226
+
227
+ # Calculate first 5 periods for display
228
+ for i in range(5):
229
+ sign = ZODIACAL_RELEASING_ORDER[(current_index + i) % 12]
230
+ period_years = SIGN_YEARS[sign]
231
+
232
+ start_age = int(accumulated_years)
233
+ end_age = int(accumulated_years + period_years)
234
+
235
+ is_current = start_age <= age < end_age
236
+
237
+ periods.append({
238
+ "period": i + 1,
239
+ "sign": sign,
240
+ "years": period_years,
241
+ "age_range": f"{start_age}-{end_age}",
242
+ "current": "← CURRENT PERIOD" if is_current else ""
243
+ })
244
+
245
+ accumulated_years += period_years
246
+
247
+ return {
248
+ "starting_sign": starting_sign,
249
+ "current_age": age,
250
+ "periods": periods
251
+ }
252
+
253
  def research_hellenistic_topic(query: str) -> str:
254
  """Research assistant for Hellenistic astrology topics"""
255
  # This will integrate with OpenAI/Anthropic APIs
 
450
 
451
  Used by Valens, Paulus Alexandrinus, and modern practitioners for annual forecasting.
452
  """)
453
+
454
+ with gr.Tab("🎯 Bounds & Decans"):
455
+ gr.Markdown("""
456
+ ### Egyptian Bounds (Terms) & Decans (Faces)
457
+ Calculate the sub-rulerships within each sign for refined essential dignity assessment.
458
+ """)
459
+
460
+ with gr.Row():
461
+ bound_sign = gr.Dropdown(
462
+ choices=list(DOMICILE_RULERS.keys()),
463
+ label="Sign",
464
+ value="Aries"
465
+ )
466
+ bound_degree = gr.Number(label="Degree (0-30)", value=15, minimum=0, maximum=30)
467
+
468
+ with gr.Row():
469
+ bound_btn = gr.Button("Get Bound Ruler", variant="primary")
470
+ decan_btn = gr.Button("Get Decan Ruler", variant="secondary")
471
+
472
+ with gr.Row():
473
+ bound_output = gr.JSON(label="Bound (Term) Result")
474
+ decan_output = gr.JSON(label="Decan (Face) Result")
475
+
476
+ bound_btn.click(
477
+ fn=get_bound_ruler,
478
+ inputs=[bound_sign, bound_degree],
479
+ outputs=bound_output
480
+ )
481
+
482
+ decan_btn.click(
483
+ fn=get_decan_ruler,
484
+ inputs=[bound_sign, bound_degree],
485
+ outputs=decan_output
486
+ )
487
+
488
+ gr.Markdown("""
489
+ **About Bounds & Decans:**
490
+
491
+ - **Egyptian Bounds** (Terms): Each sign divided into 5 unequal sections ruled by planets (+2 dignity points)
492
+ - **Decans** (Faces): Each sign divided into 3 equal 10Β° sections (+1 dignity point)
493
+
494
+ These sub-rulers provide more refined assessment of planetary condition and are used in advanced time-lord techniques.
495
+
496
+ Source: Vettius Valens, Ptolemy (though he presents his own bounds system)
497
+ """)
498
+
499
+ with gr.Tab("🌟 Zodiacal Releasing"):
500
+ gr.Markdown("""
501
+ ### Zodiacal Releasing (Loosing of the Bond)
502
+ Advanced time-lord system from Vettius Valens using the Lot of Fortune or Spirit.
503
+ """)
504
+
505
+ with gr.Row():
506
+ zr_starting_sign = gr.Dropdown(
507
+ choices=ZODIACAL_RELEASING_ORDER,
508
+ label="Starting Sign (where Lot of Fortune/Spirit falls)",
509
+ value="Cancer"
510
+ )
511
+
512
+ with gr.Row():
513
+ zr_birth_year = gr.Number(label="Birth Year", value=1990)
514
+ zr_target_year = gr.Number(label="Target Year (optional)", value=2025)
515
+
516
+ zr_btn = gr.Button("Calculate Zodiacal Releasing Periods", variant="primary")
517
+ zr_output = gr.JSON(label="ZR Periods")
518
+
519
+ zr_btn.click(
520
+ fn=calculate_zodiacal_releasing,
521
+ inputs=[zr_starting_sign, zr_birth_year, zr_target_year],
522
+ outputs=zr_output
523
+ )
524
+
525
+ gr.Markdown("""
526
+ **About Zodiacal Releasing:**
527
+
528
+ From Vettius Valens' "Anthology" - one of the most sophisticated Hellenistic timing techniques.
529
+
530
+ - Uses fixed order: Cancer β†’ Leo β†’ Virgo β†’ Libra β†’ Scorpio β†’ Sagittarius β†’ Capricorn β†’ Aquarius β†’ Pisces β†’ Aries β†’ Taurus β†’ Gemini
531
+ - Each sign has set years: Cancer (25), Leo (19), Virgo (20), Libra (8), etc.
532
+ - Usually started from Lot of Fortune (general life) or Lot of Spirit (career/reputation)
533
+ - Periods can be divided into sub-periods for precise timing
534
+ - Peak periods occur when releasing through the sign opposite your starting lot
535
+
536
+ This is a simplified version showing major periods. Full ZR includes minor and sub-minor divisions.
537
+ """)
538
+
539
  with gr.Tab("ℹ️ About"):
540
  gr.Markdown("""
541
  ## About HERMES
requirements.txt CHANGED
@@ -1,9 +1,10 @@
1
- gradio>=5.0
2
  openai>=1.0.0
3
  anthropic>=0.39.0
4
- elevenlabs>=1.0.0
5
  python-dotenv>=1.0.0
6
  pyswisseph>=2.10.0
7
  pandas>=2.0.0
8
  numpy>=1.24.0
9
- huggingface_hub>=0.15.0
 
 
1
+ gradio>=5.49.0
2
  openai>=1.0.0
3
  anthropic>=0.39.0
4
+ elevenlabs>=1.9.0
5
  python-dotenv>=1.0.0
6
  pyswisseph>=2.10.0
7
  pandas>=2.0.0
8
  numpy>=1.24.0
9
+ huggingface_hub>=0.25.0
10
+ modal>=0.63.0