Classify VedAstro capability catalog domains

This commit is contained in:
732642856
2026-07-02 20:12:43 +08:00
parent 28e920d866
commit cdd0f51da5
6 changed files with 331 additions and 10 deletions
+37
View File
@@ -31,6 +31,12 @@ ROUTE_DOMAIN_MAP = {
"career": ["career"],
"finance": ["wealth"],
"wealth": ["wealth"],
"health": ["health"],
"education": ["education"],
"property": ["property"],
"children": ["children"],
"migration": ["migration"],
"prashna": ["prashna"],
"rectification": ["marriage", "career", "wealth"],
"timing": ["career", "marriage", "wealth"],
"general": ["career", "marriage", "wealth"],
@@ -64,6 +70,36 @@ ROUTE_THEME_REQUIREMENTS = {
"requires_dual_dasha": True,
"required_local_supplements": ["wealth_structure_explainer", "narayana_dasha", "functional_benefic_malefic"],
},
"health": {
"route": "health",
"requires_dual_dasha": True,
"required_local_supplements": ["d30_health_axis", "sixth_eighth_twelfth_houses", "functional_benefic_malefic"],
},
"education": {
"route": "education",
"requires_dual_dasha": True,
"required_local_supplements": ["d24_learning_axis", "fifth_ninth_houses", "functional_benefic_malefic"],
},
"property": {
"route": "property",
"requires_dual_dasha": True,
"required_local_supplements": ["d4_property_axis", "fourth_house", "functional_benefic_malefic"],
},
"children": {
"route": "children",
"requires_dual_dasha": True,
"required_local_supplements": ["d7_children_axis", "fifth_house", "functional_benefic_malefic"],
},
"migration": {
"route": "migration",
"requires_dual_dasha": True,
"required_local_supplements": ["d4_d9_foreign_axis", "ninth_twelfth_houses", "functional_benefic_malefic"],
},
"prashna": {
"route": "prashna",
"requires_dual_dasha": False,
"required_local_supplements": ["prashna_chart", "question_context_required", "functional_benefic_malefic"],
},
"overview": {
"route": "overview",
"requires_dual_dasha": True,
@@ -120,6 +156,7 @@ def orchestrate_vedastro_evidence(
window_start, window_end = (start_date, end_date) if start_date and end_date else _default_window(reference_date)
case = _normalize_case(birth_payload)
case["reference_date"] = str(reference_date or window_start)[:10]
case["themes"] = list(domains)
domain_reports: dict[str, Any] = {}
evidence_ledger: list[dict[str, Any]] = []
top_events_by_domain: dict[str, Any] = {}
+91 -6
View File
@@ -22,7 +22,21 @@ CATALOG_STUB_ENV = "VEDASTRO_OFFICIAL_CAPABILITY_CATALOG_STUB"
PLANETS = ["Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn", "Rahu", "Ketu", "Ascendant"]
HOUSES = [f"House{i}" for i in range(1, 13)]
DEFAULT_SIGIL_SAMPLE_LIMIT = int(os.environ.get("VEDASTRO_FULL_CATALOG_SAMPLE_LIMIT", "0") or 0)
DOMAIN_ORDER = ["career", "marriage", "wealth", "rectification", "timing", "general"]
DOMAIN_ORDER = [
"career",
"marriage",
"wealth",
"health",
"education",
"property",
"children",
"migration",
"prashna",
"rectification",
"timing",
"general",
"unknown",
]
DEFAULT_DYNAMIC_THEMES = ["career", "marriage", "wealth", "rectification", "timing"]
POLICY_BUCKETS = {
"needs_user_context": "needs_user_context_methods",
@@ -74,7 +88,25 @@ def _domain_routing_for_method(method: str, capability: dict[str, Any], paramete
if any(token in text for token in ("wealth", "money", "finance", "income", "gain", "house2", "house11", "ashtakvarga")):
domains.add("wealth")
priority = "high" if priority == "low" else priority
if any(token in text for token in ("birth", "rectification", "appearance", "body", "height", "shape", "complexion")):
if any(token in text for token in ("health", "illness", "disease", "medical", "medicine", "hospital", "accident", "injury", "surgery")):
domains.add("health")
priority = "high" if any(token in text for token in ("health", "disease", "illness", "accident")) else priority
if any(token in text for token in ("education", "school", "college", "degree", "study", "studies", "learning", "exam")):
domains.add("education")
priority = "high" if any(token in text for token in ("education", "degree", "exam")) else priority
if any(token in text for token in ("property", "vehicle", "home", "house4", "house 4", "land", "realestate", "real estate", "residence")):
domains.add("property")
priority = "high" if any(token in text for token in ("property", "vehicle", "land")) else priority
if any(token in text for token in ("children", "child", "progeny", "putra", "pregnancy", "fertility")):
domains.add("children")
priority = "high" if any(token in text for token in ("children", "progeny", "pregnancy")) else priority
if any(token in text for token in ("foreign", "travel", "migration", "relocation", "abroad", "immigration", "journey")):
domains.add("migration")
priority = "high" if any(token in text for token in ("migration", "relocation", "abroad")) else priority
if any(token in text for token in ("prashna", "horary", "questiontext", "question text", "muhurta")):
domains.add("prashna")
priority = "high" if any(token in text for token in ("prashna", "horary")) else priority
if any(token in text for token in ("rectification", "appearance", "body", "height", "shape", "complexion")):
domains.add("rectification")
if priority == "low":
priority = "medium"
@@ -83,9 +115,6 @@ def _domain_routing_for_method(method: str, capability: dict[str, Any], paramete
if priority == "low":
priority = "medium"
if not domains:
domains.add("general")
if parameter_strategy in {"requires_user_context", "requires_user_text", "requires_rectification_profile"}:
execution_policy = {
"requires_user_context": "needs_user_context",
@@ -97,14 +126,46 @@ def _domain_routing_for_method(method: str, capability: dict[str, Any], paramete
else:
execution_policy = "auto"
if not domains:
domains.add("unknown" if execution_policy == "blocked" else "general")
blocked_reason = None
if execution_policy == "blocked":
blocked_reason = parameter_strategy
elif execution_policy == "needs_user_context":
blocked_reason = "requires_additional_user_context"
elif execution_policy == "needs_user_text":
blocked_reason = "requires_user_text_or_question"
elif execution_policy == "needs_rectification_profile":
blocked_reason = "requires_rectification_profile"
ordered_domains = [domain for domain in DOMAIN_ORDER if domain in domains]
return {
"domains": ordered_domains,
"execution_policy": execution_policy,
"priority": priority,
"adjudicator_use": _adjudicator_use(execution_policy, priority),
"confidence_role": _confidence_role(execution_policy, priority),
"blocked_reason": blocked_reason,
}
def _adjudicator_use(execution_policy: str, priority: str) -> str:
if execution_policy == "auto":
return "primary_candidate" if priority == "high" else "secondary_context"
if execution_policy in {"needs_user_context", "needs_user_text", "needs_rectification_profile"}:
return "secondary_context"
return "not_used"
def _confidence_role(execution_policy: str, priority: str) -> str:
if execution_policy == "auto":
return "confidence_support" if priority == "high" else "background_reference"
if execution_policy in {"needs_user_context", "needs_user_text", "needs_rectification_profile"}:
return "confidence_cap_until_context_available"
return "blocked"
def _build_domain_routing(method_statuses: dict[str, Any]) -> dict[str, Any]:
routing: dict[str, dict[str, Any]] = {}
for method, status in method_statuses.items():
@@ -161,6 +222,13 @@ def _requested_dynamic_themes(payload: dict[str, Any]) -> list[str]:
"婚恋": "marriage",
"婚姻": "marriage",
"财富": "wealth",
"健康": "health",
"教育": "education",
"房产": "property",
"子女": "children",
"迁移": "migration",
"问卜": "prashna",
"卜卦": "prashna",
"校时": "rectification",
"应期": "timing",
}
@@ -217,6 +285,9 @@ def _capability_reference(method: str, status: dict[str, Any], theme: str) -> di
"status": status.get("status"),
"execution_policy": status.get("execution_policy"),
"priority": status.get("priority"),
"adjudicator_use": status.get("adjudicator_use"),
"confidence_role": status.get("confidence_role"),
"blocked_reason": status.get("blocked_reason"),
"domains": status.get("domains") or [],
"bucket": status.get("bucket"),
"signature": status.get("signature"),
@@ -537,7 +608,7 @@ def _full_catalog_method_payload(method: str, capability: dict[str, Any], case:
return None, "requires_user_context"
if any(name in lowered for name in ("bodyheight", "bodyshape", "hair", "lips", "nose", "complexion", "faceshape", "constitution", "personality")):
return None, "requires_rectification_profile"
if any(name in lowered for name in ("rawtextdata", "birthdatarawtext", "inputtext", "textinput", "query", "fullname", "personfullname", "address", "locationname", "ipaddress")):
if any(name in lowered for name in ("rawtextdata", "birthdatarawtext", "inputtext", "textinput", "query", "questiontext", "question", "fullname", "personfullname", "address", "locationname", "ipaddress")):
return None, "requires_user_text"
return None, "unsupported_signature"
@@ -624,6 +695,18 @@ def run_full_capability_catalog(birth_payload: dict[str, Any]) -> dict[str, Any]
domain_routing = _build_domain_routing(method_statuses)
requested_themes = _requested_dynamic_themes(birth_payload)
dynamic_selection = _build_dynamic_selection(method_statuses, domain_routing, requested_themes)
unknown_method_count = sum(
1
for status in method_statuses.values()
if isinstance(status, dict) and status.get("domains") == ["unknown"]
)
misrouted_general_method_count = sum(
1
for status in method_statuses.values()
if isinstance(status, dict)
and "general" in (status.get("domains") or [])
and len(status.get("domains") or []) > 1
)
return {
"runner": "vedastro_official_capability_runner",
@@ -639,6 +722,8 @@ def run_full_capability_catalog(birth_payload: dict[str, Any]) -> dict[str, Any]
"ok_method_count": ok_count,
"unsupported_method_count": unsupported_count,
"blocked_method_count": blocked_count,
"unknown_method_count": unknown_method_count,
"misrouted_general_method_count": misrouted_general_method_count,
"sample_limit": sample_limit,
"domain_routing_count": len(domain_routing),
"dynamic_selection_theme_count": len(dynamic_selection),
+3 -2
View File
@@ -2417,6 +2417,7 @@ def _run_official_full_snapshot_case(case: dict[str, Any], case_id: str = "user_
"reference_date": case.get("reference_date") or case.get("today") or case.get("transit_date") or case.get("current_date"),
"dasha_levels": case.get("dasha_levels"),
"dasha_precision_hours": case.get("dasha_precision_hours"),
"themes": case.get("themes") or case.get("theme"),
}
manifest = _official_full_snapshot_manifest(user_case, case_id)
budget_started_at = time.monotonic()
@@ -2441,7 +2442,8 @@ def _run_official_full_snapshot_case(case: dict[str, Any], case_id: str = "user_
and official_python_bundle.get("status") != "official_snapshot_budget_exhausted"
):
official_python_bundle = _try_official_python_bridge_snapshot_bundle(user_case)
if time.monotonic() - budget_started_at < _timeout_seconds():
budget_exhausted = official_python_bundle.get("status") == "official_snapshot_budget_exhausted"
if not budget_exhausted and time.monotonic() - budget_started_at < _timeout_seconds():
official_full_capability_catalog = _try_official_full_capability_catalog_bundle(user_case)
else:
official_full_capability_catalog = {
@@ -2470,7 +2472,6 @@ def _run_official_full_snapshot_case(case: dict[str, Any], case_id: str = "user_
)
endpoint = os.environ.get("VEDASTRO_API_ENDPOINT", "").strip()
network_enabled = os.environ.get(ALLOW_NETWORK_ENV, "").strip().lower() in {"1", "true", "yes"}
budget_exhausted = official_python_bundle.get("status") == "official_snapshot_budget_exhausted"
if budget_exhausted and endpoint and network_enabled and _is_official_public_endpoint(endpoint):
result = {
"backend": "vedastro_service_adapter_candidate",