Files
life-echo/api/app/features/memoir/repo.py
2026-03-19 14:36:40 +08:00

94 lines
3.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Memoir repository — Book, Chapter, MemoirState data access."""
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Session, joinedload
from app.features.memoir.models import Book, Chapter, ChapterSection, MemoirState
async def get_current_book(user_id: str, db: AsyncSession) -> Book | None:
stmt = (
select(Book)
.where(Book.user_id == user_id)
.order_by(Book.updated_at.desc())
.limit(1)
)
result = await db.execute(stmt)
return result.scalar_one_or_none()
async def get_chapters_with_sections(
user_id: str,
db: AsyncSession,
*,
active_only: bool = True,
is_new_only: bool | None = None,
) -> list[Chapter]:
stmt = (
select(Chapter)
.where(Chapter.user_id == user_id)
.options(
joinedload(Chapter.sections),
joinedload(Chapter.images),
joinedload(Chapter.sections).joinedload(ChapterSection.image_record),
)
.order_by(Chapter.order_index)
)
if active_only:
stmt = stmt.where(Chapter.is_active == True) # noqa: E712
if is_new_only is True:
stmt = stmt.where(Chapter.is_new == True) # noqa: E712
result = await db.execute(stmt)
return list(result.unique().scalars().all())
async def get_chapter_by_id(chapter_id: str, db: AsyncSession) -> Chapter | None:
stmt = (
select(Chapter)
.where(Chapter.id == chapter_id)
.options(
joinedload(Chapter.sections),
joinedload(Chapter.images),
joinedload(Chapter.sections).joinedload(ChapterSection.image_record),
)
)
result = await db.execute(stmt)
return result.unique().scalars().one_or_none()
async def get_memoir_state(user_id: str, db: AsyncSession) -> MemoirState | None:
stmt = select(MemoirState).where(MemoirState.user_id == user_id)
result = await db.execute(stmt)
return result.scalar_one_or_none()
def get_archived_chapter_summaries_sync(
session: Session, user_id: str, category: str
) -> list[tuple[str, str]]:
"""获取已删除is_active=False的同类别章节的标题与内容摘要供 AI 参考。"""
stmt = (
select(Chapter)
.where(
Chapter.user_id == user_id,
Chapter.category == category,
Chapter.is_active == False, # noqa: E712
)
.options(joinedload(Chapter.sections))
.order_by(Chapter.updated_at.desc())
)
result = session.execute(stmt)
chapters = list(result.unique().scalars().all())
summaries: list[tuple[str, str]] = []
for ch in chapters:
sections = getattr(ch, "sections", None) or []
parts = [
(s.content or "").strip()
for s in sorted(sections, key=lambda x: getattr(x, "order_index", 0))
]
combined = "".join(parts)
preview = (combined[:200] + "...") if len(combined) > 200 else combined
if preview.strip():
summaries.append((ch.title or "", preview))
return summaries