نسخهٔ وب مستقل — پلتفرم نیروی کار هوش مصنوعی
مخزن اختصاصی برنامهٔ وب؛ محتوای پوشهٔ web در ریشهٔ مخزن قرار گرفت. تاریخچهٔ پروژهٔ ربات (agy-bot) در این مخزن وجود ندارد و هیچ وابستگی runtime به آن نیست.
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
"""Audit and usage-ledger ports.
|
||||
|
||||
``AuditPort`` writes the immutable trail; ``UsageLedgerPort`` is the billing
|
||||
source of truth. Both are append-only by contract.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
from typing import Protocol, runtime_checkable
|
||||
|
||||
from app.domain.ai_control.models import RateUnit
|
||||
from app.domain.audit.models import AuditEvent
|
||||
|
||||
|
||||
@dataclass(slots=True, kw_only=True)
|
||||
class UsageRecord:
|
||||
organization_id: str
|
||||
unit: RateUnit
|
||||
quantity: float
|
||||
unit_price: float = 0.0
|
||||
internal_cost_estimate: float = 0.0
|
||||
total_price: float = 0.0
|
||||
project_id: str | None = None
|
||||
user_id: str | None = None
|
||||
employee_id: str | None = None
|
||||
run_id: str | None = None
|
||||
metadata_json: dict = field(default_factory=dict)
|
||||
|
||||
|
||||
@dataclass(slots=True, kw_only=True)
|
||||
class UsageAggregate:
|
||||
unit: RateUnit
|
||||
quantity: float = 0.0
|
||||
total_price: float = 0.0
|
||||
internal_cost_estimate: float = 0.0
|
||||
|
||||
|
||||
@dataclass(slots=True, kw_only=True)
|
||||
class UsageBreakdown:
|
||||
"""Grouped totals for the billing dashboard."""
|
||||
|
||||
by_unit: list[UsageAggregate] = field(default_factory=list)
|
||||
by_employee: dict[str, float] = field(default_factory=dict)
|
||||
by_project: dict[str, float] = field(default_factory=dict)
|
||||
total_price: float = 0.0
|
||||
total_cost: float = 0.0
|
||||
|
||||
|
||||
@runtime_checkable
|
||||
class AuditPort(Protocol):
|
||||
async def record(self, *, event: AuditEvent) -> AuditEvent: ...
|
||||
|
||||
async def list_for_organization(
|
||||
self, *, organization_id: str, limit: int = 100, offset: int = 0
|
||||
) -> list[AuditEvent]: ...
|
||||
|
||||
|
||||
@runtime_checkable
|
||||
class UsageLedgerPort(Protocol):
|
||||
async def record(self, *, usage: UsageRecord) -> None:
|
||||
"""Append one usage event. Never raises for business reasons — a failed
|
||||
ledger write is an infrastructure error and must surface loudly."""
|
||||
...
|
||||
|
||||
async def breakdown(
|
||||
self,
|
||||
*,
|
||||
organization_id: str,
|
||||
since: datetime | None = None,
|
||||
until: datetime | None = None,
|
||||
) -> UsageBreakdown: ...
|
||||
Reference in New Issue
Block a user