2026-01-19 17:24:37 +08:00
|
|
|
"""伏笔管理 Pydantic Schema"""
|
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
from typing import Optional, List
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
from enum import Enum
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ForeshadowStatus(str, Enum):
|
|
|
|
|
"""伏笔状态枚举"""
|
|
|
|
|
PENDING = "pending" # 待埋入
|
|
|
|
|
PLANTED = "planted" # 已埋入
|
|
|
|
|
RESOLVED = "resolved" # 已回收
|
|
|
|
|
PARTIALLY_RESOLVED = "partially_resolved" # 部分回收
|
|
|
|
|
ABANDONED = "abandoned" # 已废弃
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ForeshadowSourceType(str, Enum):
|
|
|
|
|
"""伏笔来源类型"""
|
|
|
|
|
ANALYSIS = "analysis" # 分析提取
|
|
|
|
|
MANUAL = "manual" # 手动添加
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ForeshadowCategory(str, Enum):
|
|
|
|
|
"""伏笔分类"""
|
|
|
|
|
IDENTITY = "identity" # 身世
|
|
|
|
|
MYSTERY = "mystery" # 悬念
|
|
|
|
|
ITEM = "item" # 物品
|
|
|
|
|
RELATIONSHIP = "relationship" # 关系
|
|
|
|
|
EVENT = "event" # 事件
|
|
|
|
|
ABILITY = "ability" # 能力
|
|
|
|
|
PROPHECY = "prophecy" # 预言
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ForeshadowBase(BaseModel):
|
|
|
|
|
"""伏笔基础信息"""
|
|
|
|
|
title: str = Field(..., min_length=1, max_length=200, description="伏笔标题")
|
|
|
|
|
content: str = Field(..., min_length=1, description="伏笔详细内容/描述")
|
|
|
|
|
hint_text: Optional[str] = Field(None, description="埋伏笔时的暗示文本")
|
|
|
|
|
resolution_text: Optional[str] = Field(None, description="回收伏笔时的揭示文本")
|
|
|
|
|
|
|
|
|
|
# 章节关联
|
|
|
|
|
plant_chapter_number: Optional[int] = Field(None, ge=1, description="计划埋入章节号")
|
|
|
|
|
target_resolve_chapter_number: Optional[int] = Field(None, ge=1, description="计划回收章节号")
|
|
|
|
|
|
|
|
|
|
# 状态
|
|
|
|
|
is_long_term: bool = Field(False, description="是否长线伏笔")
|
|
|
|
|
|
|
|
|
|
# 重要性
|
|
|
|
|
importance: float = Field(0.5, ge=0.0, le=1.0, description="重要性评分 0.0-1.0")
|
|
|
|
|
strength: int = Field(5, ge=1, le=10, description="伏笔强度 1-10")
|
|
|
|
|
subtlety: int = Field(5, ge=1, le=10, description="隐藏度 1-10")
|
|
|
|
|
|
|
|
|
|
# 关联信息
|
|
|
|
|
related_characters: Optional[List[str]] = Field(None, description="关联角色名列表")
|
|
|
|
|
tags: Optional[List[str]] = Field(None, description="标签列表")
|
|
|
|
|
category: Optional[str] = Field(None, description="分类")
|
|
|
|
|
|
|
|
|
|
# 备注
|
|
|
|
|
notes: Optional[str] = Field(None, description="创作备注")
|
|
|
|
|
resolution_notes: Optional[str] = Field(None, description="回收方式说明")
|
|
|
|
|
|
|
|
|
|
# AI辅助设置
|
|
|
|
|
auto_remind: bool = Field(True, description="是否自动提醒")
|
|
|
|
|
remind_before_chapters: int = Field(5, ge=1, le=20, description="提前几章提醒")
|
|
|
|
|
include_in_context: bool = Field(True, description="是否包含在生成上下文中")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ForeshadowCreate(ForeshadowBase):
|
|
|
|
|
"""创建伏笔请求"""
|
|
|
|
|
project_id: str = Field(..., description="项目ID")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ForeshadowUpdate(BaseModel):
|
|
|
|
|
"""更新伏笔请求"""
|
|
|
|
|
title: Optional[str] = Field(None, min_length=1, max_length=200)
|
|
|
|
|
content: Optional[str] = Field(None, min_length=1)
|
|
|
|
|
hint_text: Optional[str] = None
|
|
|
|
|
resolution_text: Optional[str] = None
|
|
|
|
|
|
|
|
|
|
plant_chapter_number: Optional[int] = Field(None, ge=1)
|
|
|
|
|
target_resolve_chapter_number: Optional[int] = Field(None, ge=1)
|
|
|
|
|
|
|
|
|
|
status: Optional[ForeshadowStatus] = None
|
|
|
|
|
is_long_term: Optional[bool] = None
|
|
|
|
|
|
|
|
|
|
importance: Optional[float] = Field(None, ge=0.0, le=1.0)
|
|
|
|
|
strength: Optional[int] = Field(None, ge=1, le=10)
|
|
|
|
|
subtlety: Optional[int] = Field(None, ge=1, le=10)
|
|
|
|
|
urgency: Optional[int] = Field(None, ge=0, le=3)
|
|
|
|
|
|
|
|
|
|
related_characters: Optional[List[str]] = None
|
|
|
|
|
related_foreshadow_ids: Optional[List[str]] = None
|
|
|
|
|
tags: Optional[List[str]] = None
|
|
|
|
|
category: Optional[str] = None
|
|
|
|
|
|
|
|
|
|
notes: Optional[str] = None
|
|
|
|
|
resolution_notes: Optional[str] = None
|
|
|
|
|
|
|
|
|
|
auto_remind: Optional[bool] = None
|
|
|
|
|
remind_before_chapters: Optional[int] = Field(None, ge=1, le=20)
|
|
|
|
|
include_in_context: Optional[bool] = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ForeshadowResponse(ForeshadowBase):
|
|
|
|
|
"""伏笔响应"""
|
|
|
|
|
id: str
|
|
|
|
|
project_id: str
|
|
|
|
|
|
|
|
|
|
source_type: Optional[str] = None
|
|
|
|
|
source_memory_id: Optional[str] = None
|
|
|
|
|
source_analysis_id: Optional[str] = None
|
|
|
|
|
|
|
|
|
|
plant_chapter_id: Optional[str] = None
|
|
|
|
|
target_resolve_chapter_id: Optional[str] = None
|
|
|
|
|
actual_resolve_chapter_id: Optional[str] = None
|
|
|
|
|
actual_resolve_chapter_number: Optional[int] = None
|
|
|
|
|
|
|
|
|
|
status: str = "pending"
|
|
|
|
|
urgency: int = 0
|
|
|
|
|
|
|
|
|
|
related_foreshadow_ids: Optional[List[str]] = None
|
|
|
|
|
|
|
|
|
|
created_at: Optional[datetime] = None
|
|
|
|
|
updated_at: Optional[datetime] = None
|
|
|
|
|
planted_at: Optional[datetime] = None
|
|
|
|
|
resolved_at: Optional[datetime] = None
|
|
|
|
|
|
|
|
|
|
class Config:
|
|
|
|
|
from_attributes = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ForeshadowListResponse(BaseModel):
|
|
|
|
|
"""伏笔列表响应"""
|
|
|
|
|
total: int
|
|
|
|
|
items: List[ForeshadowResponse]
|
|
|
|
|
stats: Optional[dict] = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ForeshadowStatsResponse(BaseModel):
|
|
|
|
|
"""伏笔统计响应"""
|
|
|
|
|
total: int
|
|
|
|
|
pending: int
|
|
|
|
|
planted: int
|
|
|
|
|
resolved: int
|
|
|
|
|
partially_resolved: int
|
|
|
|
|
abandoned: int
|
|
|
|
|
long_term_count: int
|
|
|
|
|
overdue_count: int # 超期未回收数量
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PlantForeshadowRequest(BaseModel):
|
|
|
|
|
"""标记伏笔埋入请求"""
|
|
|
|
|
chapter_id: str = Field(..., description="埋入章节ID")
|
|
|
|
|
chapter_number: int = Field(..., ge=1, description="埋入章节号")
|
|
|
|
|
hint_text: Optional[str] = Field(None, description="暗示文本")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ResolveForeshadowRequest(BaseModel):
|
|
|
|
|
"""标记伏笔回收请求"""
|
|
|
|
|
chapter_id: str = Field(..., description="回收章节ID")
|
|
|
|
|
chapter_number: int = Field(..., ge=1, description="回收章节号")
|
|
|
|
|
resolution_text: Optional[str] = Field(None, description="揭示文本")
|
|
|
|
|
is_partial: bool = Field(False, description="是否部分回收")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SyncFromAnalysisRequest(BaseModel):
|
|
|
|
|
"""从分析同步伏笔请求"""
|
|
|
|
|
chapter_ids: Optional[List[str]] = Field(None, description="指定章节ID列表,为空则同步全部")
|
|
|
|
|
overwrite_existing: bool = Field(False, description="是否覆盖已存在的伏笔")
|
|
|
|
|
auto_set_planted: bool = Field(True, description="自动设置为已埋入状态")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SyncFromAnalysisResponse(BaseModel):
|
|
|
|
|
"""从分析同步伏笔响应"""
|
|
|
|
|
synced_count: int
|
|
|
|
|
skipped_count: int
|
2026-02-12 12:39:51 +08:00
|
|
|
resolved_count: int = 0
|
|
|
|
|
new_foreshadows: List[ForeshadowResponse] = []
|
|
|
|
|
skipped_reasons: List[dict] = []
|
2026-01-19 17:24:37 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class ForeshadowContextRequest(BaseModel):
|
|
|
|
|
"""获取章节伏笔上下文请求"""
|
|
|
|
|
chapter_number: int = Field(..., ge=1, description="章节号")
|
|
|
|
|
include_pending: bool = Field(True, description="包含待埋入伏笔")
|
|
|
|
|
include_overdue: bool = Field(True, description="包含超期伏笔")
|
|
|
|
|
lookahead: int = Field(5, ge=1, le=20, description="向前看几章")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ForeshadowContextResponse(BaseModel):
|
|
|
|
|
"""伏笔上下文响应"""
|
|
|
|
|
chapter_number: int
|
|
|
|
|
context_text: str
|
|
|
|
|
pending_plant: List[ForeshadowResponse] # 本章待埋入
|
|
|
|
|
pending_resolve: List[ForeshadowResponse] # 即将需要回收
|
|
|
|
|
overdue: List[ForeshadowResponse] # 超期未回收
|
|
|
|
|
recently_planted: List[ForeshadowResponse] # 最近埋入(可铺垫)
|