Files
dreamweaver/backend/app/db/admin_models.py
zhangtuo e9d7f8832a Initial commit: clean project structure
- Backend: FastAPI + SQLAlchemy + Celery (Python 3.11+)
- Frontend: Vue 3 + TypeScript + Pinia + Tailwind
- Admin Frontend: separate Vue 3 app for management
- Docker Compose: 9 services orchestration
- Specs: design prototypes, memory system PRD, product roadmap

Cleanup performed:
- Removed temporary debug scripts from backend root
- Removed deprecated admin_app.py (embedded UI)
- Removed duplicate docs from admin-frontend
- Updated .gitignore for Vite cache and egg-info
2026-01-20 18:20:03 +08:00

120 lines
5.2 KiB
Python

from datetime import datetime
from decimal import Decimal
from uuid import uuid4
from sqlalchemy import JSON, Boolean, DateTime, ForeignKey, Integer, Numeric, String, Text
from sqlalchemy.orm import Mapped, mapped_column
from app.db.models import Base
def _uuid() -> str:
return str(uuid4())
class Provider(Base):
"""Model provider registry."""
__tablename__ = "providers"
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
name: Mapped[str] = mapped_column(String(100), nullable=False)
type: Mapped[str] = mapped_column(String(50), nullable=False) # text/image/tts/storybook
adapter: Mapped[str] = mapped_column(String(100), nullable=False)
model: Mapped[str] = mapped_column(String(200), nullable=True)
api_base: Mapped[str] = mapped_column(String(300), nullable=True)
api_key: Mapped[str] = mapped_column(String(500), nullable=True) # 可选,优先于 config_ref
timeout_ms: Mapped[int] = mapped_column(Integer, default=60000)
max_retries: Mapped[int] = mapped_column(Integer, default=1)
weight: Mapped[int] = mapped_column(Integer, default=1)
priority: Mapped[int] = mapped_column(Integer, default=0)
enabled: Mapped[bool] = mapped_column(Boolean, default=True)
config_json: Mapped[dict | None] = mapped_column(JSON, nullable=True) # 存储额外配置(speed, vol, etc)
config_ref: Mapped[str] = mapped_column(String(100), nullable=True) # 环境变量 key 名称(回退)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=datetime.utcnow)
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=datetime.utcnow, onupdate=datetime.utcnow
)
updated_by: Mapped[str] = mapped_column(String(100), nullable=True)
class ProviderMetrics(Base):
"""供应商调用指标记录。"""
__tablename__ = "provider_metrics"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
provider_id: Mapped[str] = mapped_column(
String(36), ForeignKey("providers.id", ondelete="CASCADE"), nullable=False, index=True
)
timestamp: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=datetime.utcnow, index=True
)
success: Mapped[bool] = mapped_column(Boolean, nullable=False)
latency_ms: Mapped[int] = mapped_column(Integer, nullable=True)
cost_usd: Mapped[Decimal] = mapped_column(Numeric(10, 6), nullable=True)
error_message: Mapped[str] = mapped_column(Text, nullable=True)
request_id: Mapped[str] = mapped_column(String(100), nullable=True)
class ProviderHealth(Base):
"""供应商健康状态。"""
__tablename__ = "provider_health"
provider_id: Mapped[str] = mapped_column(
String(36), ForeignKey("providers.id", ondelete="CASCADE"), primary_key=True
)
is_healthy: Mapped[bool] = mapped_column(Boolean, default=True)
last_check: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=True)
consecutive_failures: Mapped[int] = mapped_column(Integer, default=0)
last_error: Mapped[str] = mapped_column(Text, nullable=True)
class ProviderSecret(Base):
"""供应商密钥加密存储。"""
__tablename__ = "provider_secrets"
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
name: Mapped[str] = mapped_column(String(100), unique=True, nullable=False)
encrypted_value: Mapped[str] = mapped_column(Text, nullable=False)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=datetime.utcnow)
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=datetime.utcnow, onupdate=datetime.utcnow
)
class CostRecord(Base):
"""成本记录表 - 记录每次 API 调用的成本。"""
__tablename__ = "cost_records"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
user_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
provider_id: Mapped[str] = mapped_column(String(36), nullable=True) # 可能是环境变量配置
provider_name: Mapped[str] = mapped_column(String(100), nullable=False)
capability: Mapped[str] = mapped_column(String(50), nullable=False) # text/image/tts/storybook
estimated_cost: Mapped[Decimal] = mapped_column(Numeric(10, 6), nullable=False)
timestamp: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=datetime.utcnow, index=True
)
class UserBudget(Base):
"""用户预算配置。"""
__tablename__ = "user_budgets"
user_id: Mapped[str] = mapped_column(String(36), primary_key=True)
daily_limit_usd: Mapped[Decimal] = mapped_column(Numeric(10, 4), default=Decimal("1.0"))
monthly_limit_usd: Mapped[Decimal] = mapped_column(Numeric(10, 4), default=Decimal("10.0"))
alert_threshold: Mapped[Decimal] = mapped_column(
Numeric(3, 2), default=Decimal("0.8")
) # 80% 时告警
enabled: Mapped[bool] = mapped_column(Boolean, default=True)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=datetime.utcnow)
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=datetime.utcnow, onupdate=datetime.utcnow
)