feat: add NovelPage component with bookshelf, open book, and reading views
This commit is contained in:
285
backend/models/fiction_models.py
Normal file
285
backend/models/fiction_models.py
Normal file
@@ -0,0 +1,285 @@
|
||||
"""
|
||||
爽文(Fiction / Novel)数据模型。
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class EmotionFlowStep(BaseModel):
|
||||
key: str
|
||||
text: str
|
||||
|
||||
|
||||
class EmotionFlow(BaseModel):
|
||||
id: str
|
||||
intro: str
|
||||
tags: List[str] = Field(default_factory=list)
|
||||
steps: List[EmotionFlowStep] = Field(default_factory=list)
|
||||
|
||||
|
||||
class EmotionFlowCatalog(BaseModel):
|
||||
flows: List[EmotionFlow] = Field(default_factory=list)
|
||||
|
||||
|
||||
class GuideGlobalEntry(BaseModel):
|
||||
layer: str
|
||||
title: str
|
||||
content: str
|
||||
|
||||
|
||||
class GuideGlobalEntries(BaseModel):
|
||||
entries: List[GuideGlobalEntry] = Field(default_factory=list)
|
||||
|
||||
|
||||
class FictionGuideWorldbook(BaseModel):
|
||||
"""Book-local guide 世界书:本书具体人设 / 爽点 / 用户体验 / 禁区。"""
|
||||
|
||||
persona: str = ""
|
||||
highlight: str = ""
|
||||
experience: str = ""
|
||||
forbiddenZones: str = ""
|
||||
|
||||
|
||||
class FictionBookMeta(BaseModel):
|
||||
id: str
|
||||
title: str
|
||||
allowedFlowIds: List[str] = Field(default_factory=list)
|
||||
createdAt: str = ""
|
||||
updatedAt: str = ""
|
||||
|
||||
|
||||
class FictionBookSummary(BaseModel):
|
||||
id: str
|
||||
title: str
|
||||
allowedFlowIds: List[str] = Field(default_factory=list)
|
||||
updatedAt: str = ""
|
||||
|
||||
|
||||
class FictionPrompts(BaseModel):
|
||||
openBook: str = ""
|
||||
coarseOutline: str = ""
|
||||
eventPlan: str = ""
|
||||
chapter: str = ""
|
||||
nudge: str = ""
|
||||
|
||||
|
||||
class FictionReaderSettings(BaseModel):
|
||||
contextWindowChars: int = 2000
|
||||
prefetchRemainingWords: int = 300
|
||||
|
||||
|
||||
class FictionPipelineSettings(BaseModel):
|
||||
"""半自动流水线:各层 ON=自动,OFF=需手动触发。"""
|
||||
|
||||
semiAuto: bool = False
|
||||
autoCoarse: bool = True
|
||||
autoEventPlan: bool = True
|
||||
autoChapter: bool = True
|
||||
|
||||
|
||||
class FictionBookSettings(BaseModel):
|
||||
prompts: FictionPrompts = Field(default_factory=FictionPrompts)
|
||||
reader: FictionReaderSettings = Field(default_factory=FictionReaderSettings)
|
||||
pipeline: FictionPipelineSettings = Field(default_factory=FictionPipelineSettings)
|
||||
|
||||
|
||||
class CreateFictionBookRequest(BaseModel):
|
||||
title: str
|
||||
inspiration: str = ""
|
||||
guide: FictionGuideWorldbook
|
||||
allowedFlowIds: List[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
class OpenBookRequest(BaseModel):
|
||||
inspiration: str
|
||||
profile_id: Optional[str] = None
|
||||
api_config: Optional[Dict[str, str]] = None
|
||||
|
||||
|
||||
class OpenBookResult(BaseModel):
|
||||
title: str
|
||||
optimizedIntro: str
|
||||
guide: FictionGuideWorldbook
|
||||
allowedFlowIds: List[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
class UpdateFictionBookSettingsRequest(BaseModel):
|
||||
prompts: Optional[FictionPrompts] = None
|
||||
reader: Optional[FictionReaderSettings] = None
|
||||
pipeline: Optional[FictionPipelineSettings] = None
|
||||
|
||||
|
||||
class FictionPipelineTickResult(BaseModel):
|
||||
run: FictionRunState
|
||||
started: bool = False
|
||||
pendingStages: List[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
class VolumeOutline(BaseModel):
|
||||
"""卷纲:当前 10~30 章的阶段规划,不是整本书全局大纲。"""
|
||||
|
||||
id: str
|
||||
order: int = 1
|
||||
title: str = ""
|
||||
goal: str = ""
|
||||
coreConflict: str = ""
|
||||
powerProgression: str = ""
|
||||
emotionalPromise: str = ""
|
||||
endingHook: str = ""
|
||||
targetChapterCount: int = 20
|
||||
primaryEmotionFlowId: str = ""
|
||||
status: str = "active"
|
||||
|
||||
|
||||
class CoarseOutlineEvent(BaseModel):
|
||||
"""兼容旧 coarseOutline.events,同时作为新版事件串条目的轻量视图。"""
|
||||
|
||||
id: str
|
||||
title: str
|
||||
summary: str = ""
|
||||
order: int = 1
|
||||
volumeId: str = ""
|
||||
|
||||
|
||||
class CoarseOutline(BaseModel):
|
||||
events: List[CoarseOutlineEvent] = Field(default_factory=list)
|
||||
version: int = 1
|
||||
|
||||
|
||||
class EventChainItem(BaseModel):
|
||||
"""事件串:卷纲 + 情感链在剧情层的落地。"""
|
||||
|
||||
id: str
|
||||
volumeId: str = ""
|
||||
order: int = 1
|
||||
title: str = ""
|
||||
summary: str = ""
|
||||
purpose: str = ""
|
||||
conflict: str = ""
|
||||
turningPoint: str = ""
|
||||
expectedPayoff: str = ""
|
||||
targetChapterCount: int = 3
|
||||
emotionFlowId: str = ""
|
||||
emotionStepKey: str = ""
|
||||
emotionStepText: str = ""
|
||||
status: str = "planned"
|
||||
|
||||
|
||||
class FlowStepsPlan(BaseModel):
|
||||
起: str = ""
|
||||
承: str = ""
|
||||
转: str = ""
|
||||
合: str = ""
|
||||
|
||||
|
||||
class ChapterPlanItem(BaseModel):
|
||||
seq: int
|
||||
|
||||
# 旧字段:保留以兼容现有 metadata.events[eventId].chapterPlan。
|
||||
phaseKey: str = ""
|
||||
phaseSlice: str = ""
|
||||
brief: str = ""
|
||||
|
||||
# 新字段:章纲是写章前最具体的规划层。
|
||||
eventId: str = ""
|
||||
title: str = ""
|
||||
goal: str = ""
|
||||
opening: str = ""
|
||||
mainConflict: str = ""
|
||||
emotionalTurn: str = ""
|
||||
emotionStepKey: str = ""
|
||||
emotionGoal: str = ""
|
||||
payoff: str = ""
|
||||
endingHook: str = ""
|
||||
forbidden: str = ""
|
||||
targetWords: int = 2000
|
||||
|
||||
status: str = "planned"
|
||||
|
||||
|
||||
class EventPlanEntry(BaseModel):
|
||||
emotionFlowId: str = ""
|
||||
flowStepsPlan: FlowStepsPlan = Field(default_factory=FlowStepsPlan)
|
||||
chapterPlan: List[ChapterPlanItem] = Field(default_factory=list)
|
||||
|
||||
|
||||
class FictionProgress(BaseModel):
|
||||
currentChapterSeq: int = 0
|
||||
charOffset: int = 0
|
||||
ttsPaused: bool = False
|
||||
genPaused: bool = False
|
||||
|
||||
|
||||
class FictionChapter(BaseModel):
|
||||
seq: int
|
||||
title: str = ""
|
||||
body: str = ""
|
||||
charCount: int = 0
|
||||
status: str = "written"
|
||||
eventId: str = ""
|
||||
phaseKey: str = ""
|
||||
createdAt: str = ""
|
||||
|
||||
|
||||
class FictionChapterSummary(BaseModel):
|
||||
seq: int
|
||||
title: str = ""
|
||||
charCount: int = 0
|
||||
eventId: str = ""
|
||||
phaseKey: str = ""
|
||||
|
||||
|
||||
class FictionBookMetadata(BaseModel):
|
||||
# v2 新规划结构:不再保留旧 coarseOutline/events 作为持久化主结构。
|
||||
version: int = 2
|
||||
volumes: List[VolumeOutline] = Field(default_factory=list)
|
||||
eventChains: Dict[str, List[EventChainItem]] = Field(default_factory=dict)
|
||||
chapterPlans: Dict[str, List[ChapterPlanItem]] = Field(default_factory=dict)
|
||||
progress: FictionProgress = Field(default_factory=FictionProgress)
|
||||
|
||||
|
||||
class FictionRunState(BaseModel):
|
||||
status: str = "idle"
|
||||
pipelineStage: Optional[str] = None
|
||||
stage: str = "idle"
|
||||
message: Optional[str] = None
|
||||
progress: Optional[Dict[str, int]] = None
|
||||
updatedAt: str = ""
|
||||
|
||||
|
||||
class FictionStartReadingResult(BaseModel):
|
||||
run: FictionRunState
|
||||
started: bool = False
|
||||
|
||||
|
||||
class FictionGenerationRequest(BaseModel):
|
||||
profile_id: Optional[str] = None
|
||||
api_config: Optional[Dict[str, str]] = None
|
||||
event_id: Optional[str] = None
|
||||
seq: Optional[int] = None
|
||||
stream: bool = False
|
||||
|
||||
|
||||
class UpdateFictionProgressRequest(BaseModel):
|
||||
currentChapterSeq: Optional[int] = None
|
||||
charOffset: Optional[int] = None
|
||||
ttsPaused: Optional[bool] = None
|
||||
genPaused: Optional[bool] = None
|
||||
|
||||
|
||||
class FictionPrefetchRequest(BaseModel):
|
||||
profile_id: Optional[str] = None
|
||||
api_config: Optional[Dict[str, str]] = None
|
||||
currentChapterSeq: int
|
||||
charOffset: int = 0
|
||||
remainingWords: Optional[int] = None
|
||||
|
||||
|
||||
class FictionPrefetchResult(BaseModel):
|
||||
run: FictionRunState
|
||||
started: bool = False
|
||||
targetSeq: Optional[int] = None
|
||||
skippedReason: Optional[str] = None
|
||||
Reference in New Issue
Block a user