"""ORM models for generated HTML pages and user favorites. These back the "HTML 页面定时任务" feature: a scheduled task of kind ``html_page`` renders a full HTML document each run. Every rendered page is recorded in :class:`ScheduledHtmlPageRow`; a user may bookmark one into :class:`HtmlPageFavoriteRow`, which also stores a reusable style/layout summary so a later task can be generated "in the style of" the favorite. Both tables are brand new, so ``Base.metadata.create_all`` creates them on the next startup without touching any existing schema. """ from __future__ import annotations from datetime import UTC, datetime from sqlalchemy import String, Text from sqlalchemy.orm import Mapped, mapped_column from deerflow.persistence.base import Base from deerflow.persistence.types import BeijingDateTime, PortableJSON, PortableLongText class ScheduledHtmlPageRow(Base): """One HTML page produced by a single run of an ``html_page`` task.""" __tablename__ = "scheduled_html_pages" id: Mapped[str] = mapped_column(String(64), primary_key=True) task_id: Mapped[str] = mapped_column(String(64), index=True) run_id: Mapped[str] = mapped_column(String(64), index=True) user_id: Mapped[str] = mapped_column(String(64), index=True) title: Mapped[str] = mapped_column(String(255)) # Full HTML document — can be large, so LONGTEXT on MySQL. html_content: Mapped[str] = mapped_column(PortableLongText()) html_file_path: Mapped[str | None] = mapped_column(Text) data_snapshot_json: Mapped[dict | None] = mapped_column(PortableJSON(), default=dict) prompt_snapshot_json: Mapped[dict | None] = mapped_column(PortableJSON(), default=dict) reference_favorite_id: Mapped[str | None] = mapped_column(String(64), index=True) style_summary: Mapped[str | None] = mapped_column(Text) layout_summary: Mapped[str | None] = mapped_column(Text) created_at: Mapped[datetime] = mapped_column(BeijingDateTime(), default=lambda: datetime.now(UTC)) updated_at: Mapped[datetime] = mapped_column(BeijingDateTime(), default=lambda: datetime.now(UTC), onupdate=lambda: datetime.now(UTC)) class HtmlPageFavoriteRow(Base): """A user-bookmarked HTML page, with a reusable style/layout summary.""" __tablename__ = "html_page_favorites" id: Mapped[str] = mapped_column(String(64), primary_key=True) user_id: Mapped[str] = mapped_column(String(64), index=True) page_id: Mapped[str] = mapped_column(String(64), index=True) title: Mapped[str] = mapped_column(String(255)) description: Mapped[str | None] = mapped_column(Text) tags_json: Mapped[list | None] = mapped_column(PortableJSON(), default=list) # Snapshot of the page HTML at favorite time, decoupled from the source run # so deleting the run never breaks the favorite reference. html_snapshot: Mapped[str] = mapped_column(PortableLongText()) style_summary: Mapped[str | None] = mapped_column(Text) layout_summary: Mapped[str | None] = mapped_column(Text) content_structure_summary: Mapped[str | None] = mapped_column(Text) reuse_prompt: Mapped[str | None] = mapped_column(Text) created_at: Mapped[datetime] = mapped_column(BeijingDateTime(), default=lambda: datetime.now(UTC)) updated_at: Mapped[datetime] = mapped_column(BeijingDateTime(), default=lambda: datetime.now(UTC), onupdate=lambda: datetime.now(UTC))