# 笔临 P4.1 自动写作 + 向导式写作设计规格 **版本**:1.0 **日期**:2026-07-09 **范围**:P4.1 — 实装 §6.5.2 自动写作 + §6.5.3 向导式写作(统一写作流引擎) **前置**:P4 交互式写作已交付(v0.4.0,`a8e0ba9`) **参考**:`design/readme.md` v1.1 §6.5.2–§6.5.3、`design/ui_pc.html` AI 面板模式 Tab **目标版本**:v0.5.0 --- ## 1. 背景与目标 ### 1.1 阶段定位 v0.4.0 已交付交互式写作(§6.5.1);「自动写作」「向导」Tab 仍为 `feature.comingSoon` 占位。本阶段在同一 AI 会话体系下实装: - **自动写作**:用户设定章节目标与字数范围 → AI 规划场景顺序 → 连续流式生成 → 达标或手动停止 → 成章落盘 - **向导式写作**:5 步引导收集参数 → AI 策略预览 → 自动生成 → **handoff 至交互面板**做场景微调 两模式共享 P4 的场景存储、命名暂停、流式推送与成章逻辑,并通过 **handoff** 与交互写作衔接。 ### 1.2 已确认决策(Brainstorming 2026-07-09) | 维度 | 决策 | |------|------| | 范围 | **P4.1**:§6.5.2 + §6.5.3 同时交付;§6.3 / §6.6 / §6.7 仍排除 | | 架构 | **方案 1**:统一写作流引擎,扩展 P4 表与 Service,不重写 | | 向导第 4 步 | **选项 A**:复用 `ContextEditorModal` 确认上下文(含大纲/设定中的伏笔线索),不引入知识库表 | | 向导风格 | 节奏三选一(舒缓/紧张/混合)+ 可选自由文本 `styleNote`;**不做**文风滑杆 | | 向导生成后 | 自动切入 **InteractivePanel**(toast「已进入交互微调」) | | 自动暂停 | 可「继续自动」或「转入交互微调」(handoff,保留 scenes) | | 成章落盘 | 活跃卷新建章节;`origin=auto` 或 `origin=wizard`;合并全部场景 HTML | | AI 快照 | 成章时创建 `type='ai'` 快照(标签「自动写作成章」/「向导写作成章」;**顺带补齐** P4 interactive 成章快照) | | 状态持久化 | **schema v5**:`interactive_flows` 增 `flow_mode` / `mode_config_json`;`interactive_scenes` 不变 | | 启动门槛 | **硬拦截**:复用 P4 `checkInteractiveGate` 逻辑(无正文且无大纲/设定时 Tab 禁用) | | 同会话 flow | 每 `session_id` 仅一个 `status=in_progress` flow;按 `flow_mode` 区分模式 | | AI 后端 | **LM Studio**(延续 P3/P4),`http://127.0.0.1:1234`,`gemma-4-e4b-it` | | 测试原则 | **禁止 Mock**;集成 / E2E 打真实 LM Studio | | 测试超时 | Vitest AI 用例 **240s**;Playwright 全局 **180s**;auto/wizard E2E **300s** | ### 1.3 验收标准 用户能完成: 1. 在有足够上下文的书籍中进入「自动写作」或「向导」Tab(门槛不满足时 Tab 禁用并 tooltip 提示) 2. **自动写作**:设定本章目标(大纲选取和/或手写)+ 目标字数范围 → AI 返回场景规划 → 连续流式生成场景(支持命名暂停)→ 字数达范围或点击「结束本章」→ 新建章节 `origin=auto`,编辑器自动打开 3. **自动写作干预**:生成中点击「暂停」→ flow 进入 `paused`;可「继续自动」或「转入交互微调」→ 交互面板可见已生成场景并可微调/续写 4. **向导写作**:依次完成 5 步(目标 → 节奏/风格 → 视角人物 → 上下文确认 → 策略预览)→ 确认后开始生成 → 生成完成后自动显示交互面板,可微调场景 5. 向导成章后章节 `origin=wizard`;自动成章 `origin=auto` 6. 关闭应用并重启后,未完成的 auto/wizard flow 恢复到上次步骤 7. 切换回「对话」模式时同会话聊天历史仍可见;再次进入 auto/wizard/interactive 时 **恢复已有 flow**(不无条件 reset) 8. 所有成章路径均创建 `type='ai'` 快照 ### 1.4 本规格不实现(明确排除) | 项 | 归属 | |----|------| | §6.3 文风学习与风格滑杆 | P4.2+ | | §6.6 大纲生成章节骨架 | P4.2+(可独立 spec) | | §6.7 知识自动抽取与审核工作流 | P4.2+ | | §6.4 Skill / MCP | P4+ | | 知识库伏笔追踪 UI | P4.2+ / P5 | | 导入导出、驾驶舱等 | P5+ | | 命名结果自动写入设定库 | 本阶段仅写入正文 | --- ## 2. 架构 ### 2.1 进程模型 ``` ┌──────────────────────────────────────────────────────────────────┐ │ 主进程 │ │ · schema v5:interactive_flows.flow_mode / mode_config_json │ │ · chapters.origin:manual | interactive | auto | wizard │ │ · SceneGenerationCore(从 P4 抽取:流式、命名暂停、HTML 规范化) │ │ · AutoWritingService(目标→规划→连续生成→暂停/成章/handoff) │ │ · WizardWritingService(5 步→策略预览→委托 Auto→handoff) │ │ · InteractiveWritingService(P4 不变;handoff 目标) │ │ · checkWritingGate(复用 interactive-gate 逻辑,三模式共用) │ │ · AiClientService / AiContextBuilder(复用) │ │ · IPC:auto:* / wizard:* + interactive:streamChunk(增 flowMode) │ └────────────────────────────┬─────────────────────────────────────┘ │ contextBridge ┌────────────────────────────▼─────────────────────────────────────┐ │ 渲染进程 │ │ · AiPanel:writingMode=auto|wizard 时挂载 AutoPanel/WizardPanel │ │ · handoff 后 writingMode 保持或切 interactive,显示 InteractivePanel│ │ · useAutoStore / useWizardStore + useInteractiveStore │ │ · ContextEditorModal(向导步骤 4 + 自动可选编辑上下文) │ └────────────────────────────────────────────────────────────────────┘ ``` **约束**(延续 P0–P4): - 渲染进程禁止直接 `fetch` AI API - 流式通过 `webContents.send` 推送,不阻塞 IPC invoke - 写作 flow 绑定 `ai_session_id`;关键轮次可写入 `ai_messages` 作审计(可选,非阻塞) ### 2.2 Handoff 规则 从 `auto` 或 `wizard` 转入交互微调时: 1. `interactive_scenes` 列表 **不变** 2. `flow_mode` 更新为 `'interactive'` 3. `step` 设为: - 若 `scene_draft_html` 非空 → `'scene_review'` - 否则若已有 scenes → `'plot_suggest'`(进入下一场景循环) - 否则 → `'context_confirm'` 4. `mode_config_json` 保留(只读参考),不删除 5. 渲染进程 `setWritingMode('interactive')` + toast 自动模式 **暂停**(非 handoff)时:`step='paused'`,`flow_mode` 仍为 `'auto'`。 ### 2.3 步骤机 #### 2.3.1 interactive(P4 不变) | Step | 名称 | |------|------| | `context_confirm` | 上下文确认 | | `plot_suggest` | 剧情走向 | | `plot_select` | 用户选择 | | `scene_generate` | 场景生成 | | `naming_pause` | 命名暂停 | | `scene_review` | 场景确认/微调 | | `completed` | 成章完成 | #### 2.3.2 auto | Step | 名称 | AI | |------|------|-----| | `goal_setup` | 目标/字数/大纲 | 无 | | `scene_plan` | 等待用户触发规划 | JSON 场景列表 | | `auto_generate` | 连续生成(含 naming_pause 子状态) | 流式 | | `paused` | 用户暂停 | 无 | | `completed` | 成章完成 | 无 | 生成循环:按 `scenePlan` 顺序逐场景生成;每场景完成后追加 `interactive_scenes`;累计字数(stripHtml 计)≥ `wordMin` 且 AI 判定目标达成或用户点击「结束本章」时停止。 #### 2.3.3 wizard | Step | 名称 | AI | |------|------|-----| | `wizard_goal` | 步骤 1:本章目标 | 无 | | `wizard_rhythm` | 步骤 2:节奏 + styleNote | 无 | | `wizard_pov` | 步骤 3:视角人物(设定 character) | 无 | | `wizard_context` | 步骤 4:ContextEditorModal | 无 | | `wizard_preview` | 步骤 5:策略预览 | 非流式摘要 | | `wizard_generating` | 委托 Auto 引擎生成 | 流式 | | → handoff | 见 §2.2 | — | --- ## 3. Schema v5 ### 3.1 DDL(每本书 `.sqlite`) ```sql -- schema-v5.sql ALTER TABLE interactive_flows ADD COLUMN flow_mode TEXT NOT NULL DEFAULT 'interactive'; ALTER TABLE interactive_flows ADD COLUMN mode_config_json TEXT NOT NULL DEFAULT '{}'; -- chapters.origin 在应用层扩展为 manual | interactive | auto | wizard -- v4 已有 origin 列,v5 迁移不 ALTER(字符串枚举扩展) ``` `migrate.ts`:`CURRENT_VERSION=5`;v4→v5 应用上述 ALTER。 ### 3.2 mode_config_json ```typescript export type WritingFlowMode = 'interactive' | 'auto' | 'wizard' export type AutoRhythm = 'relaxed' | 'tense' | 'mixed' export interface ScenePlanItem { label: string summary: string } export interface AutoWritingConfig { chapterGoal: string outlineItemIds?: string[] wordMin: number // 默认 2000 wordMax: number // 默认 4000 scenePlan?: ScenePlanItem[] currentPlanIndex?: number // auto_generate 进度 } export interface WizardWritingConfig extends AutoWritingConfig { rhythm: AutoRhythm styleNote?: string povSettingId?: string strategyPreview?: string // HTML contextBinding?: AiContextBinding // 步骤 4 确认结果 } ``` ### 3.3 共享类型扩展 ```typescript export type ChapterOrigin = 'manual' | 'interactive' | 'auto' | 'wizard' export type AutoStep = | 'goal_setup' | 'scene_plan' | 'auto_generate' | 'paused' | 'completed' export type WizardStep = | 'wizard_goal' | 'wizard_rhythm' | 'wizard_pov' | 'wizard_context' | 'wizard_preview' | 'wizard_generating' // InteractiveFlow 扩展: // flowMode: WritingFlowMode // modeConfig: AutoWritingConfig | WizardWritingConfig | Record // step: InteractiveStep | AutoStep | WizardStep ``` --- ## 4. 服务层 ### 4.1 SceneGenerationCore 从 `InteractiveWritingService` 抽取(或内部组合): - `generateSceneStream(flowId, planItem, config, onChunk, signal)` - `resolveNaming(flowId, chosenName, ...)` - `normalizeSceneHtml(raw: string): string` - 命名暂停检测:复用 `tryParseNamingFromBuffer` ### 4.2 AutoWritingService | 方法 | 说明 | |------|------| | `start(sessionId)` | 创建 `flow_mode=auto`, `step=goal_setup` | | `getFlow(sessionId)` | 按 session 查 in_progress | | `setGoal(flowId, config: Partial)` | 写入 mode_config,`step=scene_plan` | | `planScenes(flowId)` | AI JSON → `scenePlan`,`step=auto_generate` | | `generateNext(flowId, onChunk, signal)` | 生成当前 plan 项;处理 naming;追加 scene;更新 index | | `pause(flowId)` | `step=paused`,abort 进行中的生成 | | `resume(flowId)` | `step=auto_generate`,继续下一项 | | `handoffToInteractive(flowId)` | §2.2 | | `finishChapter(flowId, volumeId, title?)` | 合并 scenes → 新建章 `origin=auto` + AI 快照 | | `shouldStop(flowId)` | 字数 ≥ wordMin 且(最后一项 plan 完成 或 AI 返回 stop 标记) | ### 4.3 WizardWritingService | 方法 | 说明 | |------|------| | `start(sessionId)` | `flow_mode=wizard`, `step=wizard_goal` | | `setGoal` / `setRhythm` / `setPov` | 逐步写入 mode_config,推进 step | | `confirmContext(flowId, binding)` | 步骤 4;`step=wizard_preview` | | `buildPreview(flowId)` | AI 生成 strategyPreview HTML | | `startGenerate(flowId, onChunk, signal)` | `step=wizard_generating`;构建 AutoWritingConfig 并调用 AutoWritingService 全量生成 | | `handoffToInteractive(flowId)` | 生成完成后自动调用 §2.2 | ### 4.4 成章与快照(三模式统一) `finishChapter` 路径均: 1. 合并 `interactive_scenes.content_html` 2. `chapters.create(..., origin)` 3. `snapshots.create(chapterId, merged, type='ai', label=...)` 4. `flow.status=completed`, `step=completed` --- ## 5. IPC ### 5.1 通道(`ipc-channels.ts` 追加) ```typescript // auto AUTO_CHECK_GATE: 'auto:checkGate' // 实际复用 gate service AUTO_GET_FLOW: 'auto:getFlow' AUTO_START: 'auto:start' AUTO_SET_GOAL: 'auto:setGoal' AUTO_PLAN_SCENES: 'auto:planScenes' AUTO_GENERATE: 'auto:generate' // 生成下一场景或批量至 pause/stop AUTO_PAUSE: 'auto:pause' AUTO_RESUME: 'auto:resume' AUTO_HANDOFF_INTERACTIVE: 'auto:handoffInteractive' AUTO_FINISH_CHAPTER: 'auto:finishChapter' AUTO_GET_SCENE_DRAFT: 'auto:getSceneDraft' AUTO_ABORT: 'auto:abort' // wizard WIZARD_GET_FLOW: 'wizard:getFlow' WIZARD_START: 'wizard:start' WIZARD_SET_GOAL: 'wizard:setGoal' WIZARD_SET_RHYTHM: 'wizard:setRhythm' WIZARD_SET_POV: 'wizard:setPov' WIZARD_CONFIRM_CONTEXT: 'wizard:confirmContext' WIZARD_BUILD_PREVIEW: 'wizard:buildPreview' WIZARD_START_GENERATE: 'wizard:startGenerate' WIZARD_HANDOFF_INTERACTIVE: 'wizard:handoffInteractive' WIZARD_ABORT: 'wizard:abort' ``` 流式事件 `interactive:streamChunk` payload 扩展: ```typescript { flowId, flowMode: WritingFlowMode, phase: 'scene' | 'naming' | 'refine', delta: string, done: boolean } ``` ### 5.2 Preload / electron-api.d.ts 暴露 `window.electronAPI.auto.*` 与 `window.electronAPI.wizard.*` 命名空间。 --- ## 6. Prompt 设计 ### 6.1 场景规划(auto planScenes) 输入:章节目标、大纲条目摘要、已有上下文摘要、wordMin/wordMax。 输出 JSON: ```json { "scenes": [ { "label": "场景1", "summary": "…≥80字…" }, { "label": "场景2", "summary": "…" } ], "estimatedWords": 3200 } ``` 约束:3–6 个场景;总预估字数在 [wordMin, wordMax] 内。 ### 6.2 自动场景生成 输入:当前 plan item、累计 scenes 摘要、AutoWritingConfig。 输出:HTML 段落(600–1500 字/场景);命名暂停格式同 P4。 ### 6.3 向导策略预览(wizard buildPreview) 输入:WizardWritingConfig 全量 + AiContextBuilder 摘要。 输出 HTML 一段,模板语义: > 我将以 **[视角人物]** 视角,用 **[节奏]** 节奏,写一段达成 **[目标]** 的剧情。风格说明:…。重点上下文:…。 --- ## 7. 渲染进程 UI ### 7.1 AiPanel - 移除 `auto` / `wizard` 的 `comingSoon` - `handleModeClick('auto'|'wizard')`:checkGate → loadFlow → 无 flow 则 start(**不**无条件 reset 已有 flow) - `writingMode === 'auto'` → `` - `writingMode === 'wizard'` → ``;handoff 后 `writingMode='interactive'` → `` ### 7.2 AutoPanel | data-testid | 元素 | |-------------|------| | `auto-panel` | 根容器 | | `auto-goal-input` | 本章目标 | | `auto-outline-picker` | 大纲多选 | | `auto-word-min` / `auto-word-max` | 字数范围 | | `auto-plan-scenes` | 触发规划 | | `auto-start-generate` | 开始/继续生成 | | `auto-scene-preview` | 流式预览 | | `auto-pause` | 暂停 | | `auto-handoff-interactive` | 转入交互 | | `auto-finish-chapter` | 结束本章 | 步骤条:`目标 → 规划 → 生成 → 完成` ### 7.3 WizardPanel | data-testid | 元素 | |-------------|------| | `wizard-panel` | 根容器 | | `wizard-step-indicator` | 1–5 步指示 | | `wizard-goal-input` | 步骤 1 | | `wizard-rhythm-*` | 步骤 2 节奏选项 | | `wizard-style-note` | 步骤 2 风格说明 | | `wizard-pov-select` | 步骤 3 | | `wizard-context-edit` | 步骤 4 打开 ContextEditorModal | | `wizard-preview` | 步骤 5 策略摘要 | | `wizard-start-generate` | 开始生成 | 生成完成后隐藏 WizardPanel,显示 InteractivePanel(同 session)。 ### 7.4 i18n 键(zh-CN / en) `auto.gateBlocked`、`auto.gateTooltip`、`auto.step.*`、`auto.pause`、`auto.resume`、`auto.handoffInteractive`、`auto.finishChapter`、`auto.chapterCreated` `wizard.step.*`、`wizard.rhythm.*`、`wizard.previewTitle`、`wizard.startGenerate`、`wizard.handoffToast` 及步骤条、placeholder、错误 toast 文案。 --- ## 8. 错误处理 | 场景 | 行为 | |------|------| | planScenes JSON 解析失败 | 重试一次(追加「仅返回 JSON」);仍失败 → toast + 保持 `scene_plan` | | 生成中用户 pause | AbortController abort;`step=paused`;已生成 scenes 保留 | | 无活跃卷 finishChapter | IPC 错误码;toast「请先创建分卷」 | | 离线 / 非 lmstudio 且无网络 | 同 P3/P4:disabled + offline banner | | wizard 某步必填缺失 | 下一步按钮 disabled | | handoff 时无 scenes 且无 draft | 仍 handoff 到 `context_confirm`,toast 提示可手动续写 | --- ## 9. 测试 ### 9.1 单元 / 集成(Vitest,真实 LM Studio) | ID | 场景 | 超时 | |----|------|------| | UT-MIG-05 | v4 DB 迁移到 v5,flow_mode 列存在 | — | | IT-AUTO-01 | planScenes 返回 ≥2 个 scene | 240s | | IT-AUTO-02 | generateNext 写入非空 scene | 240s | | IT-AUTO-03 | pause 后 step=paused;resume 继续 | 240s | | IT-AUTO-04 | handoff 后 flow_mode=interactive | — | | IT-WIZ-01 | buildPreview 非空 HTML | 240s | | IT-WIZ-02 | startGenerate 完成后 scenes.length ≥ 1 | 300s | | IT-FIN-01 | auto finishChapter → origin=auto + ai 快照 | — | | IT-FIN-02 | interactive finishChapter → ai 快照(P4 补齐) | — | ### 9.2 E2E(Playwright,300s) | ID | 场景 | |----|------| | E2E-AUTO-01 | 自动:设目标 → 规划 → 生成 → 成章 → 编辑器非空 | | E2E-AUTO-02 | 自动:暂停 → 转交互 → accept scene 可见 | | E2E-WIZ-01 | 向导 5 步 → 生成 → InteractivePanel 可见 | | E2E-AUTO-03 | 空书 auto tab disabled(门槛,无 AI) | --- ## 10. 文件清单(实现参考) | 文件 | 职责 | |------|------| | `src/main/db/schema-v5.sql` | v5 DDL | | `src/main/db/migrate.ts` | v4→v5 | | `src/main/db/repositories/interactive.repo.ts` | flow_mode / mode_config CRUD | | `src/main/services/scene-generation-core.service.ts` | 共享生成逻辑 | | `src/main/services/auto-writing.service.ts` | 自动写作步骤机 | | `src/main/services/wizard-writing.service.ts` | 向导步骤机 | | `src/main/services/auto-prompt-builder.service.ts` | plan / scene / preview prompt | | `src/main/ipc/handlers/auto.handler.ts` | auto IPC | | `src/main/ipc/handlers/wizard.handler.ts` | wizard IPC | | `src/renderer/components/ai/AutoPanel.tsx` | 自动 UI | | `src/renderer/components/ai/WizardPanel.tsx` | 向导 UI | | `src/renderer/stores/useAutoStore.ts` | auto 状态 | | `src/renderer/stores/useWizardStore.ts` | wizard 状态 | | `tests/main/migrate-v5.test.ts` | 迁移 | | `tests/main/auto-*.test.ts` | 集成 | | `tests/main/wizard-*.test.ts` | 集成 | | `e2e/auto-writing.spec.ts` | E2E | | `e2e/wizard-writing.spec.ts` | E2E | --- ## 11. Spec 自检 | 检查项 | 结果 | |--------|------| | Placeholder 扫描 | 无 TBD/TODO;排除项已列 §1.4 | | 内部一致性 | handoff / 步骤机 / IPC / UI testid 对齐 | | 范围 | 单阶段可交付 v0.5.0;§6.7 已通过 ContextEditor 降级 | | 歧义 | 成章 origin 三分;同 session 单 in_progress flow;恢复 flow 不 reset | --- *本规格为笔临 P4.1 子项目。知识抽取、大纲骨架等各自在后续 spec 中增量修订。*