"""T6 创作工具箱 · 生成器注册表(`TOOLBOX`:把每个生成器声明成一条 `GeneratorTool`)。 「加一个生成器」= 在本表加一份声明(descriptor 在代码、不进 DB——保 Pydantic schema 为真类,避免迁移;DB `skills` 表与只读注册表/权限故事不变)。 两类形态: - **legacy**(已上架的 世界观/人设/大纲):`spec=None`,带 `legacy_route` 指向现有更丰富的 入库/冲突页面,前端据 `legacy_route` 直接跳页,不回归既测代码(通用 generate/ingest 端点对它们返 404/422); - **新工具**(8 个):带 `spec`(§5.1 声明)+ `output_schema`(结构化产物真类)+ `context_strategy`(注入策略)+ `input_fields`(声明式表单),走通用执行器;声明 `ingest` 者可经通用 ingest 端点入库(复用既有 continuity 预检 + 白名单 gate,不变量 #3)。 不变量 #2(只声明 tier,spec 已守)/ #3(AI 产出入库必经验收 gate,预览不写库)。 """ from __future__ import annotations from ww_agents import ( blurb_spec, book_title_spec, brainstorm_spec, continue_spec, de_ai_spec, expand_spec, fine_outline_spec, glossary_spec, golden_finger_spec, name_spec, opening_spec, teardown_spec, ) from ww_agents.schemas import ( BlurbResult, BookTeardownResult, ContinuationResult, DeAiResult, DetailedOutlineResult, GlossaryResult, GoldenFingerResult, IdeaListResult, NameListResult, OpeningResult, PolishResult, TitleListResult, ) from ww_skills.toolbox import GeneratorTool, IngestSpec, InputField # 复用的常见输入字段(DRY:每个生成器都有「一句话需求」textarea)。 _BRIEF_FIELD = InputField( name="brief", label="一句话需求", type="textarea", required=False, help="描述创作方向/约束;留空则按作品设定与题材自由发散", ) def _chapter_no_field() -> InputField: """按章展开的生成器(开篇/细纲)所需的章号输入。""" return InputField( name="chapter_no", label="章号", type="number", required=True, default="1", help="要生成/展开的章节号(读取该章大纲节拍)", ) # 原文输入(扩写/降AI率/拆书样本所需的大段正文)。 _SOURCE_TEXT_FIELD = InputField( name="text", label="原文", type="textarea", required=True, help="待处理的正文/样本片段(扩写/降AI 的原文;拆书的章节样本)", ) # 创作工具箱注册表:key → 描述符。legacy 3 + 新 8 = 11 条。 TOOLBOX: dict[str, GeneratorTool] = { # ---- legacy(spec=None,前端走 legacy_route 跳现有页面)---- "worldbuilding": GeneratorTool( key="worldbuilding", title="世界观生成器", subtitle="构建内部自洽的世界观与硬规则", spec=None, output_schema=None, context_strategy="with_project", input_fields=[], legacy_route="/projects/{id}/codex?gen=world", ), "character": GeneratorTool( key="character", title="人设生成器", subtitle="群像防雷同的结构化角色卡", spec=None, output_schema=None, context_strategy="with_world", input_fields=[], legacy_route="/projects/{id}/codex?gen=character", ), "outline": GeneratorTool( key="outline", title="大纲生成器", subtitle="分卷分章 + 伏笔回收窗口", spec=None, output_schema=None, context_strategy="with_project", input_fields=[], legacy_route="/projects/{id}/outline", ), # ---- 新工具(走通用执行器)---- "brainstorm": GeneratorTool( key="brainstorm", title="脑洞生成器", subtitle="突破想象,脑洞大开", spec=brainstorm_spec, output_schema=IdeaListResult, context_strategy="brief_only", input_fields=[_BRIEF_FIELD], ), "book-title": GeneratorTool( key="book-title", title="书名生成器", subtitle="一秒生成抓人书名", spec=book_title_spec, output_schema=TitleListResult, context_strategy="brief_only", input_fields=[_BRIEF_FIELD], ), "blurb": GeneratorTool( key="blurb", title="简介生成器", subtitle="多版差异化书页文案", spec=blurb_spec, output_schema=BlurbResult, context_strategy="with_project", input_fields=[_BRIEF_FIELD], ), "name": GeneratorTool( key="name", title="名字生成器", subtitle="契合世界观的人/物/地命名", spec=name_spec, output_schema=NameListResult, context_strategy="with_world", input_fields=[ _BRIEF_FIELD, InputField( name="kind", label="命名对象", type="text", required=False, help="人物 / 势力 / 地点 / 功法 / 物品 等", ), ], ), "golden-finger": GeneratorTool( key="golden-finger", title="金手指生成器", subtitle="自洽机制 + 成长 + 限制代价", spec=golden_finger_spec, output_schema=GoldenFingerResult, context_strategy="with_world", input_fields=[_BRIEF_FIELD], ingest=IngestSpec(table="world_entities"), ), "glossary": GeneratorTool( key="glossary", title="词条生成器", subtitle="带硬规则的世界观术语表", spec=glossary_spec, output_schema=GlossaryResult, context_strategy="with_world", input_fields=[_BRIEF_FIELD], ingest=IngestSpec(table="world_entities"), ), "opening": GeneratorTool( key="opening", title="黄金开篇生成器", subtitle="多版高代入感开篇正文", spec=opening_spec, output_schema=OpeningResult, context_strategy="with_outline_chapter", input_fields=[_chapter_no_field(), _BRIEF_FIELD], ), "fine-outline": GeneratorTool( key="fine-outline", title="细纲生成器", subtitle="把章节粗节拍展开为场景序列", spec=fine_outline_spec, output_schema=DetailedOutlineResult, context_strategy="with_outline_chapter", input_fields=[_chapter_no_field(), _BRIEF_FIELD], ingest=IngestSpec(table="outline"), ), # ---- 竞品快赢(Scope B):续写/扩写/降AI率 preview-only;拆书 F1 可落库 rules ---- "continue": GeneratorTool( key="continue", title="续写生成器", subtitle="承接前文,无缝续写下文", spec=continue_spec, output_schema=ContinuationResult, context_strategy="with_prior_chapter", input_fields=[ InputField( name="chapter_no", label="续写章号", type="number", required=False, help="续写的目标章号(读取该章已写正文承接;缺则按设定起笔)", ), _BRIEF_FIELD, ], ), "expand": GeneratorTool( key="expand", title="扩写生成器", subtitle="在原文基础上丰富细节铺陈", spec=expand_spec, output_schema=PolishResult, context_strategy="text_input", input_fields=[_SOURCE_TEXT_FIELD, _BRIEF_FIELD], ), "de-ai": GeneratorTool( key="de-ai", title="降 AI 率生成器", subtitle="去机翻腔,更自然的人写质感", spec=de_ai_spec, output_schema=DeAiResult, context_strategy="text_input", input_fields=[_SOURCE_TEXT_FIELD, _BRIEF_FIELD], ), "teardown": GeneratorTool( key="teardown", title="拆书生成器", subtitle="拆解主题/原型/结构/钩子套路", spec=teardown_spec, output_schema=BookTeardownResult, context_strategy="text_input", input_fields=[ InputField( name="kind", label="书名", type="text", required=False, help="待拆解作品的书名(供拆解对照)", ), _SOURCE_TEXT_FIELD, _BRIEF_FIELD, ], ingest=IngestSpec(table="rules"), # F1:拆书结论拍平为项目 rules 条目落库 ), } def get_tool(key: str) -> GeneratorTool | None: """按 key 取生成器描述符;未知 key → None(端点据此返 404)。""" return TOOLBOX.get(key)