""" AIFlow 数据库模型定义 - SQLAlchemy ORM 所有用户数据查询必须带 user_id 过滤实现物理隔离 """ import uuid from datetime import datetime, date from sqlalchemy import ( Column, String, Integer, BigInteger, Float, Boolean, DateTime, Date, Text, Enum, ForeignKey, Index, JSON, DECIMAL, UniqueConstraint ) from sqlalchemy.orm import relationship from .database import Base def gen_uuid() -> str: return str(uuid.uuid4()) # ============================================================ # 用户与权限 # ============================================================ class User(Base): __tablename__ = "users" id = Column(String(36), primary_key=True, default=gen_uuid) username = Column(String(50), unique=True, nullable=False) email = Column(String(100), default=None) phone = Column(String(20), default=None) password_hash = Column(String(255), nullable=False) avatar = Column(String(500), default=None) role = Column(String(10), nullable=False, default="user") # user / admin status = Column(String(10), nullable=False, default="active") # active / banned real_name_status = Column(String(20), nullable=False, default="unverified") real_name = Column(String(50), default=None) id_card = Column(String(20), default=None) membership_plan_id = Column(String(36), default=None) membership_level = Column(Integer, default=0) membership_expire_at = Column(DateTime, default=None) auto_renew = Column(Boolean, default=False) created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) class LoginLog(Base): __tablename__ = "login_logs" id = Column(String(36), primary_key=True, default=gen_uuid) user_id = Column(String(36), ForeignKey("users.id"), nullable=False) ip = Column(String(45), default=None) user_agent = Column(String(500), default=None) login_at = Column(DateTime, default=datetime.now) class ApiKey(Base): __tablename__ = "api_keys" id = Column(String(36), primary_key=True, default=gen_uuid) user_id = Column(String(36), ForeignKey("users.id"), nullable=False) api_key = Column(String(64), unique=True, nullable=False) secret = Column(String(128), nullable=False) name = Column(String(100), default=None) status = Column(String(10), nullable=False, default="active") # active / revoked last_used_at = Column(DateTime, default=None) created_at = Column(DateTime, default=datetime.now) expired_at = Column(DateTime, default=None) # ============================================================ # AI聊天与频道 # ============================================================ class Conversation(Base): __tablename__ = "conversations" id = Column(String(36), primary_key=True, default=gen_uuid) user_id = Column(String(36), ForeignKey("users.id"), nullable=False) title = Column(String(200), nullable=False, default="新对话") model_id = Column(String(36), default=None) status = Column(String(10), nullable=False, default="active") # active / archived pinned = Column(Boolean, default=False) knowledge_graph_count = Column(Integer, default=0) created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) class Message(Base): __tablename__ = "messages" id = Column(String(36), primary_key=True, default=gen_uuid) conversation_id = Column(String(36), ForeignKey("conversations.id"), nullable=False) role = Column(String(10), nullable=False) # user / assistant / system content = Column(Text, nullable=False) token_used = Column(Integer, default=0) model_id = Column(String(36), default=None) knowledge_ids = Column(JSON, default=None) agent_ids = Column(JSON, default=None) skill_ids = Column(JSON, default=None) used_skills = Column(JSON, default=None, comment="该轮对话调用的进化技能名列表") created_at = Column(DateTime, default=datetime.now) class Channel(Base): __tablename__ = "channels" id = Column(String(36), primary_key=True, default=gen_uuid) owner_id = Column(String(36), ForeignKey("users.id"), nullable=False) name = Column(String(100), nullable=False) description = Column(Text, default=None) platform = Column(String(20), nullable=False) webhook_url = Column(String(500), default=None) credential = Column(JSON, default=None) oauth_state = Column(String(500), default=None) settings = Column(JSON, default=None) account_name = Column(String(100), default=None) default_agent_id = Column(String(36), default=None) default_skill_id = Column(String(36), default=None) knowledge_base_id = Column(String(36), default=None) bound_model_id = Column(String(36), default=None) features = Column(JSON, default=None) status = Column(String(20), nullable=False, default="pending") is_active = Column(Boolean, default=True) last_active = Column(DateTime, default=None) created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) class ChannelMember(Base): __tablename__ = "channel_members" __table_args__ = (UniqueConstraint("channel_id", "user_id"),) id = Column(String(36), primary_key=True, default=gen_uuid) channel_id = Column(String(36), ForeignKey("channels.id"), nullable=False) user_id = Column(String(36), ForeignKey("users.id"), nullable=False) role = Column(String(10), nullable=False, default="member") # owner / member joined_at = Column(DateTime, default=datetime.now) class ChannelMessage(Base): __tablename__ = "channel_messages" id = Column(String(36), primary_key=True, default=gen_uuid) channel_id = Column(String(36), ForeignKey("channels.id"), nullable=False) user_id = Column(String(36), ForeignKey("users.id"), nullable=False) role = Column(String(10), nullable=False) content = Column(Text, nullable=False) token_used = Column(Integer, default=0) created_at = Column(DateTime, default=datetime.now) # ============================================================ # 知识库 # ============================================================ class KnowledgeBase(Base): __tablename__ = "knowledge_bases" id = Column(String(36), primary_key=True, default=gen_uuid) user_id = Column(String(36), ForeignKey("users.id"), nullable=False) name = Column(String(200), nullable=False) description = Column(Text, default=None) directory_path = Column(String(500), default="/") document_count = Column(Integer, default=0) knowledge_graph_count = Column(Integer, default=0) created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) is_official = Column(Boolean, default=False) status = Column(String(20), default="active") external_service_id = Column(String(36), default=None) external_id = Column(String(100), default=None) external_sync_status = Column(String(20), default="none") external_config = Column(JSON, default=None) class KnowledgeDirectory(Base): __tablename__ = "knowledge_directories" id = Column(String(36), primary_key=True, default=gen_uuid) user_id = Column(String(36), ForeignKey("users.id"), nullable=False) knowledge_base_id = Column(String(36), ForeignKey("knowledge_bases.id"), default=None) parent_id = Column(String(36), default=None) name = Column(String(200), nullable=False) created_at = Column(DateTime, default=datetime.now) class KnowledgeDocument(Base): __tablename__ = "knowledge_documents" id = Column(String(36), primary_key=True, default=gen_uuid) knowledge_base_id = Column(String(36), ForeignKey("knowledge_bases.id"), nullable=False) directory_id = Column(String(36), ForeignKey("knowledge_directories.id"), default=None) filename = Column(String(255), nullable=False) file_type = Column(String(20), nullable=False) file_size = Column(BigInteger, default=0) file_path = Column(String(500), default=None) status = Column(String(20), nullable=False, default="uploading") chunk_count = Column(Integer, default=0) error_message = Column(Text, default=None) content = Column(Text, default=None) created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) class KnowledgeDocumentChunk(Base): """知识库文档分段表 — Stage C.1""" __tablename__ = "knowledge_document_chunks" id = Column(String(36), primary_key=True, default=gen_uuid) document_id = Column(String(36), ForeignKey("knowledge_documents.id"), nullable=False) knowledge_base_id = Column(String(36), ForeignKey("knowledge_bases.id"), nullable=False) chunk_index = Column(Integer, nullable=False, default=0, comment="分段序号") content = Column(Text, nullable=False, comment="分段文本内容") start_char = Column(Integer, default=0, comment="起始字符位置") end_char = Column(Integer, default=0, comment="结束字符位置") chunk_metadata = Column(JSON, default=None, comment="分段元数据(标题、关键词等)") token_count = Column(Integer, default=0, comment="分段token数估算") created_at = Column(DateTime, default=datetime.now) __table_args__ = ( Index("idx_kdc_doc_id", "document_id"), Index("idx_kdc_kb_id", "knowledge_base_id"), ) class KnowledgeGraphNode(Base): __tablename__ = "knowledge_graph_nodes" id = Column(String(36), primary_key=True, default=gen_uuid) knowledge_base_id = Column(String(36), ForeignKey("knowledge_bases.id"), nullable=False) source_doc_id = Column(String(36), ForeignKey("knowledge_documents.id"), default=None) label = Column(String(500), nullable=False) type = Column(String(50), nullable=False, comment="entity/attribute/concept/event") properties = Column(JSON, default=None) description = Column(Text, default=None) created_at = Column(DateTime, default=datetime.now) class KnowledgeGraphEdge(Base): __tablename__ = "knowledge_graph_edges" id = Column(String(36), primary_key=True, default=gen_uuid) knowledge_base_id = Column(String(36), ForeignKey("knowledge_bases.id"), nullable=False) source_node_id = Column(String(36), ForeignKey("knowledge_graph_nodes.id"), nullable=False) target_node_id = Column(String(36), ForeignKey("knowledge_graph_nodes.id"), nullable=False) relation = Column(String(200), nullable=False) weight = Column(Float, default=1.0) description = Column(Text, default=None) created_at = Column(DateTime, default=datetime.now) class KnowledgeGraphBuildLog(Base): __tablename__ = "knowledge_graph_build_logs" id = Column(String(36), primary_key=True, default=gen_uuid) knowledge_base_id = Column(String(36), ForeignKey("knowledge_bases.id"), nullable=False) document_id = Column(String(36), ForeignKey("knowledge_documents.id"), nullable=False) node_count = Column(Integer, default=0) edge_count = Column(Integer, default=0) status = Column(String(20), default="completed") created_at = Column(DateTime, default=datetime.now) # ============================================================ # 应用市场 # ============================================================ class MarketApp(Base): __tablename__ = "market_apps" id = Column(String(36), primary_key=True, default=gen_uuid) name = Column(String(200), nullable=False) type = Column(String(10), nullable=False) # skill / agent / mcp source = Column(String(10), nullable=False, default="user") # official / user publisher_id = Column(String(36), ForeignKey("users.id"), default=None) publisher_name = Column(String(100), default=None) description = Column(Text, default=None) icon = Column(String(500), default=None) tutorial = Column(Text, default=None) price = Column(DECIMAL(10, 2), nullable=False, default=0.00) is_member_free = Column(Boolean, default=False) join_promotion = Column(Boolean, default=False) status = Column(String(10), nullable=False, default="pending") # pending / published / removed rating_avg = Column(DECIMAL(3, 2), default=0.00) review_count = Column(Integer, default=0) install_count = Column(Integer, default=0) skill_content = Column(Text, default=None) mcp_transport = Column(String(20), default=None) agent_endpoint = Column(String(500), default=None) created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) class AppPurchase(Base): __tablename__ = "app_purchases" id = Column(String(36), primary_key=True, default=gen_uuid) user_id = Column(String(36), ForeignKey("users.id"), nullable=False) app_id = Column(String(36), ForeignKey("market_apps.id"), nullable=False) price = Column(DECIMAL(10, 2), nullable=False, default=0.00) order_id = Column(String(36), default=None) status = Column(String(20), nullable=False, default="purchased") # purchased / installed installed_at = Column(DateTime, default=None) purchased_at = Column(DateTime, default=None) created_at = Column(DateTime, default=datetime.now) class AppReview(Base): __tablename__ = "app_reviews" __table_args__ = (UniqueConstraint("user_id", "app_id"),) id = Column(String(36), primary_key=True, default=gen_uuid) user_id = Column(String(36), ForeignKey("users.id"), nullable=False) app_id = Column(String(36), ForeignKey("market_apps.id"), nullable=False) rating = Column(Integer, nullable=False) content = Column(Text, default=None) created_at = Column(DateTime, default=datetime.now) class AppInstallation(Base): __tablename__ = "app_installations" __table_args__ = (UniqueConstraint("user_id", "app_id"),) id = Column(String(36), primary_key=True, default=gen_uuid) user_id = Column(String(36), ForeignKey("users.id"), nullable=False) app_id = Column(String(36), ForeignKey("market_apps.id"), nullable=False) installed_at = Column(DateTime, default=datetime.now) # ============================================================ # 付费与订单 # ============================================================ class MembershipPlan(Base): __tablename__ = "membership_plans" id = Column(String(36), primary_key=True, default=gen_uuid) name = Column(String(100), nullable=False) level = Column(Integer, nullable=False, default=0) duration_type = Column(String(10), nullable=False) # month / quarter / year price = Column(DECIMAL(10, 2), nullable=False) daily_free_tokens = Column(Integer, default=0) features = Column(JSON, default=None) free_app_ids = Column(JSON, default=None) free_model_ids = Column(JSON, default=None) is_active = Column(Boolean, default=True) created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) class MembershipSubscription(Base): __tablename__ = "membership_subscriptions" id = Column(String(36), primary_key=True, default=gen_uuid) user_id = Column(String(36), ForeignKey("users.id"), nullable=False) plan_id = Column(String(36), ForeignKey("membership_plans.id"), nullable=False) order_id = Column(String(36), default=None) start_at = Column(DateTime, nullable=False) end_at = Column(DateTime, nullable=False) auto_renew = Column(Boolean, default=False) status = Column(String(15), nullable=False, default="active") # active / expired / downgraded created_at = Column(DateTime, default=datetime.now) class Order(Base): __tablename__ = "orders" id = Column(String(36), primary_key=True, default=gen_uuid) user_id = Column(String(36), ForeignKey("users.id"), nullable=False) order_type = Column(String(15), nullable=False) # membership / service / app item_id = Column(String(36), default=None) item_name = Column(String(200), default=None) amount = Column(DECIMAL(10, 2), nullable=False) coupon_id = Column(String(36), default=None) discount_amount = Column(DECIMAL(10, 2), default=0.00) payment_method = Column(String(10), default=None) # wechat / alipay payment_id = Column(String(200), default=None) status = Column(String(15), nullable=False, default="pending") # pending / paid / refunded / cancelled paid_at = Column(DateTime, default=None) receipt_number = Column(String(100), default=None) receipt_type = Column(String(20), default=None) receipt_title = Column(String(200), default=None) receipt_tax_number = Column(String(50), default=None) receipt_issued_at = Column(DateTime, default=None) created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) class Coupon(Base): __tablename__ = "coupons" id = Column(String(36), primary_key=True, default=gen_uuid) code = Column(String(50), unique=True, nullable=False) type = Column(String(10), nullable=False) # fixed / percent value = Column(DECIMAL(10, 2), nullable=False) min_amount = Column(DECIMAL(10, 2), default=0.00) valid_from = Column(DateTime, nullable=False) valid_to = Column(DateTime, nullable=False) total_count = Column(Integer, default=None) used_count = Column(Integer, default=0) status = Column(String(10), nullable=False, default="active") # active / expired / disabled created_at = Column(DateTime, default=datetime.now) class UserCoupon(Base): __tablename__ = "user_coupons" id = Column(String(36), primary_key=True, default=gen_uuid) user_id = Column(String(36), ForeignKey("users.id"), nullable=False) coupon_id = Column(String(36), ForeignKey("coupons.id"), nullable=False) status = Column(String(10), nullable=False, default="unused") # unused / used / expired used_at = Column(DateTime, default=None) created_at = Column(DateTime, default=datetime.now) class ValueAddedService(Base): __tablename__ = "value_added_services" id = Column(String(36), primary_key=True, default=gen_uuid) name = Column(String(200), nullable=False) description = Column(Text, default=None) price = Column(DECIMAL(10, 2), nullable=False) type = Column(String(20), nullable=False) # app_custom / platform_proxy / data_custom / private_project features = Column(JSON, default=None) # 服务特性 status = Column(String(10), nullable=False, default="active") # active / inactive / deleted assigned_agent_id = Column(String(36), default=None) # 应用定制服务绑定的Agent(市场应用ID) created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) class CustomServiceOrder(Base): __tablename__ = "custom_service_orders" id = Column(String(36), primary_key=True, default=gen_uuid) user_id = Column(String(36), ForeignKey("users.id"), nullable=False) service_id = Column(String(36), default=None) service_type = Column(String(10), nullable=False) description = Column(Text, default=None) status = Column(String(15), nullable=False, default="pending") price = Column(DECIMAL(10, 2), default=0.00) order_id = Column(String(36), default=None) created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) class CustomServiceRequest(Base): """增值服务工单表 - 用于数据定制服务和私有化项目服务""" __tablename__ = "custom_service_requests" id = Column(String(36), primary_key=True, default=gen_uuid) user_id = Column(String(36), ForeignKey("users.id"), nullable=False) service_id = Column(String(36), ForeignKey("value_added_services.id"), nullable=False) request_type = Column(String(20), nullable=False) # data_custom / private_project title = Column(String(200), nullable=False) description = Column(Text, default=None) requirements = Column(JSON, default=None) # 需求详情JSON status = Column(String(20), nullable=False, default="pending") # pending / processing / completed / rejected assigned_agent_id = Column(String(36), default=None) created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) # ============================================================ # Token与计费 # ============================================================ class ModelProvider(Base): __tablename__ = "model_providers" id = Column(String(36), primary_key=True, default=gen_uuid) name = Column(String(100), nullable=False) protocol = Column(String(30), nullable=False, default="openai_compatible") api_key = Column(String(255), default=None) api_base_url = Column(String(500), default=None) created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) class AIModel(Base): __tablename__ = "models" id = Column(String(36), primary_key=True, default=gen_uuid) provider_id = Column(String(36), ForeignKey("model_providers.id"), nullable=False) name = Column(String(100), nullable=False) api_key = Column(String(255), default=None) endpoint = Column(String(500), default=None) capabilities = Column(JSON, default=None) timeout = Column(Integer, default=60) status = Column(String(10), nullable=False, default="paid") # free / paid price_per_million_tokens = Column(DECIMAL(10, 4), nullable=False, default=0.0000) is_enabled = Column(Boolean, default=True) is_default = Column(Boolean, default=False) # 全局默认模型 total_calls = Column(BigInteger, default=0) total_tokens = Column(BigInteger, default=0) created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) class TokenUsageLog(Base): __tablename__ = "token_usage_logs" id = Column(String(36), primary_key=True, default=gen_uuid) user_id = Column(String(36), ForeignKey("users.id"), nullable=False) model_id = Column(String(36), default=None) model_name = Column(String(100), default=None) app_id = Column(String(36), default=None) app_name = Column(String(200), default=None) conversation_id = Column(String(36), default=None) prompt_tokens = Column(Integer, default=0) completion_tokens = Column(Integer, default=0) total_tokens = Column(Integer, default=0) cost = Column(DECIMAL(10, 6), default=0.000000) created_at = Column(DateTime, default=datetime.now) class TokenBalance(Base): __tablename__ = "token_balances" id = Column(String(36), primary_key=True, default=gen_uuid) user_id = Column(String(36), ForeignKey("users.id"), unique=True, nullable=False) total_consumed = Column(BigInteger, default=0) balance = Column(BigInteger, default=0) daily_free_used = Column(BigInteger, default=0) daily_free_date = Column(Date, default=None) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) # ============================================================ # 通知与日志 # ============================================================ class Notification(Base): __tablename__ = "notifications" id = Column(String(36), primary_key=True, default=gen_uuid) user_id = Column(String(36), ForeignKey("users.id"), nullable=False) type = Column(String(15), nullable=False) title = Column(String(200), nullable=False) content = Column(Text, default=None) is_read = Column(Boolean, default=False) created_at = Column(DateTime, default=datetime.now) class OperationLog(Base): __tablename__ = "operation_logs" id = Column(String(36), primary_key=True, default=gen_uuid) user_id = Column(String(36), nullable=False) username = Column(String(50), default=None) action = Column(String(100), nullable=False) target = Column(String(100), default=None) target_id = Column(String(36), default=None) detail = Column(Text, default=None) ip = Column(String(45), default=None) created_at = Column(DateTime, default=datetime.now) class AuditLog(Base): __tablename__ = "audit_logs" id = Column(String(36), primary_key=True, default=gen_uuid) admin_id = Column(String(36), nullable=False) admin_name = Column(String(50), default=None) action = Column(String(100), nullable=False) target_type = Column(String(50), default=None) target_id = Column(String(36), default=None) detail = Column(Text, default=None) created_at = Column(DateTime, default=datetime.now) class RiskRule(Base): __tablename__ = "risk_rules" id = Column(String(36), primary_key=True, default=gen_uuid) name = Column(String(100), nullable=False) type = Column(String(15), nullable=False) threshold = Column(Integer, default=0) duration = Column(Integer, default=3600) is_enabled = Column(Boolean, default=True) created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) # ============================================================ # 系统配置 # ============================================================ class SiteSetting(Base): __tablename__ = "site_settings" id = Column(String(36), primary_key=True, default=gen_uuid) key = Column(String(100), unique=True, nullable=False) value = Column(Text, default=None) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) class EmailConfig(Base): __tablename__ = "email_configs" id = Column(String(36), primary_key=True, default=gen_uuid) smtp_host = Column(String(200), nullable=False) smtp_port = Column(Integer, nullable=False, default=587) username = Column(String(200), nullable=False) password = Column(String(200), nullable=False) from_address = Column(String(200), nullable=False) use_tls = Column(Boolean, default=True) created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) class SmsConfig(Base): __tablename__ = "sms_configs" id = Column(String(36), primary_key=True, default=gen_uuid) provider = Column(String(50), nullable=False) api_key = Column(String(200), nullable=False) api_secret = Column(String(200), nullable=False) sign_name = Column(String(100), default=None) template_code = Column(String(100), default=None) created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) class PaymentConfig(Base): __tablename__ = "payment_configs" id = Column(String(36), primary_key=True, default=gen_uuid) type = Column(String(10), nullable=False) # wechat / alipay app_id = Column(String(100), nullable=False) merchant_id = Column(String(100), default=None) # 微信: 商户号 api_key = Column(String(255), nullable=False) # 微信: APIv2密钥 / 支付宝: 应用私钥 api_v3_key = Column(String(255), default=None) # 微信: APIv3密钥 cert_path = Column(String(500), default=None) # 微信: 证书路径 cert_serial_no = Column(String(200), default=None) # 微信: 证书序列号 alipay_public_key = Column(Text, default=None) # 支付宝: 支付宝公钥 app_private_key = Column(Text, default=None) # 支付宝: 应用私钥 gateway_url = Column(String(500), default=None) # 支付宝: 网关地址 notify_url = Column(String(500), default=None) # 支付回调通知地址 return_url = Column(String(500), default=None) # 支付宝: 同步跳转地址 status = Column(String(10), nullable=False, default="inactive") # active / inactive created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) class RegisterSetting(Base): __tablename__ = "register_settings" id = Column(String(36), primary_key=True, default=gen_uuid) phone_required = Column(Boolean, default=True) phone_sms_required = Column(Boolean, default=True) email_required = Column(Boolean, default=True) email_verify_required = Column(Boolean, default=True) real_name_required = Column(Boolean, default=False) aliyun_access_key = Column(String(200), default=None) aliyun_secret_key = Column(String(200), default=None) aliyun_endpoint = Column(String(200), default=None) sms_sign_name = Column(String(100), default=None) sms_template_code = Column(String(50), default=None) created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) # ============================================================ # 广告位 # ============================================================ class AdBanner(Base): __tablename__ = "ad_banners" id = Column(String(36), primary_key=True, default=gen_uuid) title = Column(String(200), nullable=False) image_url = Column(String(500), default=None) link_app_id = Column(String(36), default=None) link_app_name = Column(String(200), default=None) sort_order = Column(Integer, default=0) click_count = Column(Integer, default=0) status = Column(String(10), nullable=False, default="active") # active / inactive created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) # ============================================================ # 资产管理 # ============================================================ class AssetCategory(Base): __tablename__ = "asset_categories" id = Column(String(36), primary_key=True, default=gen_uuid) name = Column(String(100), nullable=False) type = Column(String(10), nullable=False) icon = Column(String(200), default=None) color = Column(String(20), default=None) is_default = Column(Boolean, default=False) user_id = Column(String(36), default=None) created_at = Column(DateTime, default=datetime.now) class Asset(Base): __tablename__ = "assets" id = Column(String(36), primary_key=True, default=gen_uuid) user_id = Column(String(36), ForeignKey("users.id"), nullable=False) name = Column(String(200), nullable=False) category = Column(String(10), nullable=False) sub_category = Column(String(50), default=None) file_type = Column(String(50), default=None) size = Column(BigInteger, default=0) description = Column(Text, default=None) cover_url = Column(String(500), default=None) url = Column(String(500), default=None) content = Column(Text, default=None) novel_meta = Column(JSON, default=None) status = Column(String(10), nullable=False, default="active") # active / deleted created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) class NovelChapter(Base): __tablename__ = "novel_chapters" id = Column(String(36), primary_key=True, default=gen_uuid) asset_id = Column(String(36), ForeignKey("assets.id"), nullable=False) title = Column(String(200), nullable=False) word_count = Column(Integer, default=0) sort_order = Column(Integer, default=0) content = Column(Text(length=4294967295), default=None) created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) # ============================================================ # 预留扩展 # ============================================================ class Team(Base): __tablename__ = "teams" id = Column(String(36), primary_key=True, default=gen_uuid) owner_id = Column(String(36), ForeignKey("users.id"), nullable=False) name = Column(String(100), nullable=False) description = Column(Text, default=None) status = Column(String(10), nullable=False, default="active") created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) class Referral(Base): __tablename__ = "referrals" id = Column(String(36), primary_key=True, default=gen_uuid) referrer_id = Column(String(36), ForeignKey("users.id"), nullable=False) referee_id = Column(String(36), ForeignKey("users.id"), nullable=False) referral_code = Column(String(50), default=None) status = Column(String(10), nullable=False, default="pending") commission_rate = Column(DECIMAL(5, 2), default=0.00) created_at = Column(DateTime, default=datetime.now) class OpenApiClient(Base): __tablename__ = "open_api_clients" id = Column(String(36), primary_key=True, default=gen_uuid) user_id = Column(String(36), ForeignKey("users.id"), nullable=False) name = Column(String(100), nullable=False) client_id = Column(String(64), unique=True, nullable=False) client_secret = Column(String(128), nullable=False) allowed_models = Column(JSON, default=None) rate_limit = Column(Integer, default=60) status = Column(String(10), nullable=False, default="active") created_at = Column(DateTime, default=datetime.now) # ============================================================ # API调用统计 # ============================================================ class ApiCallStat(Base): """API调用统计表 - 按端点聚合""" __tablename__ = "api_call_stats" id = Column(String(36), primary_key=True, default=gen_uuid) endpoint = Column(String(200), nullable=False) method = Column(String(10), nullable=False) call_count = Column(BigInteger, default=0) total_response_time = Column(Float, default=0.0) error_count = Column(BigInteger, default=0) last_called_at = Column(DateTime, default=None) created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) __table_args__ = ( UniqueConstraint("endpoint", "method", name="uk_endpoint_method"), ) class SlowRequestLog(Base): """慢请求记录表""" __tablename__ = "slow_request_logs" id = Column(String(36), primary_key=True, default=gen_uuid) request_id = Column(String(64), default=None) method = Column(String(10), nullable=False) endpoint = Column(String(500), nullable=False) status_code = Column(Integer, default=0) response_time = Column(Float, default=0.0) threshold = Column(Float, default=3.0) created_at = Column(DateTime, default=datetime.now) __table_args__ = ( Index("idx_srl_created", "created_at"), ) # ============================================================ # AI自进化引擎 - 用户进化配置 # ============================================================ class UserEvolutionConfig(Base): __tablename__ = "user_evolution_config" id = Column(String(36), primary_key=True, default=gen_uuid) user_id = Column(String(36), ForeignKey("users.id"), unique=True, nullable=False, index=True) skill_dir_path = Column(String(500), nullable=True, comment="用户Skill仓库根目录") trajectory_dir_path = Column(String(500), nullable=True, comment="用户对话轨迹目录") watcher_status = Column(String(20), default="stopped", comment="运行中/已停止/错误") watcher_error = Column(String(500), nullable=True, comment="watcher异常信息") pipeline_status = Column(String(20), default="idle", comment="流水线状态: running/idle/error") pipeline_processed = Column(Integer, default=0, comment="已处理轨迹数") created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) class EvolutionSkill(Base): __tablename__ = "evolution_skills" id = Column(String(36), primary_key=True, default=gen_uuid) user_id = Column(String(36), ForeignKey("users.id"), nullable=False, index=True) skill_name = Column(String(200), nullable=False, comment="技能名称") description = Column(Text, nullable=True) tags = Column(JSON, nullable=True, comment="标签列表") category = Column(String(100), nullable=True, comment="技能分类") state = Column(String(20), default="baby", comment="baby/main/staging/frozen") use_count = Column(Integer, default=0, comment="使用次数") version = Column(Integer, default=1) skill_md_path = Column(String(500), nullable=True, comment="SKILL.md文件路径") git_commit_sha = Column(String(40), nullable=True) last_used_at = Column(DateTime, nullable=True) created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) class EvolutionEvent(Base): __tablename__ = "evolution_events" id = Column(String(36), primary_key=True, default=gen_uuid) user_id = Column(String(36), ForeignKey("users.id"), nullable=False, index=True) skill_name = Column(String(200), nullable=False) event_type = Column(String(50), nullable=False, comment="created/promoted/rejected/frozen/unfrozen/edited/deleted/milestone") description = Column(Text, nullable=True) version_before = Column(Integer, nullable=True) version_after = Column(Integer, nullable=True) created_at = Column(DateTime, default=datetime.now) class EvolutionTrajectory(Base): __tablename__ = "evolution_trajectories" id = Column(String(36), primary_key=True, default=gen_uuid) user_id = Column(String(36), ForeignKey("users.id"), nullable=False, index=True) conversation_id = Column(String(36), nullable=True, comment="关联的对话ID") file_path = Column(String(500), nullable=True, comment="轨迹文件路径") status = Column(String(20), default="discovered", comment="discovered/splitting/split_done/indexed/clustering/done/error/filtered") atom_count = Column(Integer, default=0) token_used = Column(Integer, default=0) error_msg = Column(String(500), nullable=True, comment="轨迹处理失败的错误信息") retry_count = Column(Integer, default=0, comment="失败重试次数") tasks_extracted = Column(Integer, default=0, comment="拆分的AtomTask数量") created_at = Column(DateTime, default=datetime.now) processed_at = Column(DateTime, nullable=True) class SkillTrajectoryLink(Base): """技能-轨迹关联表:记录技能与对话轨迹的关联关系""" __tablename__ = "skill_trajectory_links" id = Column(String(36), primary_key=True, default=gen_uuid) skill_name = Column(String(200), nullable=False, index=True, comment="关联的技能名称") user_id = Column(String(36), ForeignKey("users.id"), nullable=False, index=True) trajectory_id = Column(String(36), nullable=True, comment="关联的轨迹ID") atom_id = Column(String(36), nullable=True, comment="原子任务ID") weightscore = Column(Integer, default=0, comment="关联权重分") created_at = Column(DateTime, default=datetime.now) # ============================================================ # AI自进化v2 - 新增表 # ============================================================ class SkillVersion(Base): """技能版本历史表:存储每个版本的SKILL.md完整内容,支持回滚""" __tablename__ = "skill_versions" id = Column(String(36), primary_key=True, default=gen_uuid) user_id = Column(String(36), ForeignKey("users.id"), nullable=False) skill_name = Column(String(200), nullable=False) version = Column(Integer, nullable=False, default=1) skill_md_content = Column(Text(4294967295), nullable=True, comment="该版本的SKILL.md完整内容") git_commit_sha = Column(String(40), nullable=True) description = Column(Text, nullable=True, comment="版本变更说明") created_at = Column(DateTime, default=datetime.now) __table_args__ = ( Index("idx_sv_user_skill", "user_id", "skill_name"), Index("idx_sv_version", "version"), ) class EvolutionReport(Base): """进化报告表:存储周报/月报""" __tablename__ = "evolution_reports" id = Column(String(36), primary_key=True, default=gen_uuid) user_id = Column(String(36), ForeignKey("users.id"), nullable=False) report_type = Column(String(20), nullable=False, comment="weekly / monthly") period_start = Column(Date, nullable=False) period_end = Column(Date, nullable=False) report_data = Column(JSON, nullable=True, comment="报告详细数据(JSON)") created_at = Column(DateTime, default=datetime.now) __table_args__ = ( Index("idx_er_user_type", "user_id", "report_type"), Index("idx_er_period", "period_start", "period_end"), ) class SkillPublishRecord(Base): """技能市场发布记录表""" __tablename__ = "skill_publish_records" id = Column(String(36), primary_key=True, default=gen_uuid) skill_id = Column(String(36), nullable=False, comment="关联evolution_skills.id") skill_name = Column(String(200), nullable=False) user_id = Column(String(36), ForeignKey("users.id"), nullable=False) market_app_id = Column(String(36), nullable=True, comment="关联market_apps.id") price = Column(DECIMAL(10, 2), default=0.00) market_description = Column(Text, nullable=True) status = Column(String(20), nullable=False, default="published", comment="published/unpublished") published_at = Column(DateTime, default=datetime.now) created_at = Column(DateTime, default=datetime.now) __table_args__ = ( Index("idx_spr_skill_id", "skill_id"), Index("idx_spr_user_id", "user_id"), Index("idx_spr_status", "status"), ) class TeamSharedSkill(Base): """团队共享技能表""" __tablename__ = "team_shared_skills" id = Column(String(36), primary_key=True, default=gen_uuid) team_id = Column(String(36), ForeignKey("teams.id"), nullable=False) skill_id = Column(String(36), nullable=False, comment="关联evolution_skills.id") skill_name = Column(String(200), nullable=False) shared_by = Column(String(36), ForeignKey("users.id"), nullable=False) shared_by_name = Column(String(100), nullable=True, comment="分享者昵称") is_public = Column(Boolean, default=True, comment="团队内是否可见") created_at = Column(DateTime, default=datetime.now) __table_args__ = ( UniqueConstraint("team_id", "skill_id", name="uk_tss_team_skill"), ) class ExternalKBService(Base): """外部知识库服务配置""" __tablename__ = "external_kb_services" id = Column(String(36), primary_key=True, default=gen_uuid) name = Column(String(200), nullable=False) service_type = Column(String(20), nullable=False) api_url = Column(String(500), nullable=False) api_key = Column(String(255), default="") config = Column(JSON, default=None) is_enabled = Column(Boolean, default=True) status = Column(String(20), default="disconnected") created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) class OSSStorageConfig(Base): __tablename__ = "oss_storage_configs" id = Column(String(36), primary_key=True, default=gen_uuid) name = Column(String(200), nullable=False) provider = Column(String(20), nullable=False) endpoint = Column(String(500), nullable=False) access_key = Column(String(255), nullable=False) secret_key = Column(String(255), nullable=False) bucket = Column(String(200), nullable=False) region = Column(String(100), default="") base_path = Column(String(300), default="") is_default = Column(Boolean, default=False) is_enabled = Column(Boolean, default=True) status = Column(String(20), default="disconnected") config = Column(JSON, default=None) created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) class AutomatedTask(Base): __tablename__ = "automated_tasks" id = Column(String(36), primary_key=True, default=gen_uuid) name = Column(String(200), nullable=False) description = Column(Text, default="") trigger_type = Column(String(20), nullable=False) cron_expression = Column(String(100), default=None) event_condition = Column(JSON, default=None) action_type = Column(String(30), nullable=False) action_config = Column(JSON, default=None) is_enabled = Column(Boolean, default=True) status = Column(String(20), default="idle") max_retries = Column(Integer, default=3) timeout_seconds = Column(Integer, default=300) last_run_at = Column(DateTime, default=None) next_run_at = Column(DateTime, default=None) total_runs = Column(Integer, default=0) success_runs = Column(Integer, default=0) created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now) class TaskExecutionLog(Base): __tablename__ = "task_execution_logs" id = Column(String(36), primary_key=True, default=gen_uuid) task_id = Column(String(36), nullable=False) task_name = Column(String(200), default="") status = Column(String(20), default="running") trigger_type = Column(String(20), default="manual") started_at = Column(DateTime, default=None) finished_at = Column(DateTime, default=None) duration_ms = Column(Integer, default=0) result_summary = Column(Text, default="") error_message = Column(Text, default="") created_at = Column(DateTime, default=datetime.now) class MCPServer(Base): __tablename__ = "mcp_servers" id = Column(String(36), primary_key=True, default=gen_uuid) name = Column(String(100), nullable=False) description = Column(Text, default="") transport_type = Column(String(20), default="stdio") command = Column(String(500), default="") args = Column(Text, default="") env_vars = Column(Text, default="") url = Column(String(500), default="") headers = Column(Text, default="") is_enabled = Column(Boolean, default=True) status = Column(String(20), default="disconnected") last_connected_at = Column(DateTime, default=None) tools_count = Column(Integer, default=0) resources_count = Column(Integer, default=0) created_at = Column(DateTime, default=datetime.now) updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)