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:
48
projects/coulomb-pricing/observatory/usage.py
Normal file
48
projects/coulomb-pricing/observatory/usage.py
Normal file
@@ -0,0 +1,48 @@
|
||||
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),
|
||||
}
|
||||
Reference in New Issue
Block a user