Files
adaptive-pricing/projects/coulomb-pricing/observatory/usage.py
tegwick 0a38def5a5 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.
2026-06-22 23:23:31 +02:00

48 lines
1.6 KiB
Python

from __future__ import annotations
from decimal import Decimal, ROUND_HALF_UP
from typing import Any
TWOPLACES = Decimal("0.01")
def _money(value: Decimal) -> Decimal:
return value.quantize(TWOPLACES, rounding=ROUND_HALF_UP)
def load_usage_records(data_dir) -> list[dict[str, Any]]:
from pathlib import Path
from .load import _read_json, default_data_dir
root = data_dir or default_data_dir()
path = Path(root) / "usage_records.json"
if not path.exists():
return []
raw = _read_json(path)
return list(raw.get("records", []))
def build_usage_summary(records: list[dict[str, Any]], period: str) -> dict:
period_rows = [row for row in records if row.get("period") == period]
by_member: dict[str, Decimal] = {}
by_model: dict[str, Decimal] = {}
total = Decimal("0")
for row in period_rows:
cost = Decimal(str(row.get("cost_eur", "0")))
total += cost
member_id = row.get("member_id") or "unknown"
model = row.get("model") or "unknown"
by_member[member_id] = by_member.get(member_id, Decimal("0")) + cost
by_model[model] = by_model.get(model, Decimal("0")) + cost
active_members = len(by_member) or 1
return {
"period": period,
"total_ai_spend_eur": _money(total),
"cost_per_active_user_eur": _money(total / active_members),
"by_member": {key: _money(value) for key, value in sorted(by_member.items())},
"by_model": {key: _money(value) for key, value in sorted(by_model.items())},
"record_count": len(period_rows),
}