feat: add consultation and product domain registries

This commit is contained in:
Jesse_Chen
2026-08-15 06:04:23 +08:00
parent 5012ff7212
commit 6d192ad175
46 changed files with 1404 additions and 292 deletions
+84
View File
@@ -0,0 +1,84 @@
#!/usr/bin/env python3
"""Canonical consultation-domain registry shared by Python entry points."""
from __future__ import annotations
from typing import Any
CANONICAL_DOMAINS = (
"career",
"marriage",
"wealth",
"health",
"education",
"migration",
"family",
"annual",
"timing",
"general",
)
DEFAULT_THEMES = ("career", "marriage", "wealth")
DEFAULT_DOMAINS = DEFAULT_THEMES
DOMAIN_ALIASES = {
"relationship": "marriage",
"finance": "wealth",
"money": "wealth",
"health-pressure": "health",
"health_pressure": "health",
"home": "migration",
"relocation": "migration",
"foreign": "migration",
"study": "education",
"children": "family",
"yearly": "annual",
"varshaphala": "annual",
"事业": "career",
"婚恋": "marriage",
"婚姻": "marriage",
"感情": "marriage",
"财富": "wealth",
"财运": "wealth",
"健康": "health",
"迁移": "migration",
"海外": "migration",
"教育": "education",
"学习": "education",
"家庭": "family",
"子女": "family",
"年度": "annual",
"流年": "annual",
}
_CANONICAL_DOMAIN_SET = frozenset(CANONICAL_DOMAINS)
def normalize_domain(value: Any) -> str:
"""Return one canonical domain or reject the value as unknown."""
key = str(value).strip().lower()
canonical = DOMAIN_ALIASES.get(key, key)
if canonical not in _CANONICAL_DOMAIN_SET:
raise ValueError(f"Unknown theme: {value}")
return canonical
def normalize_themes(raw: Any) -> list[str]:
"""Normalize themes, preserving first-seen order and failing closed."""
if raw is None or raw == "" or (isinstance(raw, str) and raw.strip().lower() == "all"):
values = list(DEFAULT_THEMES)
elif isinstance(raw, str):
values = [raw]
elif isinstance(raw, list):
values = raw
else:
raise ValueError("theme/themes must be a string, list, or all")
if not values:
return list(DEFAULT_THEMES)
normalized: list[str] = []
for value in values:
canonical = normalize_domain(value)
if canonical not in normalized:
normalized.append(canonical)
return normalized
+112 -19
View File
@@ -65,6 +65,10 @@ try:
from scripts.unified_consultation_orchestrator import UnifiedConsultationOrchestrator
except ModuleNotFoundError: # pragma: no cover - script execution path
from unified_consultation_orchestrator import UnifiedConsultationOrchestrator
try:
from scripts.consultation_domain_registry import CANONICAL_DOMAINS
except ModuleNotFoundError: # pragma: no cover - script execution path
from consultation_domain_registry import CANONICAL_DOMAINS
try:
from scripts.skill_experience import (
build_rectification_questionnaire,
@@ -1085,7 +1089,7 @@ def execute_consultation_workflow(
'mode': 'vedastro_official_first_existing_modules_reused',
'entry_mode': entry_mode,
'question': question,
'routes': ['career', 'relationship', 'finance'],
'routes': list(CANONICAL_DOMAINS),
'themes': themes,
'routing': route_packet,
'unified_orchestrator': unified_contract,
@@ -2861,6 +2865,7 @@ class JyotishAPIHandler(BaseHTTPRequestHandler):
custom_evidence = body.get('evidence')
has_custom_evidence = isinstance(custom_evidence, dict) and bool(custom_evidence)
adapter_evidence = {}
derived_context = None
strict_workflow_contracts = upstream_contract.get('strict_workflow_contracts') if isinstance(upstream_contract.get('strict_workflow_contracts'), dict) else {}
upstream_guided_topics = upstream_contract.get('guided_topics') if isinstance(upstream_contract.get('guided_topics'), list) else []
@@ -2874,10 +2879,14 @@ class JyotishAPIHandler(BaseHTTPRequestHandler):
orchestrator = report_orchestrator.ThematicReportOrchestrator(chart)
if has_custom_evidence:
self._inject_thematic_evidence(orchestrator, custom_evidence, report_orchestrator)
adapter_evidence = self._inject_thematic_evidence(orchestrator, custom_evidence, report_orchestrator)
mode = 'custom_evidence'
elif derived_context and derived_context.get('evidence'):
self._inject_thematic_evidence(orchestrator, derived_context['evidence'], report_orchestrator)
adapter_evidence = self._inject_thematic_evidence(
orchestrator,
derived_context['evidence'],
report_orchestrator,
)
mode = 'derived_chart_evidence'
elif strict_workflow_contracts:
mode = 'upstream_contract_reuse'
@@ -2887,11 +2896,49 @@ class JyotishAPIHandler(BaseHTTPRequestHandler):
theme_values = self._requested_thematic_report_themes(body, report_orchestrator)
reports = {}
for theme in theme_values:
report = orchestrator.generate_report(theme)
reports[theme.value] = self._apply_monthly_adjudication_to_theme_report(
theme.value,
report.to_dict(),
native_theme_map = {theme.value: theme for theme in report_orchestrator.ThemeName}
consultation_capabilities = report_orchestrator.consultation_thematic_capabilities()
for theme_name in theme_values:
adapter = consultation_capabilities.get(theme_name)
native_theme = native_theme_map.get(theme_name)
if adapter and adapter.get('report_theme'):
native_theme = native_theme_map[adapter['report_theme']]
if native_theme is not None:
report = orchestrator.generate_report(native_theme)
report_payload = self._apply_monthly_adjudication_to_theme_report(
theme_name,
report.to_dict(),
)
report_payload['theme'] = theme_name
report_payload['status'] = 'supported'
report_payload['thematic_adapter'] = (
{
**adapter,
'status': 'supported',
'scope': 'canonical_consultation',
}
if adapter
else {
'domain': theme_name,
'capability_status': 'supported',
'report_theme': native_theme.value,
'reason': None,
'fallback_theme': None,
'status': 'supported',
'scope': 'independent_report',
}
)
reports[theme_name] = report_payload
continue
reports[theme_name] = report_orchestrator.build_unavailable_consultation_theme_report(
theme_name,
evidence=adapter_evidence.get(theme_name, []),
upstream_contract_available=self._thematic_upstream_contract_available(
strict_workflow_contracts,
theme_name,
report_orchestrator,
),
)
return {
@@ -2923,7 +2970,12 @@ class JyotishAPIHandler(BaseHTTPRequestHandler):
),
'themes': reports,
'theme_count': len(reports),
'available_themes': [theme.value for theme in report_orchestrator.ThemeName],
'available_themes': list(CANONICAL_DOMAINS),
'consultation_thematic_capabilities': consultation_capabilities,
'native_report_themes': [theme.value for theme in report_orchestrator.ThemeName],
'independent_report_themes': [
theme.value for theme in report_orchestrator.INDEPENDENT_REPORT_THEMES
],
'boundary': '主题化报告用于组织证据、裁决冲突和生成叙事;具体预测仍需本命承诺、Dasha、Transit 与案例验证共同收敛。',
}
@@ -3104,7 +3156,7 @@ class JyotishAPIHandler(BaseHTTPRequestHandler):
'success': True,
'endpoint': 'high_rigor_workflow',
'mode': 'plan_only_no_external_calls',
'routes': ['career', 'relationship', 'finance'],
'routes': list(CANONICAL_DOMAINS),
'themes': themes,
'event_count': len(events),
'source_priority': {
@@ -3658,13 +3710,18 @@ class JyotishAPIHandler(BaseHTTPRequestHandler):
'label': theme.name,
})
report_themes = [theme.value for theme in getattr(report_orchestrator, 'ThemeName')]
selected = [theme.value for theme in theme_values]
selected = list(theme_values)
return {
'stage': 'report_pipeline_bridge',
'reading_theme_count': len(reading_themes),
'reading_themes': reading_themes,
'report_themes': report_themes,
'selected_report_themes': selected,
'canonical_consultation_domains': list(CANONICAL_DOMAINS),
'consultation_thematic_capabilities': report_orchestrator.consultation_thematic_capabilities(),
'independent_report_themes': [
theme.value for theme in report_orchestrator.INDEPENDENT_REPORT_THEMES
],
'bridge': {
'class': getattr(orchestrator_bridge, 'OrchestratorBridge').__name__,
'capabilities': [
@@ -3686,14 +3743,35 @@ class JyotishAPIHandler(BaseHTTPRequestHandler):
values = raw
else:
raise BadRequest('theme/themes must be a string, list, or all')
mapping = {theme.value: theme for theme in report_orchestrator.ThemeName}
native_theme_names = {theme.value for theme in report_orchestrator.ThemeName}
themes = []
for value in values:
key = str(value).strip().lower()
if key not in mapping:
raise BadRequest(f'Unknown thematic report theme: {value}')
themes.append(mapping[key])
return themes or list(report_orchestrator.ThemeName)
if key not in native_theme_names:
try:
key = report_orchestrator.consultation_thematic_adapter(key).domain
except ValueError as exc:
raise BadRequest(f'Unknown thematic report theme: {value}') from exc
if key not in themes:
themes.append(key)
return themes or [theme.value for theme in report_orchestrator.ThemeName]
def _thematic_upstream_contract_available(
self,
strict_workflow_contracts,
domain,
report_orchestrator,
):
if not isinstance(strict_workflow_contracts, dict):
return False
for raw_domain, contract in strict_workflow_contracts.items():
try:
canonical = report_orchestrator.consultation_thematic_adapter(raw_domain).domain
except ValueError:
continue
if canonical == domain and bool(contract):
return True
return False
def _build_thematic_chart_data(self, raw, report_orchestrator):
if not isinstance(raw, dict) or not raw:
@@ -3775,10 +3853,18 @@ class JyotishAPIHandler(BaseHTTPRequestHandler):
def _inject_thematic_evidence(self, orchestrator, evidence, report_orchestrator):
theme_map = {theme.value: theme for theme in report_orchestrator.ThemeName}
strength_map = {level.value: level for level in report_orchestrator.StrengthLevel}
adapter_evidence = {}
for theme_name, items in evidence.items():
theme = theme_map.get(str(theme_name).strip().lower())
key = str(theme_name).strip().lower()
theme = theme_map.get(key)
canonical_domain = None
if not theme:
raise BadRequest(f'Unknown evidence theme: {theme_name}')
try:
adapter = report_orchestrator.consultation_thematic_adapter(key)
except ValueError as exc:
raise BadRequest(f'Unknown evidence theme: {theme_name}') from exc
canonical_domain = adapter.domain
theme = adapter.report_theme
if not isinstance(items, list):
raise BadRequest('evidence theme values must be arrays')
results = []
@@ -3796,7 +3882,14 @@ class JyotishAPIHandler(BaseHTTPRequestHandler):
strength=strength,
details=item.get('details') if isinstance(item.get('details'), dict) else {},
))
orchestrator.add_techniques(theme, results)
if theme is not None:
orchestrator.add_techniques(theme, results)
else:
adapter_evidence[canonical_domain] = [
orchestrator._technique_to_dict(result)
for result in results
]
return adapter_evidence
def _can_derive_thematic_evidence(self, raw):
if not isinstance(raw, dict) or not raw:
+95
View File
@@ -23,6 +23,11 @@ from enum import Enum
from typing import Any, Dict, List, Optional, Callable
from datetime import datetime
try:
from consultation_domain_registry import CANONICAL_DOMAINS, normalize_domain
except ImportError: # pragma: no cover - package import path
from scripts.consultation_domain_registry import CANONICAL_DOMAINS, normalize_domain
# ═══════════════════════════════════════════════════════════════
# 核心枚举与常量
@@ -44,6 +49,96 @@ class ThemeName(str, Enum):
SPIRITUALITY = "spirituality"
@dataclass(frozen=True)
class ConsultationThematicAdapter:
"""Explicit bridge from a canonical consultation domain to this legacy report enum."""
domain: str
capability_status: str
report_theme: Optional[ThemeName]
reason: Optional[str] = None
def to_dict(self) -> Dict[str, Any]:
return {
"domain": self.domain,
"capability_status": self.capability_status,
"report_theme": self.report_theme.value if self.report_theme else None,
"reason": self.reason,
"fallback_theme": None,
}
_NATIVE_CONSULTATION_REPORT_THEMES = {
"career": ThemeName.CAREER,
"marriage": ThemeName.MARRIAGE,
"wealth": ThemeName.WEALTH,
"health": ThemeName.HEALTH,
}
CONSULTATION_THEMATIC_ADAPTERS: Dict[str, ConsultationThematicAdapter] = {
domain: ConsultationThematicAdapter(
domain=domain,
capability_status="supported" if domain in _NATIVE_CONSULTATION_REPORT_THEMES else "blocked",
report_theme=_NATIVE_CONSULTATION_REPORT_THEMES.get(domain),
reason=(
None
if domain in _NATIVE_CONSULTATION_REPORT_THEMES
else "dedicated_thematic_report_enum_unavailable"
),
)
for domain in CANONICAL_DOMAINS
}
INDEPENDENT_REPORT_THEMES = (ThemeName.SPIRITUALITY,)
def consultation_thematic_adapter(value: Any) -> ConsultationThematicAdapter:
"""Resolve a canonical consultation domain without falling back to ``general``."""
return CONSULTATION_THEMATIC_ADAPTERS[normalize_domain(value)]
def consultation_thematic_capabilities() -> Dict[str, Dict[str, Any]]:
"""Return the ordered consultation adapter catalog for API capability surfaces."""
return {
domain: CONSULTATION_THEMATIC_ADAPTERS[domain].to_dict()
for domain in CANONICAL_DOMAINS
}
def build_unavailable_consultation_theme_report(
domain: Any,
*,
evidence: Optional[List[Dict[str, Any]]] = None,
upstream_contract_available: bool = False,
) -> Dict[str, Any]:
"""Build an explicit degraded/blocked result instead of impersonating another theme."""
adapter = consultation_thematic_adapter(domain)
if adapter.report_theme is not None:
raise ValueError(f"Native thematic report is available for: {adapter.domain}")
normalized_evidence = list(evidence or [])
runtime_status = "degraded" if normalized_evidence or upstream_contract_available else "blocked"
return {
"theme": adapter.domain,
"status": runtime_status,
"summary": "该咨询域暂无独立 thematic report 适配器。",
"narrative": "",
"evidence": normalized_evidence,
"strength": "weak",
"timing": None,
"conflicts": [],
"recommendations": [],
"thematic_adapter": {
**adapter.to_dict(),
"status": runtime_status,
"upstream_contract_available": bool(upstream_contract_available),
},
"boundary": (
"The canonical consultation domain remains available in the unified workflow, but this legacy thematic "
"report enum has no dedicated implementation. No general-theme fallback was used."
),
}
# 经典矛盾裁决优先级:D9 > D1(婚姻),D10 > D1(事业),D30 > D1(健康)
# 数值越大优先级越高
CHART_PRIORITY = {
+65 -98
View File
@@ -9,6 +9,27 @@ from dataclasses import dataclass
from pathlib import Path
from typing import Any
try:
from consultation_domain_registry import (
CANONICAL_DOMAINS,
DEFAULT_THEMES,
DOMAIN_ALIASES,
normalize_domain,
)
from consultation_domain_registry import (
normalize_themes as normalize_consultation_themes,
)
except ImportError: # pragma: no cover - import path varies in tests/CLI
from scripts.consultation_domain_registry import (
CANONICAL_DOMAINS,
DEFAULT_THEMES,
DOMAIN_ALIASES,
normalize_domain,
)
from scripts.consultation_domain_registry import (
normalize_themes as normalize_consultation_themes,
)
def _formal_divisions() -> tuple[int, ...]:
registry = Path(__file__).resolve().parents[1] / "references/oracle/d1_d60_varga_mapping_registry_2026_07_19.json"
@@ -88,52 +109,9 @@ class UnifiedConsultationOrchestrator:
"vedastro_official_raw_response",
"vedastro_official_raw_archive_manifest",
]
_THEME_ALIASES = {
"relationship": "marriage",
"marriage": "marriage",
"finance": "wealth",
"money": "wealth",
"wealth": "wealth",
"career": "career",
"health": "health",
"migration": "migration",
"foreign": "migration",
"education": "education",
"study": "education",
"family": "family",
"children": "family",
"annual": "annual",
"yearly": "annual",
"spirituality": "spirituality",
"事业": "career",
"婚恋": "marriage",
"婚姻": "marriage",
"感情": "marriage",
"财富": "wealth",
"财运": "wealth",
"健康": "health",
"迁移": "migration",
"海外": "migration",
"教育": "education",
"学习": "education",
"家庭": "family",
"子女": "family",
"年度": "annual",
"流年": "annual",
"灵性": "spirituality",
}
_DEFAULT_THEMES = ["career", "marriage", "wealth"]
_ALLOWED_THEMES = {
"annual",
"career",
"education",
"family",
"health",
"marriage",
"migration",
"spirituality",
"wealth",
}
_THEME_ALIASES = DOMAIN_ALIASES
_DEFAULT_THEMES = list(DEFAULT_THEMES)
_ALLOWED_THEMES = set(CANONICAL_DOMAINS)
_ROUTE_DEFINITIONS = {
"career": RouteDefinition(
question_type="career",
@@ -141,17 +119,17 @@ class UnifiedConsultationOrchestrator:
focus_techniques=["D10", "Dasha", "Shadbala", "Transit", "Narayana Dasha"],
display_label="career",
),
"relationship": RouteDefinition(
question_type="relationship",
"marriage": RouteDefinition(
question_type="marriage",
primary_theme="marriage",
focus_techniques=["D9", "UL Upapada", "Dasha", "Nakshatra", "Vivah Saham"],
display_label="relationship",
display_label="marriage",
),
"finance": RouteDefinition(
question_type="finance",
"wealth": RouteDefinition(
question_type="wealth",
primary_theme="wealth",
focus_techniques=["D2", "D11", "Dasha", "Shadbala", "Ashtakavarga"],
display_label="finance",
display_label="wealth",
),
"health": RouteDefinition(
question_type="health",
@@ -159,6 +137,12 @@ class UnifiedConsultationOrchestrator:
focus_techniques=["D1", "D6", "D8", "Dasha", "Shadbala", "non-medical boundary"],
display_label="health",
),
"education": RouteDefinition(
question_type="education",
primary_theme="education",
focus_techniques=["D5", "D24", "5th house", "9th house", "Dasha"],
display_label="education",
),
"migration": RouteDefinition(
question_type="migration",
primary_theme="migration",
@@ -171,12 +155,6 @@ class UnifiedConsultationOrchestrator:
focus_techniques=["D7", "D12", "4th house", "5th house", "9th house", "Dasha"],
display_label="family",
),
"education": RouteDefinition(
question_type="education",
primary_theme="education",
focus_techniques=["D5", "D24", "5th house", "9th house", "Dasha"],
display_label="education",
),
"annual": RouteDefinition(
question_type="annual",
primary_theme="annual",
@@ -185,21 +163,21 @@ class UnifiedConsultationOrchestrator:
),
"timing": RouteDefinition(
question_type="timing",
primary_theme="career",
primary_theme="timing",
focus_techniques=["Dasha", "Transit", "Double Transit", "Gochara"],
display_label="timing",
),
"general": RouteDefinition(
question_type="general",
primary_theme="career",
primary_theme="general",
focus_techniques=["D1", "D9", "Dasha", "Yoga", "Shadbala", "Ashtakavarga"],
display_label="general",
),
}
_SYNC_STEPS_BY_ROUTE = {
"career": ["compute_chart", "run_rectification_gate", "run_thematic_report"],
"relationship": ["compute_chart", "run_rectification_gate", "run_thematic_report"],
"finance": ["compute_chart", "run_rectification_gate", "run_thematic_report"],
"marriage": ["compute_chart", "run_rectification_gate", "run_thematic_report"],
"wealth": ["compute_chart", "run_rectification_gate", "run_thematic_report"],
"health": ["compute_chart", "run_rectification_gate", "run_thematic_report"],
"migration": ["compute_chart", "run_rectification_gate", "run_thematic_report"],
"family": ["compute_chart", "run_rectification_gate", "run_thematic_report"],
@@ -214,9 +192,9 @@ class UnifiedConsultationOrchestrator:
"extended_prompt_pack_refresh",
]
_DOMAIN_PROFILE_SECTIONS = {
"relationship": ["core_partner_profile", "temperament_and_compatibility", "timing_windows", "red_flags", "verification_questions"],
"marriage": ["core_partner_profile", "temperament_and_compatibility", "timing_windows", "red_flags", "verification_questions"],
"career": ["career_direction", "role_and_responsibility", "income_and_recognition", "opportunity_windows", "risks_and_verification_questions"],
"finance": ["wealth_path", "income_structure", "asset_and_cashflow_pattern", "opportunity_windows", "verification_questions"],
"wealth": ["wealth_path", "income_structure", "asset_and_cashflow_pattern", "opportunity_windows", "verification_questions"],
"health": ["non_medical_pattern", "pressure_factors", "protective_factors", "verification_questions"],
"migration": ["relocation_pattern", "foreign_link", "candidate_windows", "verification_questions"],
"family": ["family_structure", "home_and_care", "children_boundary", "verification_questions"],
@@ -234,7 +212,8 @@ class UnifiedConsultationOrchestrator:
"family": ("D1", "D7", "D12"),
"education": ("D1", "D5", "D24"),
"annual": ("D1", "D9", "D10"),
"spirituality": ("D1", "D20", "D24", "D60"),
"timing": ("D1", "D9", "D10"),
"general": ("D1", "D9"),
}
_THEME_TECHNIQUE_IDENTIFIERS = {
"career": {"D10", "A10"},
@@ -245,13 +224,17 @@ class UnifiedConsultationOrchestrator:
"family": {"D7", "D12"},
"education": {"D5", "D24"},
"annual": {"DASHA", "TRANSIT", "TAJIKA"},
"spirituality": {"D20", "D60"},
"timing": {"DASHA", "TRANSIT", "GOCHARA"},
"general": {"D1", "D9"},
}
@classmethod
def route_profile_contract(cls, route_name: str) -> dict[str, Any]:
"""Expose reader sections without replacing runtime technique audit."""
route = route_name if route_name in cls._DOMAIN_PROFILE_SECTIONS else "general"
try:
route = normalize_domain(route_name)
except ValueError:
route = "general"
return {
"version": "domain_profile_v1",
"route": route,
@@ -264,36 +247,20 @@ class UnifiedConsultationOrchestrator:
}
def normalize_themes(self, raw: Any) -> list[str]:
if raw in (None, "", "all"):
values = list(self._DEFAULT_THEMES)
elif isinstance(raw, str):
values = [raw]
elif isinstance(raw, list):
values = raw
else:
raise ValueError("theme/themes must be a string, list, or all")
normalized: list[str] = []
for value in values:
key = self._THEME_ALIASES.get(str(value).strip().lower(), str(value).strip().lower())
if key not in self._ALLOWED_THEMES:
raise ValueError(f"Unknown theme: {value}")
if key not in normalized:
normalized.append(key)
return normalized or list(self._DEFAULT_THEMES)
return normalize_consultation_themes(raw)
def resolve_route(self, question: str, themes: list[str] | None = None) -> dict[str, Any]:
text = (question or "").lower()
normalized_themes = themes or list(self._DEFAULT_THEMES)
normalized_themes = self.normalize_themes(themes)
explicit_timing_tokens = ("when", "timing", "何时", "什么时候", "应期", "几月", "哪月", "哪天", "日期")
domain_tokens = {
"career": ("career", "job", "work", "promotion", "business", "profession", "事业", "工作", "升职", "生意"),
"relationship": ("marriage", "married", "wedding", "relationship", "love", "spouse", "partner", "divorce", "婚恋", "婚姻", "感情", "配偶", "恋爱", "结婚", "marry"),
"finance": ("money", "wealth", "finance", "investment", "property", "income", "财务", "财富", "投资", "房产", "收入"),
"marriage": ("marriage", "married", "wedding", "relationship", "love", "spouse", "partner", "divorce", "婚恋", "婚姻", "感情", "配偶", "恋爱", "结婚", "marry"),
"wealth": ("money", "wealth", "finance", "investment", "property", "income", "财务", "财富", "投资", "房产", "收入"),
"health": ("health", "illness", "medical", "disease", "vitality", "健康", "疾病", "", "体力", "医疗"),
"migration": ("migration", "foreign", "abroad", "overseas", "relocation", "迁移", "海外", "出国", "搬迁", "远方"),
"family": ("family", "children", "home", "mother", "father", "家庭", "子女", "孩子", "父母", "家宅"),
"migration": ("migration", "foreign", "abroad", "overseas", "relocation", "home", "迁移", "海外", "出国", "搬迁", "远方"),
"family": ("family", "children", "mother", "father", "家庭", "子女", "孩子", "父母", "家宅"),
"education": ("education", "study", "learning", "school", "degree", "学习", "教育", "学历", "学校", "考试"),
"annual": ("annual", "yearly", "this year", "next year", "年度", "流年", "今年", "明年", "年运"),
}
@@ -316,9 +283,9 @@ class UnifiedConsultationOrchestrator:
elif "career" in normalized_themes:
route = self._ROUTE_DEFINITIONS["career"]
elif "marriage" in normalized_themes:
route = self._ROUTE_DEFINITIONS["relationship"]
route = self._ROUTE_DEFINITIONS["marriage"]
elif "wealth" in normalized_themes:
route = self._ROUTE_DEFINITIONS["finance"]
route = self._ROUTE_DEFINITIONS["wealth"]
elif "health" in normalized_themes:
route = self._ROUTE_DEFINITIONS["health"]
elif "migration" in normalized_themes:
@@ -329,6 +296,8 @@ class UnifiedConsultationOrchestrator:
route = self._ROUTE_DEFINITIONS["education"]
elif "annual" in normalized_themes:
route = self._ROUTE_DEFINITIONS["annual"]
elif "timing" in normalized_themes:
route = self._ROUTE_DEFINITIONS["timing"]
else:
route = self._ROUTE_DEFINITIONS["general"]
@@ -756,23 +725,21 @@ class UnifiedConsultationOrchestrator:
route_packet: dict[str, Any],
machine_evidence_packet: dict[str, Any] | None = None,
) -> dict[str, Any]:
route = route_packet.get("question_type") or route_packet.get("primary_theme") or "general"
if route == "marriage":
route = "relationship"
route = normalize_domain(route_packet.get("question_type") or route_packet.get("primary_theme") or "general")
case_index_by_domain = {
"career": ["references/real_case_studies/vedicka/career-success-poverty-prosperity.md"],
"finance": ["references/real_case_studies/vedicka/career-success-poverty-prosperity.md"],
"relationship": ["docs/benchmark/legacy-marriage-v6.1/verify-results-v6.1.json"],
"wealth": ["references/real_case_studies/vedicka/career-success-poverty-prosperity.md"],
"marriage": ["docs/benchmark/legacy-marriage-v6.1/verify-results-v6.1.json"],
}
case_profiles = {
"references/real_case_studies/vedicka/career-success-poverty-prosperity.md": {
"domains": ["career", "finance"],
"domains": ["career", "wealth"],
"evidence_sections": ["D1", "D10", "dasha_boundaries", "yogas"],
"recorded_outcome": "poverty_to_prosperity_global_recognition",
"event_trigger_keywords": ["Saturn dasha poverty", "Mercury dasha breakthrough", "Ketu dasha consolidation"],
},
"docs/benchmark/legacy-marriage-v6.1/verify-results-v6.1.json": {
"domains": ["relationship"],
"domains": ["marriage"],
"evidence_sections": ["D1", "D9", "UL", "dasha_boundaries"],
"recorded_outcome": "relationship_structure_validation_dataset",
"event_trigger_keywords": ["UL", "Darapada", "7th lord", "DK"],