"""故事相关 Pydantic 模型。""" 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 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(BaseModel): """Story 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(BaseModel): """Story list item.""" id: int title: str image_url: str | None created_at: datetime mode: str class FullStoryResponse(BaseModel): """完整故事响应(含图片和音频状态)。""" 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 生成请求。""" 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="是否同时生成插图") child_profile_id: str | None = None universe_id: str | None = None class StorybookPageResponse(BaseModel): """故事书单页响应。""" page_number: int text: str image_prompt: str image_url: str | None = None class StorybookResponse(BaseModel): """故事书响应。""" id: int | None = None title: str main_character: str art_style: str pages: list[StorybookPageResponse] cover_prompt: str cover_url: str | None = None # ==================== 成就模型 ==================== class AchievementItem(BaseModel): type: str description: str obtained_at: str | None = None