diff --git a/frontend/src/app/api/synastry/route.ts b/frontend/src/app/api/synastry/route.ts index c4cfdf8c..39c4a1ee 100644 --- a/frontend/src/app/api/synastry/route.ts +++ b/frontend/src/app/api/synastry/route.ts @@ -68,6 +68,40 @@ function d9Summary(varga: Record) { }; } +function planetSign(point: unknown) { + return point && typeof point === "object" && "sign" in point + ? String((point as Record).sign || "unknown") + : "unknown"; +} + +function relationshipReport(synastry: Record, selfD9: Record, partnerD9: Record) { + const total = Number(synastry.total_score ?? 0); + const max = Number(synastry.max_score ?? 36); + const ratio = max > 0 ? total / max : 0; + const band = ratio >= 0.72 ? "supportive" : ratio >= 0.5 ? "mixed" : "challenging"; + const self = d9Summary(selfD9); + const partner = d9Summary(partnerD9); + return { + status: "evidence_summary", + scoreBand: band, + headline: band === "supportive" + ? "基础匹配度偏支持,但仍需结合现实互动与长期运势。" + : band === "mixed" + ? "基础匹配度中等,适合重点观察沟通节奏、价值观与关系承诺。" + : "基础匹配度偏谨慎,需要先处理冲突模式与现实条件。", + strengths: [ + `Ashtakoot ${total}/${max}`, + `本人 D9 Moon:${planetSign(self.moon)}`, + `对方 D9 Moon:${planetSign(partner.moon)}`, + ], + risks: [ + "这不是完整婚恋结论;尚未纳入双方 Dasha、UL/DK 与长期时机。", + `D9 Venus/Mars 需要继续解释:本人 ${planetSign(self.venus)}/${planetSign(self.mars)},对方 ${planetSign(partner.venus)}/${planetSign(partner.mars)}。`, + ], + nextEvidence: ["双方 Dasha", "UL/DK", "D9 7宫/7主", "现实关系时间线"], + }; +} + async function postPython(path: string, body: unknown) { const response = await fetch(`${apiBase}${path}`, { method: "POST", @@ -113,6 +147,7 @@ export async function POST(request: Request) { selfChart: { moon: moonSummary(selfChart), d9: d9Summary(selfD9) }, partnerChart: { moon: moonSummary(partnerChart), d9: d9Summary(partnerD9) }, synastry, + relationshipReport: relationshipReport(synastry, selfD9, partnerD9), }); } catch (error) { return NextResponse.json({ diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx index 0999b3ec..45d12f06 100644 --- a/frontend/src/app/page.tsx +++ b/frontend/src/app/page.tsx @@ -1256,7 +1256,7 @@ export default function Home() { headers: { "Content-Type": "application/json" }, body: JSON.stringify({ selfProfile: profile, partnerProfile: record.profile }), }); - const payload = await response.json().catch(() => null) as { status?: string; evidenceLayers?: string[]; synastry?: { total_score?: number; max_score?: number; assessment?: string } } | null; + const payload = await response.json().catch(() => null) as { status?: string; evidenceLayers?: string[]; synastry?: { total_score?: number; max_score?: number; assessment?: string }; relationshipReport?: { headline?: string } } | null; if (response.ok && payload?.status === "ok") { const score = payload.synastry?.total_score; const max = payload.synastry?.max_score; @@ -1266,6 +1266,7 @@ export default function Home() { baseQuestion, "", `已计算基础合盘证据:${layers};Ashtakoot ${score ?? "?"}/${max ?? "?"},初步评级:${assessment || "待解释"}。请基于这个证据包继续分析。`, + payload.relationshipReport?.headline ? `结构化摘要:${payload.relationshipReport.headline}` : "", ].join("\n"), "marriage"); } else { chooseSuggestedQuestion(baseQuestion, "marriage"); diff --git a/tests/test_supabase_user_data_contract.py b/tests/test_supabase_user_data_contract.py index 0ae206d6..59a38232 100644 --- a/tests/test_supabase_user_data_contract.py +++ b/tests/test_supabase_user_data_contract.py @@ -168,6 +168,9 @@ def test_synastry_route_orchestrates_python_chart_and_ashtakoot() -> None: "moonLongitude(selfChart)", "moonSummary(selfChart)", "d9Summary(selfD9)", + "relationshipReport", + "scoreBand", + "nextEvidence", "ashtakoot_plus_moon_nakshatra_d9", 'evidenceLayers: ["ashtakoot", "moon_nakshatra", "d9_navamsa"]', 'status: "blocked"',