This commit is contained in:
xiamuceer
2025-10-30 11:14:43 +08:00
parent b97410d973
commit 0f6c2d344a
91 changed files with 22309 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
"""Pydantic数据模型"""
+57
View File
@@ -0,0 +1,57 @@
"""章节相关的Pydantic模型"""
from pydantic import BaseModel, Field
from typing import Optional
from datetime import datetime
class ChapterBase(BaseModel):
"""章节基础模型"""
title: str = Field(..., description="章节标题")
chapter_number: int = Field(..., description="章节序号")
content: Optional[str] = Field(None, description="章节内容")
summary: Optional[str] = Field(None, description="章节摘要")
word_count: Optional[int] = Field(0, description="字数")
status: Optional[str] = Field("draft", description="章节状态")
class ChapterCreate(BaseModel):
"""创建章节的请求模型"""
project_id: str = Field(..., description="所属项目ID")
title: str = Field(..., description="章节标题")
chapter_number: int = Field(..., description="章节序号")
content: Optional[str] = Field(None, description="章节内容")
summary: Optional[str] = Field(None, description="章节摘要")
status: Optional[str] = Field("draft", description="章节状态")
class ChapterUpdate(BaseModel):
"""更新章节的请求模型"""
title: Optional[str] = None
content: Optional[str] = None
# chapter_number 不允许修改,只能通过大纲的重排序来调整
summary: Optional[str] = None
# word_count 自动计算,不允许手动修改
status: Optional[str] = None
class ChapterResponse(BaseModel):
"""章节响应模型"""
id: str
project_id: str
title: str
chapter_number: int
content: Optional[str] = None
summary: Optional[str] = None
word_count: int = 0
status: str
created_at: datetime
updated_at: datetime
class Config:
from_attributes = True
class ChapterListResponse(BaseModel):
"""章节列表响应模型"""
total: int
items: list[ChapterResponse]
+67
View File
@@ -0,0 +1,67 @@
"""角色相关的Pydantic模型"""
from pydantic import BaseModel, Field
from typing import Optional, List, Dict, Any
from datetime import datetime
class CharacterBase(BaseModel):
"""角色基础模型"""
name: str = Field(..., description="角色/组织姓名")
age: Optional[str] = Field(None, description="年龄")
gender: Optional[str] = Field(None, description="性别")
is_organization: bool = Field(False, description="是否为组织")
role_type: Optional[str] = Field(None, description="角色类型:protagonist/supporting/antagonist")
personality: Optional[str] = Field(None, description="性格特点/组织特性")
background: Optional[str] = Field(None, description="背景故事")
appearance: Optional[str] = Field(None, description="外貌特征")
relationships: Optional[str] = Field(None, description="人际关系(JSON)")
organization_type: Optional[str] = Field(None, description="组织类型")
organization_purpose: Optional[str] = Field(None, description="组织目的")
organization_members: Optional[str] = Field(None, description="组织成员(JSON)")
traits: Optional[str] = Field(None, description="特征标签(JSON)")
class CharacterUpdate(BaseModel):
"""更新角色的请求模型"""
name: Optional[str] = None
age: Optional[str] = None
gender: Optional[str] = None
is_organization: Optional[bool] = None
role_type: Optional[str] = None
personality: Optional[str] = None
background: Optional[str] = None
appearance: Optional[str] = None
relationships: Optional[str] = None
organization_type: Optional[str] = None
organization_purpose: Optional[str] = None
organization_members: Optional[str] = None
traits: Optional[str] = None
class CharacterResponse(CharacterBase):
"""角色响应模型"""
id: str
project_id: str
avatar_url: Optional[str] = None
created_at: datetime
updated_at: datetime
class Config:
from_attributes = True
class CharacterGenerateRequest(BaseModel):
"""AI生成角色的请求模型"""
project_id: str = Field(..., description="项目ID")
name: Optional[str] = Field(None, description="角色名称")
role_type: Optional[str] = Field(None, description="角色类型")
background: Optional[str] = Field(None, description="角色背景")
requirements: Optional[str] = Field(None, description="特殊要求")
provider: Optional[str] = Field(None, description="AI提供商")
model: Optional[str] = Field(None, description="AI模型")
class CharacterListResponse(BaseModel):
"""角色列表响应模型"""
total: int
items: List[CharacterResponse]
+88
View File
@@ -0,0 +1,88 @@
"""大纲相关的Pydantic模型"""
from pydantic import BaseModel, Field
from typing import Optional
from datetime import datetime
class OutlineBase(BaseModel):
"""大纲基础模型"""
title: str = Field(..., description="章节标题")
content: str = Field(..., description="章节内容概要")
class OutlineCreate(BaseModel):
"""创建大纲的请求模型"""
project_id: str = Field(..., description="所属项目ID")
title: str = Field(..., description="章节标题")
content: str = Field(..., description="章节内容概要")
order_index: int = Field(..., description="章节序号", ge=1)
structure: Optional[str] = Field(None, description="结构化大纲数据(JSON)")
class OutlineUpdate(BaseModel):
"""更新大纲的请求模型"""
title: Optional[str] = None
content: Optional[str] = None
# order_index 不允许通过普通更新修改,只能通过 reorder_outlines 接口批量调整
# structure 暂不支持修改
class OutlineResponse(BaseModel):
"""大纲响应模型"""
id: str
project_id: str
title: str
content: str
structure: Optional[str] = None
order_index: int
created_at: datetime
updated_at: datetime
class Config:
from_attributes = True
class OutlineGenerateRequest(BaseModel):
"""AI生成大纲的请求模型 - 支持全新生成和智能续写"""
project_id: str = Field(..., description="项目ID")
genre: Optional[str] = Field(None, description="小说类型,如:玄幻、都市、悬疑等")
theme: str = Field(..., description="小说主题")
chapter_count: int = Field(..., ge=1, description="章节数量")
narrative_perspective: str = Field(..., description="叙事视角")
world_context: Optional[dict] = Field(None, description="世界观背景")
characters_context: Optional[list] = Field(None, description="角色信息")
target_words: int = Field(100000, description="目标字数")
requirements: Optional[str] = Field(None, description="其他特殊要求")
provider: Optional[str] = Field(None, description="AI提供商")
model: Optional[str] = Field(None, description="AI模型")
# 续写相关参数
mode: str = Field("auto", description="生成模式: auto(自动判断), new(全新生成), continue(续写)")
story_direction: Optional[str] = Field(None, description="故事发展方向提示(续写时使用)")
plot_stage: str = Field("development", description="情节阶段: development(发展), climax(高潮), ending(结局)")
keep_existing: bool = Field(False, description="是否保留现有大纲(续写时)")
class ChapterOutlineGenerateRequest(BaseModel):
"""为单个章节生成大纲的请求模型"""
outline_id: str = Field(..., description="大纲ID")
context: Optional[str] = Field(None, description="额外上下文")
provider: Optional[str] = Field(None, description="AI提供商")
model: Optional[str] = Field(None, description="AI模型")
class OutlineListResponse(BaseModel):
"""大纲列表响应模型"""
total: int
items: list[OutlineResponse]
class OutlineReorderItem(BaseModel):
"""单个大纲重排序项"""
id: str = Field(..., description="大纲ID")
order_index: int = Field(..., description="新的序号", ge=1)
class OutlineReorderRequest(BaseModel):
"""大纲批量重排序请求"""
orders: list[OutlineReorderItem] = Field(..., description="排序列表")
+20
View File
@@ -0,0 +1,20 @@
"""AI去味相关的Pydantic模型"""
from pydantic import BaseModel, Field
from typing import Optional
class PolishRequest(BaseModel):
"""AI去味请求模型"""
original_text: str = Field(..., description="原始文本(AI生成的文本)")
project_id: Optional[int] = Field(None, description="项目ID(可选,用于记录历史)")
provider: Optional[str] = Field(None, description="AI提供商")
model: Optional[str] = Field(None, description="AI模型")
temperature: Optional[float] = Field(0.8, description="温度参数,建议0.7-0.9")
class PolishResponse(BaseModel):
"""AI去味响应模型"""
original_text: str = Field(..., description="原始文本")
polished_text: str = Field(..., description="去味后的文本")
word_count_before: int = Field(..., description="处理前字数")
word_count_after: int = Field(..., description="处理后字数")
+83
View File
@@ -0,0 +1,83 @@
"""项目相关的Pydantic模型"""
from pydantic import BaseModel, Field
from typing import Optional
from datetime import datetime
class ProjectBase(BaseModel):
"""项目基础模型"""
title: str = Field(..., description="项目标题")
description: Optional[str] = Field(None, description="项目描述")
theme: Optional[str] = Field(None, description="主题")
genre: Optional[str] = Field(None, description="小说类型")
target_words: Optional[int] = Field(None, description="目标字数")
class ProjectCreate(ProjectBase):
"""创建项目的请求模型"""
pass
class ProjectUpdate(BaseModel):
"""更新项目的请求模型"""
title: Optional[str] = None
description: Optional[str] = None
theme: Optional[str] = None
genre: Optional[str] = None
target_words: Optional[int] = None
status: Optional[str] = None
# wizard_status 和 wizard_step 只能通过向导API修改,普通更新不允许
world_time_period: Optional[str] = None
world_location: Optional[str] = None
world_atmosphere: Optional[str] = None
world_rules: Optional[str] = None
chapter_count: Optional[int] = None
narrative_perspective: Optional[str] = None
character_count: Optional[int] = None
# current_words 由章节内容自动计算,不允许手动修改
class ProjectResponse(ProjectBase):
"""项目响应模型"""
id: str # UUID字符串
status: str
current_words: int
wizard_status: Optional[str] = None
wizard_step: Optional[int] = None
world_time_period: Optional[str] = None
world_location: Optional[str] = None
world_atmosphere: Optional[str] = None
world_rules: Optional[str] = None
chapter_count: Optional[int] = None
narrative_perspective: Optional[str] = None
character_count: Optional[int] = None
created_at: datetime
updated_at: datetime
class Config:
from_attributes = True
class ProjectListResponse(BaseModel):
"""项目列表响应模型"""
total: int
items: list[ProjectResponse]
class ProjectWizardRequest(BaseModel):
"""项目创建向导请求模型"""
title: str = Field(..., description="书名")
theme: str = Field(..., description="主题")
genre: Optional[str] = Field(None, description="类型")
chapter_count: int = Field(..., ge=1, description="章节数量")
narrative_perspective: str = Field(..., description="叙事视角")
character_count: int = Field(5, ge=5, description="角色数量(至少5个)")
target_words: Optional[int] = Field(None, description="目标字数")
class WorldBuildingResponse(BaseModel):
"""世界构建响应模型"""
time_period: str = Field(..., description="时间背景")
location: str = Field(..., description="地理位置")
atmosphere: str = Field(..., description="氛围基调")
rules: str = Field(..., description="世界规则")
+204
View File
@@ -0,0 +1,204 @@
"""关系管理相关的Pydantic模型"""
from pydantic import BaseModel, Field
from typing import Optional, List
from datetime import datetime
# ============ 关系类型相关 ============
class RelationshipTypeResponse(BaseModel):
"""关系类型响应模型"""
id: int
name: str
category: str
reverse_name: Optional[str] = None
intimacy_range: Optional[str] = None
icon: Optional[str] = None
description: Optional[str] = None
created_at: datetime
class Config:
from_attributes = True
# ============ 角色关系相关 ============
class CharacterRelationshipBase(BaseModel):
"""角色关系基础模型"""
relationship_type_id: Optional[int] = Field(None, description="关系类型ID")
relationship_name: Optional[str] = Field(None, description="自定义关系名称")
intimacy_level: int = Field(50, ge=0, le=100, description="亲密度:0-100")
status: str = Field("active", description="状态:active/broken/past/complicated")
description: Optional[str] = Field(None, description="关系描述")
started_at: Optional[str] = Field(None, description="关系开始时间(故事时间)")
ended_at: Optional[str] = Field(None, description="关系结束时间")
class CharacterRelationshipCreate(CharacterRelationshipBase):
"""创建角色关系的请求模型"""
project_id: str = Field(..., description="项目ID")
character_from_id: str = Field(..., description="角色A的ID")
character_to_id: str = Field(..., description="角色B的ID")
class CharacterRelationshipUpdate(BaseModel):
"""更新角色关系的请求模型"""
relationship_type_id: Optional[int] = None
relationship_name: Optional[str] = None
intimacy_level: Optional[int] = Field(None, ge=0, le=100)
status: Optional[str] = None
description: Optional[str] = None
started_at: Optional[str] = None
ended_at: Optional[str] = None
class CharacterRelationshipResponse(CharacterRelationshipBase):
"""角色关系响应模型"""
id: str
project_id: str
character_from_id: str
character_to_id: str
source: str
created_at: datetime
updated_at: datetime
class Config:
from_attributes = True
class RelationshipGraphNode(BaseModel):
"""关系图谱节点"""
id: str
name: str
type: str # character / organization
role_type: Optional[str] = None
avatar: Optional[str] = None
class RelationshipGraphLink(BaseModel):
"""关系图谱连线"""
source: str
target: str
relationship: str
intimacy: int
status: str
class RelationshipGraphData(BaseModel):
"""关系图谱数据"""
nodes: List[RelationshipGraphNode]
links: List[RelationshipGraphLink]
# ============ 组织相关 ============
class OrganizationBase(BaseModel):
"""组织基础模型"""
parent_org_id: Optional[str] = Field(None, description="父组织ID")
level: int = Field(0, description="组织层级")
power_level: int = Field(50, ge=0, le=100, description="势力等级")
location: Optional[str] = Field(None, description="所在地")
motto: Optional[str] = Field(None, description="组织宗旨")
color: Optional[str] = Field(None, description="代表颜色")
class OrganizationCreate(OrganizationBase):
"""创建组织的请求模型"""
character_id: str = Field(..., description="关联的角色ID(组织记录)")
project_id: str = Field(..., description="项目ID")
class OrganizationUpdate(BaseModel):
"""更新组织的请求模型"""
parent_org_id: Optional[str] = None
level: Optional[int] = None
power_level: Optional[int] = Field(None, ge=0, le=100)
location: Optional[str] = None
motto: Optional[str] = None
color: Optional[str] = None
class OrganizationResponse(OrganizationBase):
"""组织响应模型"""
id: str
character_id: str
project_id: str
member_count: int
created_at: datetime
updated_at: datetime
class Config:
from_attributes = True
class OrganizationDetailResponse(BaseModel):
"""组织详情响应(包含基本信息)"""
id: str
character_id: str
name: str
type: Optional[str] = None
purpose: Optional[str] = None
member_count: int
power_level: int
location: Optional[str] = None
motto: Optional[str] = None
color: Optional[str] = None
# ============ 组织成员相关 ============
class OrganizationMemberBase(BaseModel):
"""组织成员基础模型"""
position: str = Field(..., description="职位名称")
rank: int = Field(0, description="职位等级")
status: str = Field("active", description="状态:active/retired/expelled/deceased")
joined_at: Optional[str] = Field(None, description="加入时间(故事时间)")
left_at: Optional[str] = Field(None, description="离开时间")
loyalty: int = Field(50, ge=0, le=100, description="忠诚度")
contribution: int = Field(0, ge=0, le=100, description="贡献度")
notes: Optional[str] = Field(None, description="备注")
class OrganizationMemberCreate(OrganizationMemberBase):
"""创建组织成员的请求模型"""
character_id: str = Field(..., description="角色ID")
class OrganizationMemberUpdate(BaseModel):
"""更新组织成员的请求模型"""
position: Optional[str] = None
rank: Optional[int] = None
status: Optional[str] = None
joined_at: Optional[str] = None
left_at: Optional[str] = None
loyalty: Optional[int] = Field(None, ge=0, le=100)
contribution: Optional[int] = Field(None, ge=0, le=100)
notes: Optional[str] = None
class OrganizationMemberResponse(OrganizationMemberBase):
"""组织成员响应模型"""
id: str
organization_id: str
character_id: str
source: str
created_at: datetime
updated_at: datetime
class Config:
from_attributes = True
class OrganizationMemberDetailResponse(BaseModel):
"""组织成员详情响应(包含角色信息)"""
id: str
character_id: str
character_name: str
position: str
rank: int
loyalty: int
contribution: int
status: str
joined_at: Optional[str] = None
left_at: Optional[str] = None
notes: Optional[str] = None