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