Complete Phase 1 implementation: Backend (FastAPI + MongoDB + Celery): - Core: config, DB with indexes, JWT security, API key auth middleware - Models: org hierarchy (workspace/team/project), user mirror, pricing, usage events/rollups, budgets, alert log, audit log - Services: pricing engine (LiteLLM/YAML/override priority), budget check with preflight, email alerts at 50/80/100%, analytics aggregations, audit logger - API routes: public (preflight/record/upsert), admin CRUD, pricing management, budget management, analytics (summary/timeseries/breakdown/pivot), Microsoft SSO auth - Celery tasks: daily LiteLLM price sync with change notifications, daily rollup aggregation, 5-minute alert evaluator - Pricing catalogue: ElevenLabs + Google Cloud TTS in models.yaml SDK (oliver-cost-tracker Python package): - CostTracker client with httpx + exponential backoff (3 retries) - SQLite outbox with 30s background flusher (never blocks AI pipeline) - Estimators: token/char estimation per provider - BudgetExceeded / CostTrackerUnavailable exceptions Frontend (React 18 + Vite + TypeScript): - Dashboard with KPI cards, daily cost timeseries, top-model/top-user charts - Pivot Explorer with multi-dim row/col selection + stacked bar chart + table - Admin pages: Workspaces, Pricing (with LiteLLM sync + override), Budgets (with live spend bar), API Keys (show-once), Users (mirror), Audit Log - Microsoft SSO login flow Infra: docker-compose.yml (mongo + redis + api + celery worker + beat + frontend) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
57 lines
1.8 KiB
Python
57 lines
1.8 KiB
Python
from datetime import datetime
|
|
from typing import Any, Literal, Optional
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
class UsageUnits(BaseModel):
|
|
input_tokens: Optional[int] = None
|
|
output_tokens: Optional[int] = None
|
|
chars: Optional[int] = None
|
|
seconds: Optional[float] = None
|
|
|
|
|
|
class UsageEvent(BaseModel):
|
|
id: Optional[str] = Field(None, alias="_id")
|
|
ts: Optional[datetime] = None
|
|
source_app: str
|
|
request_id: Optional[str] = None # from preflight; links preflight→record
|
|
user_external_id: str
|
|
workspace_id: Optional[str] = None
|
|
team_id: Optional[str] = None
|
|
project_id: Optional[str] = None
|
|
job_external_id: Optional[str] = None
|
|
provider: str
|
|
model: str
|
|
units: UsageUnits = UsageUnits()
|
|
cost_usd: Optional[float] = None
|
|
price_id: Optional[str] = None # ref to model_prices._id used
|
|
pricing_missing: bool = False # true if no price found at record time
|
|
latency_ms: Optional[int] = None
|
|
status: Literal["success", "error", "timeout"] = "success"
|
|
error_message: Optional[str] = None
|
|
metadata: dict[str, Any] = {}
|
|
|
|
class Config:
|
|
populate_by_name = True
|
|
|
|
|
|
class UsageRollup(BaseModel):
|
|
"""Pre-aggregated daily rollup for fast analytics queries."""
|
|
id: Optional[str] = Field(None, alias="_id")
|
|
date: str # "YYYY-MM-DD"
|
|
workspace_id: Optional[str] = None
|
|
team_id: Optional[str] = None
|
|
project_id: Optional[str] = None
|
|
user_external_id: Optional[str] = None
|
|
source_app: Optional[str] = None
|
|
provider: Optional[str] = None
|
|
model: Optional[str] = None
|
|
total_calls: int = 0
|
|
total_cost_usd: float = 0.0
|
|
total_input_tokens: int = 0
|
|
total_output_tokens: int = 0
|
|
total_chars: int = 0
|
|
|
|
class Config:
|
|
populate_by_name = True
|