Files
SillyTavern_replica/backend/models/fiction_models.py

286 lines
6.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
爽文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