Files
dreamweaver/backend/app/schemas/story_schemas.py
torin a97a2fe005
Some checks failed
Build and Push Docker Images / changes (push) Has been cancelled
Build and Push Docker Images / build-backend (push) Has been cancelled
Build and Push Docker Images / build-frontend (push) Has been cancelled
Build and Push Docker Images / build-admin-frontend (push) Has been cancelled
feat: persist story generation states and cache audio
2026-04-17 17:14:09 +08:00

129 lines
3.0 KiB
Python

"""Story-related Pydantic schemas."""
from datetime import datetime
from typing import Literal
from pydantic import BaseModel, Field
MAX_DATA_LENGTH = 2000
MAX_EDU_THEME_LENGTH = 200
MAX_TTS_LENGTH = 4000
class StoryStatusMixin(BaseModel):
"""Shared generation status fields returned by story APIs."""
generation_status: str
image_status: str
audio_status: str
last_error: str | None = None
class GenerateRequest(BaseModel):
"""Story generation request."""
type: Literal["keywords", "full_story"]
data: str = Field(..., min_length=1, max_length=MAX_DATA_LENGTH)
education_theme: str | None = Field(default=None, max_length=MAX_EDU_THEME_LENGTH)
child_profile_id: str | None = None
universe_id: str | None = None
class StoryResponse(StoryStatusMixin):
"""Story generation response."""
id: int
title: str
story_text: str
cover_prompt: str | None
image_url: str | None
mode: str
child_profile_id: str | None = None
universe_id: str | None = None
class StoryListItem(StoryStatusMixin):
"""Story list item."""
id: int
title: str
image_url: str | None
created_at: datetime
mode: str
class FullStoryResponse(StoryStatusMixin):
"""Full story response with asset status."""
id: int
title: str
story_text: str
cover_prompt: str | None
image_url: str | None
audio_ready: bool
mode: str
errors: dict[str, str | None] = Field(default_factory=dict)
child_profile_id: str | None = None
universe_id: str | None = None
class StorybookRequest(BaseModel):
"""Storybook generation request."""
keywords: str = Field(..., min_length=1, max_length=200)
page_count: int = Field(default=6, ge=4, le=12)
education_theme: str | None = Field(default=None, max_length=MAX_EDU_THEME_LENGTH)
generate_images: bool = Field(default=False, description="Whether to generate images too.")
child_profile_id: str | None = None
universe_id: str | None = None
class StorybookPageResponse(BaseModel):
"""One storybook page."""
page_number: int
text: str
image_prompt: str
image_url: str | None = None
class StorybookResponse(StoryStatusMixin):
"""Storybook generation response."""
id: int | None = None
title: str
main_character: str
art_style: str
pages: list[StorybookPageResponse]
cover_prompt: str
cover_url: str | None = None
class StoryDetailResponse(StoryStatusMixin):
"""Story detail response for both stories and storybooks."""
id: int
title: str
story_text: str | None = None
pages: list[StorybookPageResponse] | None = None
cover_prompt: str | None
image_url: str | None
mode: str
child_profile_id: str | None = None
universe_id: str | None = None
class StoryImageResponse(StoryStatusMixin):
"""Cover image generation response."""
image_url: str | None
class AchievementItem(BaseModel):
"""Achievement item returned for a story."""
type: str
description: str
obtained_at: str | None = None