feat: AI虚拟用户新闻互动系统 v1.3.0 初始提交
- 虚拟用户管理(昵称/头像/性别/简介/邮箱同步到目标平台) - AI互动调度(点赞/收藏/评论/转发) - 日志时间改为北京时间 - 评论达上限后继续执行点赞收藏转发 - 一键登出全部功能 - 浅色主题UI
This commit is contained in:
132
backend/app/models/__init__.py
Normal file
132
backend/app/models/__init__.py
Normal file
@@ -0,0 +1,132 @@
|
||||
"""SQLAlchemy ORM 模型"""
|
||||
from datetime import datetime
|
||||
from sqlalchemy import (
|
||||
BigInteger, Integer, SmallInteger, String, Text, DateTime,
|
||||
Boolean, Float, Date, JSON, func
|
||||
)
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
from app.core.database import Base
|
||||
|
||||
|
||||
class VirtualUser(Base):
|
||||
__tablename__ = "virtual_users"
|
||||
|
||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||
nickname: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||
account: Mapped[str] = mapped_column(String(128), nullable=False, unique=True)
|
||||
password_enc: Mapped[str] = mapped_column(String(512), nullable=False)
|
||||
avatar_url: Mapped[str | None] = mapped_column(String(512))
|
||||
status: Mapped[int] = mapped_column(SmallInteger, default=0)
|
||||
activity_level: Mapped[int] = mapped_column(SmallInteger, default=1)
|
||||
daily_comment_limit: Mapped[int] = mapped_column(Integer, default=10)
|
||||
daily_like_limit: Mapped[int] = mapped_column(Integer, default=30)
|
||||
today_comment_count: Mapped[int] = mapped_column(Integer, default=0)
|
||||
today_like_count: Mapped[int] = mapped_column(Integer, default=0)
|
||||
total_interactions: Mapped[int] = mapped_column(Integer, default=0)
|
||||
session_token: Mapped[str | None] = mapped_column(Text)
|
||||
session_expires_at: Mapped[datetime | None] = mapped_column(DateTime)
|
||||
last_login_at: Mapped[datetime | None] = mapped_column(DateTime)
|
||||
last_interact_at: Mapped[datetime | None] = mapped_column(DateTime)
|
||||
real_name: Mapped[str | None] = mapped_column(String(64)) # 真实姓名(从平台同步)
|
||||
sex: Mapped[int] = mapped_column(SmallInteger, default=0) # 性别 0未知 1男 2女
|
||||
platform_uid: Mapped[str | None] = mapped_column(String(64)) # 平台用户ID
|
||||
remark: Mapped[str | None] = mapped_column(String(256))
|
||||
is_enabled: Mapped[int] = mapped_column(SmallInteger, default=1)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||
updated_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), onupdate=func.now())
|
||||
|
||||
|
||||
class UserPersonality(Base):
|
||||
__tablename__ = "user_personalities"
|
||||
|
||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(BigInteger, nullable=False, unique=True)
|
||||
character_type: Mapped[str | None] = mapped_column(String(32))
|
||||
language_style: Mapped[str | None] = mapped_column(String(32))
|
||||
interest_tags: Mapped[dict | None] = mapped_column(JSON)
|
||||
interact_tendency: Mapped[str | None] = mapped_column(String(32))
|
||||
word_count_min: Mapped[int] = mapped_column(Integer, default=20)
|
||||
word_count_max: Mapped[int] = mapped_column(Integer, default=100)
|
||||
personality_desc: Mapped[str | None] = mapped_column(Text)
|
||||
comment_style_prompt: Mapped[str | None] = mapped_column(Text)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||
updated_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), onupdate=func.now())
|
||||
|
||||
|
||||
class InteractionRecord(Base):
|
||||
__tablename__ = "interaction_records"
|
||||
|
||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(BigInteger, nullable=False, index=True)
|
||||
user_nickname: Mapped[str | None] = mapped_column(String(64))
|
||||
user_account: Mapped[str | None] = mapped_column(String(128))
|
||||
article_id: Mapped[str | None] = mapped_column(String(64))
|
||||
article_title: Mapped[str | None] = mapped_column(String(256))
|
||||
interact_type: Mapped[str] = mapped_column(String(16), nullable=False, index=True)
|
||||
content: Mapped[str | None] = mapped_column(Text)
|
||||
platform_record_id: Mapped[str | None] = mapped_column(String(64)) # 平台返回的记录ID(用于取消互动)
|
||||
parent_comment_id: Mapped[str | None] = mapped_column(String(64))
|
||||
session_id: Mapped[str | None] = mapped_column(String(128))
|
||||
token_consumed: Mapped[int] = mapped_column(Integer, default=0)
|
||||
status: Mapped[int] = mapped_column(SmallInteger, default=0)
|
||||
error_msg: Mapped[str | None] = mapped_column(String(512))
|
||||
retry_count: Mapped[int] = mapped_column(SmallInteger, default=0)
|
||||
executed_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), index=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||
|
||||
|
||||
class TokenStat(Base):
|
||||
__tablename__ = "token_stats"
|
||||
|
||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||
stat_date: Mapped[datetime] = mapped_column(Date, nullable=False, unique=True)
|
||||
model_name: Mapped[str | None] = mapped_column(String(64))
|
||||
total_tokens: Mapped[int] = mapped_column(Integer, default=0)
|
||||
prompt_tokens: Mapped[int] = mapped_column(Integer, default=0)
|
||||
completion_tokens: Mapped[int] = mapped_column(Integer, default=0)
|
||||
call_count: Mapped[int] = mapped_column(Integer, default=0)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||
updated_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), onupdate=func.now())
|
||||
|
||||
|
||||
class AIModelConfig(Base):
|
||||
__tablename__ = "ai_model_configs"
|
||||
|
||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||
model_name: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||
provider: Mapped[str] = mapped_column(String(32), nullable=False)
|
||||
api_base_url: Mapped[str | None] = mapped_column(String(256))
|
||||
api_key_enc: Mapped[str | None] = mapped_column(String(512))
|
||||
model_version: Mapped[str | None] = mapped_column(String(64))
|
||||
temperature: Mapped[float] = mapped_column(Float, default=0.7)
|
||||
max_tokens: Mapped[int] = mapped_column(Integer, default=1000)
|
||||
timeout_seconds: Mapped[int] = mapped_column(Integer, default=30)
|
||||
is_default: Mapped[int] = mapped_column(SmallInteger, default=0)
|
||||
is_enabled: Mapped[int] = mapped_column(SmallInteger, default=1)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||
updated_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), onupdate=func.now())
|
||||
|
||||
|
||||
class SystemConfig(Base):
|
||||
__tablename__ = "system_configs"
|
||||
|
||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||
config_key: Mapped[str] = mapped_column(String(64), nullable=False, unique=True)
|
||||
config_value: Mapped[str | None] = mapped_column(Text)
|
||||
config_type: Mapped[str] = mapped_column(String(16), default="string")
|
||||
description: Mapped[str | None] = mapped_column(String(256))
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||
updated_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), onupdate=func.now())
|
||||
|
||||
|
||||
class LoginLog(Base):
|
||||
__tablename__ = "login_logs"
|
||||
|
||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
|
||||
user_id: Mapped[int] = mapped_column(BigInteger, nullable=False, index=True)
|
||||
user_account: Mapped[str | None] = mapped_column(String(128))
|
||||
action: Mapped[str] = mapped_column(String(16), nullable=False)
|
||||
session_id: Mapped[str | None] = mapped_column(String(128))
|
||||
ip_address: Mapped[str | None] = mapped_column(String(64))
|
||||
error_msg: Mapped[str | None] = mapped_column(String(512))
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), index=True)
|
||||
19
backend/app/models/all_models.py
Normal file
19
backend/app/models/all_models.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# models package - re-export all models
|
||||
from app.models import (
|
||||
VirtualUser, UserPersonality, InteractionRecord,
|
||||
TokenStat, AIModelConfig, SystemConfig, LoginLog
|
||||
)
|
||||
|
||||
# Aliases for import compatibility
|
||||
virtual_user = VirtualUser
|
||||
personality = UserPersonality
|
||||
interaction = InteractionRecord
|
||||
token_stat = TokenStat
|
||||
ai_model = AIModelConfig
|
||||
system_config = SystemConfig
|
||||
login_log = LoginLog
|
||||
|
||||
__all__ = [
|
||||
"VirtualUser", "UserPersonality", "InteractionRecord",
|
||||
"TokenStat", "AIModelConfig", "SystemConfig", "LoginLog",
|
||||
]
|
||||
Reference in New Issue
Block a user