1167 lines
52 KiB
Python
1167 lines
52 KiB
Python
"""
|
||
AIFlow 数据库模型定义 - SQLAlchemy ORM
|
||
所有用户数据查询必须带 user_id 过滤实现物理隔离
|
||
"""
|
||
import uuid
|
||
from datetime import datetime, date
|
||
from sqlalchemy import (
|
||
Text,
|
||
Column, String, Integer, BigInteger, Float, Boolean,
|
||
DateTime, Date, Text, Enum, ForeignKey, Index, JSON,
|
||
DECIMAL, UniqueConstraint
|
||
)
|
||
from sqlalchemy.orm import relationship
|
||
from sqlalchemy import Text # PG-compatible (was MEDIUMTEXT from mysql dialect)
|
||
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)
|
||
description = Column(String(500), default=None, comment="密钥描述")
|
||
rate_limit = Column(Integer, default=60, comment="速率限制(请求/分钟)")
|
||
total_calls = Column(BigInteger, default=0, comment="总调用次数")
|
||
|
||
|
||
# ============================================================
|
||
# 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)
|
||
knowledge_graph_base_id = Column(String(64), default=None, comment="已生成的知识图谱知识库ID")
|
||
source = Column(String(32), default=None, comment="对话来源,如 wechat_bot")
|
||
ext_agent_conversation_id = Column(String(128), default=None, comment="外部Agent(Dify/Coze)会话ID,用于维持多轮上下文")
|
||
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)
|
||
mcp_ids = Column(JSON, default=None, comment="该轮对话选择的MCP应用ID列表")
|
||
attachments = Column(JSON, default=None, comment="该轮对话附带的文件附件列表")
|
||
used_skills = Column(JSON, default=None, comment="该轮对话调用的进化技能名列表")
|
||
used_mcp = Column(JSON, default=None, comment="该轮对话调用的MCP应用名列表")
|
||
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)
|
||
# 分类与标签:DB 表 market_apps 已存在 category(varchar50)/tags(varchar500) 两列,
|
||
# 此前 ORM 漏声明导致后台读取分类恒为 None -> 回退 "other"(#679 根因)。此处补齐。
|
||
category = Column(String(50), default="other", comment="技能/应用分类(9类: writing/coding/data_analysis/qa/automation/creativity/communication/reasoning/other)")
|
||
tags = Column(String(500), default=None, comment="标签,逗号分隔")
|
||
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)
|
||
platform = Column(String(20), default=None, comment="Agent 接入平台:dify/n8n/coze")
|
||
capability = Column(String(20), default=None, comment="能力分类:text/thinking/vision/tool/image/audio/asr/ocr/embedding/rerank/video")
|
||
agent_endpoint = Column(String(500), default=None)
|
||
agent_api_key = Column(Text, default=None, comment="Agent 接入 API Key(3.2 起 Fernet 加密存储)")
|
||
tool_policy = Column(JSON, default=None, comment="Agent 工具/MCP 权限沙箱策略(3.1)")
|
||
orchestration = Column(JSON, default=None, comment="Agent 多Agent编排图(3.3)")
|
||
# Phase 4.1: 市场安检 + 版本化 + 绿标
|
||
version = Column(String(20), default="1.0.0", comment="应用版本号(4.1)")
|
||
security_scan = Column(JSON, default=None, comment="安全扫描结果(4.1)")
|
||
dependencies = Column(JSON, default=None, comment="依赖声明(4.1)")
|
||
verified = Column(Boolean, default=False, comment="绿标/官方安检通过(4.1)")
|
||
created_at = Column(DateTime, default=datetime.now)
|
||
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|
||
|
||
|
||
class MarketAppVersion(Base):
|
||
"""Phase 4.1: 应用版本快照表,支持灰度回滚。"""
|
||
__tablename__ = "market_app_versions"
|
||
|
||
id = Column(String(36), primary_key=True, default=gen_uuid)
|
||
app_id = Column(String(36), ForeignKey("market_apps.id"), nullable=False, index=True)
|
||
version = Column(String(20), nullable=False)
|
||
type = Column(String(10), nullable=False)
|
||
config = Column(JSON, default=None, comment="该版本完整配置快照(4.1)")
|
||
security_scan = Column(JSON, default=None, comment="该版本安检结果(4.1)")
|
||
dependencies = Column(JSON, default=None, comment="该版本依赖声明(4.1)")
|
||
created_by = Column(String(36), default=None)
|
||
created_at = Column(DateTime, default=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)
|
||
# 配额字段
|
||
max_agents = Column(Integer, default=5)
|
||
max_workflows = Column(Integer, default=3)
|
||
max_knowledge_bases = Column(Integer, default=2)
|
||
max_storage_mb = Column(Integer, default=1024)
|
||
api_calls_per_day = Column(Integer, default=100)
|
||
api_calls_per_min = Column(Integer, default=10)
|
||
# 权限字段
|
||
can_publish_apps = Column(Boolean, default=False)
|
||
can_create_api_keys = Column(Boolean, default=False)
|
||
can_use_workflow = Column(Boolean, default=False)
|
||
can_use_mcp = Column(Boolean, default=False)
|
||
can_use_code_exec = Column(Boolean, default=False)
|
||
can_use_privacy_mode = Column(Boolean, default=False)
|
||
can_use_dag = Column(Boolean, default=False)
|
||
allowed_model_tiers = Column(JSON, default=None)
|
||
permissions = 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)
|
||
auth_header = Column(String(100), default="Authorization: Bearer", comment="自定义认证头,如MiMo用api-key")
|
||
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)
|
||
display_name = Column(String(200), default=None, comment="display name")
|
||
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)
|
||
trace_id = Column(String(64), 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)
|
||
use_ssl = Column(Boolean, default=False)
|
||
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)
|
||
# 短信宝 (SMSBao) 字段
|
||
username = Column(String(100), default=None) # 短信宝用户名 u
|
||
password = Column(String(200), default=None) # 短信宝密码(明文存储,发送时 MD5 32位)
|
||
goods_id = Column(String(100), default=None) # 短信宝专属通道产品 ID g
|
||
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
|
||
knowledge_doc_id = Column(String(36), default=None, comment="关联的知识库文档ID(由知识库同步资产时写入)")
|
||
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)
|
||
total_calls = Column(BigInteger, default=0, comment="总调用次数")
|
||
last_used_at = Column(DateTime, default=None, comment="最后使用时间")
|
||
|
||
|
||
# ============================================================
|
||
# 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(128), nullable=True, comment="原子任务ID(形如 trajectory_id_atom_N,需容纳 UUID+后缀)")
|
||
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 UserStorageQuota(Base):
|
||
__tablename__ = "user_storage_quotas"
|
||
|
||
id = Column(String(36), primary_key=True, default=gen_uuid)
|
||
user_id = Column(String(36), nullable=False, unique=True)
|
||
quota_bytes = Column(BigInteger, nullable=False, default=1073741824)
|
||
used_bytes = Column(BigInteger, nullable=False, default=0)
|
||
quota_type = Column(String(20), nullable=False, default="membership")
|
||
membership_level = Column(Integer, default=0)
|
||
plan_id = Column(String(36), 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)
|
||
|
||
|
||
class SmsVerificationCode(Base):
|
||
__tablename__ = "sms_verification_codes"
|
||
|
||
id = Column(String(36), primary_key=True, default=gen_uuid)
|
||
phone = Column(String(20), nullable=False, index=True)
|
||
code = Column(String(10), nullable=False)
|
||
purpose = Column(String(30), nullable=False) # register / reset_password
|
||
expires_at = Column(DateTime, nullable=False)
|
||
used = Column(Boolean, default=False)
|
||
created_at = Column(DateTime, default=datetime.now)
|
||
|
||
|
||
|
||
class ConversationSummary(Base):
|
||
__tablename__ = "conversation_summaries"
|
||
|
||
conversation_id = Column(String(64), primary_key=True)
|
||
summary_text = Column(Text, nullable=False, default="")
|
||
token_count = Column(Integer, default=0)
|
||
structured_memory = Column(JSON, default=None) # T2: Semantica 式结构化长期记忆
|
||
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|