"""Direct (non-agent) Bayesian compute endpoints. These are useful both as a fallback (when no API key is configured) and as a fast path the frontend can call directly when the user is hand-driving the workbench instead of talking to the Agent. """ from __future__ import annotations from fastapi import APIRouter, HTTPException from app.api.schemas import ( BayesComputeRequest, BayesResultModel, SensitivityPointModel, SensitivityRequest, SensitivityResponse, bayes_result_to_model, ) from app.domain.bayesian import compute, kde, sensitivity_analysis from app.domain.report import render_markdown_report router = APIRouter(prefix="/api/bayesian", tags=["bayesian"]) @router.post("/compute", response_model=BayesResultModel) async def post_compute(req: BayesComputeRequest) -> BayesResultModel: try: result = compute(req.data, req.judgments, req.R) except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) from e return bayes_result_to_model(result) @router.post("/sensitivity", response_model=SensitivityResponse) async def post_sensitivity(req: SensitivityRequest) -> SensitivityResponse: try: points = sensitivity_analysis(req.data, req.judgments, req.r_values) except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) from e return SensitivityResponse( points=[ SensitivityPointModel(R=p["R"], result=bayes_result_to_model(p["result"])) for p in points ] ) @router.post("/kde") async def post_kde(req: BayesComputeRequest) -> dict: """Return the KDE curve for the dataset (200 points). Used by the PriorPosterior / KDE chart on the frontend.""" try: pts = kde(req.data, n_points=200) except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) from e return {"points": pts} @router.post("/report") async def post_report(req: BayesComputeRequest) -> dict: """Compute + render a structured Markdown report in one call.""" try: result = compute(req.data, req.judgments, req.R) sweep = sensitivity_analysis(req.data, req.judgments, [2.0, 5.0, 10.0, 20.0, 50.0]) except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) from e sens_rows = [ { "R": p["R"], "posterior_mean": p["result"].posterior.stats.mean, "posterior_std": p["result"].posterior.stats.std, "ci95_lower": p["result"].posterior.stats.ci95_lower, "ci95_upper": p["result"].posterior.stats.ci95_upper, } for p in sweep ] md = render_markdown_report( result, scenario_name=req.scenario_name or "未命名情景", reference_case=req.reference_case or "", sensitivity_rows=sens_rows, ) return {"markdown": md, "result": bayes_result_to_model(result).model_dump()}