企業內部新聞彙整與分析系統 - 自動新聞抓取 (Digitimes, 經濟日報, 工商時報) - AI 智慧摘要 (OpenAI/Claude/Ollama) - 群組管理與訂閱通知 - 已清理 Python 快取檔案 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
80 lines
3.6 KiB
Python
80 lines
3.6 KiB
Python
"""
|
|
報告資料模型
|
|
"""
|
|
from datetime import datetime, date
|
|
from sqlalchemy import String, Boolean, ForeignKey, Text, Date, Enum as SQLEnum, UniqueConstraint, Index
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
from typing import Optional, List
|
|
import enum
|
|
|
|
from app.db.session import Base
|
|
|
|
|
|
class ReportStatus(str, enum.Enum):
|
|
"""報告狀態"""
|
|
DRAFT = "draft"
|
|
PENDING = "pending"
|
|
PUBLISHED = "published"
|
|
DELAYED = "delayed"
|
|
|
|
|
|
class Report(Base):
|
|
"""報告表"""
|
|
__tablename__ = "reports"
|
|
__table_args__ = (
|
|
UniqueConstraint("group_id", "report_date", name="uk_group_date"),
|
|
Index("idx_reports_status", "status"),
|
|
Index("idx_reports_date", "report_date"),
|
|
)
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
|
group_id: Mapped[int] = mapped_column(ForeignKey("groups.id"), nullable=False, comment="所屬群組ID")
|
|
title: Mapped[str] = mapped_column(String(200), nullable=False, comment="報告標題")
|
|
report_date: Mapped[date] = mapped_column(Date, nullable=False, comment="報告日期")
|
|
ai_summary: Mapped[Optional[str]] = mapped_column(Text, comment="AI綜合摘要")
|
|
edited_summary: Mapped[Optional[str]] = mapped_column(Text, comment="編輯後摘要")
|
|
status: Mapped[ReportStatus] = mapped_column(SQLEnum(ReportStatus), default=ReportStatus.DRAFT, comment="狀態")
|
|
published_at: Mapped[Optional[datetime]] = mapped_column(comment="發布時間")
|
|
published_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)
|
|
|
|
# 關聯
|
|
group: Mapped["Group"] = relationship(back_populates="reports")
|
|
report_articles: Mapped[List["ReportArticle"]] = relationship(back_populates="report", cascade="all, delete-orphan")
|
|
favorites: Mapped[List["Favorite"]] = relationship(back_populates="report", cascade="all, delete-orphan")
|
|
comments: Mapped[List["Comment"]] = relationship(back_populates="report", cascade="all, delete-orphan")
|
|
notes: Mapped[List["Note"]] = relationship(back_populates="report", cascade="all, delete-orphan")
|
|
notifications: Mapped[List["NotificationLog"]] = relationship(back_populates="report")
|
|
|
|
@property
|
|
def final_summary(self) -> str:
|
|
"""取得最終摘要(優先使用編輯後版本)"""
|
|
return self.edited_summary or self.ai_summary or ""
|
|
|
|
|
|
class ReportArticle(Base):
|
|
"""報告-新聞關聯表"""
|
|
__tablename__ = "report_articles"
|
|
__table_args__ = (
|
|
UniqueConstraint("report_id", "article_id", name="uk_report_article"),
|
|
)
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
|
report_id: Mapped[int] = mapped_column(ForeignKey("reports.id", ondelete="CASCADE"), nullable=False)
|
|
article_id: Mapped[int] = mapped_column(ForeignKey("news_articles.id"), nullable=False)
|
|
is_included: Mapped[bool] = mapped_column(Boolean, default=True, comment="是否納入報告")
|
|
display_order: Mapped[int] = mapped_column(default=0, comment="顯示順序")
|
|
created_at: Mapped[datetime] = mapped_column(default=datetime.utcnow)
|
|
|
|
# 關聯
|
|
report: Mapped["Report"] = relationship(back_populates="report_articles")
|
|
article: Mapped["NewsArticle"] = relationship(back_populates="report_articles")
|
|
|
|
|
|
# 避免循環引入
|
|
from app.models.group import Group
|
|
from app.models.news import NewsArticle
|
|
from app.models.interaction import Favorite, Comment, Note
|
|
from app.models.system import NotificationLog
|