Files
life-echo/api/app/features/memoir/cover_eligibility.py

52 lines
1.7 KiB
Python
Raw Normal View History

2026-03-20 15:15:35 +08:00
"""章节封面是否可入队(与 Celery 任务共享,避免循环 import"""
from __future__ import annotations
from typing import Any
from app.features.memoir.memoir_images.schema import (
IMAGE_STATUS_FAILED,
IMAGE_STATUS_PENDING,
)
def primary_chapter_memoir_image(chapter: Any) -> Any | None:
"""章节级 MemoirImage封面槽位按 order_index 最小取第一条。"""
imgs = sorted(
getattr(chapter, "images", None) or [],
key=lambda m: getattr(m, "order_index", 0),
)
return imgs[0] if imgs else None
def chapter_needs_cover_enqueue(chapter) -> bool:
"""尚无 cover_asset 且章节有正文时,可派发 generate_chapter_cover。"""
if not chapter:
return False
if getattr(chapter, "cover_asset_id", None):
return False
md = (getattr(chapter, "canonical_markdown", None) or "").strip()
return bool(md)
def chapter_has_cover_to_generate(chapter) -> bool:
"""章节是否有待生成的封面图(任一条 chapter 级 MemoirImage 为 pending/failed"""
for m in getattr(chapter, "images", None) or []:
status = (getattr(m, "status") or "").strip()
if status in (IMAGE_STATUS_PENDING, IMAGE_STATUS_FAILED):
return True
return False
def cover_memoir_image_pending_or_failed(chapter: Any) -> Any | None:
"""用于补图任务:按 order_index 找到第一条 pending/failed 的章节配图行。"""
images = sorted(
getattr(chapter, "images", None) or [],
key=lambda m: getattr(m, "order_index", 0),
)
for m in images:
st = (getattr(m, "status") or "").strip()
if st in (IMAGE_STATUS_PENDING, IMAGE_STATUS_FAILED):
return m
return None