Files
Jyotisha/scripts/professional_report_reference.py
T
2026-09-23 10:42:17 +08:00

129 lines
4.7 KiB
Python

"""Public professional-reference export assembly for the Jyotish API.
This boundary performs no writing-agent, persistence, billing, or telemetry work.
It validates the public export request, reuses the handler's one full-reading
calculation, and delegates packet assembly/rendering to ``jyotish_engine``.
"""
from __future__ import annotations
from datetime import datetime
from importlib import import_module
from types import SimpleNamespace
from typing import Any
try:
from scripts.reader_appendix_language import clean_reader_appendix_markdown
from scripts.reader_dasha_applicability import render_dasha_applicability
from scripts.report_density_packet import report_density_packet
except ModuleNotFoundError: # pragma: no cover - direct scripts/ execution path
from reader_appendix_language import clean_reader_appendix_markdown
from reader_dasha_applicability import render_dasha_applicability
from report_density_packet import report_density_packet
class ProfessionalReportReferenceInputError(ValueError):
"""The professional-reference request is outside the public contract."""
def _normalize_format(value: Any) -> str:
if value is None:
return "json"
if not isinstance(value, str):
raise ProfessionalReportReferenceInputError("format must be json or markdown")
normalized = value.strip().lower()
if normalized not in {"json", "markdown"}:
raise ProfessionalReportReferenceInputError("format must be json or markdown")
return normalized
def _normalize_packs(value: Any) -> list[str]:
if value is None:
return []
if isinstance(value, str):
raw_items = value.split(",")
elif isinstance(value, list):
if any(not isinstance(item, str) for item in value):
raise ProfessionalReportReferenceInputError("packs must contain only strings")
raw_items = value
else:
raise ProfessionalReportReferenceInputError("packs must be a string or array of strings")
selected: list[str] = []
seen: set[str] = set()
for item in raw_items:
pack_id = item.strip()
if pack_id and pack_id not in seen:
selected.append(pack_id)
seen.add(pack_id)
return selected
def _load_engine():
try:
return import_module("scripts.jyotish_engine")
except ModuleNotFoundError: # pragma: no cover - direct scripts/ execution path
return import_module("jyotish_engine")
def _export_args(birth: dict[str, Any]) -> SimpleNamespace:
today = birth.get("today") or datetime.now().strftime("%Y-%m-%d")
raw_target = birth.get("target_year")
if raw_target in (None, ""):
target_year = int(str(today)[:4])
else:
target_year = int(raw_target)
raw_age = birth.get("age")
if raw_age in (None, ""):
try:
age = int(target_year) - int(birth["year"])
except (TypeError, ValueError, KeyError):
age = None
else:
age = int(raw_age)
payload = {
**birth,
"hour": int(birth["hour"]),
"minute": int(birth["minute"]),
"second": int(birth.get("second", 0) or 0),
"today": today,
"target_year": target_year,
"age": age,
"visual_chart_observations": birth.get("visual_chart_observations"),
"startrack_language_bridge": bool(birth.get("startrack_language_bridge")),
}
return SimpleNamespace(**payload)
def build_professional_report_reference(handler, body: dict[str, Any], *, engine=None) -> dict[str, Any]:
"""Build one JSON or Markdown response from one reused full-reading result."""
if not isinstance(body, dict):
raise ProfessionalReportReferenceInputError("request body must be an object")
output_format = _normalize_format(body.get("format"))
packs = _normalize_packs(body.get("packs"))
birth = handler._high_rigor_birth_payload(body)
full_reading = handler._compute_full_reading_for_thematic(birth)
resolved_engine = engine or _load_engine()
try:
packet = resolved_engine.build_professional_report_reference_packet(
full_reading,
_export_args(birth),
packs,
)
except ValueError as exc:
raise ProfessionalReportReferenceInputError(str(exc)) from exc
if output_format == "markdown":
return {
"format": "markdown",
"markdown": resolved_engine.render_pl9_markdown(packet),
**({"fact_table_packet": report_density_packet(packet),
"reader_dasha_applicability": clean_reader_appendix_markdown(render_dasha_applicability(packet))}
if body.get("include_fact_tables") is True else {}),
}
return {
"format": "json",
"report": packet,
}