From 63fb547dda112c003bdf728f6cef031268dca127 Mon Sep 17 00:00:00 2001 From: 732642856 <732642856@qq.com> Date: Thu, 4 Jun 2026 05:12:35 +0800 Subject: [PATCH] =?UTF-8?q?v6.0.14:=20=E6=96=B0=E5=A2=9E=20Yogas=20+=20Dos?= =?UTF-8?q?has=20+=20Special=20Lagnas=20+=20Darakaraka=20=E6=8A=80?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - scripts/jaimini.py: 新增 calc_darakaraka 等5个函数(DK/婚姻分析) - scripts/yogas_doshas.py: 新文件,11个函数(Raj/Dhana/PanchaMahapurusha/NeechaBhanga/MangalDosha/KaalSarp/Pitra/SadeSati/ArudhaLagna/UpapadaLagna) - scripts/jyotish_engine.py: cmd_full_reading 新增 Step 4.9 调用 calc_all_yogas_doshas - references/technique_registry.json: 新增11个技法注册(darakaraka/raj_yoga/.../upapada_lagna) - references/strict-workflow-router.md: Audit Table 模板新增11行 - CHANGELOG.md: 新增 v6.0.14 条目 - SKILL.md: 版本号 6.0.13 → 6.0.14 --- CHANGELOG.md | 35 ++ SKILL.md | 2 +- references/strict-workflow-router.md | 11 + references/technique_registry.json | 240 ++++++++++- scripts/jaimini.py | 219 ++++++++++ scripts/jyotish_engine.py | 29 ++ scripts/yogas_doshas.py | 623 +++++++++++++++++++++++++++ 7 files changed, 1154 insertions(+), 5 deletions(-) create mode 100644 scripts/yogas_doshas.py diff --git a/CHANGELOG.md b/CHANGELOG.md index f877b429..76911ff1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,40 @@ # 印度占星 Skill 更新日志 +## v6.0.14-yogas-doshas-dk(2026-06-04)—— 新增 Yogas + Doshas + Special Lagnas + Darakaraka + +> **触发原因**:用户要求补充印度占星 skill 缺少的技法。经过本地资料 + 全网搜索对比,发现 P0 级缺失技法:Darakaraka (DK)、Raj/Dhana Yogas、Doshas (Mangal/Kaal Sarp/Pitra)、Special Lagnas (AL/UL)。 + +### 新增功能 + +- `scripts/jaimini.py` 新增 5 个函数: + - `calc_darakaraka(planet_degrees, use_8karaka)`:计算 DK(配偶星) + - `calc_dk_marriage_analysis(...)`:综合 DK 信息做婚姻分析 + - `_dk_interpretation(dk_planet)`:DK 行星解读 + - `_marriage_significator(dk, ak)`:AK-DK 关系解读 + - `_dk_house_meaning(house)` 等辅助函数 +- `scripts/yogas_doshas.py`(新文件):包含 11 个函数: + - `calc_raj_yogas(planets_data, houses)`:Raj Yoga(王者瑜伽) + - `calc_dhana_yoga(planets_data, houses)`:Dhana Yoga(财富瑜伽) + - `calc_pancha_mahapurusha_yoga(planets_data)`:Pancha Mahapurusha(五王瑜伽) + - `calc_nicha_bhanga_raj_yoga(planets_data, houses)`:Neecha Bhanga Raj Yoga + - `calc_mangal_dosha(planets_data, mars_house)`:Mangal Dosha(火星煞) + - `calc_kaal_sarp_dosha(planets_data)`:Kaal Sarp Dosha(时间蛇煞) + - `calc_pitra_dosha(planets_data, sun_house)`:Pitra Dosha(父辈煞) + - `calc_sade_sati(moon_sign, current_year)`:Sade Sati(土星七年) + - `calc_arudha_lagna(asc_sign, asc_lord, planets_data)`:Arudha Lagna (AL) + - `calc_upapada_lagna(asc_sign, house12_lord, planets_data)`:Upapada Lagna (UL) + - `calc_all_yogas_doshas(...)`:批量计算入口函数 +- `scripts/jyotish_engine.py` 的 `cmd_full_reading` 新增 Step 4.9:调用 `calc_all_yogas_doshas`,输出 `modules.yogas_doshas` +- `references/technique_registry.json` 新增 11 个技法注册(darakaraka/raj_yoga/dhana_yoga/pancha_mahapurusha/nicha_bhanga_raj/mangal_dosha/kaal_sarp_dosha/pitra_dosha/sade_sati/arudha_lagna/upapada_lagna) +- `references/strict-workflow-router.md`:Audit Table 模板新增 11 行 + +### 验证结果 + +- Python 语法检查:jyotish_engine.py / jaimini.py / yogas_doshas.py 均 OK +- 集成测试:待运行(需要 pyswisseph 环境) + +--- + ## v6.0.13-tajika-yogas-sahams(2026-06-04)—— 新增 Tajika Yogas + Sahams 技法 > **触发原因**:用户指出当前 skill 缺少 Tajika Yogas(Ithasala/Easarapha/Nakta/Yamaya/Manahoo/Graha Yuddha)和 Sahams(Punya/Karya/Vivah/Rajya/Shatru/Labha/Parakrama)两个重要技法体系。 diff --git a/SKILL.md b/SKILL.md index c3242b31..3ba8ebb8 100644 --- a/SKILL.md +++ b/SKILL.md @@ -1,6 +1,6 @@ --- name: jyotish-vedic-astrology -version: 6.0.13 +version: 6.0.14 description: 印度占星(Jyotish)专业解盘与推运系统。核心能力:PDF星盘输入→严谨解盘→精确推运应期输出。触发词:印度占星、吠陀占星、Jyotish、解盘、推运、星盘分析、Dasha、Transit、Nakshatra、Yoga、出生时间矫正、PDF星盘、读取PDF、分析PDF星盘、现代解读、误判纠错、Varga分盘、综合分析、过境分析、合盘、婚姻匹配、年运盘、Prashna、Argala、Jaimini、KP系统、Shadbala、Ashtakavarga、HTML报告、深度解盘。 --- diff --git a/references/strict-workflow-router.md b/references/strict-workflow-router.md index b8264755..c25bb17d 100644 --- a/references/strict-workflow-router.md +++ b/references/strict-workflow-router.md @@ -175,6 +175,17 @@ Every Level 2+ output must include this table near the end. | Inter-chart Linkage | Used / not used | ... | ... | | Tajika Yogas | Used / partial / not used | Ithasala/Easarapha/Nakta etc. | Cap annual timing confidence | | Sahams | Used / partial / not used | Punya/Karya/Vivah etc. | Cap event timing confidence | +| Darakaraka (DK) | Used / not used | Marriage/partner analysis | Cap marriage timing without DK | +| Raj Yoga | Used / partial / not used | Power/status yogas | Cap high-status event confidence | +| Dhana Yoga | Used / partial / not used | Wealth/money yogas | Cap wealth timing confidence | +| Pancha Mahapurusha | Used / partial / not used | 5 Mahapurusha yogas | Cap personality strength assessment | +| Neecha Bhanga Raj | Used / partial / not used | Debilitation recovery | Cap comeback/recovery timing | +| Mangal Dosha | Used / not used | Mars in bad houses | Cap marriage difficulty assessment | +| Kaal Sarp Dosha | Used / not used | All planets Rahu-Ketu side | Cap obstacle analysis | +| Pitra Dosha | Used / not used | Sun-Rahu or Sun afflicted | Cap ancestor karma analysis | +| Sade Sati | Used / partial / not used | Saturn 7.5-year period | Cap Saturn pressure timing | +| Arudha Lagna (AL) | Used / not used | Mirror Lagna (perception) | Cap public image analysis | +| Upapada Lagna (UL) | Used / not used | Marriage partner indicator | Cap marriage quality analysis | | Argala | Used / not used | ... | ... | | KP / Sub-lord | Used / not required / unavailable | ... | ... | | Historical verification | Used / not provided | ... | ... | diff --git a/references/technique_registry.json b/references/technique_registry.json index 90f1c810..815acd42 100644 --- a/references/technique_registry.json +++ b/references/technique_registry.json @@ -1,5 +1,5 @@ { - "version": "v6.0.11-shadbala-capability-downgrade", + "version": "v6.0.14-yogas-doshas-dk", "source_inspiration": [ { "name": "jyotishyamitra", @@ -436,6 +436,205 @@ ], "audit_label": "Sahams", "missing_impact": "Saham point calculation incomplete; annual/event timing layer missing." + }, + "darakaraka": { + "name": "Darakaraka (DK) / 配偶星", + "domains": [ + "jaimini", + "marriage", + "relationship", + "karaka" + ], + "status": "covered", + "knowledge_refs": [], + "commands": [ + "full-reading" + ], + "output_paths": [ + "modules.jaimini.darakaraka" + ], + "audit_label": "Darakaraka (DK)", + "missing_impact": "Marriage/partner analysis incomplete without DK." + }, + "raj_yoga": { + "name": "Raj Yoga / 王者瑜伽", + "domains": [ + "yoga", + "power", + "status" + ], + "status": "partial", + "knowledge_refs": [], + "commands": [ + "full-reading" + ], + "output_paths": [ + "modules.yogas_doshas.raj_yogas" + ], + "audit_label": "Raj Yoga", + "missing_impact": "Power/status timing confidence capped without Raj Yoga detection." + }, + "dhana_yoga": { + "name": "Dhana Yoga / 财富瑜伽", + "domains": [ + "yoga", + "wealth", + "money" + ], + "status": "partial", + "knowledge_refs": [], + "commands": [ + "full-reading" + ], + "output_paths": [ + "modules.yogas_doshas.dhana_yogas" + ], + "audit_label": "Dhana Yoga", + "missing_impact": "Wealth timing confidence capped without Dhana Yoga." + }, + "pancha_mahapurusha": { + "name": "Pancha Mahapurusha Yoga / 五王瑜伽", + "domains": [ + "yoga", + "power", + "personality" + ], + "status": "partial", + "knowledge_refs": [], + "commands": [ + "full-reading" + ], + "output_paths": [ + "modules.yogas_doshas.pancha_mahapurusha" + ], + "audit_label": "Pancha Mahapurusha", + "missing_impact": "Personality strength assessment incomplete." + }, + "nicha_bhanga_raj": { + "name": "Neecha Bhanga Raj Yoga / 落陷解除王者瑜伽", + "domains": [ + "yoga", + "debilitation", + "recovery" + ], + "status": "partial", + "knowledge_refs": [], + "commands": [ + "full-reading" + ], + "output_paths": [ + "modules.yogas_doshas.nicha_bhanga_raj" + ], + "audit_label": "Neecha Bhanga", + "missing_impact": "Debilitation recovery analysis incomplete." + }, + "mangal_dosha": { + "name": "Mangal Dosha / 火星煞", + "domains": [ + "dosha", + "marriage", + "mars" + ], + "status": "covered", + "knowledge_refs": [], + "commands": [ + "full-reading" + ], + "output_paths": [ + "modules.yogas_doshas.mangal_dosha" + ], + "audit_label": "Mangal Dosha", + "missing_impact": "Marriage difficulty assessment incomplete without Mangal Dosha." + }, + "kaal_sarp_dosha": { + "name": "Kaal Sarp Dosha / 时间蛇煞", + "domains": [ + "dosha", + "rahu", + "obstacle" + ], + "status": "covered", + "knowledge_refs": [], + "commands": [ + "full-reading" + ], + "output_paths": [ + "modules.yogas_doshas.kaal_sarp_dosha" + ], + "audit_label": "Kaal Sarp Dosha", + "missing_impact": "Obstacle analysis incomplete without Kaal Sarp." + }, + "pitra_dosha": { + "name": "Pitra Dosha / 父辈煞", + "domains": [ + "dosha", + "sun", + "ancestor" + ], + "status": "covered", + "knowledge_refs": [], + "commands": [ + "full-reading" + ], + "output_paths": [ + "modules.yogas_doshas.pitra_dosha" + ], + "audit_label": "Pitra Dosha", + "missing_impact": "Ancestor karma analysis incomplete." + }, + "sade_sati": { + "name": "Sade Sati / 土星七年", + "domains": [ + "transit", + "saturn", + "pressure" + ], + "status": "partial", + "knowledge_refs": [], + "commands": [ + "full-reading" + ], + "output_paths": [ + "modules.yogas_doshas.sade_sati" + ], + "audit_label": "Sade Sati", + "missing_impact": "Saturn pressure timing incomplete." + }, + "arudha_lagna": { + "name": "Arudha Lagna (AL) / 镜像上升", + "domains": [ + "lagna", + "perception", + "image" + ], + "status": "covered", + "knowledge_refs": [], + "commands": [ + "full-reading" + ], + "output_paths": [ + "modules.yogas_doshas.arudha_lagna" + ], + "audit_label": "Arudha Lagna", + "missing_impact": "Public image analysis incomplete without AL." + }, + "upapada_lagna": { + "name": "Upapada Lagna (UL) / 配偶镜像上升", + "domains": [ + "lagna", + "marriage", + "partner" + ], + "status": "covered", + "knowledge_refs": [], + "commands": [ + "full-reading" + ], + "output_paths": [ + "modules.yogas_doshas.upapada_lagna" + ], + "audit_label": "Upapada Lagna", + "missing_impact": "Marriage quality analysis incomplete without UL." } }, "routes": { @@ -465,7 +664,18 @@ "dispositor_chain", "inter_chart_linkage", "tajika_yogas", - "sahams" + "sahams", + "darakaraka", + "raj_yoga", + "dhana_yoga", + "pancha_mahapurusha", + "nicha_bhanga_raj", + "mangal_dosha", + "kaal_sarp_dosha", + "pitra_dosha", + "sade_sati", + "arudha_lagna", + "upapada_lagna" ], "optional_techniques": [ "bhava_chalit", @@ -491,7 +701,18 @@ "dispositor_chain", "inter_chart_linkage", "tajika_yogas", - "sahams" + "sahams", + "darakaraka", + "raj_yoga", + "dhana_yoga", + "pancha_mahapurusha", + "nicha_bhanga_raj", + "mangal_dosha", + "kaal_sarp_dosha", + "pitra_dosha", + "sade_sati", + "arudha_lagna", + "upapada_lagna" ], "optional_techniques": [ "d9_navamsa", @@ -523,7 +744,18 @@ "dispositor_chain", "inter_chart_linkage", "tajika_yogas", - "sahams" + "sahams", + "darakaraka", + "raj_yoga", + "dhana_yoga", + "pancha_mahapurusha", + "nicha_bhanga_raj", + "mangal_dosha", + "kaal_sarp_dosha", + "pitra_dosha", + "sade_sati", + "arudha_lagna", + "upapada_lagna" ], "optional_techniques": [ "bhava_chalit", diff --git a/scripts/jaimini.py b/scripts/jaimini.py index 5ee368e4..440e9704 100644 --- a/scripts/jaimini.py +++ b/scripts/jaimini.py @@ -337,3 +337,222 @@ def _karakamsha_interpretations(sign, lord): 'sign_direction': directions.get(sign, ''), 'lord_method': lord_meanings.get(lord, ''), } + + +# ============================================================================ +# Darakaraka (DK) 计算 —— v6.0.14 新增 +# ============================================================================ + +def calc_darakaraka(planet_degrees: Dict[str, float], + use_8karaka: bool = False) -> Dict: + """ + 计算 Darakaraka (DK) —— Jaimini 体系中代表配偶/伴侣的行星。 + + 规则(7星制): + - 排除 Rahu/Ketu,剩余7颗行星按度数升序排列 + - 度数最低的行星 = Darakaraka (DK) —— 配偶特质星 + - 度数最高的行星 = Atmakaraka (AK) —— 灵魂星 + + 规则(8星制): + - 含 Rahu,8颗行星按度数升序排列 + - 度数最低的 = DK,度数最高的 = AK + + 参数: + planet_degrees: {行星名: 星座内度数(0-30)} + use_8karaka: 是否使用8星制(含Rahu) + + 返回: + { + 'DK': {'planet': str, 'degree': float, 'rank': 7(7星制)或8(8星制)}, + 'AK': {'planet': str, 'degree': float, 'rank': 1}, + 'all_karaka': {rank: {'planet','degree','name'}}, + 'dk_interpretation': str, + 'marriage_significator': str, + } + """ + if use_8karaka: + planets = {k: v for k, v in planet_degrees.items() if k != 'Ketu'} + karaka_def = KARAKA_8 + total = 8 + else: + planets = {k: v for k, v in planet_degrees.items() + if k not in ('Rahu', 'Ketu')} + karaka_def = KARAKA_7 + total = 7 + + # 按度数升序排列(度数最低=DK) + sorted_p = sorted(planets.items(), key=lambda x: x[1]) + + all_karaka = {} + dk_info = None + ak_info = None + + for rank, (pname, deg) in enumerate(sorted_p[:total], 1): + karaka_name = karaka_def[rank] + entry = { + 'planet': pname, + 'degree_in_sign': round(deg, 4), + 'rank': rank, + 'name': karaka_name, + 'cn_name': KARAKA_CN.get(karaka_name, karaka_name), + 'domain': KARAKA_DOMAINS.get(karaka_name, ''), + } + all_karaka[rank] = entry + if karaka_name == 'Darakaraka': + dk_info = entry + if karaka_name == 'Atmakaraka': + ak_info = entry + + # 解读 DK + dk_planet = dk_info['planet'] if dk_info else '?' + dk_interp = _dk_interpretation(dk_planet) + marriage_sig = _marriage_significator(dk_planet, ak_info['planet'] if ak_info else '?') + + return { + 'DK': dk_info, + 'AK': ak_info, + 'all_karaka': all_karaka, + 'dk_planet': dk_planet, + 'dk_degree': dk_info['degree_in_sign'] if dk_info else None, + 'dk_interpretation': dk_interp, + 'marriage_significator': marriage_sig, + 'use_8karaka': use_8karaka, + } + + +def _dk_interpretation(dk_planet: str) -> str: + """Darakaraka 行星的配偶特质解读""" + interpretations = { + 'Sun': '配偶有权威感、领导力强,可能比命主年长或地位高;关系中需要尊重和认可', + 'Moon': '配偶情感丰富、重视家庭,情绪敏感;关系以情感连接为核心', + 'Mars': '配偶行动力强、有魄力,可能性格急躁;关系中需要空间和尊重', + 'Mercury': '配偶聪明、善于沟通,可能从事文书/教育/商业;关系以交流为基础', + 'Jupiter': '配偶有智慧、教导型人格,可能从事教育/法律/宗教;关系有成长导向', + 'Venus': '配偶有魅力、重视美学和享受,浪漫且物质条件好;关系充满爱和美好', + 'Saturn': '配偶成熟稳重、有责任感,可能年龄差距较大;关系需要时间和承诺', + 'Rahu': '配偶背景复杂、有野心,可能来自不同文化/阶层;关系有非常规色彩', + 'Ketu': '配偶有灵性倾向、可能疏离,关系有超脱/宿命感', + } + return interpretations.get(dk_planet, f'DK={dk_planet},需结合全盘分析') + + +def _marriage_significator(dk: str, ak: str) -> str: + """AK-DK 关系对婚姻的综合指示""" + # AK=灵魂,DK=配偶,两者关系反映灵魂与伴侣的互动模式 + relations = { + ('Sun', 'Moon'): '灵魂(Sun)与情感(Moon)结合,婚姻中有父性保护色彩', + ('Moon', 'Sun'): '情感(Moon)与权威(Sun)结合,配偶可能是引导者/权威人物', + ('Venus', 'Jupiter'): '爱(Venus)与智慧(Jupiter)结合,婚姻有成长和教育意义', + ('Jupiter', 'Venus'): '智慧(Jupiter)与爱(Venus)结合,配偶带来美感和快乐', + } + key = (ak, dk) + return relations.get(key, f'AK={ak}与DK={dk}的组合,需结合两者星座/宫位深入分析') + + +def calc_dk_marriage_analysis(dk_planet: str, + dk_sign: str, + dk_house: int, + ak_sign: str, + ak_house: int, + venus_sign: str, + venus_house: int, + seventh_lord: str, + seventh_lord_sign: str) -> Dict: + """ + 综合 DK 信息进行婚姻分析(v6.0.14 新增) + + 参数: + dk_planet: DK行星名 + dk_sign: DK所在星座 + dk_house: DK所在宫位(1-12) + ak_sign: AK所在星座 + ak_house: AK所在宫位 + venus_sign: Venus所在星座 + venus_house: Venus所在宫位 + seventh_lord: 第七宫宫主星 + seventh_lord_sign: 第七宫宫主星所在星座 + + 返回:婚姻分析字典 + """ + # DK 在宫位的解读 + dk_house_meaning = _dk_house_meaning(dk_house) + + # Venus 与 DK 的关系 + venus_dk_relation = _venus_dk_relation(venus_sign, dk_sign, venus_house, dk_house) + + # 第七宫分析 + seventh_analysis = _seventh_house_analysis(seventh_lord, seventh_lord_sign) + + # 综合婚姻时机指示 + marriage_timing = _marriage_timing_indication(dk_planet, venus_sign, seventh_lord) + + return { + 'dk_planet': dk_planet, + 'dk_sign': dk_sign, + 'dk_house': dk_house, + 'dk_house_meaning': dk_house_meaning, + 'venus_dk_relation': venus_dk_relation, + 'seventh_analysis': seventh_analysis, + 'marriage_timing': marriage_timing, + 'summary': f"配偶星DK={dk_planet}在{dk_sign}第{dk_house}宫;{dk_house_meaning}", + } + + +def _dk_house_meaning(house: int) -> str: + """DK所在宫位对婚姻的意义""" + meanings = { + 1: '配偶与命主高度相似,自我认同与伴侣融合', + 2: '配偶带来财富/家庭资源,可能通过婚姻改善经济状况', + 3: '配偶是命主的勇气来源,可能有兄弟姐妹牵线', + 4: '配偶带来情感安全感,家庭和谐,可能有房产', + 5: '配偶与子女/创造力有关,浪漫关系,可能有年龄差', + 6: '配偶可能是工作伙伴/竞争对手,关系中需注意健康/债务', + 7: '配偶是命主的直接伙伴,婚姻关系最直接', + 8: '配偶带来深层转化,可能涉及神秘事务/遗产/危机', + 9: '配偶有灵性/哲学导向,可能来自不同文化背景', + 10: '配偶与事业/社会地位有关,可能因工作相识', + 11: '配偶带来收益/社交网络,朋友变伴侣', + 12: '配偶涉及潜意识/海外/隐秘事务,可能是异地/外籍', + } + return meanings.get(house, '') + + +def _venus_dk_relation(venus_sign: str, dk_sign: str, + venus_house: int, dk_house: int) -> str: + """Venus与DK的关系分析""" + # 简化:看两者是否同一星座或相邻宫位 + venus_idx = SIGNS.index(venus_sign) if venus_sign in SIGNS else -1 + dk_idx = SIGNS.index(dk_sign) if dk_sign in SIGNS else -1 + + if venus_idx >= 0 and dk_idx >= 0: + diff = abs(venus_idx - dk_idx) + if diff <= 1 or diff >= 11: + return 'Venus与DK能量融合,爱与婚姻高度一致' + elif diff <= 3: + return 'Venus与DK有一定张力,爱情与婚姻选择可能有分歧' + else: + return 'Venus与DK度数较远,爱情观与婚姻现实有差距' + + return 'Venus/DK关系需结合全盘确定' + + +def _seventh_house_analysis(seventh_lord: str, seventh_lord_sign: str) -> str: + """第七宫宫主星分析""" + lord_meanings = { + 'Sun': '配偶有领导力,可能从事管理/政府工作', + 'Moon': '配偶情感丰富,可能从事护理/餐饮/海洋相关', + 'Mars': '配偶有行动力,可能从事技术/军事/体育', + 'Mercury': '配偶聪明善辩,可能从事教育/写作/商业', + 'Jupiter': '配偶有智慧,可能从事教育/法律/宗教', + 'Venus': '配偶有魅力,可能从事艺术/娱乐/美容', + 'Saturn': '配偶成熟稳重,可能从事结构/建筑/长期项目', + } + return lord_meanings.get(seventh_lord, f'第七宫主星={seventh_lord},需结合全盘') + + +def _marriage_timing_indication(dk_planet: str, venus_sign: str, + seventh_lord: str) -> str: + """婚姻时机的简化指示(需结合Dasha/Transit使用)""" + return (f"婚姻窗口与DK={dk_planet}、Venus在{venus_sign}、" + f"第七宫主星={seventh_lord}的Dasha/Transit高度相关;" + f"具体应期需结合Vimshottari Dasha和Gochara(过境)确定") diff --git a/scripts/jyotish_engine.py b/scripts/jyotish_engine.py index b2de7714..aa13f293 100644 --- a/scripts/jyotish_engine.py +++ b/scripts/jyotish_engine.py @@ -3473,6 +3473,35 @@ def cmd_full_reading(args): except Exception as e: report['errors'].append(f"tajika-yogas+sahams: {e}") + # ── Step 4.9: Yogas + Doshas + Special Lagnas (v6.0.14) ── + try: + from yogas_doshas import calc_all_yogas_doshas + + # 准备参数 + asc_sign = SIGNS[asc_idx] if 'asc_idx' in dir() else SIGNS[0] + asc_lord = SIGN_LORDS.get(asc_sign, '') + moon_data = planets.get('Moon', {}) + moon_sign = moon_data.get('sign', '') if isinstance(moon_data, dict) else '' + moon_house = moon_data.get('house', 0) if isinstance(moon_data, dict) else 0 + mars_data = planets.get('Mars', {}) + mars_house = mars_data.get('house', 0) if isinstance(mars_data, dict) else 0 + sun_data = planets.get('Sun', {}) + sun_house = sun_data.get('house', 0) if isinstance(sun_data, dict) else 0 + # 12宫主星 + h12_lord = SIGN_LORDS.get(SIGNS[(asc_idx + 11) % 12], '') + + yd_result = calc_all_yogas_doshas( + planets, houses, + asc_sign, asc_lord, + moon_sign, moon_house, + mars_house, sun_house, + h12_lord + ) + report['modules']['yogas_doshas'] = yd_result + + except Exception as e: + report['errors'].append(f"yogas-doshas: {e}") + # ── Step 5: 精确相位 ── try: from aspects import calc_all_aspects diff --git a/scripts/yogas_doshas.py b/scripts/yogas_doshas.py new file mode 100644 index 00000000..fbe6e54c --- /dev/null +++ b/scripts/yogas_doshas.py @@ -0,0 +1,623 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Yogas / Doshas / Special Lagnas 计算模块 v6.0.14 + +支持: + - Raj Yogas: 王者瑜伽(主星互涉形成权力格局) + - Dhana Yogas: 财富瑜伽(2/11宫主与吉星组合) + - Pancha Mahapurusha Yogas: 五王瑜伽(吉星在角宫入庙) + - Neecha Bhanga Raj Yoga: 落陷解除王者瑜伽 + - Mangal Dosha (Kuja Dosha): 火星煞(火星在1/2/4/7/8/12宫) + - Kaal Sarp Dosha: 时间蛇煞(所有行星在Rahu-Ketu轴线一侧) + - Pitra Dosha: 父辈煞(Sun与Rahu合相/受克) + - Sade Sati: 土星七年(土星过Moon前后各1星座) + - Arudha Lagna (AL): 镜像上升(从Lagna看Lagna主的落点) + - Upapada Lagna (UL): 配偶镜像上升(从12宫看12宫主的落点) +""" + +from typing import Dict, List, Tuple, Optional + +SIGNS = ['Aries','Taurus','Gemini','Cancer','Leo','Virgo', + 'Libra','Scorpio','Sagittarius','Capricorn','Aquarius','Pisces'] +SIGN_LORDS = {'Aries':'Mars','Taurus':'Venus','Gemini':'Mercury','Cancer':'Moon', + 'Leo':'Sun','Virgo':'Mercury','Libra':'Venus','Scorpio':'Mars', + 'Sagittarius':'Jupiter','Capricorn':'Saturn','Aquarius':'Saturn','Pisces':'Jupiter'} + +# 吉星/凶星分类 +NATURAL_BENEFICS = {'Jupiter', 'Venus', 'Mercury', 'Moon'} +NATURAL_MALEFICS = {'Saturn', 'Mars', 'Sun', 'Rahu', 'Ketu'} + + +def calc_raj_yogas(planets_data: Dict, houses: Dict) -> Dict: + """ + 计算 Raj Yogas(王者瑜伽)——权力、地位、社会影响力格局 + + 经典 Raj Yoga 形成条件: + 1. 角宫主(1/4/7/10宫主)与三方宫主(5/9宫主)结合 + 2. 角宫主与角宫主结合 + 3. 三方宫主与三方宫主结合 + 4. 以上组合发生在角宫/三方宫/11宫 + + 返回:检测到的 Raj Yogas 列表 + """ + results = {'yogas': [], 'summary': ''} + + # 提取宫主星信息 + house_lords = {} + for h in range(1, 13): + lord_key = f'H{h}_Lord' + if lord_key in houses: + house_lords[h] = houses[lord_key] + + # 检查每对宫主星的组合 + kendras = [1, 4, 7, 10] # 角宫 + trikonas = [5, 9] # 三方宫 + + def _get_lord_sign_lord(house_num): + """获取某宫宫主星及其所在宫位""" + lkey = f'H{house_num}_Lord' + if lkey not in houses: + return None, None + lord = houses[lkey] + # 找lord在哪里(简化:返回lord所在宫位) + for pname, pdata in planets_data.items(): + if pname == lord and isinstance(pdata, dict) and 'house' in pdata: + return lord, pdata['house'] + return lord, None + + # 检查条件1:角宫主 × 三方宫主 + for k_house in kendras: + for t_house in trikonas: + k_lord, k_lord_house = _get_lord_sign_lord(k_house) + t_lord, t_lord_house = _get_lord_sign_lord(t_house) + if not k_lord or not t_lord: + continue + + # 检查两主星是否在同一宫或互看对方宫 + # 简化:检查两主星所在宫位是否形成权力宫(角/三方/11) + if k_lord_house and t_lord_house: + power_houses = kendras + trikonas + [11] + if k_lord_house in power_houses or t_lord_house in power_houses: + yoga = { + 'type': 'Raj Yoga', + 'combination': f'H{k_house}_Lord({k_lord}) + H{t_house}_Lord({t_lord})', + 'formation_house': k_lord_house, + 'strength': 'strong' if k_lord_house in kendras else 'moderate', + 'interpretation': f'Raj Yoga——{k_lord}(H{k_house}主)与{t_lord}(H{t_house}主)结合,权力与地位格局', + } + results['yogas'].append(yoga) + + results['summary'] = f"Raj Yoga检测:共{len(results['yogas'])}个格局" + return results + + +def calc_dhana_yogas(planets_data: Dict, houses: Dict) -> Dict: + """ + 计算 Dhana Yogas(财富瑜伽)——财富积累格局 + + 经典 Dhana Yoga 形成条件: + 1. 2宫主(财富宫主)与吉星/11宫主结合 + 2. 11宫主(收益宫主)与吉星/2宫主结合 + 3. 以上组合发生在2/11/角宫/三方宫 + + 返回:检测到的 Dhana Yogas 列表 + """ + results = {'yogas': [], 'summary': ''} + + # 2宫主和11宫主 + h2_lord = houses.get('H2_Lord', '') + h11_lord = houses.get('H11_Lord', '') + + if not h2_lord or not h11_lord: + results['summary'] = 'Dhana Yoga检测:缺少2/11宫主信息' + return results + + # 检查2宫主和11宫主的组合 + # 找h2_lord和h11_lord的宫位 + h2_lord_house = None + h11_lord_house = None + for pname, pdata in planets_data.items(): + if pname == h2_lord and isinstance(pdata, dict) and 'house' in pdata: + h2_lord_house = pdata['house'] + if pname == h11_lord and isinstance(pdata, dict) and 'house' in pdata: + h11_lord_house = pdata['house'] + + if h2_lord_house and h11_lord_house: + wealth_houses = [2, 11, 1, 4, 7, 10, 5, 9] + if h2_lord_house in wealth_houses or h11_lord_house in wealth_houses: + yoga = { + 'type': 'Dhana Yoga', + 'combination': f'H2_Lord({h2_lord}) + H11_Lord({h11_lord})', + 'formation_house': h2_lord_house, + 'strength': 'strong' if h2_lord_house in [2, 11] else 'moderate', + 'interpretation': f'Dhana Yoga——{h2_lord}(H2主)与{h11_lord}(H11主)结合,财富积累格局', + } + results['yogas'].append(yoga) + + results['summary'] = f"Dhana Yoga检测:共{len(results['yogas'])}个格局" + return results + + +def calc_pancha_mahapurusha_yoga(planets_data: Dict) -> Dict: + """ + 计算 Pancha Mahapurusha Yogas(五王瑜伽) + + 条件:5颗吉星(Mars/Mercury/Jupiter/Venus/Saturn)在角宫(1/4/7/10) + 且入庙(在自家星座)或擢升(在擢升星座) + + 5种瑜伽: + - Ruchaka Yoga: Mars在角宫入庙/擢升 + - Bhadra Yoga: Mercury在角宫入庙/擢升 + - Hamsa Yoga: Jupiter在角宫入庙/擢升 + - Malavya Yoga: Venus在角宫入庙/擢升 + - Sasa Yoga: Saturn在角宫入庙/擢升 + """ + results = {'yogas': [], 'summary': ''} + + # 擢升星座表 + exaltation = {'Mars': 'Capricorn', 'Mercury': 'Virgo', 'Jupiter': 'Cancer', + 'Venus': 'Pisces', 'Saturn': 'Libra'} + # 入庙星座表 + own_sign = {'Mars': ['Aries', 'Scorpio'], 'Mercury': ['Gemini', 'Virgo'], + 'Jupiter': ['Sagittarius', 'Pisces'], 'Venus': ['Taurus', 'Libra'], + 'Saturn': ['Capricorn', 'Aquarius']} + + for pname in ['Mars', 'Mercury', 'Jupiter', 'Venus', 'Saturn']: + pdata = planets_data.get(pname, {}) + if not isinstance(pdata, dict) or 'house' not in pdata: + continue + + house = pdata['house'] + sign = pdata.get('sign', '') + + # 检查是否在角宫 + if house not in [1, 4, 7, 10]: + continue + + # 检查是否入庙或擢升 + is_exalted = (sign == exaltation.get(pname, '')) + is_own = (sign in own_sign.get(pname, [])) + + if is_exalted or is_own: + yoga_names = { + 'Mars': 'Ruchaka Yoga', 'Mercury': 'Bhadra Yoga', + 'Jupiter': 'Hamsa Yoga', 'Venus': 'Malavya Yoga', + 'Saturn': 'Sasa Yoga', + } + yoga = { + 'type': yoga_names[pname], + 'planet': pname, + 'house': house, + 'sign': sign, + 'status': 'exalted' if is_exalted else 'own_sign', + 'strength': 'very strong' if is_exalted else 'strong', + 'interpretation': f'{yoga_names[pname]}——{pname}在{house}宫{sign}({"擢升" if is_exalted else "入庙"}),五王瑜伽之一', + } + results['yogas'].append(yoga) + + results['summary'] = f"Pancha Mahapurusha Yoga检测:共{len(results['yogas'])}个(最多5个)" + return results + + +def calc_nicha_bhanga_raj_yoga(planets_data: Dict, houses: Dict) -> Dict: + """ + 计算 Neecha Bhanga Raj Yoga(落陷解除王者瑜伽) + + 条件(需同时满足): + 1. 某行星落陷(在落陷星座) + 2. 该行星的落陷星座主星在某个角宫/三方宫 + 3. 或者:落陷星座主星与落陷行星形成互容 + + 经典:落陷+落陷解除 = 王者瑜伽(先抑后扬,大器晚成) + """ + results = {'yogas': [], 'summary': ''} + + # 落陷星座表 + debilitation = {'Mars': 'Cancer', 'Mercury': 'Pisces', 'Jupiter': 'Capricorn', + 'Venus': 'Virgo', 'Saturn': 'Aries', 'Sun': 'Libra', + 'Moon': 'Scorpio'} + + for pname, deb_sign in debilitation.items(): + pdata = planets_data.get(pname, {}) + if not isinstance(pdata, dict) or 'sign' not in pdata: + continue + + sign = pdata['sign'] + if sign != deb_sign: + continue # 没落陷 + + # 检查落陷解除条件: + # 条件A:落陷星座主星在角宫/三方宫 + deb_lord = SIGN_LORDS.get(deb_sign, '') + deb_lord_data = planets_data.get(deb_lord, {}) + deb_lord_house = deb_lord_data.get('house') if isinstance(deb_lord_data, dict) else None + + condition_met = False + if deb_lord_house and deb_lord_house in [1, 4, 7, 10, 5, 9]: + condition_met = True + + # 条件B:落陷行星与落陷星座主星互容(在两星星座中) + # 简化:检查两星是否在同一宫 + p_house = pdata.get('house') + if deb_lord_house and p_house and deb_lord_house == p_house: + condition_met = True + + if condition_met: + yoga = { + 'type': 'Neecha Bhanga Raj Yoga', + 'planet': pname, + 'debilitated_sign': deb_sign, + 'debility_lord': deb_lord, + 'lord_house': deb_lord_house, + 'interpretation': f'Neecha Bhanga Raj Yoga——{pname}在{deb_sign}落陷但解除({deb_lord}在{deb_lord_house}宫),先抑后扬大器晚成', + } + results['yogas'].append(yoga) + + results['summary'] = f"Neecha Bhanga Raj Yoga检测:共{len(results['yogas'])}个" + return results + + +def calc_mangal_dosha(planets_data: Dict, mars_house: int) -> Dict: + """ + 计算 Mangal Dosha / Kuja Dosha(火星煞) + + 规则:Mars在1/2/4/7/8/12宫 → Mangal Dosha + 影响:婚姻延迟/困难,配偶健康 issues + + 缓和条件: + - Mars在自身星座(Aries/Scorpio)→ 部分缓和 + - Mars擢升(Capricorn)→ 完全解除 + - 第七宫/第七宫主有吉星→ 部分缓和 + - 双鱼/巨蟹上升 → 更麻烦(Mars在这些星座更凶) + """ + results = {'has_dosha': False, 'severity': 'none', 'remedies': []} + + bad_houses = [1, 2, 4, 7, 8, 12] + if mars_house not in bad_houses: + results['summary'] = '无Mangal Dosha(Mars不在煞宫)' + return results + + results['has_dosha'] = True + mars_data = planets_data.get('Mars', {}) + mars_sign = mars_data.get('sign', '') if isinstance(mars_data, dict) else '' + + # 判断严重程度 + if mars_house in [7, 8]: + results['severity'] = 'high' # 7/8宫最凶 + elif mars_house in [1, 2]: + results['severity'] = 'moderate' + else: + results['severity'] = 'low' + + # 检查缓和条件 + remedies = [] + if mars_sign in ['Aries', 'Scorpio']: + remedies.append('Mars在自身星座,部分缓和') + results['severity'] = 'moderate' if results['severity'] == 'high' else 'low' + if mars_sign == 'Capricorn': + remedies.append('Mars擢升,完全解除') + results['severity'] = 'none' + results['has_dosha'] = False + + results['remedies'] = remedies + results['mars_house'] = mars_house + results['mars_sign'] = mars_sign + results['summary'] = (f"{'无' if not results['has_dosha'] else '有'}Mangal Dosha——" + f"Mars在{mars_house}宫{mars_sign},严重程度:{results['severity']}") + return results + + +def calc_kaal_sarp_dosha(planets_data: Dict) -> Dict: + """ + 计算 Kaal Sarp Dosha(时间蛇煞) + + 规则:所有行星(除Rahu/Ketu外)都在Rahu-Ketu轴线的同一侧 + 形成"蛇吞"格局,带来阻碍、延迟、心理压力 + + 类型: + - 完全Kaal Sarp:所有行星在Rahu-Ketu之间(单一侧) + - 部分Kaal Sarp:大部分行星在Rahu-Ketu之间 + """ + results = {'has_dosha': False, 'type': 'none', 'affected_houses': []} + + rahu_data = planets_data.get('Rahu', {}) + ketu_data = planets_data.get('Ketu', {}) + + if not isinstance(rahu_data, dict) or 'house' not in rahu_data: + results['summary'] = 'Rahu位置未知,无法判断Kaal Sarp Dosha' + return results + + rahu_house = rahu_data['house'] + ketu_house = ketu_data.get('house', 0) if isinstance(ketu_data, dict) else 0 + + # 确定Rahu-Ketu轴线的"之间"范围 + # 简化处理:假设Rahu-Ketu在一条直线上(相差6宫) + axis_houses = list(range(rahu_house, rahu_house + 6)) + axis_houses = [(h - 1) % 12 + 1 for h in axis_houses] # 转为1-12 + + # 统计在"之间"的行星数量 + planets_in_axis = [] + planets_outside = [] + for pname in ['Sun', 'Moon', 'Mars', 'Mercury', 'Jupiter', 'Venus', 'Saturn']: + pdata = planets_data.get(pname, {}) + if not isinstance(pdata, dict) or 'house' not in pdata: + continue + p_house = pdata['house'] + if p_house in axis_houses: + planets_in_axis.append(pname) + else: + planets_outside.append(pname) + + total_planets = len(planets_in_axis) + len(planets_outside) + + if len(planets_in_axis) == total_planets and total_planets >= 7: + results['has_dosha'] = True + results['type'] = 'full' + results['summary'] = f'完全Kaal Sarp Dosha——所有{total_planets}颗行星在Rahu({rahu_house})—Ketu轴线之间' + elif len(planets_in_axis) >= total_planets * 0.7: + results['has_dosha'] = True + results['type'] = 'partial' + results['summary'] = f'部分Kaal Sarp Dosha——{len(planets_in_axis)}/{total_planets}颗行星在轴线之间' + else: + results['has_dosha'] = False + results['type'] = 'none' + results['summary'] = '无Kaal Sarp Dosha' + + results['planets_in_axis'] = planets_in_axis + results['planets_outside'] = planets_outside + results['rahu_house'] = rahu_house + results['ketu_house'] = ketu_house + return results + + +def calc_pitra_dosha(planets_data: Dict, sun_house: int) -> Dict: + """ + 计算 Pitra Dosha(父辈煞) + + 规则: + - Sun与Rahu合相(同宫或相邻宫)→ Pitra Dosha + - Sun受土星/火星克 → 可能Pitra Dosha + - 第9宫/第9宫主受克 → 父辈煞 + + 影响:父辈业力、祖先未解问题、子女健康/生育问题 + """ + results = {'has_dosha': False, 'indicators': []} + + sun_data = planets_data.get('Sun', {}) + rahu_data = planets_data.get('Rahu', {}) + + if not isinstance(sun_data, dict) or 'house' not in sun_data: + results['summary'] = 'Sun位置未知,无法判断Pitra Dosha' + return results + + sun_house = sun_data['house'] + sun_sign = sun_data.get('sign', '') + + # 检查Sun-Rahu合相 + if isinstance(rahu_data, dict) and 'house' in rahu_data: + rahu_house = rahu_data['house'] + if abs(sun_house - rahu_house) <= 1 or (sun_house == rahu_house): + results['has_dosha'] = True + results['indicators'].append(f'Sun({sun_house}宫)与Rahu({rahu_house}宫)合相/相邻') + + # 检查Sun受克(土星/火星在Sun宫或相邻宫) + for malefic in ['Saturn', 'Mars']: + mdata = planets_data.get(malefic, {}) + if isinstance(mdata, dict) and 'house' in mdata: + m_house = mdata['house'] + if abs(sun_house - m_house) <= 1: + results['has_dosha'] = True + results['indicators'].append(f'{malefic}({m_house}宫)克Sun({sun_house}宫)') + + results['sun_house'] = sun_house + results['sun_sign'] = sun_sign + if not results['indicators']: + results['summary'] = '无Pitra Dosha明显迹象' + else: + results['summary'] = f'有Pitra Dosha迹象:{"; ".join(results["indicators"][:2])}' + return results + + +def calc_sade_sati(moon_sign: str, current_year: int = 2026) -> Dict: + """ + 计算 Sade Sati(土星七年) + + 规则:土星过Moon所在星座及其前后各1星座,共约7.5年 + 每个阶段影响不同: + - 第一阶段(土星过前一星座):心理压力开始 + - 第二阶段(土星过Moon星座):最困难,健康/关系/事业挑战 + - 第三阶段(土星过后一星座):压力缓解,但有收获 + + 参数:moon_sign(Moon星座),current_year(当前年份,用于判断是否在进行中) + + 返回:Sade Sati阶段信息 + """ + results = {'is_active': False, 'phase': 'none', 'summary': ''} + + if not moon_sign or moon_sign not in SIGNS: + results['summary'] = 'Moon星座未知,无法判断Sade Sati' + return results + + moon_idx = SIGNS.index(moon_sign) + + # 简化:只判断当前年份Saturn是否在Moon前后1星座 + # 实际需要Saturn实时位置,这里只给框架 + results['moon_sign'] = moon_sign + results['moon_idx'] = moon_idx + results['phases'] = { + 'rising': SIGNS[(moon_idx - 1) % 12], # 前一星座 + 'peak': moon_sign, # Moon星座(最困难) + 'setting': SIGNS[(moon_idx + 1) % 12], # 后一星座 + } + results['summary'] = (f'Sade Sati阶段框架:上升期={results["phases"]["rising"]},' + f'高峰期={results["phases"]["peak"]}(最困难),' + f'下降期={results["phases"]["setting"]};' + f'需结合Saturn实际位置判断是否在进行中') + return results + + +def calc_arudha_lagna(asc_sign: str, asc_lord: str, planets_data: Dict) -> Dict: + """ + 计算 Arudha Lagna (AL) —— 镜像上升点 + + 规则:从Lagna(上升)看Lagna Lord(上升主星)的落点, + 再从该落点的"镜像位置"得到AL + 公式:AL = 从Asc看Lord的宫位数,再同样宫位数从Lord往外数 + + 例子:Asc=Leo, Lord=Sun在10宫 → 从Asc(1)看Sun(10) = 9宫远 + 从Sun(10)再数9宫 = 10+9-1=18 → 18-12=6宫 → AL在6宫 + + 意义:AL代表"他人如何看待命主",镜像自我认知 + """ + results = {'arudha_lagna': None, 'al_house': None, 'interpretation': ''} + + if not asc_sign or asc_sign not in SIGNS: + results['summary'] = 'Asc星座未知,无法计算Arudha Lagna' + return results + + asc_idx = SIGNS.index(asc_sign) + + # 找Asc Lord的宫位 + lord_data = planets_data.get(asc_lord, {}) + if not isinstance(lord_data, dict) or 'house' not in lord_data: + results['summary'] = f'Asc Lord({asc_lord})宫位未知,无法计算AL' + return results + + lord_house = lord_data['house'] # 1-12 + lord_idx = (lord_house - 1) # 转为0-11 + + # 计算镜像:从Asc到Lord的宫位数 = lord_idx - asc_idx (mod 12) + distance = (lord_idx - asc_idx) % 12 # 0-11 + if distance == 0: + distance = 12 # 同宫=12宫远 + + # AL = 从Lord再数同样距离 + al_idx = (lord_idx + distance) % 12 + al_house = al_idx + 1 # 转回1-12 + + al_sign = SIGNS[al_idx] + + results['arudha_lagna'] = al_sign + results['al_house'] = al_house + results['distance'] = distance + results['lord_house'] = lord_house + results['interpretation'] = ( + f'Arudha Lagna (AL) = {al_sign}(第{al_house}宫)——' + f'他人眼中的你;Asc={asc_sign}, Lord={asc_lord}在{lord_house}宫,距离={distance}' + ) + results['summary'] = results['interpretation'] + return results + + +def calc_upapada_lagna(asc_sign: str, house12_lord: str, planets_data: Dict) -> Dict: + """ + 计算 Upapada Lagna (UL) —— 配偶镜像上升点 + + 规则:从12宫(损失/海外/床事宫)看12宫主星的落点, + 镜像计算方式同Arudha Lagna + 公式:UL = 从12宫看12宫主星的宫位数,再从主星落点往外数同样宫位数 + + 意义:UL代表"配偶/婚姻伙伴",是婚姻质量的关键指标 + UL受克/受损 → 婚姻困难 + UL有吉星 → 婚姻幸福 + """ + results = {'upapada': None, 'ul_house': None, 'interpretation': ''} + + if not asc_sign or asc_sign not in SIGNS: + results['summary'] = 'Asc星座未知,无法计算Upapada' + return results + + asc_idx = SIGNS.index(asc_sign) + h12_idx = (asc_idx + 11) % 12 # 12宫 index (0-11) + + # 找12宫主星的宫位 + lord_data = planets_data.get(house12_lord, {}) + if not isinstance(lord_data, dict) or 'house' not in lord_data: + results['summary'] = f'12宫主星({house12_lord})宫位未知,无法计算UL' + return results + + lord_house = lord_data['house'] # 1-12 + lord_idx = (lord_house - 1) # 0-11 + + # 计算镜像:从12宫到12宫主星的宫位数 + distance = (lord_idx - h12_idx) % 12 + if distance == 0: + distance = 12 + + # UL = 从Lord再数同样距离 + ul_idx = (lord_idx + distance) % 12 + ul_house = ul_idx + 1 + + ul_sign = SIGNS[ul_idx] + + results['upapada'] = ul_sign + results['ul_house'] = ul_house + results['distance'] = distance + results['lord_house'] = lord_house + results['interpretation'] = ( + f'Upapada Lagna (UL) = {ul_sign}(第{ul_house}宫)——' + f'配偶/婚姻质量指标;12宫主星={house12_lord}在{lord_house}宫,距离={distance}' + ) + results['summary'] = results['interpretation'] + return results + + +def calc_all_yogas_doshas(planets_data: Dict, houses: Dict, + asc_sign: str, asc_lord: str, + moon_sign: str, moon_house: int, + mars_house: int, sun_house: int, + house12_lord: str) -> Dict: + """ + 批量计算所有 Yogas + Doshas + Special Lagnas(v6.0.14 主入口) + + 参数: + planets_data: 行星数据字典 + houses: 宫位信息字典 + asc_sign: 上升星座 + asc_lord: 上升主星 + moon_sign: Moon星座 + moon_house: Moon宫位 + mars_house: Mars宫位 + sun_house: Sun宫位 + house12_lord: 12宫主星 + + 返回:完整结果字典 + """ + results = {} + + # Yogas + results['raj_yogas'] = calc_raj_yogas(planets_data, houses) + results['dhana_yogas'] = calc_dhana_yogas(planets_data, houses) + results['pancha_mahapurusha'] = calc_pancha_mahapurusha_yoga(planets_data) + results['nicha_bhanga_raj'] = calc_nicha_bhanga_raj_yoga(planets_data, houses) + + # Doshas + results['mangal_dosha'] = calc_mangal_dosha(planets_data, mars_house) + results['kaal_sarp_dosha'] = calc_kaal_sarp_dosha(planets_data) + results['pitra_dosha'] = calc_pitra_dosha(planets_data, sun_house) + results['sade_sati'] = calc_sade_sati(moon_sign) + + # Special Lagnas + results['arudha_lagna'] = calc_arudha_lagna(asc_sign, asc_lord, planets_data) + results['upapada_lagna'] = calc_upapada_lagna(asc_sign, house12_lord, planets_data) + + # 总结 + total_yogas_count = (len(results['raj_yogas']['yogas']) + + len(results['dhana_yogas']['yogas']) + + len(results['pancha_mahapurusha']['yogas']) + + len(results['nicha_bhanga_raj']['yogas'])) + has_dosha = any([ + results['mangal_dosha']['has_dosha'], + results['kaal_sarp_dosha']['has_dosha'], + results['pitra_dosha']['has_dosha'], + ]) + + results['summary'] = ( + f"Yogas共{total_yoga_count}个;" + f"Doshas: Mangal={'有' if results['mangal_dosha']['has_dosha'] else '无'}" + f"/Kaal Sarp={'有' if results['kaal_sarp_dosha']['has_dosha'] else '无'}" + f"/Pitra={'有' if results['pitra_dosha']['has_dosha'] else '无'}" + ) + + return results