Implement a unified LLM Gateway supporting multiple API formats and providers: Features: - OpenAI Chat Completions, Responses API, and Anthropic Messages API - Provider adapters for OpenAI, Anthropic, Azure OpenAI, Google Gemini, AWS Bedrock - Model aliasing with weighted round-robin load balancing - Virtual API keys with RPM/TPM rate limiting - Budget control at key and project levels - Request logging, usage statistics, and audit logs - Fallback/retry with circuit breaker pattern - Admin CRUD APIs for providers, projects, keys, models, usage - Provider health checks Tech stack: - FastAPI with async SQLAlchemy 2.0 - SQLite with aiosqlite - bcrypt for API key hashing, AES-256 for provider key encryption - Docker containerization Tests: 18 passing integration tests for admin API endpoints Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
49 lines
1.9 KiB
Python
49 lines
1.9 KiB
Python
"""API Key model."""
|
|
from datetime import datetime
|
|
from decimal import Decimal
|
|
from uuid import uuid4
|
|
|
|
from sqlalchemy import Boolean, DateTime, ForeignKey, Integer, Numeric, String, Text
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from app.db.database import Base
|
|
|
|
|
|
class APIKey(Base):
|
|
"""Virtual API Key for authentication and usage tracking."""
|
|
|
|
__tablename__ = "api_keys"
|
|
|
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4()))
|
|
key_hash: Mapped[str] = mapped_column(String(128), unique=True, nullable=False, index=True)
|
|
key_prefix: Mapped[str] = mapped_column(String(20), nullable=False) # e.g., "sk-proj_abc..."
|
|
name: Mapped[str] = mapped_column(String(100), nullable=False)
|
|
|
|
# Project relationship
|
|
project_id: Mapped[str | None] = mapped_column(String(36), ForeignKey("projects.id"))
|
|
project: Mapped["Project"] = relationship("Project", backref="api_keys")
|
|
|
|
enabled: Mapped[bool] = mapped_column(Boolean, default=True)
|
|
expires_at: Mapped[datetime | None] = mapped_column(DateTime)
|
|
|
|
# Rate Limits
|
|
rpm_limit: Mapped[int | None] = mapped_column(Integer)
|
|
tpm_limit: Mapped[int | None] = mapped_column(Integer)
|
|
|
|
# Budget
|
|
budget_limit: Mapped[Decimal | None] = mapped_column(Numeric(10, 2))
|
|
budget_period: Mapped[str | None] = mapped_column(String(20)) # daily, weekly, monthly
|
|
|
|
# Permissions
|
|
allowed_models: Mapped[str | None] = mapped_column(Text) # JSON array
|
|
|
|
# Usage Stats
|
|
current_usage: Mapped[Decimal] = mapped_column(Numeric(10, 2), default=Decimal("0"))
|
|
total_requests: Mapped[int] = mapped_column(Integer, default=0)
|
|
|
|
# Timestamps
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime, default=datetime.utcnow, onupdate=datetime.utcnow
|
|
)
|