Spaces:
Sleeping
Sleeping
| """ | |
| Database models for billing and usage tracking. | |
| """ | |
| from sqlalchemy import Column, String, Integer, Float, DateTime, Boolean, ForeignKey, Text | |
| from sqlalchemy.orm import relationship | |
| from datetime import datetime | |
| from typing import Optional | |
| from app.db.database import Base | |
| class Tenant(Base): | |
| """Tenant/organization model.""" | |
| __tablename__ = "tenants" | |
| id = Column(String, primary_key=True, index=True) | |
| name = Column(String, nullable=False) | |
| created_at = Column(DateTime, default=datetime.utcnow, nullable=False) | |
| updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False) | |
| # Relationships | |
| plan = relationship("TenantPlan", back_populates="tenant", uselist=False) | |
| usage_events = relationship("UsageEvent", back_populates="tenant") | |
| daily_usage = relationship("UsageDaily", back_populates="tenant") | |
| monthly_usage = relationship("UsageMonthly", back_populates="tenant") | |
| class TenantPlan(Base): | |
| """Tenant subscription plan.""" | |
| __tablename__ = "tenant_plans" | |
| id = Column(Integer, primary_key=True, autoincrement=True) | |
| tenant_id = Column(String, ForeignKey("tenants.id"), unique=True, nullable=False, index=True) | |
| plan_name = Column(String, nullable=False, index=True) # "starter", "growth", "pro" | |
| monthly_chat_limit = Column(Integer, nullable=False) # -1 for unlimited | |
| created_at = Column(DateTime, default=datetime.utcnow, nullable=False) | |
| updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False) | |
| # Relationships | |
| tenant = relationship("Tenant", back_populates="plan") | |
| class UsageEvent(Base): | |
| """Individual usage event (each /chat request).""" | |
| __tablename__ = "usage_events" | |
| id = Column(Integer, primary_key=True, autoincrement=True) | |
| request_id = Column(String, unique=True, nullable=False, index=True) | |
| tenant_id = Column(String, ForeignKey("tenants.id"), nullable=False, index=True) | |
| user_id = Column(String, nullable=False, index=True) | |
| kb_id = Column(String, nullable=False) | |
| # LLM details | |
| provider = Column(String, nullable=False) # "gemini" or "openai" | |
| model = Column(String, nullable=False) | |
| # Token usage | |
| prompt_tokens = Column(Integer, nullable=False, default=0) | |
| completion_tokens = Column(Integer, nullable=False, default=0) | |
| total_tokens = Column(Integer, nullable=False, default=0) | |
| # Cost tracking | |
| estimated_cost_usd = Column(Float, nullable=False, default=0.0) | |
| # Timestamp | |
| request_timestamp = Column(DateTime, default=datetime.utcnow, nullable=False, index=True) | |
| # Relationships | |
| tenant = relationship("Tenant", back_populates="usage_events") | |
| class UsageDaily(Base): | |
| """Daily aggregated usage per tenant.""" | |
| __tablename__ = "usage_daily" | |
| id = Column(Integer, primary_key=True, autoincrement=True) | |
| tenant_id = Column(String, ForeignKey("tenants.id"), nullable=False, index=True) | |
| date = Column(DateTime, nullable=False, index=True) | |
| # Aggregated metrics | |
| total_requests = Column(Integer, nullable=False, default=0) | |
| total_tokens = Column(Integer, nullable=False, default=0) | |
| total_cost_usd = Column(Float, nullable=False, default=0.0) | |
| # Provider breakdown | |
| gemini_requests = Column(Integer, nullable=False, default=0) | |
| openai_requests = Column(Integer, nullable=False, default=0) | |
| created_at = Column(DateTime, default=datetime.utcnow, nullable=False) | |
| updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False) | |
| # Unique constraint: one record per tenant per day | |
| __table_args__ = ( | |
| {"sqlite_autoincrement": True}, | |
| ) | |
| # Relationships | |
| tenant = relationship("Tenant", back_populates="daily_usage") | |
| class UsageMonthly(Base): | |
| """Monthly aggregated usage per tenant.""" | |
| __tablename__ = "usage_monthly" | |
| id = Column(Integer, primary_key=True, autoincrement=True) | |
| tenant_id = Column(String, ForeignKey("tenants.id"), nullable=False, index=True) | |
| year = Column(Integer, nullable=False, index=True) | |
| month = Column(Integer, nullable=False, index=True) # 1-12 | |
| # Aggregated metrics | |
| total_requests = Column(Integer, nullable=False, default=0) | |
| total_tokens = Column(Integer, nullable=False, default=0) | |
| total_cost_usd = Column(Float, nullable=False, default=0.0) | |
| # Provider breakdown | |
| gemini_requests = Column(Integer, nullable=False, default=0) | |
| openai_requests = Column(Integer, nullable=False, default=0) | |
| created_at = Column(DateTime, default=datetime.utcnow, nullable=False) | |
| updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False) | |
| # Unique constraint: one record per tenant per month | |
| __table_args__ = ( | |
| {"sqlite_autoincrement": True}, | |
| ) | |
| # Relationships | |
| tenant = relationship("Tenant", back_populates="monthly_usage") | |