Files
Jyotisha/scripts/cmd_muhurta.py
2026-06-29 03:25:03 +08:00

187 lines
7.0 KiB
Python
Raw Permalink 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.
"""
cmd_muhurta.py v6.0.21 — muhurta 子命令实现
用法:
python jyotish_engine.py muhurta --date 2026-06-15 --activity marriage
python jyotish_engine.py muhurta --date 2026-06-15 (全部活动)
python jyotish_engine.py muhurta --scan-days 7 --activity business (扫描7天)
对于完整解盘(full-reading),也会附带当日 Muhurta 基本信息。
"""
from __future__ import annotations
from typing import Dict, Optional, List
from datetime import datetime, timedelta
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from ayanamsa_utils import sidereal_flags
def _weekday_to_vara(py_weekday: int) -> int:
"""Python weekday (0=Mon) → Vara index (0=Sun)"""
return (py_weekday + 1) % 7
def _get_sun_moon_lons(year: int, month: int, day: int,
hour: int = 12, ayanamsa_name: str = 'lahiri') -> tuple:
"""获取太阳/月亮恒星黄经。优先 swisseph,退化为近似算法。"""
def _primary_longitude(value):
if isinstance(value, (list, tuple)):
return float(value[0])
return float(value)
try:
import swisseph as swe
jd_ut = swe.julday(year, month, day, hour)
flags = sidereal_flags(swe, ayanamsa_name)
sun_res = swe.calc_ut(jd_ut, swe.SUN, flags)
moon_res = swe.calc_ut(jd_ut, swe.MOON, flags)
return _primary_longitude(sun_res[0]), _primary_longitude(moon_res[0]), True
except Exception:
pass
# 近似算法
from muhurta import _approx_sun_moon_lon
sun_lon, moon_lon = _approx_sun_moon_lon(year, month, day)
return sun_lon, moon_lon, False
def _format_panchanga_summary(panchanga: Dict) -> List[str]:
lines = []
p = panchanga
lines.append(f" Tithi: {p['tithi']['full_name']} ({p['tithi']['quality']})")
lines.append(f" Nakshatra: {p['nakshatra']['nakshatra']} [{p['nakshatra']['type']}] ({p['nakshatra']['quality']})")
lines.append(f" Yoga: {p['yoga']['yoga']} ({p['yoga']['quality']})")
lines.append(f" Karana: {p['karana']['karana']} ({p['karana']['quality']})")
lines.append(f" Vara: {p['vara']['vara']} / {p['vara']['vara_lord']} ({p['vara']['quality']})")
lines.append(f" Hora: {p['hora']['hora_lord']} ({p['hora']['quality']})")
lines.append(f" 综合评分: {p['overall_quality']} ({p['overall_score']:.0%},吉 {p['auspicious_count']}/{p['total_elements']})")
if p['warnings']:
for w in p['warnings']:
lines.append(f" {w}")
return lines
def _format_activity_checks(activity_checks: Dict, target_activity: Optional[str] = None) -> List[str]:
lines = []
ACTIVITY_NAMES_ZH = {
'marriage': '婚礼/伴侣(Vivaha',
'business': '开业/签约(Vyapar',
'travel': '出行(Yatra',
'medical': '手术/医疗(Chikitsa',
'education': '学习/入学(Vidyarambha',
}
for act, chk in activity_checks.items():
if target_activity and act != target_activity:
continue
zh_name = ACTIVITY_NAMES_ZH.get(act, act)
verdict = chk.get('verdict', '未知')
icon = '' if '大吉' in verdict or ('' in verdict and '不宜' not in verdict) else \
'⚠️' if '一般' in verdict or '' in verdict else ''
lines.append(f" {icon} {zh_name}: {verdict}")
if chk.get('notes'):
for note in chk['notes'][:3]:
lines.append(f"{note}")
return lines
def cmd_muhurta(args, chart_data: Optional[Dict] = None) -> int:
"""
Muhurta 子命令主入口。
args 属性:
args.date: '2026-06-15'(查询日期,默认今天)
args.activity: 活动类型(可选,默认全部)
args.scan_days: 扫描天数(可选,>1 时扫描多天)
args.hour_from_sunrise: 从日出起算的小时(默认 6h)
"""
from muhurta import muhurta_full_report, ACTIVITY_RULES
# 解析日期
if hasattr(args, 'date') and args.date:
try:
query_dt = datetime.strptime(args.date, '%Y-%m-%d')
except ValueError:
print(f"[ERROR] 日期格式错误: {args.date},请用 YYYY-MM-DD")
return 1
else:
query_dt = datetime.now()
hour_from_sunrise = getattr(args, 'hour_from_sunrise', 6.0)
target_activity = getattr(args, 'activity', None)
scan_days = getattr(args, 'scan_days', 1)
ayanamsa_name = getattr(args, 'ayanamsa', 'lahiri')
activities = list(ACTIVITY_RULES.keys())
if target_activity and target_activity not in activities:
print(f"[ERROR] 未知活动: {target_activity}。支持: {', '.join(activities)}")
return 1
print("=" * 64)
print("🕐 Muhurta 择时分析(印度吉凶历)")
print("=" * 64)
dates_to_check = [query_dt + timedelta(days=i) for i in range(max(1, int(scan_days)))]
for dt in dates_to_check:
sun_lon, moon_lon, has_swe = _get_sun_moon_lons(
dt.year, dt.month, dt.day, int(hour_from_sunrise + 6), # rough solar hour
ayanamsa_name=ayanamsa_name,
)
vara_idx = _weekday_to_vara(dt.weekday())
date_str = dt.strftime('%Y-%m-%d')
report = muhurta_full_report(
sun_lon=sun_lon,
moon_lon=moon_lon,
weekday=vara_idx,
hour_from_sunrise=hour_from_sunrise,
query_date_str=date_str,
activities=activities,
)
precision_note = '' if has_swe else '(近似值,±2°精度)'
print(f"\n📅 {date_str} {precision_note}")
print(f" Sun: {sun_lon:.1f}° Moon: {moon_lon:.1f}°")
print()
print("── Panchanga 五要素 ──")
for line in _format_panchanga_summary(report['panchanga']):
print(line)
print()
print("── Abhijit Muhurta ──")
abh = report['abhijit_muhurta']
print(f" {abh['description']}")
print(f" 持续: {abh['duration_minutes']} 分钟 | {abh['warning']}")
print()
print("── 活动适宜性 ──")
for line in _format_activity_checks(report['activity_checks'], target_activity):
print(line)
print()
summary = report['summary']
best = summary.get('best_activities', [])
avoid = summary.get('avoid_activities', [])
if best:
print(f" ✨ 适宜: {', '.join(best)}")
if avoid:
print(f" 🚫 不宜: {', '.join(avoid)}")
if len(dates_to_check) > 1:
print("-" * 40)
print()
print("" * 64)
print("注意事项:")
print(" 1. 本分析基于恒星黄经(Lahiri Ayanamsa),为 Parashari 传统")
print(" 2. 精确 Muhurta 还需考虑出生盘 Lagna 与目标时间的相位关系")
print(" 3. 建议结合 Ascendant 力量、吉星位置做综合判断")
if not has_swe:
print(" 4. ⚠️ 当前使用近似算法(swisseph 未安装),精度约 ±2°")
print("" * 64)
return 0