Spaces:
Sleeping
Sleeping
| """ | |
| ROI Calculator endpoint — Calculate return on investment for OptiQ deployment. | |
| """ | |
| from __future__ import annotations | |
| from fastapi import APIRouter, Depends | |
| from pydantic import BaseModel, Field | |
| from config import CFG | |
| from api.auth import optional_auth, FirebaseUser | |
| router = APIRouter() | |
| # OptiQ pricing tiers (from README) | |
| PRICING = { | |
| "saas": { | |
| "name": "SaaS Subscription", | |
| "price_per_feeder_month": 200, | |
| "price_per_feeder_year": 2400, | |
| "description": "Pay-as-you-go pricing. Best for small deployments.", | |
| }, | |
| "revenue_share": { | |
| "name": "Revenue Share", | |
| "share_pct": 15, | |
| "description": "No upfront cost. Pay 15% of verified savings.", | |
| }, | |
| "enterprise": { | |
| "name": "Enterprise License", | |
| "annual_fee": 500000, | |
| "max_feeders": 1000, | |
| "price_per_feeder_year": 500, | |
| "description": "Flat annual fee for up to 1,000 feeders.", | |
| }, | |
| } | |
| # Impact per feeder (from README benchmarks) | |
| PER_FEEDER_IMPACT = { | |
| "loss_reduction_pct": 31.15, | |
| "energy_saved_kwh_year": 553020, | |
| "co2_saved_tonnes_year": 26.3, | |
| "cost_saved_subsidised_year": 16591, # at $0.03/kWh | |
| "cost_saved_real_year": 44242, # at $0.08/kWh | |
| } | |
| class ROIRequest(BaseModel): | |
| number_of_feeders: int = Field(ge=1, le=100000, description="Number of feeders to deploy") | |
| pricing_model: str = Field(default="saas", description="Pricing model: saas, revenue_share, or enterprise") | |
| use_real_cost: bool = Field(default=True, description="Use real electricity cost (True) or subsidised (False)") | |
| def calculate_roi(req: ROIRequest, user: FirebaseUser = Depends(optional_auth)): | |
| """Calculate ROI for OptiQ deployment. | |
| Returns annual savings, OptiQ cost, and net profit for the given number of feeders. | |
| """ | |
| n = req.number_of_feeders | |
| impact = PER_FEEDER_IMPACT | |
| # Calculate savings per feeder | |
| if req.use_real_cost: | |
| savings_per_feeder = impact["cost_saved_real_year"] | |
| electricity_rate = 0.08 | |
| else: | |
| savings_per_feeder = impact["cost_saved_subsidised_year"] | |
| electricity_rate = 0.03 | |
| total_savings = savings_per_feeder * n | |
| total_energy_saved = impact["energy_saved_kwh_year"] * n | |
| total_co2_saved = impact["co2_saved_tonnes_year"] * n | |
| # Calculate OptiQ cost based on pricing model | |
| pricing = PRICING[req.pricing_model] | |
| if req.pricing_model == "saas": | |
| optiq_cost = pricing["price_per_feeder_year"] * n | |
| effective_price_per_feeder = pricing["price_per_feeder_year"] | |
| elif req.pricing_model == "revenue_share": | |
| optiq_cost = total_savings * (pricing["share_pct"] / 100) | |
| effective_price_per_feeder = optiq_cost / n if n > 0 else 0 | |
| else: # enterprise | |
| if n <= pricing["max_feeders"]: | |
| optiq_cost = pricing["annual_fee"] | |
| else: | |
| # Additional feeders at $500/feeder/year | |
| optiq_cost = pricing["annual_fee"] + (n - pricing["max_feeders"]) * pricing["price_per_feeder_year"] | |
| effective_price_per_feeder = optiq_cost / n if n > 0 else 0 | |
| net_profit = total_savings - optiq_cost | |
| roi_pct = (net_profit / optiq_cost * 100) if optiq_cost > 0 else float("inf") | |
| savings_to_cost_ratio = total_savings / optiq_cost if optiq_cost > 0 else float("inf") | |
| payback_months = (optiq_cost / (total_savings / 12)) if total_savings > 0 else float("inf") | |
| return { | |
| "number_of_feeders": n, | |
| "pricing_model": req.pricing_model, | |
| "pricing_details": pricing, | |
| "electricity_rate_usd_kwh": electricity_rate, | |
| "per_feeder": { | |
| "energy_saved_kwh_year": impact["energy_saved_kwh_year"], | |
| "co2_saved_tonnes_year": impact["co2_saved_tonnes_year"], | |
| "cost_saved_usd_year": savings_per_feeder, | |
| "loss_reduction_pct": impact["loss_reduction_pct"], | |
| }, | |
| "annual_totals": { | |
| "energy_saved_mwh": round(total_energy_saved / 1000, 2), | |
| "energy_saved_gwh": round(total_energy_saved / 1_000_000, 4), | |
| "co2_saved_tonnes": round(total_co2_saved, 2), | |
| "utility_savings_usd": round(total_savings, 2), | |
| "optiq_cost_usd": round(optiq_cost, 2), | |
| "net_profit_usd": round(net_profit, 2), | |
| }, | |
| "metrics": { | |
| "roi_pct": round(roi_pct, 1) if roi_pct != float("inf") else "∞", | |
| "savings_to_cost_ratio": round(savings_to_cost_ratio, 1) if savings_to_cost_ratio != float("inf") else "∞", | |
| "payback_months": round(payback_months, 1) if payback_months != float("inf") else 0, | |
| "effective_price_per_feeder_year": round(effective_price_per_feeder, 2), | |
| }, | |
| "equivalents": { | |
| "trees_planted": int(total_co2_saved * 1000 / 21), | |
| "cars_removed": round(total_co2_saved / 4.6, 0), | |
| "homes_powered": int(total_energy_saved / 10000), # Average home ~10 MWh/year | |
| }, | |
| } | |
| def get_pricing(user: FirebaseUser = Depends(optional_auth)): | |
| """Get available pricing models.""" | |
| return { | |
| "pricing_models": PRICING, | |
| "per_feeder_impact": PER_FEEDER_IMPACT, | |
| "factors": { | |
| "egypt_emission_factor_kg_kwh": CFG.egypt.emission_factor, | |
| "electricity_price_subsidised": CFG.egypt.electricity_price_subsidised, | |
| "electricity_price_real": CFG.egypt.electricity_price_real, | |
| }, | |
| } | |
| def compare_pricing(number_of_feeders: int = 100, user: FirebaseUser = Depends(optional_auth)): | |
| """Compare all pricing models for a given number of feeders.""" | |
| results = {} | |
| for model in PRICING.keys(): | |
| req = ROIRequest(number_of_feeders=number_of_feeders, pricing_model=model) | |
| results[model] = calculate_roi(req, user) | |
| # Find best model | |
| best_model = max( | |
| results.keys(), | |
| key=lambda m: results[m]["annual_totals"]["net_profit_usd"] | |
| ) | |
| return { | |
| "number_of_feeders": number_of_feeders, | |
| "comparison": results, | |
| "recommended": best_model, | |
| "recommendation_reason": f"{PRICING[best_model]['name']} offers the highest net profit for {number_of_feeders} feeders", | |
| } | |