配置 SSOT(TOML + .env) 统一错误契约 Auth 与事务边界 Redis / Celery 可靠性:业务 Redis(DB/0)与 Celery broker/backend(DB/1)显式拆分;连接池、sync client 可观测性(OpenTelemetry + LGTM)
130 lines
3.3 KiB
Python
130 lines
3.3 KiB
Python
from pydantic import BaseModel, ConfigDict, Field
|
||
|
||
from app.agents.state_schema import MemoirStateSchema as MemoirStateResponse
|
||
|
||
__all__ = [
|
||
"BookResponse",
|
||
"ChapterDetailResponse",
|
||
"ChapterListItemResponse",
|
||
"CoverGenerationResponse",
|
||
"ExportPdfRequest",
|
||
"ExportPdfResponse",
|
||
"ImageAssetResponse",
|
||
"MemoirStateResponse",
|
||
"NextQuestionContextResponse",
|
||
"ReadingSegmentResponse",
|
||
"SetChapterStoryOrderRequest",
|
||
"StatusMessageResponse",
|
||
"StoryOrderResponse",
|
||
"UpdateBookRequest",
|
||
]
|
||
|
||
|
||
class ImageAssetResponse(BaseModel):
|
||
placeholder: str = ""
|
||
description: str = ""
|
||
index: int = 0
|
||
status: str = "pending"
|
||
prompt: str | None = None
|
||
url: str | None = None
|
||
provider: str | None = None
|
||
style: str | None = None
|
||
size: str | None = None
|
||
error: str | None = None
|
||
retryable: bool | None = None
|
||
created_at: str | None = None
|
||
updated_at: str | None = None
|
||
|
||
|
||
class ReadingSegmentResponse(BaseModel):
|
||
story_id: str
|
||
body_markdown: str = ""
|
||
cover_asset: ImageAssetResponse | None = None
|
||
|
||
|
||
class UpdateBookRequest(BaseModel):
|
||
title: str
|
||
subtitle: str | None = None
|
||
|
||
|
||
class ExportPdfRequest(BaseModel):
|
||
book_id: str
|
||
|
||
|
||
class SetChapterStoryOrderRequest(BaseModel):
|
||
"""按顺序绑定本章节要收录的 stories(覆盖原有 chapter_story_links)。"""
|
||
|
||
story_ids: list[str]
|
||
|
||
|
||
class BookResponse(BaseModel):
|
||
id: str | None = None
|
||
title: str | None = None
|
||
total_pages: int | None = None
|
||
total_words: int | None = None
|
||
cover_image_url: str | None = None
|
||
has_update: bool | None = None
|
||
last_update_chapter_id: str | None = None
|
||
message: str | None = None
|
||
|
||
|
||
class StatusMessageResponse(BaseModel):
|
||
status: str
|
||
message: str | None = None
|
||
|
||
|
||
class ExportPdfResponse(BaseModel):
|
||
pdf_base64: str
|
||
filename: str
|
||
|
||
|
||
class ChapterListItemResponse(BaseModel):
|
||
model_config = ConfigDict(extra="ignore")
|
||
|
||
id: str
|
||
title: str | None = None
|
||
category: str | None = None
|
||
order_index: int | None = None
|
||
status: str = "draft"
|
||
summary: str = ""
|
||
canonical_markdown: str = ""
|
||
cover_asset: ImageAssetResponse | None = None
|
||
images: list[ImageAssetResponse] = Field(default_factory=list)
|
||
word_count: int = 0
|
||
updated_at: str | None = None
|
||
is_new: bool = False
|
||
source_segments: list[str] = Field(default_factory=list)
|
||
|
||
|
||
class ChapterDetailResponse(BaseModel):
|
||
model_config = ConfigDict(extra="ignore")
|
||
|
||
id: str
|
||
title: str | None = None
|
||
canonical_markdown: str = ""
|
||
order_index: int | None = None
|
||
status: str | None = None
|
||
category: str | None = None
|
||
images: list[ImageAssetResponse] = Field(default_factory=list)
|
||
cover_asset: ImageAssetResponse | None = None
|
||
reading_segments: list[ReadingSegmentResponse] = Field(default_factory=list)
|
||
updated_at: str | None = None
|
||
is_new: bool = False
|
||
source_segments: list[str] = Field(default_factory=list)
|
||
|
||
|
||
class CoverGenerationResponse(BaseModel):
|
||
triggered: list[str] = Field(default_factory=list)
|
||
|
||
|
||
class StoryOrderResponse(BaseModel):
|
||
status: str
|
||
chapter_id: str
|
||
story_count: int
|
||
|
||
|
||
class NextQuestionContextResponse(BaseModel):
|
||
current_stage: str | None = None
|
||
empty_slots: list[str] = Field(default_factory=list)
|
||
covered_stages: list[str] = Field(default_factory=list)
|