初始提交: Qihu-AIFlow v2.0.1 完整项目
- 前端 React+TypeScript (源码+构建产物) - 后端 Python FastAPI - 数据库迁移 001-015 - Docker部署配置 - 微信ClawBot API频道绑定 - 项目文档 README.md
This commit is contained in:
commit
78ff261b5a
199 files changed
+69126
No files matched your search
@@ -0,0 +1,937 @@
|
||||
"""
|
||||
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)
|
||||
|
||||
|
||||
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 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"),
|
||||
)
|
||||
Reference in new issue
Block a user