feat: add generation trace and partial-ready workflow status
This commit is contained in:
@@ -10,6 +10,7 @@ class StoryGenerationStatus(str, Enum):
|
||||
"""Overall story generation lifecycle."""
|
||||
|
||||
NARRATIVE_READY = "narrative_ready"
|
||||
PARTIAL_READY = "partial_ready"
|
||||
ASSETS_GENERATING = "assets_generating"
|
||||
COMPLETED = "completed"
|
||||
DEGRADED_COMPLETED = "degraded_completed"
|
||||
@@ -30,7 +31,10 @@ class StoryLike(Protocol):
|
||||
|
||||
story_text: str | None
|
||||
pages: list[dict] | None
|
||||
cover_prompt: str | None
|
||||
image_url: str | None
|
||||
generation_status: str
|
||||
text_status: str
|
||||
image_status: str
|
||||
audio_status: str
|
||||
last_error: str | None
|
||||
@@ -55,6 +59,37 @@ def has_narrative_content(story: StoryLike) -> bool:
|
||||
return bool(story.story_text) or bool(story.pages)
|
||||
|
||||
|
||||
def _has_retryable_image(story: StoryLike, image_status: StoryAssetStatus) -> bool:
|
||||
if image_status in {StoryAssetStatus.READY, StoryAssetStatus.GENERATING}:
|
||||
return False
|
||||
|
||||
pages = story.pages or []
|
||||
has_missing_page_image = any(
|
||||
isinstance(page, dict)
|
||||
and page.get("image_prompt")
|
||||
and not page.get("image_url")
|
||||
for page in pages
|
||||
)
|
||||
return bool(story.cover_prompt and not story.image_url) or has_missing_page_image
|
||||
|
||||
|
||||
def _has_pending_assets(
|
||||
story: StoryLike,
|
||||
*,
|
||||
image_status: StoryAssetStatus,
|
||||
audio_status: StoryAssetStatus,
|
||||
) -> bool:
|
||||
"""Whether readable content still has optional assets to complete."""
|
||||
|
||||
if _has_retryable_image(story, image_status):
|
||||
return True
|
||||
|
||||
return bool(story.story_text) and audio_status not in {
|
||||
StoryAssetStatus.READY,
|
||||
StoryAssetStatus.GENERATING,
|
||||
}
|
||||
|
||||
|
||||
def resolve_story_generation_status(story: StoryLike) -> StoryGenerationStatus:
|
||||
"""Derive the overall status from narrative and asset states."""
|
||||
|
||||
@@ -70,6 +105,9 @@ def resolve_story_generation_status(story: StoryLike) -> StoryGenerationStatus:
|
||||
if StoryAssetStatus.FAILED in (image_status, audio_status):
|
||||
return StoryGenerationStatus.DEGRADED_COMPLETED
|
||||
|
||||
if _has_pending_assets(story, image_status=image_status, audio_status=audio_status):
|
||||
return StoryGenerationStatus.PARTIAL_READY
|
||||
|
||||
if (
|
||||
image_status == StoryAssetStatus.NOT_REQUESTED
|
||||
and audio_status == StoryAssetStatus.NOT_REQUESTED
|
||||
@@ -105,6 +143,12 @@ def sync_story_status(
|
||||
if last_error is not _ERROR_UNSET:
|
||||
story.last_error = last_error
|
||||
|
||||
story.text_status = (
|
||||
StoryAssetStatus.READY.value
|
||||
if has_narrative_content(story)
|
||||
else StoryAssetStatus.FAILED.value
|
||||
)
|
||||
|
||||
generation_status = resolve_story_generation_status(story)
|
||||
story.generation_status = generation_status.value
|
||||
|
||||
|
||||
Reference in New Issue
Block a user