74 lines
2.3 KiB
Python
74 lines
2.3 KiB
Python
from typing import Any, Dict, List, cast
|
|
|
|
from fastapi import APIRouter, HTTPException, Request, status
|
|
from pydantic import BaseModel
|
|
|
|
from services.reporting import generate_report
|
|
|
|
|
|
router = APIRouter(prefix="/api/reporting", tags=["Reporting"])
|
|
|
|
|
|
def _validate_payload(payload: Any) -> List[Dict[str, float]]:
|
|
if not isinstance(payload, list):
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="Invalid input format",
|
|
)
|
|
|
|
typed_payload = cast(List[Any], payload)
|
|
|
|
validated: List[Dict[str, float]] = []
|
|
for index, item in enumerate(typed_payload):
|
|
if not isinstance(item, dict):
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail=f"Entry at index {index} must be an object",
|
|
)
|
|
value = cast(Dict[str, Any], item).get("result")
|
|
if not isinstance(value, (int, float)):
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail=f"Entry at index {index} must include numeric 'result'",
|
|
)
|
|
validated.append({"result": float(value)})
|
|
return validated
|
|
|
|
|
|
class ReportSummary(BaseModel):
|
|
count: int
|
|
mean: float
|
|
median: float
|
|
min: float
|
|
max: float
|
|
std_dev: float
|
|
variance: float
|
|
percentile_10: float
|
|
percentile_90: float
|
|
percentile_5: float
|
|
percentile_95: float
|
|
value_at_risk_95: float
|
|
expected_shortfall_95: float
|
|
|
|
|
|
@router.post("/summary", response_model=ReportSummary)
|
|
async def summary_report(request: Request):
|
|
payload = await request.json()
|
|
validated_payload = _validate_payload(payload)
|
|
summary = generate_report(validated_payload)
|
|
return ReportSummary(
|
|
count=int(summary["count"]),
|
|
mean=float(summary["mean"]),
|
|
median=float(summary["median"]),
|
|
min=float(summary["min"]),
|
|
max=float(summary["max"]),
|
|
std_dev=float(summary["std_dev"]),
|
|
variance=float(summary["variance"]),
|
|
percentile_10=float(summary["percentile_10"]),
|
|
percentile_90=float(summary["percentile_90"]),
|
|
percentile_5=float(summary["percentile_5"]),
|
|
percentile_95=float(summary["percentile_95"]),
|
|
value_at_risk_95=float(summary["value_at_risk_95"]),
|
|
expected_shortfall_95=float(summary["expected_shortfall_95"]),
|
|
)
|