Initial commit: Daily News App
企業內部新聞彙整與分析系統 - 自動新聞抓取 (Digitimes, 經濟日報, 工商時報) - AI 智慧摘要 (OpenAI/Claude/Ollama) - 群組管理與訂閱通知 - 已清理 Python 快取檔案 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
82
app/models/group.py
Normal file
82
app/models/group.py
Normal file
@@ -0,0 +1,82 @@
|
||||
"""
|
||||
群組與關鍵字資料模型
|
||||
"""
|
||||
from datetime import datetime
|
||||
from sqlalchemy import String, Boolean, ForeignKey, Text, JSON, Enum as SQLEnum, UniqueConstraint, Index, DECIMAL
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from typing import Optional, List
|
||||
import enum
|
||||
|
||||
from app.db.session import Base
|
||||
|
||||
|
||||
class GroupCategory(str, enum.Enum):
|
||||
"""群組分類"""
|
||||
INDUSTRY = "industry"
|
||||
TOPIC = "topic"
|
||||
|
||||
|
||||
class Group(Base):
|
||||
"""群組表"""
|
||||
__tablename__ = "groups"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
name: Mapped[str] = mapped_column(String(100), nullable=False, comment="群組名稱")
|
||||
description: Mapped[Optional[str]] = mapped_column(Text, comment="群組描述")
|
||||
category: Mapped[GroupCategory] = mapped_column(SQLEnum(GroupCategory), nullable=False, comment="分類")
|
||||
ai_background: Mapped[Optional[str]] = mapped_column(Text, comment="AI背景資訊設定")
|
||||
ai_prompt: Mapped[Optional[str]] = mapped_column(Text, comment="AI摘要方向提示")
|
||||
is_active: Mapped[bool] = mapped_column(Boolean, default=True, comment="是否啟用")
|
||||
created_by: Mapped[Optional[int]] = mapped_column(ForeignKey("users.id"), comment="建立者ID")
|
||||
created_at: Mapped[datetime] = mapped_column(default=datetime.utcnow)
|
||||
updated_at: Mapped[datetime] = mapped_column(default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||
|
||||
# 關聯
|
||||
keywords: Mapped[List["Keyword"]] = relationship(back_populates="group", cascade="all, delete-orphan")
|
||||
article_matches: Mapped[List["ArticleGroupMatch"]] = relationship(back_populates="group", cascade="all, delete-orphan")
|
||||
reports: Mapped[List["Report"]] = relationship(back_populates="group")
|
||||
subscriptions: Mapped[List["Subscription"]] = relationship(back_populates="group", cascade="all, delete-orphan")
|
||||
|
||||
|
||||
class Keyword(Base):
|
||||
"""關鍵字表"""
|
||||
__tablename__ = "keywords"
|
||||
__table_args__ = (
|
||||
UniqueConstraint("group_id", "keyword", name="uk_group_keyword"),
|
||||
Index("idx_keywords_keyword", "keyword"),
|
||||
)
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
group_id: Mapped[int] = mapped_column(ForeignKey("groups.id", ondelete="CASCADE"), nullable=False, comment="所屬群組ID")
|
||||
keyword: Mapped[str] = mapped_column(String(100), nullable=False, comment="關鍵字")
|
||||
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
|
||||
created_at: Mapped[datetime] = mapped_column(default=datetime.utcnow)
|
||||
|
||||
# 關聯
|
||||
group: Mapped["Group"] = relationship(back_populates="keywords")
|
||||
|
||||
|
||||
class ArticleGroupMatch(Base):
|
||||
"""新聞-群組匹配關聯表"""
|
||||
__tablename__ = "article_group_matches"
|
||||
__table_args__ = (
|
||||
UniqueConstraint("article_id", "group_id", name="uk_article_group"),
|
||||
Index("idx_matches_group", "group_id"),
|
||||
)
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
article_id: Mapped[int] = mapped_column(ForeignKey("news_articles.id", ondelete="CASCADE"), nullable=False)
|
||||
group_id: Mapped[int] = mapped_column(ForeignKey("groups.id", ondelete="CASCADE"), nullable=False)
|
||||
matched_keywords: Mapped[Optional[list]] = mapped_column(JSON, comment="匹配到的關鍵字列表")
|
||||
match_score: Mapped[Optional[float]] = mapped_column(DECIMAL(5, 2), comment="匹配分數")
|
||||
created_at: Mapped[datetime] = mapped_column(default=datetime.utcnow)
|
||||
|
||||
# 關聯
|
||||
article: Mapped["NewsArticle"] = relationship(back_populates="group_matches")
|
||||
group: Mapped["Group"] = relationship(back_populates="article_matches")
|
||||
|
||||
|
||||
# 避免循環引入
|
||||
from app.models.news import NewsArticle
|
||||
from app.models.report import Report
|
||||
from app.models.interaction import Subscription
|
||||
Reference in New Issue
Block a user