generated from coulomb/repo-seed
Complete Economic Observatory MVP (ADAPTIVE-WP-0002)
Add file-based Bubble, Stripe, and OpenRouter importers; usage attribution, cost allocation, pricing simulator, credit wallets, and recommendations in the dashboard API. Document whynot-design UI workflow and archive the finished workplan with all ten tasks marked done.
This commit is contained in:
70
projects/coulomb-pricing/observatory/simulator.py
Normal file
70
projects/coulomb-pricing/observatory/simulator.py
Normal file
@@ -0,0 +1,70 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from decimal import Decimal, ROUND_HALF_UP
|
||||
|
||||
from .models import EconomicsSnapshot, PricingModel
|
||||
|
||||
TWOPLACES = Decimal("0.01")
|
||||
OVERAGE_RATE = Decimal("0.002") # EUR per token above allowance (observatory estimate)
|
||||
|
||||
|
||||
def _money(value: Decimal) -> Decimal:
|
||||
return value.quantize(TWOPLACES, rounding=ROUND_HALF_UP)
|
||||
|
||||
|
||||
def _simulate_model(
|
||||
model: PricingModel,
|
||||
snapshot: EconomicsSnapshot,
|
||||
ai_cost_per_member: Decimal,
|
||||
included_tokens: int = 100_000,
|
||||
actual_tokens: int = 120_000,
|
||||
) -> dict:
|
||||
members = snapshot.active_members or 1
|
||||
subscription_revenue = model.access_fee_amount * members
|
||||
overage_revenue = Decimal("0")
|
||||
if model.model_type == "hybrid_subscription_usage" and actual_tokens > included_tokens:
|
||||
overage_tokens = actual_tokens - included_tokens
|
||||
overage_revenue = OVERAGE_RATE * overage_tokens * members
|
||||
|
||||
gross_revenue = subscription_revenue + overage_revenue
|
||||
platform_cost = snapshot.monthly_total_platform_cost + (ai_cost_per_member * members)
|
||||
margin = gross_revenue - platform_cost
|
||||
margin_pct = (margin / gross_revenue * Decimal("100")) if gross_revenue else Decimal("0")
|
||||
|
||||
return {
|
||||
"model_id": model.id,
|
||||
"model_name": model.name,
|
||||
"model_type": model.model_type,
|
||||
"status": model.status,
|
||||
"access_fee_eur": model.access_fee_amount,
|
||||
"projected_revenue_eur": _money(gross_revenue),
|
||||
"projected_overage_eur": _money(overage_revenue),
|
||||
"projected_platform_cost_eur": _money(platform_cost),
|
||||
"projected_margin_eur": _money(margin),
|
||||
"projected_margin_pct": _money(margin_pct),
|
||||
"assumed_tokens_per_member": actual_tokens,
|
||||
"included_tokens": included_tokens if model.model_type != "flat_subscription" else None,
|
||||
}
|
||||
|
||||
|
||||
def build_pricing_simulations(
|
||||
snapshot: EconomicsSnapshot,
|
||||
models: list[PricingModel],
|
||||
ai_cost_per_member: Decimal,
|
||||
) -> dict:
|
||||
scenarios = [
|
||||
_simulate_model(model, snapshot, ai_cost_per_member)
|
||||
for model in models
|
||||
if model.status in ("active", "candidate")
|
||||
]
|
||||
active = next((item for item in scenarios if item["status"] == "active"), scenarios[0])
|
||||
best_margin = max(scenarios, key=lambda item: item["projected_margin_eur"])
|
||||
|
||||
return {
|
||||
"period": snapshot.period,
|
||||
"currency": snapshot.currency,
|
||||
"active_scenario_id": active["model_id"],
|
||||
"best_margin_scenario_id": best_margin["model_id"],
|
||||
"scenarios": scenarios,
|
||||
"notes": "Projections hold member count and infrastructure cost constant; overage uses observatory token estimate.",
|
||||
}
|
||||
Reference in New Issue
Block a user