feat(character): appearance/motive 全栈穿线 + motive/traits 口径重切

打通 appearance/motive 从生成→schema→契约→落库→前端整条穿线
(DB 列早在初始迁移、此前一直 NULL,无新迁移),并原子重切人物
内驱口径。

- @llm: CharacterCard/character-gen.md 加 appearance/motive(给默认值守
  解析韧性),重切——动机唯一落 motive、traits 只留核心/表层/阴影三层、
  arc 引用 motive;regen prompt_hashes.json 金标准。
- @backend: CharacterCardView + CharacterWriteRepo/SqlCharacterWriteRepo
  (create + update backfill 分支)+ CharacterWriteFields + 路由双向形变
  与 _existing_characters 带上两字段。
- @frontend: pnpm gen:api 重生成 TS 客户端;CharacterCardItem 展示/编辑
  两字段。
- 测试: schema 默认值/解析、动机不双写重切回归、card_to_view 双向、
  ingest 透传、list 暴露、SqlCharacterWriteRepo create/backfill 真 pg 集成。
This commit is contained in:
Yaojia Wang
2026-07-06 14:36:11 +02:00
parent 6854dac98f
commit acde715515
13 changed files with 297 additions and 15 deletions

View File

@@ -285,10 +285,18 @@ class CharacterCard(BaseModel):
role: str = Field(description="角色定位(主角 / CP / 对手 / 导师 / 工具人 等)")
traits: list[str] = Field(
default_factory=list,
description="性格特质清单(核心-表层-阴影 / 动机 / 欲望 / 恐惧",
description="性格特质清单(核心-表层-阴影三层;动机/欲望/恐惧落 motive",
)
appearance: str = Field(
default="",
description="外貌形象(身形/五官/气质/标志性外观/常着装扮);缺则空串(守解析韧性)",
)
motive: str = Field(
default="",
description="核心动机/欲望/恐惧驱动行动的唯一内驱arc 由此推动);缺则空串",
)
backstory: str = Field(description="背景故事(出身、关键经历、创伤/转折点)")
arc: str = Field(description="人物弧光(起点 → 转变 → 终点,与剧情挂钩)")
arc: str = Field(description="人物弧光(起点 → 转变 → 终点,与剧情挂钩,由 motive 推动")
speech_tics: list[str] = Field(
default_factory=list,
description="口癖/语言风格(用词偏好、口头禅,喂给文风一致性)",