Files
Jyotisha/scripts/curse_yoga_detector.py
T
732642856 0f0c5dbdfa v6.1.0: Add 6 core missing modules + infrastructure
New modules (from Chinese reference articles):
- darakaraka_reader.py: DK spouse deep analysis (planet/sign/house/aspects)
- rashi_tulya_navamsa.py: RTN mapping engine (D9->D1, Gunas, curse detection)
- curse_yoga_detector.py: Curse yoga naming (Yama/Preta/Rakshasa/Pisacha)
- spouse_status_yoga.py: High-status spouse detection (7 principles)
- pancha_pakshi.py: Five-bird electional timing (daily schedule)
- tithi_analyzer.py: Tithi lord emotional pattern analysis

Infrastructure:
- technique_registry.py: Unified technique registry (31 techniques tracked)
- reading_orchestrator.py: Theme-based reading orchestrator (5 themes)

All 6 modules tested and runnable.
Current baseline: Precision 94.66%, Recall 92.95%, F1 93.80%
2026-06-07 12:11:15 +08:00

490 lines
19 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
curse_yoga_detector.py — 凶星合相命名与检测引擎
================================================
检测并命名危险的行星合相,提供预警和补救建议
版本: v1.0 | 2026-06-07
"""
from typing import Dict, List, Optional, Tuple
from dataclasses import dataclass, field
# 凶星合相定义
CURSE_DEFINITIONS = {
"yama_yoga": {
"name": "Yama Yoga",
"name_cn": "阎魔瑜伽",
"planets": ["Mars", "Saturn"],
"houses_critical": [1, 2, 7, 8, 12], # 在这些宫位更危险
"meaning": "死亡之神 sitting,等待激活。可能造成危险疾病、事故、家族血脉中断。",
"activation": ["Mars或Saturn的Dasha", "Mars或Saturn的Transit", "Mula Dasha激活"],
"severity": 5, # 1-5
"remedy": "需要上师保护,唱诵Guru Vandana,侍奉上师",
"deity": "上师/Guru",
"body_parts": ["血液", "骨骼", "神经系统"],
"family_effect": "家族血脉可能中断,无子女或子女早夭",
},
"preta_yoga_saturn_rahu": {
"name": "Preta Yoga",
"name_cn": "亡灵瑜伽(土星+罗喉)",
"planets": ["Saturn", "Rahu"],
"houses_critical": [8, 11, 6], # 8宫=死亡,11宫=Badhaka6宫=疾病
"meaning": "过早死亡风险,慢性疾病,可能来自祖先未解决的业力(未得葬礼的祖先鬼魂)。",
"activation": ["Saturn或Rahu的Dasha", "Badhaka宫被激活", "水瓶座相关事件"],
"severity": 5,
"remedy": "湿婆能量,唱诵Mahamrityunjaya Mantra,进行祖先祭祀",
"deity": "湿婆/Shiva",
"body_parts": ["慢性疾病部位", "骨骼", "神经系统退化"],
"family_effect": "家族血脉停止,女性不婚或无子女,男性只有女儿",
},
"preta_yoga_saturn_ketu": {
"name": "Preta Yoga",
"name_cn": "亡灵瑜伽(土星+计都)",
"planets": ["Saturn", "Ketu"],
"houses_critical": [8, 11, 6],
"meaning": "过早死亡风险,慢性疾病,灵性干扰,可能来自祖先业力。",
"activation": ["Saturn或Ketu的Dasha", "灵性敏感期"],
"severity": 5,
"remedy": "湿婆能量,唱诵Mahamrityunjaya Mantra,火供",
"deity": "湿婆/Shiva",
"body_parts": ["慢性疾病", "灵性困扰", "睡眠障碍"],
"family_effect": "家族业力传递,后代受影响",
},
"rakshasa_yoga": {
"name": "Rakshasa Yoga",
"name_cn": "恶魔瑜伽",
"planets": ["Mars", "Rahu"],
"houses_critical": [6, 8], # 6宫=暴力/疾病,8宫=突变/死亡
"meaning": "暴力事件,外部攻击,神经系统受损,可能被粗俗或微妙的恶魔力量攻击。",
"activation": ["Mars或Rahu的Dasha", "6宫或8宫被Transit激活"],
"severity": 4,
"remedy": "杜尔迦女神,唱诵Durga Saptashati,建立界限",
"deity": "杜尔迦/Durga",
"body_parts": ["神经系统", "肌肉", "免疫系统"],
"family_effect": "家族成员可能遭受暴力或事故",
},
"pisacha_yoga": {
"name": "Pisacha Yoga",
"name_cn": "鬼魅瑜伽",
"planets": ["Mars", "Ketu"],
"houses_critical": [8, 1, 6], # 8宫=死亡,1宫=身体,6宫=疾病
"meaning": "与有毒的人接触,被充满愤怒仇恨的鬼魂困扰,可能遭遇事故前感到被推动。",
"activation": ["Mars或Ketu的Dasha", "天蝎座相关事件", "8宫被激活"],
"severity": 4,
"remedy": "毗湿奴,唱诵Vishnu Sahasranama,去除毒素",
"deity": "毗湿奴/Vishnu",
"body_parts": ["血液", "毒素", "生殖系统"],
"family_effect": "与有毒人物的关系,婚姻中毒性伴侣",
},
}
# 宫位拟人化(哪个身体部位/生活领域受影响)
HOUSE_PERSONIFICATION = {
1: "自身/身体/个性",
2: "家庭/财富/语言能力",
3: "兄弟姐妹/勇气/沟通",
4: "母亲/房产/内心",
5: "子女/创造力/投机",
6: "疾病/敌人/服务",
7: "配偶/合作/公开对手",
8: "死亡/突变/遗产/灵性",
9: "父亲/长途旅行/高等教育",
10: "事业/社会地位/母亲",
11: "收益/愿望/社交网络",
12: "损失/隐秘/灵性/海外",
}
# 行星拟人化(如果某行星在此位置,代表谁变得有毒/危险)
PLANET_PERSONIFICATION = {
"Sun": "父亲/权威人物",
"Moon": "母亲/情感滋养者",
"Mars": "兄弟/竞争对手/行动者",
"Mercury": "兄弟姐妹/年轻亲戚/商人",
"Jupiter": "导师/子女/丈夫(女性)",
"Venus": "配偶/妻子(男性)/艺术家",
"Saturn": "长辈/仆人/苦行者",
"Rahu": "外国人/非传统人物/野心家",
"Ketu": "灵性导师/分离者/神秘人物",
}
@dataclass
class CurseDetection:
"""单个诅咒检测结果"""
curse_type: str # yama/preta/rakshasa/pisacha
curse_name: str
curse_name_cn: str
planets: List[str]
house: int
house_meaning: str
sign: str
# 严重程度
severity: int # 1-5
severity_label: str # critical/high/medium/low
# 影响范围
affected_area: str # 影响的宫位主题
affected_person: str # 可能受影响的人(拟人化)
body_parts: List[str]
family_effect: str
# 激活条件
activation_triggers: List[str]
current_dasha_relevant: bool # 当前Dasha是否相关
transit_relevant: bool # 当前Transit是否相关
# 补救
remedy: str
deity: str
mantras: List[str]
# 叙事
narrative: str = ""
@dataclass
class CurseAnalysis:
"""诅咒分析结果"""
curses_detected: List[CurseDetection] = field(default_factory=list)
overall_risk: str = "low" # low/medium/high/critical
risk_score: float = 0.0 # 0-1
# 综合建议
general_remedies: List[str] = field(default_factory=list)
general_mantras: List[str] = field(default_factory=list)
lifestyle_advice: List[str] = field(default_factory=list)
# 时间预警
upcoming_danger_periods: List[Dict] = field(default_factory=list)
narrative: str = ""
class CurseYogaDetector:
"""凶星合相命名与检测引擎"""
def __init__(self):
self.definitions = CURSE_DEFINITIONS
self.house_person = HOUSE_PERSONIFICATION
self.planet_person = PLANET_PERSONIFICATION
def analyze(self, chart_data: Dict, current_dasha: Optional[str] = None,
transit_data: Optional[Dict] = None) -> CurseAnalysis:
"""
检测凶星合相
Args:
chart_data: 标准星盘数据
current_dasha: 当前Dasha主星(可选)
transit_data: 当前Transit数据(可选)
Returns:
CurseAnalysis对象
"""
planets = chart_data.get("planets", {})
asc_sign = chart_data.get("ascendant", {}).get("sign", "")
analysis = CurseAnalysis()
# Step 1: 在D1中检测
d1_curses = self._detect_in_chart(planets, "D1")
analysis.curses_detected.extend(d1_curses)
# Step 2: 在D9中检测(如果有)
context = chart_data.get("context", {})
d9_planets = context.get("navamsa_planets", {})
if d9_planets:
d9_curses = self._detect_in_chart(d9_planets, "D9")
for c in d9_curses:
c.narrative = f"[Navamsa] {c.narrative}"
analysis.curses_detected.extend(d9_curses)
# Step 3: 评估与当前Dasha/Transit的关联
if current_dasha:
self._assess_dasha_relevance(analysis, current_dasha)
# Step 4: 综合评估
self._comprehensive_assessment(analysis)
# Step 5: 生成建议
self._generate_remedies(analysis)
# Step 6: 生成叙事
analysis.narrative = self._generate_narrative(analysis)
return analysis
def _detect_in_chart(self, planets: Dict, chart_name: str) -> List[CurseDetection]:
"""在单个星盘中检测诅咒Yoga"""
detected = []
# 将行星按宫位分组
house_planets = {}
for pname, pdata in planets.items():
if not isinstance(pdata, dict):
continue
house = pdata.get("house", 0)
if house not in house_planets:
house_planets[house] = []
house_planets[house].append((pname, pdata))
# 在每个宫位检查诅咒合相
for house, plists in house_planets.items():
if len(plists) < 2:
continue
planet_names = [p[0] for p in plists]
sign = plists[0][1].get("sign", "")
# 检查所有行星对
for i, (p1, data1) in enumerate(plists):
for p2, data2 in plists[i+1:]:
pair = tuple(sorted([p1, p2]))
# 匹配诅咒定义
for curse_id, definition in self.definitions.items():
def_planets = definition["planets"]
if set(pair) == set(def_planets):
detection = self._create_detection(
curse_id, definition, pair, house, sign, chart_name
)
detected.append(detection)
return detected
def _create_detection(self, curse_id: str, definition: Dict,
planets: Tuple[str, ...], house: int,
sign: str, chart_name: str) -> CurseDetection:
"""创建单个检测结果"""
severity = definition["severity"]
severity_label = "critical" if severity >= 5 else "high" if severity >= 4 else "medium"
# 如果在危险宫位,提高严重程度
if house in definition.get("houses_critical", []):
severity = min(severity + 1, 5)
severity_label = "critical"
# 确定受影响的人
affected_person = ""
for p in planets:
if p in self.planet_person:
affected_person = self.planet_person[p]
break
return CurseDetection(
curse_type=curse_id,
curse_name=definition["name"],
curse_name_cn=definition["name_cn"],
planets=list(planets),
house=house,
house_meaning=self.house_person.get(house, ""),
sign=sign,
severity=severity,
severity_label=severity_label,
affected_area=self.house_person.get(house, ""),
affected_person=affected_person,
body_parts=definition.get("body_parts", []),
family_effect=definition.get("family_effect", ""),
activation_triggers=definition.get("activation", []),
current_dasha_relevant=False,
transit_relevant=False,
remedy=definition.get("remedy", ""),
deity=definition.get("deity", ""),
mantras=self._get_mantras(definition.get("deity", "")),
narrative=f"[{chart_name}] 在{sign}{house}宫发现 {definition['name']} ({definition['name_cn']})",
)
def _get_mantras(self, deity: str) -> List[str]:
"""获取对应神祇的咒语"""
mantras = {
"上师/Guru": ["Om Guruve Namah", "Guru Vandana"],
"湿婆/Shiva": ["Om Namah Shivaya", "Mahamrityunjaya Mantra"],
"杜尔迦/Durga": ["Om Dum Durgayei Namah", "Durga Saptashati"],
"毗湿奴/Vishnu": ["Om Namo Bhagavate Vasudevaya", "Vishnu Sahasranama"],
}
return mantras.get(deity, ["Om Shanti Shanti Shanti"])
def _assess_dasha_relevance(self, analysis: CurseAnalysis, current_dasha: str):
"""评估与当前Dasha的关联"""
for curse in analysis.curses_detected:
# 如果当前Dasha主星是诅咒行星之一
if current_dasha in curse.planets:
curse.current_dasha_relevant = True
def _comprehensive_assessment(self, analysis: CurseAnalysis):
"""综合风险评估"""
if not analysis.curses_detected:
analysis.overall_risk = "low"
analysis.risk_score = 0.0
return
# 计算风险分数
max_severity = max(c.severity for c in analysis.curses_detected)
count = len(analysis.curses_detected)
dasha_active = sum(1 for c in analysis.curses_detected if c.current_dasha_relevant)
score = (max_severity / 5.0) * 0.4 + (min(count / 3.0, 1.0)) * 0.3 + (dasha_active / max(count, 1)) * 0.3
analysis.risk_score = min(score, 1.0)
if analysis.risk_score >= 0.8:
analysis.overall_risk = "critical"
elif analysis.risk_score >= 0.6:
analysis.overall_risk = "high"
elif analysis.risk_score >= 0.3:
analysis.overall_risk = "medium"
else:
analysis.overall_risk = "low"
def _generate_remedies(self, analysis: CurseAnalysis):
"""生成补救建议"""
# 收集所有涉及的神祇
deities = set(c.deity for c in analysis.curses_detected)
analysis.general_remedies = [
"定期进行冥想和灵性练习",
"保持Sattvic(纯善)的生活方式",
"避免Tamas(惰性)的活动和食物",
"佩戴适合的宝石(需咨询专业占星师)",
]
for deity in deities:
if "湿婆" in deity:
analysis.general_remedies.append("每周一进行湿婆礼拜")
elif "毗湿奴" in deity:
analysis.general_remedies.append("每周三/六进行毗湿奴礼拜")
elif "杜尔迦" in deity:
analysis.general_remedies.append("每周二/五进行杜尔迦礼拜")
analysis.lifestyle_advice = [
"避免与有毒的人接触",
"定期进行健康检查",
"在危险Dasha周期特别注意安全",
"保持规律的作息和饮食",
"参与慈善和志愿服务",
]
def _generate_narrative(self, analysis: CurseAnalysis) -> str:
"""生成叙事"""
parts = []
parts.append("### 凶星合相命名与危机预警\n")
if not analysis.curses_detected:
parts.append("✅ 未发现显著的凶星合相诅咒。\n")
parts.append("您的星盘在凶星合相方面相对安全。\n")
return "\n".join(parts)
# 风险等级
risk_labels = {
"critical": "🔴 严重",
"high": "🟠 高",
"medium": "🟡 中等",
"low": "🟢 低",
}
parts.append(f"\n**总体风险等级: {risk_labels.get(analysis.overall_risk, analysis.overall_risk)}** ({analysis.risk_score:.0%})\n")
# 逐个列出
for curse in analysis.curses_detected:
parts.append(f"\n---\n")
parts.append(f"#### {curse.curse_name} ({curse.curse_name_cn})\n")
parts.append(f"**涉及行星**: {', '.join(curse.planets)}\n")
parts.append(f"**位置**: {curse.sign}{curse.house}宫 ({curse.house_meaning})\n")
parts.append(f"**严重程度**: {'' * curse.severity}\n")
parts.append(f"**含义**: {self.definitions.get(curse.curse_type, {}).get('meaning', '')}\n")
if curse.current_dasha_relevant:
parts.append(f"⚠️ **当前Dasha与此诅咒相关,需特别注意!**\n")
if curse.affected_person:
parts.append(f"**可能影响的人**: {curse.affected_person}\n")
if curse.body_parts:
parts.append(f"**相关身体部位**: {', '.join(curse.body_parts)}\n")
if curse.family_effect:
parts.append(f"**家族影响**: {curse.family_effect}\n")
parts.append(f"**激活条件**: {'; '.join(curse.activation_triggers)}\n")
parts.append(f"**补救措施**: {curse.remedy}\n")
parts.append(f"**守护神祇**: {curse.deity}\n")
if curse.mantras:
parts.append(f"**推荐咒语**: {'; '.join(curse.mantras)}\n")
# 综合建议
if analysis.general_remedies:
parts.append(f"\n#### 综合补救建议\n")
for r in analysis.general_remedies:
parts.append(f"- {r}\n")
if analysis.lifestyle_advice:
parts.append(f"\n#### 生活方式建议\n")
for a in analysis.lifestyle_advice:
parts.append(f"- {a}\n")
return "\n".join(parts)
def to_dict(self, analysis: CurseAnalysis) -> Dict:
"""转换为字典"""
return {
"curses_detected": [
{
"type": c.curse_type,
"name": c.curse_name,
"name_cn": c.curse_name_cn,
"planets": c.planets,
"house": c.house,
"sign": c.sign,
"severity": c.severity,
"severity_label": c.severity_label,
"affected_area": c.affected_area,
"remedy": c.remedy,
"deity": c.deity,
}
for c in analysis.curses_detected
],
"overall_risk": analysis.overall_risk,
"risk_score": round(analysis.risk_score, 2),
"general_remedies": analysis.general_remedies,
"lifestyle_advice": analysis.lifestyle_advice,
"narrative": analysis.narrative,
}
# ============================================================================
# 便捷函数
# ============================================================================
def detect_curse_yogas(chart_data: Dict, current_dasha: Optional[str] = None) -> Dict:
"""便捷函数:检测凶星合相"""
detector = CurseYogaDetector()
analysis = detector.analyze(chart_data, current_dasha)
return detector.to_dict(analysis)
# ============================================================================
# CLI 调试
# ============================================================================
if __name__ == "__main__":
mock_chart = {
"ascendant": {"sign": "Capricorn"},
"planets": {
"Mars": {"sign": "Aquarius", "house": 2, "degree": 320},
"Saturn": {"sign": "Aquarius", "house": 2, "degree": 322},
"Rahu": {"sign": "Scorpio", "house": 11, "degree": 230},
"Ketu": {"sign": "Scorpio", "house": 11, "degree": 50},
},
}
print("=" * 60)
print("凶星合相命名与检测引擎")
print("=" * 60)
result = detect_curse_yogas(mock_chart, current_dasha="Saturn")
print(result["narrative"])
print(f"\n总体风险: {result['overall_risk']} ({result['risk_score']})")