Files
bilin/docs/superpowers/specs/2026-07-09-bilin-p41-auto-wizard-design.md
T

483 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 笔临 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 v5interactive_flows.flow_mode / mode_config_json │
│ · chapters.originmanual | interactive | auto | wizard │
│ · SceneGenerationCore(从 P4 抽取:流式、命名暂停、HTML 规范化) │
│ · AutoWritingService(目标→规划→连续生成→暂停/成章/handoff) │
│ · WizardWritingService5 步→策略预览→委托 Auto→handoff
│ · InteractiveWritingServiceP4 不变;handoff 目标) │
│ · checkWritingGate(复用 interactive-gate 逻辑,三模式共用) │
│ · AiClientService / AiContextBuilder(复用) │
│ · IPCauto:* / wizard:* + interactive:streamChunk(增 flowMode
└────────────────────────────┬─────────────────────────────────────┘
│ contextBridge
┌────────────────────────────▼─────────────────────────────────────┐
│ 渲染进程 │
│ · AiPanelwritingMode=auto|wizard 时挂载 AutoPanel/WizardPanel │
│ · handoff 后 writingMode 保持或切 interactive,显示 InteractivePanel│
│ · useAutoStore / useWizardStore + useInteractiveStore │
│ · ContextEditorModal(向导步骤 4 + 自动可选编辑上下文) │
└────────────────────────────────────────────────────────────────────┘
```
**约束**(延续 P0P4):
- 渲染进程禁止直接 `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 interactiveP4 不变)
| 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` | 步骤 4ContextEditorModal | 无 |
| `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<string, never>
// 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<AutoWritingConfig>)` | 写入 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'``<AutoPanel />`
- `writingMode === 'wizard'``<WizardPanel />`handoff 后 `writingMode='interactive'``<InteractivePanel />`
### 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` | 15 步指示 |
| `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/P4disabled + offline banner |
| wizard 某步必填缺失 | 下一步按钮 disabled |
| handoff 时无 scenes 且无 draft | 仍 handoff 到 `context_confirm`toast 提示可手动续写 |
---
## 9. 测试
### 9.1 单元 / 集成(Vitest,真实 LM Studio
| ID | 场景 | 超时 |
|----|------|------|
| UT-MIG-05 | v4 DB 迁移到 v5flow_mode 列存在 | — |
| IT-AUTO-01 | planScenes 返回 ≥2 个 scene | 240s |
| IT-AUTO-02 | generateNext 写入非空 scene | 240s |
| IT-AUTO-03 | pause 后 step=pausedresume 继续 | 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 E2EPlaywright300s
| 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 中增量修订。*