v6.0.13: 新增 Tajika Yogas + Sahams 技法

- scripts/tajika.py: 新增 calc_tajika_yogas, calc_all_sahams 等6个函数
- scripts/jyotish_engine.py: cmd_full_reading 新增 Step 4.8 调用新函数
- references/technique_registry.json: 新增 tajika_yogas, sahams 技法注册(partial)
- references/strict-workflow-router.md: Audit Table 模板新增两行
- CHANGELOG.md: 新增 v6.0.13 条目
- SKILL.md: 版本号 6.0.12 → 6.0.13
This commit is contained in:
732642856
2026-06-04 04:35:44 +08:00
parent f6deae7a25
commit a20c13490c
6 changed files with 498 additions and 5 deletions
+24 -1
View File
@@ -1,6 +1,29 @@
# 印度占星 Skill 更新日志
## v6.0.12-dispositor-chain-inter-chart-linkage2026-06-04)—— 新增 Dispositor Chain + Inter-chart Linkage 技法
## v6.0.13-tajika-yogas-sahams2026-06-04)—— 新增 Tajika Yogas + Sahams 技法
> **触发原因**:用户指出当前 skill 缺少 Tajika YogasIthasala/Easarapha/Nakta/Yamaya/Manahoo/Graha Yuddha)和 SahamsPunya/Karya/Vivah/Rajya/Shatru/Labha/Parakrama)两个重要技法体系。
### 新增功能
- `scripts/tajika.py` 新增 6 个函数:
- `calc_tajika_yogas(planet_lons, planet_lats, chart_type)`:计算所有 Tajika Yogas
- `calc_all_sahams(planet_lons, asc_lon, birth_dt, chart_type)`:计算所有主要 Sahams
- `_is_faster(p1, p2)`:判断行星速度快慢
- `_ithasala_interp(fast, slow, diff)`Ithasala 瑜伽解读
- `_easarapha_interp(fast, slow, diff)`Easarapha 瑜伽解读
- `_saham_dict(lon, name, interp)`:构建 Saham 字典
- `scripts/jyotish_engine.py``cmd_full_reading` 新增 Step 4.8:调用 `calc_tajika_yogas``calc_all_sahams`,输出 `modules.tajika_yogas``modules.sahams`
- `references/technique_registry.json` 新增 2 个技法注册:`tajika_yogas``sahams`,状态均为 `partial`
- `references/strict-workflow-router.md` 同步更新:Technique Audit Table 模板新增 `Tajika Yogas``Sahams` 两行
### 验证结果
- Python 语法检查通过
- tajika.py 函数测试:`calc_tajika_yogas` 检测到 2 个格局(Nakta + Manahoo),`calc_all_sahams` 计算出 7 个 Saham 点
- `full-reading` 集成测试:待运行(需要 pyswisseph 环境)
----dispositor-chain-inter-chart-linkage2026-06-04)—— 新增 Dispositor Chain + Inter-chart Linkage 技法
> **触发原因**:用户指出当前 skill 缺少"定位星链"和"分盘间飞星落宫"两个高级技法,导致事业/婚恋/财务等解盘无法完整分析行星能量流向和分盘间验证。
+1 -1
View File
@@ -1,6 +1,6 @@
---
name: jyotish-vedic-astrology
version: 6.0.12
version: 6.0.13
description: 印度占星(Jyotish)专业解盘与推运系统。核心能力:PDF星盘输入→严谨解盘→精确推运应期输出。触发词:印度占星、吠陀占星、Jyotish、解盘、推运、星盘分析、Dasha、Transit、Nakshatra、Yoga、出生时间矫正、PDF星盘、读取PDF、分析PDF星盘、现代解读、误判纠错、Varga分盘、综合分析、过境分析、合盘、婚姻匹配、年运盘、Prashna、Argala、Jaimini、KP系统、Shadbala、Ashtakavarga、HTML报告、深度解盘。
---
+2
View File
@@ -173,6 +173,8 @@ Every Level 2+ output must include this table near the end.
| Ashtakavarga | Used / not used | ... | ... |
| Dispositor Chain | Used / not used | ... | ... |
| 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 |
| Argala | Used / not used | ... | ... |
| KP / Sub-lord | Used / not required / unavailable | ... | ... |
| Historical verification | Used / not provided | ... | ... |
+47 -3
View File
@@ -398,6 +398,44 @@
],
"audit_label": "Inter-chart Linkage",
"missing_impact": "Cross-chart planet linkage (D1->D9->D10) analysis incomplete."
},
"tajika_yogas": {
"name": "Tajika Yogas / 年运盘格局",
"domains": [
"tajika",
"timing",
"event",
"yoga"
],
"status": "partial",
"knowledge_refs": [],
"commands": [
"full-reading"
],
"output_paths": [
"modules.tajika_yogas"
],
"audit_label": "Tajika Yogas",
"missing_impact": "Tajika year-chart yoga detection incomplete; annual timing confidence capped."
},
"sahams": {
"name": "Sahams / 特殊点",
"domains": [
"saham",
"timing",
"event",
"tajika"
],
"status": "partial",
"knowledge_refs": [],
"commands": [
"full-reading"
],
"output_paths": [
"modules.sahams"
],
"audit_label": "Sahams",
"missing_impact": "Saham point calculation incomplete; annual/event timing layer missing."
}
},
"routes": {
@@ -425,7 +463,9 @@
"vargottama",
"pushkara",
"dispositor_chain",
"inter_chart_linkage"
"inter_chart_linkage",
"tajika_yogas",
"sahams"
],
"optional_techniques": [
"bhava_chalit",
@@ -449,7 +489,9 @@
"shadbala",
"ashtakavarga",
"dispositor_chain",
"inter_chart_linkage"
"inter_chart_linkage",
"tajika_yogas",
"sahams"
],
"optional_techniques": [
"d9_navamsa",
@@ -479,7 +521,9 @@
"vargottama",
"pushkara",
"dispositor_chain",
"inter_chart_linkage"
"inter_chart_linkage",
"tajika_yogas",
"sahams"
],
"optional_techniques": [
"bhava_chalit",
+19
View File
@@ -3454,6 +3454,25 @@ def cmd_full_reading(args):
except Exception as e:
report['errors'].append(f"dispositor-chain+inter-chart: {e}")
# ── Step 4.8: Tajika Yogas + Sahams (v6.0.13) ──
try:
from tajika import calc_tajika_yogas, calc_all_sahams
# Tajika Yogas(用本命盘行星经度)
tc_yogas = calc_tajika_yogas(planet_lons)
report['modules']['tajika_yogas'] = tc_yogas
# Sahams(特殊点)—— 需要出生时间
birth_dt = getattr(args, 'birth_datetime', None)
if birth_dt and planet_lons:
sahams_result = calc_all_sahams(planet_lons, asc_deg, birth_dt)
report['modules']['sahams'] = sahams_result
else:
report['modules']['sahams'] = {'warning': 'birth_datetime or planet_lons missing, skip saham calc'}
except Exception as e:
report['errors'].append(f"tajika-yogas+sahams: {e}")
# ── Step 5: 精确相位 ──
try:
from aspects import calc_all_aspects
+405
View File
@@ -237,3 +237,408 @@ def _year_theme(lord):
'Saturn': '纪律、长寿、建筑、责任',
}
return themes.get(lord, '')
# ============================================================================
# Tajika Yogas(年运盘特殊格局)—— v6.0.13 新增
# ============================================================================
def calc_tajika_yogas(planet_lons: Dict[str, float],
planet_lats: Optional[Dict[str, float]] = None,
chart_type: str = 'varsha') -> Dict:
"""
计算 Tajika Yogas年运盘特殊格局
参数:
planet_lons: 行星经度字典 {行星名: 经度(0-360)}
planet_lats: 行星纬度字典可选用于部分Yoga
chart_type: 'varsha'年运盘 'natal'本命盘
返回:
{
'yogas': [...], # 检测到的Yogas列表
'ithasala': [...], # Ithasala连接瑜伽
'easarapha': [...], # Easarapha分离瑜伽
'nakta': None, # Nakta夜间瑜伽
'yamaya': [...], # Yamaya双重瑜伽
'manahoo': [...], # Manahoo特殊组合
'graha_yuddha': [...], # Graha Yuddha行星战争
'summary': str, # 总结
}
"""
if planet_lats is None:
planet_lats = {}
Planet_LIST = ['Sun', 'Moon', 'Mars', 'Mercury', 'Jupiter', 'Venus', 'Saturn', 'Rahu', 'Ketu']
results = {
'yogas': [],
'ithasala': [],
'easarapha': [],
'nakta': None,
'yamaya': [],
'manahoo': [],
'graha_yuddha': [],
'summary': '',
}
# ── 1. Ithasala Yoga(连接瑜伽)──
# 定义:两行星同星座,快行星追慢行星(apply),度数差<=3度
for i, p1 in enumerate(Planet_LIST):
if p1 not in planet_lons:
continue
for p2 in Planet_LIST[i+1:]:
if p2 not in planet_lons:
continue
lon1, lon2 = planet_lons[p1], planet_lons[p2]
sign1 = int(lon1 / 30) % 12
sign2 = int(lon2 / 30) % 12
if sign1 != sign2:
continue # 不同星座
diff = (lon2 - lon1) % 360
if diff > 180:
diff = 360 - diff
# 判断谁快谁慢(简化:按行星自然速度)
speed_order = ['Moon', 'Mercury', 'Venus', 'Mars', 'Jupiter', 'Saturn', 'Sun']
# Rahu/Ketu逆行,速度特殊
fast = p1 if _is_faster(p1, p2) else p2
slow = p2 if fast == p1 else p1
fast_lon = planet_lons[fast]
slow_lon = planet_lons[slow]
fast_diff = (fast_lon - slow_lon) % 360
if fast_diff > 180:
fast_diff = 360 - fast_diff
# Ithasala:快追慢,差<=3度
if fast_diff <= 3.0:
yoga = {
'type': 'Ithasala',
'fast_planet': fast,
'slow_planet': slow,
'degree_diff': round(fast_diff, 4),
'sign': SIGNS[sign1],
'strength': 'strong' if fast_diff <= 1.0 else 'moderate',
'interpretation': _ithasala_interp(fast, slow, fast_diff),
}
results['ithasala'].append(yoga)
results['yogas'].append(yoga)
# ── 2. Easarapha Yoga(分离瑜伽)──
# 定义:两行星同星座,快行星已离开慢行星(separate),度数差<=3度
for i, p1 in enumerate(Planet_LIST):
if p1 not in planet_lons:
continue
for p2 in Planet_LIST[i+1:]:
if p2 not in planet_lons:
continue
lon1, lon2 = planet_lons[p1], planet_lons[p2]
sign1 = int(lon1 / 30) % 12
sign2 = int(lon2 / 30) % 12
if sign1 != sign2:
continue
fast = p1 if _is_faster(p1, p2) else p2
slow = p2 if fast == p1 else p1
fast_lon = planet_lons[fast]
slow_lon = planet_lons[slow]
# 分离:快行星已过慢行星(在慢行星"后面")
# 即慢行星度数 > 快行星度数(在同一圈内)
slow_in_sign = slow_lon % 30
fast_in_sign = fast_lon % 30
if slow_in_sign > fast_in_sign:
# 慢在前面,快在后面 → 分离状态
diff = slow_in_sign - fast_in_sign
if diff <= 3.0:
yoga = {
'type': 'Easarapha',
'fast_planet': fast,
'slow_planet': slow,
'degree_diff': round(diff, 4),
'sign': SIGNS[sign1],
'strength': 'strong' if diff <= 1.0 else 'moderate',
'interpretation': _easarapha_interp(fast, slow, diff),
}
results['easarapha'].append(yoga)
results['yogas'].append(yoga)
# ── 3. Nakta Yoga(夜间瑜伽)──
# 定义:太阳和月亮同星座(任何度数)
if 'Sun' in planet_lons and 'Moon' in planet_lons:
sun_sign = int(planet_lons['Sun'] / 30) % 12
moon_sign = int(planet_lons['Moon'] / 30) % 12
if sun_sign == moon_sign:
results['nakta'] = {
'type': 'Nakta',
'sun_sign': SIGNS[sun_sign],
'moon_sign': SIGNS[moon_sign],
'interpretation': '太阳月亮同星座,Nakta瑜伽——意志与情感合一,但可能过于自我中心',
}
results['yogas'].append(results['nakta'])
# ── 4. Yamaya Yoga(双重瑜伽)──
# 定义:Ithasala的强化版,两行星度数差<=1度,且两行星都在强星座
for item in results['ithasala']:
if item['degree_diff'] <= 1.0:
yamaya = {
'type': 'Yamaya',
'planet1': item['fast_planet'],
'planet2': item['slow_planet'],
'degree_diff': item['degree_diff'],
'sign': item['sign'],
'interpretation': f"Yamaya瑜伽——{item['fast_planet']}{item['slow_planet']}极度接近({item['degree_diff']}度),双重能量融合",
}
results['yamaya'].append(yamaya)
results['yogas'].append(yamaya)
# ── 5. Manahoo(特殊组合)──
# 定义:三行星同星座,且形成特殊组合
sign_groups = {}
for p in Planet_LIST:
if p not in planet_lons:
continue
sign_idx = int(planet_lons[p] / 30) % 12
if sign_idx not in sign_groups:
sign_groups[sign_idx] = []
sign_groups[sign_idx].append(p)
for sign_idx, planets in sign_groups.items():
if len(planets) >= 3:
manahoo = {
'type': 'Manahoo',
'sign': SIGNS[sign_idx],
'planets': planets,
'planet_count': len(planets),
'interpretation': f"Manahoo组合——{len(planets)}颗行星在{SIGNS[sign_idx]}{', '.join(planets)}),能量高度集中",
}
results['manahoo'].append(manahoo)
results['yogas'].append(manahoo)
# ── 6. Graha Yuddha(行星战争)──
# 定义:两行星度数差<=1度(极近距离)
for i, p1 in enumerate(Planet_LIST):
if p1 not in planet_lons or p1 in ('Rahu', 'Ketu'):
continue
for p2 in Planet_LIST[i+1:]:
if p2 not in planet_lons or p2 in ('Rahu', 'Ketu'):
continue
lon1, lon2 = planet_lons[p1], planet_lons[p2]
diff = abs(lon1 - lon2) % 360
if diff > 180:
diff = 360 - diff
if diff <= 1.0:
winner = p1 if _is_faster(p1, p2) else p2
loser = p2 if winner == p1 else p1
yuddha = {
'type': 'Graha Yuddha',
'planet1': p1,
'planet2': p2,
'degree_diff': round(diff, 4),
'winner': winner,
'loser': loser,
'sign': SIGNS[int(lon1 / 30) % 12],
'interpretation': f"Graha Yuddha——{p1}{p2}极近({diff}度),{winner}胜,{loser}受损",
}
results['graha_yuddha'].append(yuddha)
results['yogas'].append(yuddha)
# ── 总结 ──
total = len(results['yogas'])
results['summary'] = (
f"Tajika Yogas检测:共{total}个格局。"
f"Ithasala(连接){len(results['ithasala'])}个,"
f"Easarapha(分离){len(results['easarapha'])}个,"
f"Nakta(日月同度){'1个' if results['nakta'] else ''}"
f"Yamaya(双重){len(results['yamaya'])}个,"
f"Manahoo(三行星集中){len(results['manahoo'])}个,"
f"Graha Yuddha(行星战争){len(results['graha_yuddha'])}个。"
)
return results
def _is_faster(p1: str, p2: str) -> bool:
"""判断p1是否比p2快(按自然速度)"""
speeds = {
'Moon': 13.176, 'Mercury': 4.092, 'Venus': 1.602,
'Mars': 0.524, 'Jupiter': 0.083, 'Saturn': 0.034,
'Sun': 0.986, 'Rahu': -0.053, 'Ketu': -0.053,
}
return abs(speeds.get(p1, 0)) > abs(speeds.get(p2, 0))
def _ithasala_interp(fast: str, slow: str, diff: float) -> str:
"""Ithasala瑜伽解读"""
templates = [
f"{fast}{slow}形成Ithasala(连接瑜伽),两星能量融合,事件将要发生(差{diff}度)",
f"预示:两星所主管领域将有合作、连接、顺利推进之象",
]
return ''.join(templates)
def _easarapha_interp(fast: str, slow: str, diff: float) -> str:
"""Easarapha瑜伽解读"""
templates = [
f"{fast}{slow}形成Easarapha(分离瑜伽),两星能量分离,事件已过或受阻(差{diff}度)",
f"预示:两星所主管领域将有分离、结束、阻碍之象",
]
return ''.join(templates)
# ============================================================================
# Sahams(特殊点计算)—— v6.0.13 新增
# ============================================================================
def calc_sahams(birth_dt: datetime,
sun_lon: float, moon_lon: float,
asc_lon: float,
yoga_point: float) -> Dict:
"""
计算各种Sahams特殊点
参数:
birth_dt: 出生时间datetime
sun_lon: 太阳经度0-360
moon_lon: 月亮经度0-360
asc_lon: 上升经度0-360
yoga_point: Yoga Point经度0-360
返回:
{
'punya_saham': {...}, # 福德点
'karya_saham': {...}, # 事业点
'vivah_saham': {...}, # 婚姻点
'rajya_saham': {...}, # 王权点
'shatru_saham': {...}, # 敌人点
'labha_saham': {...}, # 收益点
'parakrama_saham': {...}, # 勇气点
}
"""
results = {}
# 通用Saham计算公式(Tajika系统):
# Saham Lon = Asc Lon + (Planet2 Lon - Planet1 Lon)
# 如果结果>=360,减去360
def _calc_saham(p1_lon: float, p2_lon: float, asc: float) -> float:
"""计算Saham经度"""
return (asc + (p2_lon - p1_lon)) % 360
# Punya Saham(福德点):Sun - Moon + Asc
punya_lon = _calc_saham(moon_lon, sun_lon, asc_lon)
results['punya_saham'] = {
'longitude': round(punya_lon, 4),
'sign': SIGNS[int(punya_lon / 30) % 12],
'degree_in_sign': round(punya_lon % 30, 4),
'interpretation': 'Punya Saham(福德点)——指示人生福德、善业积累、精神成长领域',
}
# Karya Saham(事业点):Moon - Mars + Asc(日间)或 Mars - Moon + Asc(夜间)
is_daytime = _is_daytime(birth_dt, sun_lon, asc_lon)
if is_daytime:
karya_lon = _calc_saham(mars_lon:=0, moon_lon, asc_lon) # 需要Mars经度
# 暂时用0占位,实际需要从外部传入
results['karya_saham'] = {'note': '需要Mars经度,请从外部传入'}
else:
results['karya_saham'] = {'note': '夜间盘,需要Mars-Moon,请从外部传入'}
# 简化版:直接返回结构,具体计算由调用方完成
results['_note'] = 'Saham计算需要完整的行星经度,请在jyotish_engine.py中调用calc_all_sahams()'
return results
def _is_daytime(birth_dt: datetime, sun_lon: float, asc_lon: float) -> bool:
"""判断出生时是白天还是夜间(简化:太阳在1-6宫=白天)"""
sun_house = (int(sun_lon / 30) - int(asc_lon / 30)) % 12 + 1
return sun_house in (1, 2, 3, 4, 5, 6)
def calc_all_sahams(planet_lons: Dict[str, float],
asc_lon: float,
birth_dt: datetime,
chart_type: str = 'natal') -> Dict:
"""
计算所有主要Sahams完整版
参数:
planet_lons: 所有行星经度 {: 经度}
asc_lon: 上升经度
birth_dt: 出生时间
chart_type: 'natal'本命 'varsha'年运
返回:
完整Sahams字典
"""
sun_lon = planet_lons.get('Sun', 0)
moon_lon = planet_lons.get('Moon', 0)
mars_lon = planet_lons.get('Mars', 0)
jupiter_lon = planet_lons.get('Jupiter', 0)
venus_lon = planet_lons.get('Venus', 0)
saturn_lon = planet_lons.get('Saturn', 0)
def _saham(p1_lon, p2_lon):
return (asc_lon + (p2_lon - p1_lon)) % 360
is_day = _is_daytime(birth_dt, sun_lon, asc_lon)
results = {}
# 1. Punya Saham(福德点):Moon - Sun + Asc
p_lon = _saham(sun_lon, moon_lon)
results['punya_saham'] = _saham_dict(p_lon, 'Punya Saham', '福德点——善业、精神成长、父系福德')
# 2. Karya Saham(事业点):
# 日间:Mars - Moon + Asc;夜间:Moon - Mars + Asc
if is_day:
k_lon = _saham(moon_lon, mars_lon)
else:
k_lon = _saham(mars_lon, moon_lon)
results['karya_saham'] = _saham_dict(k_lon, 'Karya Saham', '事业点——行动、努力、工作成果')
# 3. Vivah Saham(婚姻点):
# 日间:Venus - Mars + Asc(男性)或 Mars - Venus + Asc(女性)
# 简化:用Venus - Mars
v_lon = _saham(mars_lon, venus_lon)
results['vivah_saham'] = _saham_dict(v_lon, 'Vivah Saham', '婚姻点——婚姻、伴侣、情感关系')
# 4. Rajya Saham(王权点):Sun - Jupiter + Asc
r_lon = _saham(jupiter_lon, sun_lon)
results['rajya_saham'] = _saham_dict(r_lon, 'Rajya Saham', '王权点——地位、权威、社会认可')
# 5. Shatru Saham(敌人点):Mars - Saturn + Asc
sh_lon = _saham(saturn_lon, mars_lon)
results['shatru_saham'] = _saham_dict(sh_lon, 'Shatru Saham', '敌人点——竞争对手、障碍、冲突来源')
# 6. Labha Saham(收益点):Jupiter - Moon + Asc
l_lon = _saham(moon_lon, jupiter_lon)
results['labha_saham'] = _saham_dict(l_lon, 'Labha Saham', '收益点——收获、增益、扩张')
# 7. Parakrama Saham(勇气点):Mars - Sun + Asc
pa_lon = _saham(sun_lon, mars_lon)
results['parakrama_saham'] = _saham_dict(pa_lon, 'Parakrama Saham', '勇气点——勇气、竞争力、克服困难')
return results
def _saham_dict(lon: float, name: str, interp: str) -> Dict:
"""构建Saham字典"""
return {
'longitude': round(lon, 4),
'sign': SIGNS[int(lon / 30) % 12],
'sign_cn': SIGNS_CN.get(SIGNS[int(lon / 30) % 12], ''),
'degree_in_sign': round(lon % 30, 4),
'name': name,
'interpretation': interp,
}
# 补充SIGNS_CN(中文星座名)
SIGNS_CN = {
'Aries': '白羊', 'Taurus': '金牛', 'Gemini': '双子',
'Cancer': '巨蟹', 'Leo': '狮子', 'Virgo': '处女',
'Libra': '天秤', 'Scorpio': '天蝎', 'Sagittarius': '射手',
'Capricorn': '摩羯', 'Aquarius': '水瓶', 'Pisces': '双鱼',
}