fix(yoga): Chinese combination text from a Chinese source, not 未判定 (#91 fix2 F3, BUG-1418)
Removing the English-to-Chinese back-translation left every BVR semantic note and every yogas_doshas raj/dhana "H*_Lord(...) in H*" sentence as 未判定 in the Chinese yoga table and pages. - yoga_engine: semantic conditions return BiText(Chinese, old note). The Chinese comes from references/yoga_semantic_notes_zh.json, one sentence per note, so dedup keeps the same equality classes. English-only custom templates get the same lookup. combination_en is unchanged. - yogas_doshas: raj/dhana rows add combination_zh; combination is unchanged. - chinese_combination prefers a clean combination_zh. Which yogas fire, their strength and category are unchanged (fictional charts 0-19, same rows as staging; only set-iteration order differs). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HwMNZEzdzmrbPhuRNmZe3C
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
00c2b4d498
commit
ac3dccbac8
@@ -647,6 +647,10 @@ def chinese_yoga_label(item: dict) -> str:
|
||||
|
||||
def chinese_combination(item: dict) -> str:
|
||||
"""Use the Chinese combination sentence. An English sentence is not translated word by word."""
|
||||
authored = str(item.get("combination_zh") or "").strip()
|
||||
if authored and re.search(r"[一-鿿]", authored) and not _has_prose_glue(authored):
|
||||
# Written in Chinese by the detector itself (yogas_doshas raj / dhana rows).
|
||||
return authored
|
||||
combination = str(item.get("combination") or "").strip()
|
||||
han = bool(re.search(r"[\u4e00-\u9fff]", combination))
|
||||
function = bool(_HAN_FUNCTION_RE.search(combination)) if combination else False
|
||||
|
||||
+46
-3
@@ -162,6 +162,48 @@ STRENGTH_EN = {
|
||||
}
|
||||
|
||||
|
||||
# Chinese wording for the English ``note`` of semantic (BVR / PyJHora batch)
|
||||
# conditions. The note stays the English twin. One note maps to one Chinese
|
||||
# sentence, so the dedup key keeps the same equality classes (BUG-1418).
|
||||
_SEMANTIC_NOTES_ZH_PATH = os.path.join(
|
||||
os.path.dirname(os.path.abspath(__file__)), "..", "references", "yoga_semantic_notes_zh.json")
|
||||
# A condition without a note used to print its type key. Keep one fixed
|
||||
# sentence per type so two matches of the same type still dedupe together.
|
||||
_SEMANTIC_TYPE_ZH = {
|
||||
"planet_in_house": "行星落在规则指定的宫位",
|
||||
"planet_in_lagna": "行星落在上升宫",
|
||||
}
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=1)
|
||||
def _semantic_notes_zh() -> Dict[str, str]:
|
||||
try:
|
||||
with open(_SEMANTIC_NOTES_ZH_PATH, "r", encoding="utf-8") as handle:
|
||||
data = json.load(handle)
|
||||
except (OSError, ValueError):
|
||||
return {}
|
||||
return {str(key): str(value) for key, value in data.items()} if isinstance(data, dict) else {}
|
||||
|
||||
|
||||
def _semantic_text(cond: Dict, ctype: str):
|
||||
"""``cond.get("note", ctype)`` with Chinese text; the old value stays as ``.en``."""
|
||||
if "note" in cond:
|
||||
note = cond.get("note")
|
||||
zh = _semantic_notes_zh().get(str(note)) if note else None
|
||||
return BiText(zh, note) if zh else note
|
||||
zh = _SEMANTIC_TYPE_ZH.get(str(ctype))
|
||||
return BiText(zh, ctype) if zh else ctype
|
||||
|
||||
|
||||
def _template_text(zh: str, en) -> BiText:
|
||||
"""``BiText(zh, en)``; a rule template written only in English gets its Chinese sentence (BUG-1418)."""
|
||||
if not any("\u4e00" <= char <= "\u9fff" for char in zh):
|
||||
chinese = _semantic_notes_zh().get(zh)
|
||||
if chinese:
|
||||
return BiText(chinese, zh if en is None else en)
|
||||
return BiText(zh, en)
|
||||
|
||||
|
||||
def _combo(cond: Dict, default_zh: str, **values) -> BiText:
|
||||
"""Format the rule's combination template in Chinese (unchanged) and in English."""
|
||||
zh = cond.get("combo_template", default_zh).format(**values)
|
||||
@@ -172,7 +214,7 @@ def _combo(cond: Dict, default_zh: str, **values) -> BiText:
|
||||
en = en_template.format(**{key: (value.en if isinstance(value, BiText) else value) for key, value in values.items()})
|
||||
except (KeyError, IndexError, ValueError):
|
||||
en = None
|
||||
return BiText(zh, en)
|
||||
return _template_text(zh, en)
|
||||
|
||||
|
||||
def _get_dignity_level(planet: str, sign: str) -> str:
|
||||
@@ -1465,7 +1507,7 @@ class YogaEngine:
|
||||
combo = cond.get("combo_template", "自定义条件满足")
|
||||
if isinstance(combo, str):
|
||||
# Custom templates were never formatted; keep that, and pair the English text.
|
||||
combo = BiText(combo, cond.get("combo_template_en") if "combo_template" in cond else DEFAULT_COMBO_EN["自定义条件满足"])
|
||||
combo = _template_text(combo, cond.get("combo_template_en") if "combo_template" in cond else DEFAULT_COMBO_EN["自定义条件满足"])
|
||||
if callable(combo):
|
||||
combo = combo(ctx, bindings)
|
||||
strength = cond.get("strength", rule.get("strength", "中"))
|
||||
@@ -1788,7 +1830,8 @@ class YogaEngine:
|
||||
def _eval_semantic_condition(self, ctype, cond, ctx, rule, bindings):
|
||||
"""兼容批量抽取规则中的语义型条件。返回保守布尔匹配。"""
|
||||
def success(combo=None):
|
||||
return [{"combination": combo or cond.get("note", ctype), "strength": rule.get("strength", "中")}]
|
||||
text = combo or _semantic_text(cond, ctype)
|
||||
return [{"combination": text, "strength": rule.get("strength", "中")}]
|
||||
|
||||
def house(ref):
|
||||
if isinstance(ref, int):
|
||||
|
||||
@@ -29,6 +29,24 @@ NATURAL_BENEFICS = {'Jupiter', 'Venus', 'Mercury', 'Moon'}
|
||||
NATURAL_MALEFICS = {'Saturn', 'Mars', 'Sun', 'Rahu', 'Ketu'}
|
||||
|
||||
|
||||
# Chinese twins of the raj / dhana combination strings. ``combination`` keeps its
|
||||
# old text; the Chinese report reads ``combination_zh`` (BUG-1418).
|
||||
_PLANET_ZH = {
|
||||
'Sun': '太阳', 'Moon': '月亮', 'Mars': '火星', 'Mercury': '水星', 'Jupiter': '木星',
|
||||
'Venus': '金星', 'Saturn': '土星', 'Rahu': '罗睺', 'Ketu': '计都',
|
||||
}
|
||||
|
||||
|
||||
def _cn(planet) -> str:
|
||||
return _PLANET_ZH.get(str(planet), str(planet))
|
||||
|
||||
|
||||
def _houses_cn(houses) -> str:
|
||||
if isinstance(houses, (list, tuple)):
|
||||
return '、'.join(str(house) for house in houses)
|
||||
return str(houses)
|
||||
|
||||
|
||||
def calc_raj_yogas(planets_data: Dict, houses: Dict) -> Dict:
|
||||
"""
|
||||
计算 Raj Yogas(王者瑜伽)——权力、地位、社会影响力格局 v7.0
|
||||
@@ -109,6 +127,7 @@ def calc_raj_yogas(planets_data: Dict, houses: Dict) -> Dict:
|
||||
'type': 'Raj Yoga',
|
||||
'subtype': 'dual_lordship',
|
||||
'combination': f'{lord}(H{k_houses}主+H{t_houses}主)',
|
||||
'combination_zh': f'{_cn(lord)}同时是第{_houses_cn(k_houses)}宫主(角宫)与第{_houses_cn(t_houses)}宫主(三方宫)',
|
||||
'formation_house': lord_house,
|
||||
'strength': 'strong' if lord_house in kendras else 'moderate',
|
||||
'interpretation': f'Raj Yoga——{lord}同时掌管角宫{k_houses}和三方宫{t_houses},且在{lord_house}宫,双重权力格局',
|
||||
@@ -134,6 +153,7 @@ def calc_raj_yogas(planets_data: Dict, houses: Dict) -> Dict:
|
||||
'type': 'Raj Yoga',
|
||||
'subtype': 'conjunction',
|
||||
'combination': f'{kl}(角宫主) + {tl}(三方宫主)',
|
||||
'combination_zh': f'角宫主{_cn(kl)}与三方宫主{_cn(tl)}同宫',
|
||||
'formation_house': house_from_asc,
|
||||
'strength': 'strong' if house_from_asc in kendras else 'moderate',
|
||||
'interpretation': f'Raj Yoga——{kl}(角宫主)与{tl}(三方宫主)同宫在{SIGNS_LIST[kl_sign]},权力格局',
|
||||
@@ -146,6 +166,7 @@ def calc_raj_yogas(planets_data: Dict, houses: Dict) -> Dict:
|
||||
'type': 'Raj Yoga',
|
||||
'subtype': 'mutual_aspect',
|
||||
'combination': f'{kl}(角宫主) ↔ {tl}(三方宫主)',
|
||||
'combination_zh': f'角宫主{_cn(kl)}与三方宫主{_cn(tl)}对宫互视',
|
||||
'interpretation': f'Raj Yoga——{kl}(角宫主)与{tl}(三方宫主)互看(对宫相位),权力格局',
|
||||
}
|
||||
results['yogas'].append(yoga)
|
||||
@@ -166,6 +187,7 @@ def calc_raj_yogas(planets_data: Dict, houses: Dict) -> Dict:
|
||||
'type': 'Raj Yoga',
|
||||
'subtype': 'parivartana',
|
||||
'combination': f'{kl}(角宫主) ⇄ {tl}(三方宫主)',
|
||||
'combination_zh': f'角宫主{_cn(kl)}与三方宫主{_cn(tl)}互换星座',
|
||||
'interpretation': f'Raj Yoga——{kl}(角宫主)与{tl}(三方宫主)互容交换,权力格局强化',
|
||||
}
|
||||
results['yogas'].append(yoga)
|
||||
@@ -185,6 +207,7 @@ def calc_raj_yogas(planets_data: Dict, houses: Dict) -> Dict:
|
||||
'type': 'Viparita Raja Yoga',
|
||||
'subtype': 'dusthana_in_dusthana',
|
||||
'combination': f'H{h}_Lord({lord}) in H{lord_house}',
|
||||
'combination_zh': f'{h}宫主{_cn(lord)}落第{lord_house}宫',
|
||||
'interpretation': f'Viparita Raja Yoga——{h}宫主{lord}落入{lord_house}宫(凶中凶),先苦后甜逆转格局',
|
||||
}
|
||||
results['yogas'].append(yoga)
|
||||
@@ -254,6 +277,7 @@ def calc_dhana_yogas(planets_data: Dict, houses: Dict) -> Dict:
|
||||
'type': 'Dhana Yoga',
|
||||
'subtype': '2nd_11th_lords_strong',
|
||||
'combination': f'H2_Lord({lord_2}) in H{h2} + H11_Lord({lord_11}) in H{h11}',
|
||||
'combination_zh': f'2宫主{_cn(lord_2)}落第{h2}宫,11宫主{_cn(lord_11)}落第{h11}宫',
|
||||
'strength': 'strong' if h2 in KENDRA and h11 in KENDRA else 'moderate',
|
||||
'interpretation': f'Dhana Yoga——2宫主{lord_2}(H{h2})与11宫主{lord_11}(H{h11})均落强宫,财富积累格局',
|
||||
})
|
||||
@@ -268,6 +292,7 @@ def calc_dhana_yogas(planets_data: Dict, houses: Dict) -> Dict:
|
||||
'type': 'Dhana Yoga',
|
||||
'subtype': '5th_9th_conjunction',
|
||||
'combination': f'H5_Lord({lord_5}) + H9_Lord({lord_9})',
|
||||
'combination_zh': f'5宫主{_cn(lord_5)}与9宫主{_cn(lord_9)}同宫',
|
||||
'strength': 'strong',
|
||||
'interpretation': f'Dhana Yoga——5宫主{lord_5}与9宫主{lord_9}同宫在{s},财富+幸运格局',
|
||||
})
|
||||
@@ -281,6 +306,7 @@ def calc_dhana_yogas(planets_data: Dict, houses: Dict) -> Dict:
|
||||
'type': 'Dhana Yoga',
|
||||
'subtype': '5th_9th_mutual_aspect',
|
||||
'combination': f'H5_Lord({lord_5}) ↔ H9_Lord({lord_9})',
|
||||
'combination_zh': f'5宫主{_cn(lord_5)}与9宫主{_cn(lord_9)}对宫互视',
|
||||
'strength': 'moderate',
|
||||
'interpretation': f'Dhana Yoga——5宫主{lord_5}(H{h5})与9宫主{lord_9}(H{h9})互看,财富格局',
|
||||
})
|
||||
@@ -290,6 +316,7 @@ def calc_dhana_yogas(planets_data: Dict, houses: Dict) -> Dict:
|
||||
'type': 'Dhana Yoga',
|
||||
'subtype': '5th_9th_strong_houses',
|
||||
'combination': f'H5_Lord({lord_5}) in H{h5} + H9_Lord({lord_9}) in H{h9}',
|
||||
'combination_zh': f'5宫主{_cn(lord_5)}落第{h5}宫,9宫主{_cn(lord_9)}落第{h9}宫',
|
||||
'strength': 'moderate',
|
||||
'interpretation': f'Dhana Yoga——5宫主{lord_5}与9宫主{lord_9}均落强宫,财富格局',
|
||||
})
|
||||
@@ -302,6 +329,7 @@ def calc_dhana_yogas(planets_data: Dict, houses: Dict) -> Dict:
|
||||
'type': 'Dhana Yoga',
|
||||
'subtype': '2nd_9th_conjunction',
|
||||
'combination': f'H2_Lord({lord_2}) + H9_Lord({lord_9})',
|
||||
'combination_zh': f'2宫主{_cn(lord_2)}与9宫主{_cn(lord_9)}同宫',
|
||||
'strength': 'strong',
|
||||
'interpretation': f'Dhana Yoga——2宫主{lord_2}与9宫主{lord_9}同宫在{s},财富+幸运组合',
|
||||
})
|
||||
@@ -314,6 +342,7 @@ def calc_dhana_yogas(planets_data: Dict, houses: Dict) -> Dict:
|
||||
'type': 'Dhana Yoga',
|
||||
'subtype': '11th_9th_conjunction',
|
||||
'combination': f'H11_Lord({lord_11}) + H9_Lord({lord_9})',
|
||||
'combination_zh': f'11宫主{_cn(lord_11)}与9宫主{_cn(lord_9)}同宫',
|
||||
'strength': 'strong',
|
||||
'interpretation': f'Dhana Yoga——11宫主{lord_11}与9宫主{lord_9}同宫在{s},收益+幸运组合',
|
||||
})
|
||||
@@ -329,6 +358,7 @@ def calc_dhana_yogas(planets_data: Dict, houses: Dict) -> Dict:
|
||||
'type': 'Dhana Yoga',
|
||||
'subtype': f'{w_house}th_lord_benefic_conjunction',
|
||||
'combination': f'H{w_house}_Lord({wealth_lord}) + {benefic}',
|
||||
'combination_zh': f'{w_house}宫主{_cn(wealth_lord)}与{_cn(benefic)}同宫',
|
||||
'strength': 'moderate',
|
||||
'interpretation': f'Dhana Yoga——{w_house}宫主{wealth_lord}与吉星{benefic}同宫在{s},财富助力格局',
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user