From d9d2e22d796ea06a634f5df91b23e0ae85e7ad3a Mon Sep 17 00:00:00 2001 From: Heet Ranpura Date: Fri, 24 Apr 2026 02:53:45 +0530 Subject: [PATCH] =?UTF-8?q?feat:=20headless=20/api/v1/calculate=20endpoint?= =?UTF-8?q?=20=E2=80=94=20sub-50ms,=20no=20LLM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add ComputeAllOutput schema at end of schemas.py (no overlap with other PRs) - Create engines/compute.py with compute_all() function - Add POST /api/v1/calculate endpoint after health check (no auth required) - Pure math, zero LLM, zero API budget cost, target < 50ms - Designed for frontend real-time sliders and comparison tools --- backend/engines/compute.py | 64 ++++++++++++++++++++++++++++++++++++++ backend/main.py | 25 +++++++++++++++ backend/schemas/schemas.py | 14 ++++++++- 3 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 backend/engines/compute.py diff --git a/backend/engines/compute.py b/backend/engines/compute.py new file mode 100644 index 0000000..e4c9249 --- /dev/null +++ b/backend/engines/compute.py @@ -0,0 +1,64 @@ +""" +Headless Compute Engine — All deterministic math in one function call. + +compute_all() runs every deterministic agent in sequence and returns the +complete bundled result. This is the function behind the /api/v1/calculate +endpoint — designed for sub-50ms execution with zero LLM involvement. + +Use cases: + - Frontend real-time sliders that update as the user drags + - Comparison tools that need fast recalculation + - Batch processing without burning API quota + - Unit testing the math pipeline in isolation +""" +import sys +import os +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +from schemas.schemas import UserInput, ComputeAllOutput +from engines.india_defaults import calculate_true_total_cost +from agents.deterministic.financial_reality import calculate_affordability +from agents.deterministic.scenario_simulation import run_all_scenarios +from agents.deterministic.risk_scorer import calculate_risk_score + + +def compute_all(user_input: UserInput) -> ComputeAllOutput: + """ + Run every deterministic calculation and return the bundled result. + + Execution order (respects dependencies): + 1. india_defaults — hidden cost breakdown (independent) + 2. affordability — EMI, ratios, cash flow (independent) + 3. scenarios — stress tests (depends on #2) + 4. risk_score — composite score (depends on #2 and #3) + + Total execution time target: < 50ms on a single CPU core. + All functions are pure Python arithmetic with no I/O. + """ + loan_amount = user_input.property_price - user_input.down_payment + if loan_amount < 0: + loan_amount = 0.0 + + india_costs = calculate_true_total_cost( + base_price=user_input.property_price, + state=user_input.state, + property_type=user_input.property_type.value, + loan_amount=loan_amount, + area_sqft=user_input.area_sqft if user_input.area_sqft else 1000, + ) + + financial_reality = calculate_affordability(user_input) + all_scenarios = run_all_scenarios(user_input, financial_reality) + risk_score = calculate_risk_score( + financial_reality=financial_reality, + all_scenarios=all_scenarios, + age=user_input.age, + tenure_years=user_input.tenure_years, + ) + + return ComputeAllOutput( + india_cost_breakdown=india_costs, + financial_reality=financial_reality, + all_scenarios=all_scenarios, + risk_score=risk_score, + ) diff --git a/backend/main.py b/backend/main.py index 63c206e..1e8523a 100644 --- a/backend/main.py +++ b/backend/main.py @@ -48,6 +48,8 @@ from agents.deterministic.risk_scorer import calculate_risk_score from engines.pdf_generator import generate_pdf from storage.gcs_client import upload_pdf +# Headless compute engine (PR: headless-calculate-endpoint) +from engines.compute import compute_all # --------------------------------------------------------------------------- @@ -102,6 +104,29 @@ async def health_check(): return {"status": "healthy", "service": "niv-ai-home-buying-advisor", "version": "1.0.0"} +# --------------------------------------------------------------------------- +# Headless calculate — pure math, no LLM, no auth required +# --------------------------------------------------------------------------- + +@app.post("/api/v1/calculate", response_model=APIResponse) +async def calculate_route(user_input: UserInput): + """ + Headless deterministic calculation endpoint. + Runs all math agents and returns the bundled result. + No auth required — pure math, zero API budget cost. + Designed for frontend real-time sliders. Target: < 50ms. + """ + try: + result = compute_all(user_input) + return APIResponse( + success=True, + message="Calculation complete", + data=result.model_dump(), + ) + except Exception as e: + raise HTTPException(status_code=500, detail=f"Calculation failed: {str(e)}") + + # --------------------------------------------------------------------------- # Session management # --------------------------------------------------------------------------- diff --git a/backend/schemas/schemas.py b/backend/schemas/schemas.py index 7724f9e..0381c21 100644 --- a/backend/schemas/schemas.py +++ b/backend/schemas/schemas.py @@ -576,4 +576,16 @@ class SessionStartResponse(BaseModel): class ConversationResponse(BaseModel): session_id: str conversation_output: ConversationOutput - updated_analysis: Optional[AnalysisResponse] = None \ No newline at end of file + updated_analysis: Optional[AnalysisResponse] = None + + +# ----------------------------------------------------------------------------- +# Headless compute engine output (PR: headless-calculate-endpoint) +# ----------------------------------------------------------------------------- + +class ComputeAllOutput(BaseModel): + """Bundled output of all deterministic calculations — no LLM involved.""" + india_cost_breakdown: IndiaCostBreakdown + financial_reality: FinancialRealityOutput + all_scenarios: AllScenariosOutput + risk_score: RiskScoreOutput \ No newline at end of file