"""Verbrauch je Modellaufruf (→ Konzept 8.1, 13): Tokens und Kosten, unabhängig von Chats. Einträge bleiben erhalten, wenn Chats oder Workspaces gelöscht werden; die Kosten werden mit dem Preis zum Zeitpunkt des Aufrufs festgeschrieben. """ import uuid from datetime import datetime from decimal import Decimal from sqlalchemy import BigInteger, ForeignKey, Identity, Integer, Numeric, String, Uuid from sqlalchemy.orm import Mapped, mapped_column from app.core.database import Base, now class UsageRecord(Base): __tablename__ = "usage_records" id: Mapped[int] = mapped_column(BigInteger, Identity(), primary_key=True) time: Mapped[datetime] = mapped_column(default=now, index=True) # Kein Fremdschlüssel: der Run kann mit dem Chat gelöscht werden, der Verbrauch bleibt run_id: Mapped[uuid.UUID | None] = mapped_column(Uuid, index=True) team_id: Mapped[int | None] = mapped_column(ForeignKey("teams.id", ondelete="SET NULL"), index=True) workspace_id: Mapped[int | None] = mapped_column(ForeignKey("workspaces.id", ondelete="SET NULL"), index=True) user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL")) model: Mapped[str] = mapped_column(String(200)) input_tokens: Mapped[int] = mapped_column(Integer, default=0) cached_tokens: Mapped[int] = mapped_column(Integer, default=0) output_tokens: Mapped[int] = mapped_column(Integer, default=0) reasoning_tokens: Mapped[int] = mapped_column(Integer, default=0) # Leer, wenn für das Modell kein Preis hinterlegt war cost: Mapped[Decimal | None] = mapped_column(Numeric(14, 6))