backend update

This commit is contained in:
stardrophere
2026-03-09 13:43:00 +08:00
parent 39d4e9ef8f
commit 3c57dd0cce
15 changed files with 433 additions and 0 deletions
View File
+294
View File
@@ -0,0 +1,294 @@
from datetime import datetime, timezone, time
from typing import Optional, Any
import enum
from sqlalchemy import (
String, Integer, BigInteger, Text, Boolean, DateTime, Time,
Float, JSON, ForeignKey, Enum, UniqueConstraint, Index
)
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
# ==========================================
# 0. 全局基类与枚举定义
# ==========================================
class Base(DeclarativeBase):
"""SQLAlchemy 2.0 声明式基类"""
pass
class SourceType(str, enum.Enum):
HOT_TREND = "HOT_TREND"
RSS_FEED = "RSS_FEED"
API = "API"
class TargetType(str, enum.Enum):
EVENT = "EVENT"
TREND = "TREND"
ARTICLE = "ARTICLE"
class TaskStatus(str, enum.Enum):
SUCCESS = "SUCCESS"
ERROR = "ERROR"
class GenderType(str, enum.Enum):
MALE = "MALE"
FEMALE = "FEMALE"
OTHER = "OTHER"
UNKNOWN = "UNKNOWN"
def utcnow():
"""获取带UTC时区的当前时间 (推荐实践)"""
return datetime.now(timezone.utc)
# ==========================================
# 模块一:信息源管理
# ==========================================
class InfoSource(Base):
__tablename__ = "info_sources"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
source_name: Mapped[str] = mapped_column(String(100), comment="信息源名称")
source_type: Mapped[SourceType] = mapped_column(Enum(SourceType))
home_url: Mapped[Optional[str]] = mapped_column(String(255))
is_enabled: Mapped[bool] = mapped_column(Boolean, default=True)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow)
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow, onupdate=utcnow)
# ==========================================
# 模块二:AI 语义聚类中枢 (大事件池)
# ==========================================
class UnifiedEvent(Base):
__tablename__ = "unified_events"
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
unified_title: Mapped[str] = mapped_column(String(255), comment="AI统一标题")
ai_comprehensive_summary: Mapped[Optional[str]] = mapped_column(Text, comment="AI全局深度总结")
# SQLite 没有原生 Vector 类型,存为用逗号分隔的字符串或JSON,Postgres可换成 PGVector
center_embedding: Mapped[Optional[str]] = mapped_column(Text, comment="中心向量")
hot_score: Mapped[int] = mapped_column(Integer, default=0, comment="聚合热度得分")
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow)
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow, onupdate=utcnow)
# ==========================================
# 模块三:内容存储库 (热搜 & 新闻子节点)
# ==========================================
class TrendingEvent(Base):
__tablename__ = "trending_events"
__table_args__ = (
UniqueConstraint("source_id", "external_id", name="idx_unique_external_trend"),
)
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
source_id: Mapped[int] = mapped_column(ForeignKey("info_sources.id"))
unified_event_id: Mapped[Optional[int]] = mapped_column(ForeignKey("unified_events.id"))
external_id: Mapped[str] = mapped_column(String(32), comment="32位MD5哈希指纹防重")
title_embedding: Mapped[Optional[str]] = mapped_column(Text)
icon_url: Mapped[Optional[str]] = mapped_column(String(500))
current_headline: Mapped[str] = mapped_column(String(255))
event_url: Mapped[Optional[str]] = mapped_column(String(500))
app_link: Mapped[Optional[str]] = mapped_column(String(500))
current_ranking: Mapped[Optional[int]] = mapped_column(Integer)
brief_snippet: Mapped[Optional[str]] = mapped_column(Text)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow)
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow, onupdate=utcnow)
class NewsArticle(Base):
__tablename__ = "news_articles"
__table_args__ = (
UniqueConstraint("source_id", "external_id", name="idx_unique_external_article"),
)
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
source_id: Mapped[int] = mapped_column(ForeignKey("info_sources.id"))
unified_event_id: Mapped[Optional[int]] = mapped_column(ForeignKey("unified_events.id"))
external_id: Mapped[str] = mapped_column(String(32))
title_embedding: Mapped[Optional[str]] = mapped_column(Text)
cover_image_url: Mapped[Optional[str]] = mapped_column(String(500))
article_title: Mapped[str] = mapped_column(String(255))
article_url: Mapped[Optional[str]] = mapped_column(String(500))
author_name: Mapped[Optional[str]] = mapped_column(String(100))
original_summary: Mapped[Optional[str]] = mapped_column(Text)
publish_time: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True))
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow)
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow, onupdate=utcnow)
# ==========================================
# 模块四:热度与轨迹追踪
# ==========================================
class HeadlineRevision(Base):
__tablename__ = "headline_revisions"
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
event_id: Mapped[int] = mapped_column(ForeignKey("trending_events.id"))
previous_headline: Mapped[str] = mapped_column(String(255))
revised_headline: Mapped[str] = mapped_column(String(255))
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow)
class RankingLog(Base):
__tablename__ = "ranking_logs"
__table_args__ = (
Index("idx_event_time", "event_id", "observed_at"),
)
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
event_id: Mapped[int] = mapped_column(ForeignKey("trending_events.id"))
ranking_position: Mapped[int] = mapped_column(Integer)
observed_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow)
# ==========================================
# 模块五:多态话题与多态评论
# ==========================================
class ExtractedTopic(Base):
__tablename__ = "extracted_topics"
__table_args__ = (
Index("idx_topic_keyword", "topic_keyword"),
Index("idx_polymorphic_topics", "target_type", "target_id"),
)
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
target_type: Mapped[TargetType] = mapped_column(Enum(TargetType))
target_id: Mapped[int] = mapped_column(BigInteger)
topic_keyword: Mapped[str] = mapped_column(String(100))
relevance_score: Mapped[Optional[float]] = mapped_column(Float)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow)
class DiscussionComment(Base):
__tablename__ = "discussion_comments"
__table_args__ = (
Index("idx_polymorphic_comments", "target_type", "target_id"),
)
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
target_type: Mapped[TargetType] = mapped_column(Enum(TargetType))
target_id: Mapped[int] = mapped_column(BigInteger)
commenter_name: Mapped[Optional[str]] = mapped_column(String(100))
comment_content: Mapped[str] = mapped_column(Text)
likes_count: Mapped[int] = mapped_column(Integer, default=0)
external_comment_id: Mapped[Optional[str]] = mapped_column(String(32))
comment_time: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True))
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow)
# ==========================================
# 模块六:用户画像与多渠道高可用推送系统
# ==========================================
class AppUser(Base):
__tablename__ = "app_users"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
email: Mapped[str] = mapped_column(String(150), unique=True, index=True)
password_hash: Mapped[Optional[str]] = mapped_column(String(255))
nickname: Mapped[Optional[str]] = mapped_column(String(100))
avatar_url: Mapped[Optional[str]] = mapped_column(String(500))
gender: Mapped[GenderType] = mapped_column(Enum(GenderType), default=GenderType.UNKNOWN)
# 核心:万能扩展收纳箱 (SQLite 完美支持通过 SQLAlchemy 存储 JSON)
metadata_: Mapped[Optional[Any]] = mapped_column("metadata", JSON, comment="自定义扩展偏好")
timezone: Mapped[str] = mapped_column(String(50), default="Asia/Shanghai")
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow)
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow, onupdate=utcnow)
class UserPushEndpoint(Base):
__tablename__ = "user_push_endpoints"
__table_args__ = (
UniqueConstraint("user_id", "channel_type", name="idx_unique_user_channel"),
)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
user_id: Mapped[int] = mapped_column(ForeignKey("app_users.id"))
channel_type: Mapped[str] = mapped_column(String(50), comment="如 EMAIL, WECHAT")
channel_account: Mapped[str] = mapped_column(String(255))
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
priority_level: Mapped[int] = mapped_column(Integer, default=1, comment="1最高,降级重试")
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow)
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow, onupdate=utcnow)
class UserTopicPreference(Base):
__tablename__ = "user_topic_preferences"
__table_args__ = (
UniqueConstraint("user_id", "interested_keyword", name="idx_unique_preference"),
)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
user_id: Mapped[int] = mapped_column(ForeignKey("app_users.id"))
interested_keyword: Mapped[str] = mapped_column(String(100))
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow)
class UserDeliverySchedule(Base):
__tablename__ = "user_delivery_schedules"
__table_args__ = (
UniqueConstraint("user_id", "delivery_time", name="idx_unique_schedule"),
)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
user_id: Mapped[int] = mapped_column(ForeignKey("app_users.id"))
delivery_time: Mapped[time] = mapped_column(Time, comment="如 08:30:00")
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow)
class DeliveryHistory(Base):
__tablename__ = "delivery_history"
__table_args__ = (
UniqueConstraint("user_id", "target_type", "target_id", name="idx_prevent_duplicate_push"),
)
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
user_id: Mapped[int] = mapped_column(ForeignKey("app_users.id"))
target_type: Mapped[TargetType] = mapped_column(Enum(TargetType))
target_id: Mapped[int] = mapped_column(BigInteger)
status: Mapped[TaskStatus] = mapped_column(Enum(TaskStatus))
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow)
# ==========================================
# 模块七:系统任务监控
# ==========================================
class DataSyncTask(Base):
__tablename__ = "data_sync_tasks"
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
source_id: Mapped[int] = mapped_column(ForeignKey("info_sources.id"))
items_fetched: Mapped[int] = mapped_column(Integer, default=0)
task_status: Mapped[TaskStatus] = mapped_column(Enum(TaskStatus))
error_trace: Mapped[Optional[str]] = mapped_column(Text)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow)