feat: M4 文风 + M5 生成/多provider/Skill + Kimi Code 订阅接入 + 本地联调修复

M4(文风): style-auditor 双轨(提取指纹/漂移第四审)+ jobs 长任务框架(zombie reaper) + 回炉 refine + GET /style read-back。
M5(生成+扩展): worldbuilder/character-gen(入库 continuity 409 gate + partition_writes 白名单 + schema→JSONB 形变);
  网关多 provider 回退链/熔断/能力降级(Anthropic/Gemini 适配器);Skill registry + 表权限沙箱 + 规则;
  前端 角色生成器/世界观/Codex/规则页/技能库/⌘K 命令面板。
K1(Kimi Code 订阅接入): OAuth device-flow(kimi-code)+ 静态 Console key(kimi-code-key)两路径;
  coding 端点 KimiCLI 伪造头(实测 UA allow-list 门禁,缺则 403)+ JSON 模式结构化(thinking ⊥ tool_choice)。
本地联调修复: CORS 中间件;assemble 注入 premise+「写第N章」指令(修空 prompt 400);
  GET /outline·/draft read-back + 大纲/工作台/审稿页重载;写页 client/server 常量边界 + notFound 健壮化;
  字数 toLocaleString locale 水合;审稿页终稿从已存草稿 seed(修 accept 422)。
门禁: backend ruff/mypy(157)/alembic 无漂移/pytest 451 · frontend lint/tsc/vitest/build。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Yaojia Wang
2026-06-20 10:39:58 +02:00
parent 5fb7bfb1de
commit 765dbdfbd4
161 changed files with 17330 additions and 208 deletions

View File

@@ -147,3 +147,154 @@ class PaceReview(BaseModel):
default_factory=list,
description="逐段爽点节拍强度序列(整数,供前端节拍图可视化)",
)
# ---- 文风提取轨结构化输出ARCH §5.4 style-auditor「提取」轨 / §6.9----
class StyleDimension(BaseModel):
"""单维文风指纹:维度名 + 取值 + 原文证据引用ARCH §6.9)。
每维必须带原文证据quotes便于作者核验「这条文风结论来自哪句」。
"""
name: str = Field(description="文风维度名(如句长节奏 / 叙事人称 / 用词风格)")
value: str = Field(description="该维度在样本中的取值/概括")
evidence: list[str] = Field(
default_factory=list,
description="原文证据:支撑该维度判定的样本原句摘录",
)
class StyleFingerprintResult(BaseModel):
"""文风指纹提取产出16 维文风指纹清单ARCH §5.4 提取轨)。
声明式 writes不变量 #3本结构是从样本提取的纯产物落 `style_fingerprint` 表
经端点T4.3),不在 agent 节点直接写库。16 维 = 9 通用 + 7 中文网文专有。
"""
dimensions: list[StyleDimension] = Field(
default_factory=list,
description="文风维度清单(每维带原文证据);无则空列表",
)
# ---- 文风漂移轨结构化输出ARCH §5.4 style-auditor「打分」轨 = 第四审)----
class StyleDriftSegment(BaseModel):
"""单个漂移段:段索引 + 相似度分 + 可选标签ARCH §5.4 打分轨)。
`idx` 是本章段索引0 起),`score` 是该段相对文风指纹的相似度0100越低越偏
`label` 可缺(如「机翻腔」「叙述拖沓」等漂移类型说明)。
"""
idx: int = Field(description="本章段索引0 起)")
score: int = Field(description="该段相对文风指纹的相似度0100越低越偏离")
label: str | None = Field(default=None, description="漂移类型标签(如「机翻腔」);可缺")
class StyleDriftReview(BaseModel):
"""文风漂移续审结构化产出:整体相似度 + 低相似段ARCH §5.4 / 第四审)。
只读(不变量 #3。`score` 是整章相对文风指纹的整体相似度0100
**无指纹优雅降级**:材料中无文风指纹时返回 `score=100, segments=[]`(默认值),
不报错、不阻塞其余审§5.2 失败隔离之外的内容性兜底)。
"""
score: int = Field(default=100, description="整章相对文风指纹的整体相似度0100")
segments: list[StyleDriftSegment] = Field(
default_factory=list,
description="低相似度(疑似漂移)段清单;无则空列表(含无指纹降级)",
)
# ---- worldbuilder 结构化输出ARCH §5.4 worldbuilder 行 / §6.5 / §4.5----
class WorldEntityCard(BaseModel):
"""单个世界观实体ARCH §5.4`{type,name,rules}` 硬规则显式)。
`type`(势力/地理/力量体系/物品…)+ `name` + `rules`**显式硬规则**清单:
不可违背的设定,供后续 continuity 续审引用比对)。映射 `world_entities` 表
type/name 列 + rules 入 JSONB落库经入库端点T5.2,不变量 #3
"""
type: str = Field(description="实体类型(势力 / 地理 / 力量体系 / 物品 / 概念 等)")
name: str = Field(description="实体名")
rules: list[str] = Field(
default_factory=list,
description="该实体的硬规则清单(显式不可违背设定,供 continuity 校验引用)",
)
class WorldGenResult(BaseModel):
"""worldbuilder 结构化产出世界观实体清单ARCH §5.4 writes=world_entities
声明式 writes不变量 #3本结构是 worldbuilder 的纯产物,落 `world_entities` 表
经入库端点T5.2),不在 agent 节点直接写库。
"""
entities: list[WorldEntityCard] = Field(
default_factory=list,
description="生成的世界观实体清单;无则空列表",
)
# ---- character-gen 结构化输出ARCH §5.4 character-gen 行 / §6.5 / §4.5----
class CharacterRelation(BaseModel):
"""单条人物关系(写入 `characters.relations` JSONB 冗余)。
`name`(关系对象角色名)+ `kind`(宿敌 / 师徒 / CP / 同盟 …)+ 可选 `note`。
双向边由编排器在入库时统一维护§4.5 三关键能力之三),本 schema 仅声明本侧。
"""
name: str = Field(description="关系对象的角色名")
kind: str = Field(description="关系类型(宿敌 / 师徒 / CP / 同盟 / 工具人 等)")
note: str | None = Field(default=None, description="关系说明(可缺)")
class CharacterCard(BaseModel):
"""单张结构化角色卡ARCH §5.4 character-gen 行name/role/traits/backstory/arc/...)。
映射 `characters` 表列name/role/backstory + traits/arc/speech_tics/tags/relations
入 JSONB落库经入库端点T5.2,不变量 #3。`role` = 角色定位(主角/CP/对手/导师/
工具人§4.5 网文专属)。
"""
name: str = Field(description="角色名(取名风格契合世界观)")
role: str = Field(description="角色定位(主角 / CP / 对手 / 导师 / 工具人 等)")
traits: list[str] = Field(
default_factory=list,
description="性格特质清单(核心-表层-阴影 / 动机 / 欲望 / 恐惧)",
)
backstory: str = Field(description="背景故事(出身、关键经历、创伤/转折点)")
arc: str = Field(description="人物弧光(起点 → 转变 → 终点,与剧情挂钩)")
speech_tics: list[str] = Field(
default_factory=list,
description="口癖/语言风格(用词偏好、口头禅,喂给文风一致性)",
)
tags: list[str] = Field(
default_factory=list,
description="人设标签/萌点(网文专属,辅助检索与差异化)",
)
relations: list[CharacterRelation] = Field(
default_factory=list,
description="关系网:与已有/同批角色建边;无则空列表",
)
class CharacterGenResult(BaseModel):
"""character-gen 结构化产出一组角色卡ARCH §5.4 writes=characters / §4.5 群像)。
声明式 writes不变量 #3本结构是 character-gen 的纯产物,落 `characters` 表
经入库端点T5.2),且**入库前过编排器 continuity 校验**§6.5)。单生成 → 1 张卡;
批量群像 → 多张(防雷同:生成时注入「已生成卡 + 已有角色」要求差异化)。
"""
cards: list[CharacterCard] = Field(
default_factory=list,
description="生成的角色卡清单;无则空列表",
)