905 lines
30 KiB
Python
905 lines
30 KiB
Python
"""
|
||
数据库模型定义
|
||
"""
|
||
|
||
import uuid
|
||
from datetime import datetime
|
||
from typing import Dict, List, Optional, Any
|
||
from sqlalchemy import (
|
||
Column, String, Text, DateTime, Boolean, Integer,
|
||
JSON, ForeignKey, Index, UniqueConstraint
|
||
)
|
||
from sqlalchemy.ext.declarative import declarative_base
|
||
from sqlalchemy.orm import relationship
|
||
from sqlalchemy.dialects.postgresql import UUID
|
||
from sqlalchemy.types import TypeDecorator, CHAR
|
||
import sqlalchemy as sa
|
||
|
||
Base = declarative_base()
|
||
|
||
|
||
class GUID(TypeDecorator):
|
||
"""跨数据库兼容的UUID类型"""
|
||
impl = CHAR(36)
|
||
cache_ok = True
|
||
|
||
def load_dialect_impl(self, dialect):
|
||
if dialect.name == "postgresql":
|
||
return dialect.type_descriptor(UUID(as_uuid=True))
|
||
return dialect.type_descriptor(CHAR(36))
|
||
|
||
def process_bind_param(self, value, dialect):
|
||
if value is None:
|
||
return value
|
||
if isinstance(value, uuid.UUID):
|
||
return str(value)
|
||
return str(uuid.UUID(value))
|
||
|
||
def process_result_value(self, value, dialect):
|
||
if value is None:
|
||
return value
|
||
# 如果已经是UUID对象(包括asyncpg的UUID),先转换为字符串再转换
|
||
if hasattr(value, '__str__') and not isinstance(value, str):
|
||
# 处理asyncpg的UUID对象
|
||
try:
|
||
from asyncpg.pgproto.pgproto import UUID as AsyncUUID
|
||
if isinstance(value, AsyncUUID):
|
||
value = str(value)
|
||
except (ImportError, AttributeError):
|
||
pass
|
||
# 如果是标准UUID对象,直接返回
|
||
if isinstance(value, uuid.UUID):
|
||
return value
|
||
# 其他对象转换为字符串
|
||
value = str(value)
|
||
# 字符串转换为UUID
|
||
return uuid.UUID(value)
|
||
|
||
|
||
class BaseModel:
|
||
"""基础模型类"""
|
||
id = Column(GUID(), primary_key=True, default=uuid.uuid4)
|
||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||
updated_at = Column(
|
||
DateTime,
|
||
default=datetime.utcnow,
|
||
onupdate=datetime.utcnow,
|
||
nullable=False
|
||
)
|
||
|
||
|
||
class User(BaseModel, Base):
|
||
"""用户模型(租户使用者)"""
|
||
__tablename__ = "users"
|
||
|
||
name = Column(String(100), nullable=False)
|
||
email = Column(String(255), unique=True, nullable=False)
|
||
password_hash = Column(String(255), nullable=False)
|
||
role = Column(String(50), nullable=False, default="user") # user, channel_admin, billing_admin, operations_admin, admin, super_admin, provider_admin
|
||
channel_id = Column(GUID(), ForeignKey("channels.id"))
|
||
|
||
# 订阅和计费
|
||
subscription_tier = Column(String(20), default="free")
|
||
discount = Column(sa.Numeric(5, 2), default=0)
|
||
balance = Column(sa.Numeric(12, 2), default=0) # 账户余额
|
||
credit_limit = Column(sa.Numeric(12, 2), default=0) # 授信额度
|
||
|
||
status = Column(String(20), default="active")
|
||
|
||
# 兼容旧字段
|
||
username = Column(String(50))
|
||
hashed_password = Column(String(255))
|
||
full_name = Column(String(100))
|
||
is_active = Column(Boolean, default=True)
|
||
is_admin = Column(Boolean, default=False)
|
||
|
||
# 关联关系
|
||
channel = relationship("Channel", back_populates="tenants")
|
||
agents = relationship("Agent", back_populates="owner", cascade="all, delete-orphan")
|
||
sessions = relationship("Session", back_populates="user", cascade="all, delete-orphan")
|
||
api_keys = relationship("APIKey", back_populates="user", cascade="all, delete-orphan")
|
||
workflows = relationship("Workflow", back_populates="user", cascade="all, delete-orphan")
|
||
|
||
# 索引
|
||
__table_args__ = (
|
||
Index("idx_user_email", email),
|
||
Index("idx_user_channel", channel_id),
|
||
)
|
||
|
||
|
||
class Agent(BaseModel, Base):
|
||
"""Agent模型(平台Agent和自定义Agent)"""
|
||
__tablename__ = "agents"
|
||
|
||
name = Column(String(100), nullable=False)
|
||
type = Column(String(20), nullable=False, default="platform") # platform, custom
|
||
description = Column(Text)
|
||
category = Column(String(50))
|
||
|
||
# Agent配置
|
||
role = Column(String(200)) # Agent的角色定义
|
||
goal = Column(Text) # Agent的目标描述
|
||
config = Column(JSON, default=dict) # Agent的配置信息
|
||
tools = Column(JSON, default=list) # Agent授权使用的工具列表
|
||
capabilities = Column(JSON, default=list) # Agent的能力列表
|
||
|
||
# 资源配置
|
||
cpu = Column(sa.Numeric(5, 2), nullable=False, default=2)
|
||
memory = Column(sa.Numeric(5, 2), nullable=False, default=4) # GB
|
||
max_instances = Column(Integer, default=100)
|
||
|
||
# 状态信息
|
||
status = Column(String(20), default="active") # active, inactive, error, available, unavailable
|
||
version = Column(String(20), default="1.0.0")
|
||
|
||
# 性能统计
|
||
total_executions = Column(Integer, default=0)
|
||
success_rate = Column(sa.Float, default=0.0)
|
||
avg_execution_time = Column(sa.Float, default=0.0) # 毫秒
|
||
|
||
# 关联关系
|
||
owner_id = Column(GUID(), ForeignKey("users.id"))
|
||
owner = relationship("User", back_populates="agents")
|
||
|
||
executions = relationship("Execution", back_populates="agent", cascade="all, delete-orphan")
|
||
resource_allocations = relationship("ResourceAllocation",
|
||
foreign_keys="[ResourceAllocation.resource_id]",
|
||
primaryjoin="and_(Agent.id==ResourceAllocation.resource_id, ResourceAllocation.resource_type=='agent')")
|
||
|
||
# 索引和约束
|
||
__table_args__ = (
|
||
Index("idx_agent_name", name),
|
||
Index("idx_agent_type", type),
|
||
Index("idx_agent_owner", owner_id),
|
||
Index("idx_agent_status", status),
|
||
)
|
||
|
||
|
||
class Tool(BaseModel, Base):
|
||
"""工具模型"""
|
||
__tablename__ = "tools"
|
||
|
||
name = Column(String(100), nullable=False)
|
||
description = Column(Text)
|
||
category = Column(String(50)) # api, function, integration等
|
||
|
||
# 工具定义
|
||
schema = Column(JSON, nullable=False) # OpenAPI或Pydantic schema
|
||
endpoint = Column(String(500)) # API端点URL
|
||
method = Column(String(10), default="POST") # HTTP方法
|
||
|
||
# 认证信息
|
||
auth_type = Column(String(20)) # api_key, oauth, basic等
|
||
auth_config = Column(JSON, default=dict)
|
||
|
||
# 限制和配额
|
||
rate_limit = Column(Integer, default=100) # 每分钟调用次数
|
||
cost_per_call = Column(sa.Float, default=0.0) # 每次调用成本(EU)
|
||
timeout = Column(Integer, default=30) # 超时时间(秒)
|
||
|
||
# 状态信息
|
||
is_active = Column(Boolean, default=True)
|
||
is_public = Column(Boolean, default=False) # 是否公开可用
|
||
|
||
# 统计信息
|
||
total_calls = Column(Integer, default=0)
|
||
success_rate = Column(sa.Float, default=0.0)
|
||
avg_response_time = Column(sa.Float, default=0.0)
|
||
|
||
# 关联关系
|
||
owner_id = Column(GUID(), ForeignKey("users.id"))
|
||
owner = relationship("User")
|
||
|
||
# 索引
|
||
__table_args__ = (
|
||
Index("idx_tool_name", name),
|
||
Index("idx_tool_category", category),
|
||
Index("idx_tool_active", is_active),
|
||
)
|
||
|
||
|
||
class GatewayAPI(BaseModel, Base):
|
||
"""Service gateway API definitions (JSON or URL based)."""
|
||
|
||
__tablename__ = "gateway_apis"
|
||
|
||
name = Column(String(150), nullable=False)
|
||
method = Column(String(10), default="json") # json | url
|
||
content = Column(Text, nullable=False)
|
||
owner_id = Column(GUID(), ForeignKey("users.id"))
|
||
|
||
__table_args__ = (
|
||
Index("idx_gateway_api_name", name),
|
||
)
|
||
|
||
|
||
class DataTemplate(BaseModel, Base):
|
||
"""Data templates for ingestion or cloud storage configs."""
|
||
|
||
__tablename__ = "data_templates"
|
||
|
||
name = Column(String(150), nullable=False)
|
||
type = Column(String(50), nullable=False) # json_api | cloud_storage
|
||
config = Column(JSON, default=dict)
|
||
owner_id = Column(GUID(), ForeignKey("users.id"))
|
||
|
||
__table_args__ = (
|
||
Index("idx_data_template_name", name),
|
||
Index("idx_data_template_type", type),
|
||
)
|
||
|
||
|
||
class Session(BaseModel, Base):
|
||
"""会话模型"""
|
||
__tablename__ = "sessions"
|
||
|
||
session_id = Column(String(100), unique=True, nullable=False)
|
||
|
||
# 会话信息
|
||
context = Column(JSON, default=dict) # 会话上下文
|
||
session_metadata = Column(JSON, default=dict) # 元数据
|
||
|
||
# 状态
|
||
status = Column(String(20), default="active") # active, completed, failed
|
||
|
||
# 关联关系
|
||
user_id = Column(GUID(), ForeignKey("users.id"), nullable=False)
|
||
user = relationship("User", back_populates="sessions")
|
||
|
||
executions = relationship("Execution", back_populates="session", cascade="all, delete-orphan")
|
||
|
||
# 索引
|
||
__table_args__ = (
|
||
Index("idx_session_id", session_id),
|
||
Index("idx_session_user", user_id),
|
||
Index("idx_session_status", status),
|
||
)
|
||
|
||
|
||
class Channel(BaseModel, Base):
|
||
"""渠道合作伙伴模型"""
|
||
|
||
__tablename__ = "channels"
|
||
|
||
name = Column(String(100), nullable=False)
|
||
email = Column(String(255), unique=True, nullable=False)
|
||
password_hash = Column(String(255), nullable=False)
|
||
commission_rate = Column(sa.Numeric(5, 2), default=0)
|
||
channel_credit = Column(sa.Numeric(12, 2), default=0) # 渠道授信额度
|
||
custom_agent_cpu = Column(sa.Numeric(12, 2), default=2) # 自定义Agent CPU
|
||
custom_agent_memory = Column(sa.Numeric(12, 2), default=4) # 自定义Agent 内存(GB)
|
||
status = Column(String(20), default="active")
|
||
|
||
# 关联关系
|
||
tenants = relationship("User", back_populates="channel")
|
||
resource_allocations = relationship("ResourceAllocation",
|
||
foreign_keys="[ResourceAllocation.target_id]",
|
||
primaryjoin="and_(Channel.id==ResourceAllocation.target_id, ResourceAllocation.target_type=='channel')")
|
||
applications = relationship("Application", back_populates="channel", cascade="all, delete-orphan")
|
||
|
||
__table_args__ = (
|
||
Index("idx_channel_name", name),
|
||
Index("idx_channel_email", email),
|
||
)
|
||
|
||
|
||
class ModelProvider(BaseModel, Base):
|
||
"""模型供应商表"""
|
||
|
||
__tablename__ = "model_providers"
|
||
|
||
name = Column(String(100), nullable=False)
|
||
provider = Column(String(50), nullable=False) # openai, anthropic, azure, google, aws
|
||
api_url = Column(String(500), nullable=False)
|
||
api_key_encrypted = Column(Text, nullable=False)
|
||
supported_models = Column(JSON, default=list, nullable=False)
|
||
rpm = Column(Integer, nullable=False, default=0)
|
||
tpm = Column(Integer, nullable=False, default=0)
|
||
status = Column(String(20), default="active")
|
||
owner_id = Column(GUID(), ForeignKey("users.id"))
|
||
is_active = Column(Boolean, default=True)
|
||
|
||
__table_args__ = (
|
||
Index("idx_model_provider_name", name),
|
||
Index("idx_model_provider_active", is_active),
|
||
)
|
||
|
||
|
||
class ResourceAllocation(BaseModel, Base):
|
||
"""资源分配表(渠道和租户的资源分配)"""
|
||
|
||
__tablename__ = "resource_allocations"
|
||
|
||
target_id = Column(GUID(), nullable=False)
|
||
target_type = Column(String(20), nullable=False) # channel, tenant
|
||
resource_type = Column(String(20), nullable=False) # agent, model
|
||
resource_id = Column(GUID(), nullable=False)
|
||
|
||
# Agent资源配置
|
||
quantity = Column(Integer) # Agent数量
|
||
|
||
# 模型资源配置
|
||
rpm = Column(Integer) # 模型RPM
|
||
tpm = Column(Integer) # 模型TPM
|
||
|
||
__table_args__ = (
|
||
Index("idx_resource_allocation_target", target_id, target_type),
|
||
Index("idx_resource_allocation_resource", resource_id, resource_type),
|
||
)
|
||
|
||
|
||
class Execution(BaseModel, Base):
|
||
"""执行记录模型"""
|
||
__tablename__ = "executions"
|
||
|
||
execution_id = Column(String(100), unique=True, nullable=False)
|
||
|
||
# 执行信息
|
||
method = Column(String(50), nullable=False) # MCP方法名
|
||
params = Column(JSON, default=dict) # 执行参数
|
||
result = Column(JSON, default=dict) # 执行结果
|
||
error = Column(Text) # 错误信息
|
||
|
||
# 时间信息
|
||
started_at = Column(DateTime, nullable=False)
|
||
completed_at = Column(DateTime)
|
||
execution_time = Column(sa.Float) # 执行时间(毫秒)
|
||
|
||
# 状态
|
||
status = Column(String(20), nullable=False) # running, completed, failed
|
||
|
||
# 资源消耗
|
||
cpu_usage = Column(sa.Float, default=0.0) # CPU使用率
|
||
memory_usage = Column(sa.Float, default=0.0) # 内存使用(MB)
|
||
network_io = Column(sa.Float, default=0.0) # 网络IO(KB)
|
||
eu_consumed = Column(sa.Float, default=0.0) # 消耗的执行单元
|
||
|
||
# 关联关系
|
||
agent_id = Column(GUID(), ForeignKey("agents.id"), nullable=False)
|
||
agent = relationship("Agent", back_populates="executions")
|
||
|
||
session_id = Column(GUID(), ForeignKey("sessions.id"))
|
||
session = relationship("Session", back_populates="executions")
|
||
|
||
# 索引
|
||
__table_args__ = (
|
||
Index("idx_execution_id", execution_id),
|
||
Index("idx_execution_agent", agent_id),
|
||
Index("idx_execution_status", status),
|
||
Index("idx_execution_started", started_at),
|
||
)
|
||
|
||
|
||
class APIKey(BaseModel, Base):
|
||
"""API密钥模型"""
|
||
__tablename__ = "api_keys"
|
||
|
||
user_id = Column(GUID(), ForeignKey("users.id"), nullable=False)
|
||
api_key_hash = Column(String(255), nullable=False)
|
||
api_key_prefix = Column(String(10), nullable=False) # sk-xxxx
|
||
last_used = Column(DateTime)
|
||
|
||
# 兼容旧字段
|
||
name = Column(String(100))
|
||
key_hash = Column(String(255))
|
||
prefix = Column(String(20))
|
||
scopes = Column(JSON, default=list)
|
||
rate_limit = Column(Integer, default=1000)
|
||
is_active = Column(Boolean, default=True)
|
||
expires_at = Column(DateTime)
|
||
total_requests = Column(Integer, default=0)
|
||
|
||
# 关联关系
|
||
user = relationship("User", back_populates="api_keys")
|
||
|
||
# 索引
|
||
__table_args__ = (
|
||
Index("idx_api_key_hash", api_key_hash),
|
||
Index("idx_api_key_prefix", api_key_prefix),
|
||
Index("idx_api_key_user", user_id),
|
||
)
|
||
|
||
|
||
class Billing(BaseModel, Base):
|
||
"""计费详情模型(按执行记录计费)"""
|
||
__tablename__ = "billing"
|
||
|
||
execution_id = Column(GUID(), ForeignKey("executions.id"), nullable=False)
|
||
eu_consumed = Column(sa.Float, nullable=False, default=0.0)
|
||
cost = Column(sa.Float, nullable=False, default=0.0)
|
||
currency = Column(String(10), default="EU")
|
||
|
||
# 资源使用详情
|
||
cpu_time = Column(sa.Float, default=0.0)
|
||
memory_max = Column(sa.Float, default=0.0)
|
||
network_io = Column(sa.Float, default=0.0)
|
||
storage_io = Column(sa.Float, default=0.0)
|
||
|
||
user_id = Column(GUID(), ForeignKey("users.id"), nullable=False)
|
||
|
||
# 关联关系
|
||
user = relationship("User")
|
||
execution = relationship("Execution")
|
||
|
||
# 索引
|
||
__table_args__ = (
|
||
Index("idx_billing_execution", execution_id),
|
||
Index("idx_billing_user", user_id),
|
||
Index("idx_billing_created", "created_at"),
|
||
)
|
||
|
||
|
||
class Balance(BaseModel, Base):
|
||
"""用户余额模型"""
|
||
__tablename__ = "balances"
|
||
|
||
user_id = Column(GUID(), ForeignKey("users.id"), nullable=False, unique=True)
|
||
eu_balance = Column(sa.Float, nullable=False, default=0.0)
|
||
|
||
# 关联关系
|
||
user = relationship("User")
|
||
|
||
# 索引
|
||
__table_args__ = (
|
||
Index("idx_balance_user", user_id),
|
||
)
|
||
|
||
|
||
class BillingRecord(BaseModel, Base):
|
||
"""计费记录模型"""
|
||
__tablename__ = "billing_records"
|
||
|
||
timestamp = Column(DateTime, nullable=False, default=datetime.utcnow)
|
||
channel_id = Column(GUID(), ForeignKey("channels.id"))
|
||
tenant_id = Column(GUID(), ForeignKey("users.id")) # 租户即为user
|
||
agent_id = Column(GUID(), ForeignKey("agents.id"))
|
||
agent_name = Column(String(100), nullable=False)
|
||
|
||
duration = Column(Integer, nullable=False) # 秒
|
||
eu = Column(Integer, nullable=False) # 执行单元:1 EU = 10秒
|
||
cost = Column(sa.Numeric(12, 4), nullable=False)
|
||
|
||
# 关联关系
|
||
channel = relationship("Channel")
|
||
tenant = relationship("User", foreign_keys=[tenant_id])
|
||
agent = relationship("Agent")
|
||
|
||
# 索引
|
||
__table_args__ = (
|
||
Index("idx_billing_timestamp", timestamp),
|
||
Index("idx_billing_channel", channel_id),
|
||
Index("idx_billing_tenant", tenant_id),
|
||
)
|
||
|
||
|
||
class RechargeRecord(BaseModel, Base):
|
||
"""充值记录表"""
|
||
__tablename__ = "recharge_records"
|
||
|
||
user_id = Column(GUID(), ForeignKey("users.id"))
|
||
channel_id = Column(GUID(), ForeignKey("channels.id"))
|
||
amount = Column(sa.Numeric(12, 2), nullable=False)
|
||
payment_method = Column(String(50))
|
||
status = Column(String(20), default="pending") # pending, success, failed
|
||
order_id = Column(String(100))
|
||
completed_at = Column(DateTime)
|
||
|
||
# 关联关系
|
||
user = relationship("User")
|
||
channel = relationship("Channel")
|
||
|
||
__table_args__ = (
|
||
Index("idx_recharge_user", user_id),
|
||
Index("idx_recharge_channel", channel_id),
|
||
Index("idx_recharge_status", status),
|
||
)
|
||
|
||
|
||
class Application(BaseModel, Base):
|
||
"""申请审批表(渠道申请资源)"""
|
||
__tablename__ = "applications"
|
||
|
||
channel_id = Column(GUID(), ForeignKey("channels.id"), nullable=False)
|
||
type = Column(String(20), nullable=False) # model, agent
|
||
|
||
# 模型申请
|
||
model_name = Column(String(100))
|
||
rpm = Column(Integer)
|
||
tpm = Column(Integer)
|
||
|
||
# Agent申请
|
||
agent_type = Column(String(100))
|
||
quantity = Column(Integer)
|
||
|
||
reason = Column(Text)
|
||
status = Column(String(20), default="pending") # pending, approved, rejected
|
||
reviewed_by = Column(GUID())
|
||
review_reason = Column(Text)
|
||
reviewed_at = Column(DateTime)
|
||
|
||
# 关联关系
|
||
channel = relationship("Channel", back_populates="applications")
|
||
|
||
__table_args__ = (
|
||
Index("idx_application_channel", channel_id),
|
||
Index("idx_application_status", status),
|
||
)
|
||
|
||
|
||
class Workflow(BaseModel, Base):
|
||
"""工作流表"""
|
||
__tablename__ = "workflows"
|
||
|
||
user_id = Column(GUID(), ForeignKey("users.id"), nullable=False)
|
||
name = Column(String(100), nullable=False)
|
||
description = Column(Text)
|
||
gateway = Column(String(20), nullable=False) # MCP, A2A, API
|
||
nodes = Column(JSON, nullable=False, default=list) # 最多3个节点
|
||
status = Column(String(20), default="active")
|
||
|
||
# 关联关系
|
||
user = relationship("User", back_populates="workflows")
|
||
|
||
__table_args__ = (
|
||
Index("idx_workflow_user", user_id),
|
||
Index("idx_workflow_status", status),
|
||
)
|
||
|
||
|
||
class AuditLog(BaseModel, Base):
|
||
"""审计日志模型"""
|
||
__tablename__ = "audit_logs"
|
||
|
||
# 操作信息
|
||
action = Column(String(50), nullable=False) # 操作类型
|
||
resource_type = Column(String(50), nullable=False) # 资源类型
|
||
resource_id = Column(String(100)) # 资源ID
|
||
|
||
# 详细信息
|
||
details = Column(JSON, default=dict) # 操作详情
|
||
ip_address = Column(String(45)) # IP地址
|
||
user_agent = Column(Text) # 用户代理
|
||
|
||
# 结果
|
||
success = Column(Boolean, nullable=False)
|
||
error_message = Column(Text)
|
||
|
||
# 关联关系
|
||
user_id = Column(GUID(), ForeignKey("users.id"))
|
||
user = relationship("User")
|
||
|
||
# 索引
|
||
__table_args__ = (
|
||
Index("idx_audit_action", action),
|
||
Index("idx_audit_resource", resource_type, resource_id),
|
||
Index("idx_audit_user", user_id),
|
||
Index("idx_audit_created", "created_at"),
|
||
)
|
||
|
||
|
||
class ChannelAgentQuota(BaseModel, Base):
|
||
"""渠道Agent配额模型"""
|
||
__tablename__ = "channel_agent_quotas"
|
||
|
||
channel_id = Column(GUID(), ForeignKey("channels.id"), nullable=False)
|
||
agent_id = Column(GUID(), ForeignKey("agents.id"), nullable=False)
|
||
quantity = Column(Integer, nullable=False, default=0)
|
||
|
||
# 关联关系
|
||
channel = relationship("Channel")
|
||
agent = relationship("Agent")
|
||
|
||
# 索引
|
||
__table_args__ = (
|
||
Index("idx_channel_agent_quota_channel", channel_id),
|
||
Index("idx_channel_agent_quota_agent", agent_id),
|
||
UniqueConstraint("channel_id", "agent_id", name="uq_channel_agent"),
|
||
)
|
||
|
||
|
||
class ProviderModel(BaseModel, Base):
|
||
"""模型提供商模型(前端集成使用)"""
|
||
__tablename__ = "provider_models"
|
||
|
||
name = Column(String(100), nullable=False)
|
||
api_url = Column(String(500), nullable=False)
|
||
api_key = Column(Text, nullable=False)
|
||
supported_models = Column(JSON, default=list)
|
||
rpm = Column(Integer, default=0)
|
||
tpm = Column(Integer, default=0)
|
||
status = Column(String(20), default="active")
|
||
|
||
# 索引
|
||
__table_args__ = (
|
||
Index("idx_provider_model_name", name),
|
||
)
|
||
|
||
|
||
# 别名:Tenant 指向 User(租户即为user)
|
||
Tenant = User
|
||
|
||
|
||
class TokenBlacklist(BaseModel, Base):
|
||
"""Token黑名单(用于JWT登出和Token失效)"""
|
||
__tablename__ = "token_blacklist"
|
||
|
||
token_jti = Column(String(255), unique=True, nullable=False) # JWT ID
|
||
user_id = Column(GUID(), ForeignKey("users.id"), nullable=False)
|
||
expires_at = Column(DateTime, nullable=False) # Token过期时间
|
||
reason = Column(String(100)) # 黑名单原因:logout, revoked, security
|
||
|
||
# 关联关系
|
||
user = relationship("User")
|
||
|
||
__table_args__ = (
|
||
Index("idx_token_blacklist_jti", token_jti),
|
||
Index("idx_token_blacklist_expires", expires_at),
|
||
)
|
||
|
||
|
||
class ResourceUsage(BaseModel, Base):
|
||
"""资源使用记录(用于监控和统计)"""
|
||
__tablename__ = "resource_usage"
|
||
|
||
user_id = Column(GUID(), ForeignKey("users.id"), nullable=False)
|
||
agent_id = Column(GUID(), ForeignKey("agents.id"))
|
||
|
||
# 资源使用量
|
||
cpu_seconds = Column(sa.Float, default=0.0) # CPU使用秒数
|
||
memory_mb_seconds = Column(sa.Float, default=0.0) # 内存MB*秒
|
||
network_bytes = Column(sa.BigInteger, default=0) # 网络流量字节
|
||
storage_bytes = Column(sa.BigInteger, default=0) # 存储使用字节
|
||
api_calls = Column(Integer, default=0) # API调用次数
|
||
|
||
# 时间范围
|
||
period_start = Column(DateTime, nullable=False)
|
||
period_end = Column(DateTime, nullable=False)
|
||
granularity = Column(String(20), default="hourly") # hourly, daily, monthly
|
||
|
||
# 关联关系
|
||
user = relationship("User")
|
||
agent = relationship("Agent")
|
||
|
||
__table_args__ = (
|
||
Index("idx_resource_usage_user", user_id),
|
||
Index("idx_resource_usage_period", period_start, period_end),
|
||
Index("idx_resource_usage_granularity", granularity),
|
||
)
|
||
|
||
|
||
class QuotaAlert(BaseModel, Base):
|
||
"""配额预警记录"""
|
||
__tablename__ = "quota_alerts"
|
||
|
||
user_id = Column(GUID(), ForeignKey("users.id"), nullable=False)
|
||
channel_id = Column(GUID(), ForeignKey("channels.id"))
|
||
|
||
# 预警信息
|
||
alert_type = Column(String(50), nullable=False) # balance_low, quota_exceeded, rate_limit
|
||
threshold_percent = Column(Integer) # 触发阈值百分比
|
||
current_value = Column(sa.Numeric(12, 4)) # 当前值
|
||
threshold_value = Column(sa.Numeric(12, 4)) # 阈值
|
||
|
||
# 状态
|
||
status = Column(String(20), default="active") # active, acknowledged, resolved
|
||
acknowledged_at = Column(DateTime)
|
||
resolved_at = Column(DateTime)
|
||
|
||
# 通知
|
||
notification_sent = Column(Boolean, default=False)
|
||
notification_channel = Column(String(50)) # email, webhook, sms
|
||
|
||
# 关联关系
|
||
user = relationship("User")
|
||
channel = relationship("Channel")
|
||
|
||
__table_args__ = (
|
||
Index("idx_quota_alert_user", user_id),
|
||
Index("idx_quota_alert_status", status),
|
||
Index("idx_quota_alert_type", alert_type),
|
||
)
|
||
|
||
|
||
class ModelPricing(BaseModel, Base):
|
||
"""模型定价配置"""
|
||
__tablename__ = "model_pricing"
|
||
|
||
provider_id = Column(GUID(), ForeignKey("model_providers.id"), nullable=False)
|
||
model_name = Column(String(100), nullable=False)
|
||
|
||
# 定价(每1K tokens)
|
||
input_price_per_1k = Column(sa.Numeric(10, 6), nullable=False) # 输入价格
|
||
output_price_per_1k = Column(sa.Numeric(10, 6), nullable=False) # 输出价格
|
||
|
||
# EU转换
|
||
eu_per_1k_tokens = Column(sa.Numeric(8, 4), default=0.1) # 每1K tokens消耗的EU
|
||
|
||
# 限制
|
||
max_context_length = Column(Integer, default=4096)
|
||
max_output_tokens = Column(Integer, default=2048)
|
||
|
||
# 状态
|
||
is_active = Column(Boolean, default=True)
|
||
effective_from = Column(DateTime, default=datetime.utcnow)
|
||
effective_until = Column(DateTime)
|
||
|
||
# 关联关系
|
||
provider = relationship("ModelProvider")
|
||
|
||
__table_args__ = (
|
||
Index("idx_model_pricing_provider", provider_id),
|
||
Index("idx_model_pricing_model", model_name),
|
||
UniqueConstraint("provider_id", "model_name", name="uq_provider_model_pricing"),
|
||
)
|
||
|
||
|
||
class ProviderHealthCheck(BaseModel, Base):
|
||
"""供应商健康检查记录"""
|
||
__tablename__ = "provider_health_checks"
|
||
|
||
provider_id = Column(GUID(), ForeignKey("model_providers.id"), nullable=False)
|
||
|
||
# 检查结果
|
||
is_healthy = Column(Boolean, nullable=False)
|
||
response_time_ms = Column(Integer) # 响应时间毫秒
|
||
status_code = Column(Integer) # HTTP状态码
|
||
error_message = Column(Text)
|
||
|
||
# 检查类型
|
||
check_type = Column(String(50), default="ping") # ping, model_list, completion
|
||
|
||
# 关联关系
|
||
provider = relationship("ModelProvider")
|
||
|
||
__table_args__ = (
|
||
Index("idx_provider_health_provider", provider_id),
|
||
Index("idx_provider_health_time", "created_at"),
|
||
Index("idx_provider_health_status", is_healthy),
|
||
)
|
||
|
||
|
||
class AgentTrace(BaseModel, Base):
|
||
"""Agent执行轨迹(详细追踪记录)"""
|
||
__tablename__ = "agent_traces"
|
||
|
||
execution_id = Column(GUID(), ForeignKey("executions.id"), nullable=False)
|
||
agent_id = Column(GUID(), ForeignKey("agents.id"), nullable=False)
|
||
user_id = Column(GUID(), ForeignKey("users.id"), nullable=False)
|
||
|
||
# 轨迹信息
|
||
trace_id = Column(String(100), nullable=False) # 分布式追踪ID
|
||
span_id = Column(String(100), nullable=False) # 跨度ID
|
||
parent_span_id = Column(String(100)) # 父跨度ID
|
||
|
||
# 操作信息
|
||
operation_name = Column(String(200), nullable=False)
|
||
operation_type = Column(String(50)) # tool_call, llm_call, function_exec
|
||
|
||
# 时间信息
|
||
started_at = Column(DateTime, nullable=False)
|
||
ended_at = Column(DateTime)
|
||
duration_ms = Column(Integer)
|
||
|
||
# 输入输出
|
||
input_data = Column(JSON) # 输入数据(脱敏)
|
||
output_data = Column(JSON) # 输出数据(脱敏)
|
||
|
||
# 状态
|
||
status = Column(String(20), nullable=False) # running, success, error
|
||
error_type = Column(String(100))
|
||
error_message = Column(Text)
|
||
|
||
# 资源消耗
|
||
tokens_used = Column(Integer, default=0)
|
||
eu_consumed = Column(sa.Numeric(10, 4), default=0)
|
||
|
||
# 关联关系
|
||
execution = relationship("Execution")
|
||
agent = relationship("Agent")
|
||
user = relationship("User")
|
||
|
||
__table_args__ = (
|
||
Index("idx_agent_trace_execution", execution_id),
|
||
Index("idx_agent_trace_trace_id", trace_id),
|
||
Index("idx_agent_trace_user", user_id),
|
||
Index("idx_agent_trace_time", started_at),
|
||
)
|
||
|
||
|
||
class BillingEvent(BaseModel, Base):
|
||
"""计费事件(用于NATS消息队列)"""
|
||
__tablename__ = "billing_events"
|
||
|
||
# 事件信息
|
||
event_type = Column(String(50), nullable=False) # execution_start, execution_end, quota_check
|
||
event_id = Column(String(100), unique=True, nullable=False)
|
||
|
||
# 关联实体
|
||
user_id = Column(GUID(), ForeignKey("users.id"), nullable=False)
|
||
agent_id = Column(GUID(), ForeignKey("agents.id"))
|
||
execution_id = Column(GUID(), ForeignKey("executions.id"))
|
||
|
||
# 事件数据
|
||
payload = Column(JSON, nullable=False)
|
||
|
||
# 处理状态
|
||
status = Column(String(20), default="pending") # pending, processing, completed, failed
|
||
processed_at = Column(DateTime)
|
||
retry_count = Column(Integer, default=0)
|
||
error_message = Column(Text)
|
||
|
||
# 关联关系
|
||
user = relationship("User")
|
||
agent = relationship("Agent")
|
||
execution = relationship("Execution")
|
||
|
||
__table_args__ = (
|
||
Index("idx_billing_event_type", event_type),
|
||
Index("idx_billing_event_status", status),
|
||
Index("idx_billing_event_user", user_id),
|
||
Index("idx_billing_event_time", "created_at"),
|
||
)
|
||
|
||
|
||
class ChannelProviderAccess(BaseModel, Base):
|
||
"""渠道供应商授权表(记录渠道可使用的供应商)"""
|
||
__tablename__ = "channel_provider_access"
|
||
|
||
channel_id = Column(GUID(), ForeignKey("channels.id"), nullable=False)
|
||
provider_id = Column(GUID(), ForeignKey("model_providers.id"), nullable=False)
|
||
|
||
# 授权信息
|
||
status = Column(String(20), default="active") # active, suspended, expired
|
||
|
||
# 限制配置(可覆盖供应商默认值)
|
||
rpm_limit = Column(Integer) # 每分钟请求数限制
|
||
tpm_limit = Column(Integer) # 每分钟Token数限制
|
||
|
||
# 审批信息
|
||
approved_by = Column(GUID(), ForeignKey("users.id"))
|
||
approved_at = Column(DateTime)
|
||
expires_at = Column(DateTime) # 可选的过期时间
|
||
|
||
# 关联关系
|
||
channel = relationship("Channel")
|
||
provider = relationship("ModelProvider")
|
||
approver = relationship("User", foreign_keys=[approved_by])
|
||
|
||
__table_args__ = (
|
||
Index("idx_channel_provider_channel", channel_id),
|
||
Index("idx_channel_provider_provider", provider_id),
|
||
Index("idx_channel_provider_status", status),
|
||
UniqueConstraint("channel_id", "provider_id", name="uq_channel_provider"),
|
||
)
|
||
|
||
|
||
class ProviderApplication(BaseModel, Base):
|
||
"""供应商使用申请表(渠道申请使用供应商)"""
|
||
__tablename__ = "provider_applications"
|
||
|
||
channel_id = Column(GUID(), ForeignKey("channels.id"), nullable=False)
|
||
provider_id = Column(GUID(), ForeignKey("model_providers.id"), nullable=False)
|
||
|
||
# 申请信息
|
||
requested_rpm = Column(Integer) # 申请的RPM限制
|
||
requested_tpm = Column(Integer) # 申请的TPM限制
|
||
reason = Column(Text, nullable=False) # 申请理由
|
||
|
||
# 审批状态
|
||
status = Column(String(20), default="pending") # pending, approved, rejected
|
||
reviewed_by = Column(GUID(), ForeignKey("users.id"))
|
||
review_reason = Column(Text) # 审批意见
|
||
reviewed_at = Column(DateTime)
|
||
|
||
# 关联关系
|
||
channel = relationship("Channel")
|
||
provider = relationship("ModelProvider")
|
||
reviewer = relationship("User", foreign_keys=[reviewed_by])
|
||
|
||
__table_args__ = (
|
||
Index("idx_provider_app_channel", channel_id),
|
||
Index("idx_provider_app_provider", provider_id),
|
||
Index("idx_provider_app_status", status),
|
||
)
|
||
|