Files
bilin/docs/superpowers/specs/2026-07-07-bilin-p52-writing-logs-extraction-design.md

18 KiB
Raw Permalink Blame History

笔临 P5.2 写作日志 + AI 知识抽取 设计规格

版本1.0
日期2026-07-07
范围P5.2 — writing_logs 日更追踪 + 驾驶舱热力图/连更 + AI 章节知识自动抽取与审核增强
前置:P6 AI 知识上下文已交付(v0.7.0,aa2c7df
参考design/readme.md v1.1 §6.7 / §8 / §9、docs/superpowers/specs/2026-07-06-bilin-p5-workflow-knowledge-design.mddocs/superpowers/specs/2026-07-07-bilin-p6-ai-context-design.md

目标版本v0.8.0


1. 背景与目标

1.1 阶段定位

v0.7.0 已交付知识半自动推荐与四种 AI 模式注入,但知识库条目仍依赖手动录入;驾驶舱缺少日更写作数据(writing_logs、热力图、连更),dailyWordGoal 仅有设置项未驱动 UI。本阶段(P5.2)补齐 写作数据闭环AI 知识抽取上游,形成「成章/保存 → 抽取 → 审核 → P6 注入」完整链路。

1.2 已确认决策(Brainstorming 2026-07-07

维度 决策
交付范围 核心包writing_logs + 热力图 + 连更 + AI 抽取;不含番茄钟 / 里程碑徽章 / 预计完本
抽取触发 成章自动(默认开)+ 手动「抽取本章」+ 全局 knowledgeAutoExtract 开关
统计范围 当前书籍:热力图、连更、dailyWordGoal 达标均按本书当日净增
日更累计 保存差分 + 成章补计CHAPTER_UPDATE 记录净增;finishChapter 补计未入账字数
重复处理 AI 合并建议 + 预填更新suggestedMergeId + proposedPatch;确认后 patch 已有条目或另存为新条目
架构 方案 2:全局 writing_logs + 每书 chapter_writing_snapshots + 独立 KnowledgeExtractionService
schema v7 迁移(每书);全局 writing_logs.sqliteuserData
AI 测试 集成/E2E 含抽取时禁止 Mock,走 LM Studio

1.3 验收标准

用户能完成:

  1. 编辑章节并保存后,驾驶舱今日字数365 天热力图更新;dailyWordGoal > 0 时状态栏进度条反映本书当日进度(绿≥100%,橙≥80%)
  2. 连更天数在驾驶舱展示(仅当 dailyWordGoal > 0);中断后归零
  3. 交互/自动/向导 成章落盘后,若 knowledgeAutoExtract 开启,知识库「待审核」出现本批 AI 抽取项(含置信度)
  4. 在知识库或章节操作区点击 「抽取本章」 手动触发;设置中可关闭自动抽取
  5. 待审核项含 合并建议 时,打开预填编辑器;确认后更新已有 approved 条目,或选择「作为新条目」
  6. 「全部采纳高置信度」批量通过 ≥ 阈值(默认 0.8)的纯新建条目;含合并建议的条目不自动批量采纳
  7. 采纳后的条目可被 P6 suggestContext 推荐并注入 AI 上下文

1.4 本规格不实现(明确排除)

归属
番茄钟、7/30/100 天里程碑徽章、达标推送通知 §8 延后
预计完本、写作速度仪表盘、时段热力图 §9 延后
角色弧线简报、Cytoscape 关系图谱 P6+ / §20.3
语义 embedding 检索 后续
注入历史 / 反向链接 P6.1
导入导出、平台投稿预设 P7
关系「建议」自动写入 settings P6+(本阶段仅 relationship 类型知识条目)

2. 架构

2.1 进程模型

┌──────────────────────────────────────────────────────────────────┐
│ 主进程                                                            │
│  · WritingLogServiceuserData/writing_logs.sqlite              │
│  · ChapterWritingTracker(差分 + 成章补计)                        │
│  · KnowledgeExtractionServiceAiClient + 解析 JSON               │
│  · KnowledgeService 扩展(合并 patch、批量高置信度采纳)           │
│  · CockpitService 扩展(热力图、连更、今日进度)                   │
│  · chapter.handler / interactive|auto finishChapter 挂钩          │
└────────────────────────────┬─────────────────────────────────────┘
                             │ IPC
┌────────────────────────────▼─────────────────────────────────────┐
│ 渲染进程                                                          │
│  · CockpitModal 热力图 + 连更 + 今日进度                          │
│  · EditorLayout 状态栏日更进度条                                  │
│  · KnowledgePanel 抽取批次、合并建议 UI、批量高置信度             │
│  · SettingsPage knowledgeAutoExtract / 置信度阈值                 │
│  · 章节列表/编辑器「抽取本章」入口                                 │
└──────────────────────────────────────────────────────────────────┘

2.2 模块边界

模块 职责 依赖
WritingLogService (date, bookId) 读写/累加日字数 全局 sqlite
ChapterWritingTracker 维护 chapter_writing_snapshots,计算 delta 每书 DB、WritingLogService
KnowledgeExtractionService 构建 prompt、调用 AI、解析、落库 pending AiClientService, KnowledgeRepository
KnowledgeService 合并 patch、批量采纳、拒绝 现有 CRUD
CockpitService 扩展 WritingStats 聚合 WritingLogService, GlobalSettings

原则:抽取异步不阻塞成章;抽取失败 toast + 可重试;写作追踪同步、轻量。


3. 数据模型

3.1 全局 userDatawriting_logs.sqlite

CREATE TABLE writing_logs (
  date       TEXT NOT NULL,   -- YYYY-MM-DD,本地时区
  book_id    TEXT NOT NULL,
  word_count INTEGER NOT NULL DEFAULT 0,
  PRIMARY KEY (date, book_id)
);

WritingLogServiceuserDataDir 管理,与 books_registry.json 同级。

3.2 每书 schema v7

新文件 schema-v7.sql

CREATE TABLE chapter_writing_snapshots (
  chapter_id            TEXT PRIMARY KEY,
  logged_word_count     INTEGER NOT NULL DEFAULT 0,
  finish_supplemented   INTEGER NOT NULL DEFAULT 0,
  FOREIGN KEY (chapter_id) REFERENCES chapters(id) ON DELETE CASCADE
);

-- knowledge_entries 扩展列(迁移时 ALTER 或重建后拷贝)
-- extraction_confidence REAL
-- merge_target_id       TEXT   -- 建议合并的 approved 条目 id
-- extraction_batch_id   TEXT   -- 同次抽取 UUID,便于 UI 分组

migrate.tsCURRENT_VERSION = 7v6→v7 对已有 knowledge_entries 执行 ALTER TABLE ADD COLUMN(三列均可 NULL)。

3.3 类型扩展(src/shared/types.ts

export interface WritingDayLog {
  date: string
  bookId: string
  wordCount: number
}

export interface WritingStats {
  todayWords: number
  dailyGoal: number
  goalProgress: number      // 01+goal=0 时为 0
  streakDays: number        // goal=0 时为 0
  heatmap: WritingDayLog[]  // 最近 365 天,含 wordCount=0 的日期
}

export interface ExtractedKnowledgeItem {
  type: KnowledgeType
  title: string
  content: string
  importance?: number
  confidence: number
  foreshadowStatus?: ForeshadowStatus
  suggestedMergeId?: string
  proposedPatch?: Partial<CreateKnowledgeInput>
}

export interface KnowledgeExtractionResult {
  batchId: string
  chapterId: string
  items: ExtractedKnowledgeItem[]
}

扩展 CockpitSummary

writingStats?: WritingStats

扩展 KnowledgeEntry

extractionConfidence?: number
mergeTargetId?: string
extractionBatchId?: string

扩展 GlobalSettings

knowledgeAutoExtract: boolean           // default true
knowledgeExtractConfidenceThreshold: number  // default 0.8

4. 日更追踪

4.1 差分算法(ChapterWritingTracker

recordDelta(bookId, chapterId, newWordCount)(在 CHAPTER_UPDATE 成功后调用):

  1. 读取 chapter_writing_snapshots.logged_word_count(无则 0
  2. delta = newWordCount - logged
  3. delta !== 0WritingLogService.addToday(bookId, delta)(当日累计不低于 0
  4. 更新 snapshotlogged_word_count = newWordCount

supplementOnFinish(bookId, chapterId, wordCount)(在 finishChapter 创建章节后调用):

  1. 若 snapshot 不存在,创建 logged=0, finish_supplemented=0
  2. gap = wordCount - snapshot.logged_word_count
  3. gap > 0addToday(bookId, gap),更新 logged = wordCount
  4. finish_supplemented = 1

删除章节时 CASCADE 删除 snapshotwriting_logs 历史不回溯修正(接受已知限制)。

4.2 连更计算

  • 仅当 dailyWordGoal > 0 时计算
  • 从今日向前遍历 writing_logs(本书),连续天数满足 word_count >= dailyWordGoal
  • 今日未达标时 streak 不计入今日(展示为截至昨日的连更)

4.3 时区

使用主进程 IntltoLocaleDateString('sv-SE') 生成本地 YYYY-MM-DD,与作者所在系统时区一致。


5. AI 知识抽取

5.1 触发点

触发 条件 行为
成章落盘 finishChapter 成功且 knowledgeAutoExtract 入队 extractForChapter(bookId, chapterId)
手动 knowledge:extractChapter IPC 同上
设置关闭 knowledgeAutoExtract === false 仅手动触发

抽取在 setImmediate / 微任务队列异步执行,不延长成章 IPC 响应时间。

5.2 Prompt 与解析

输入:章节标题 + 正文纯文本(stripHtml,上限 12000 字,超出截断并注明)+ 本书已有 approved 条目标题列表(上限 30 条,供合并判断)。

输出 JSON 数组(严格解析,失败重试一次「仅返回 JSON」):

[
  {
    "type": "foreshadow",
    "title": "测灵石异常",
    "content": "入门考核时石头发热,暗示主角特殊灵根",
    "importance": 4,
    "confidence": 0.92,
    "foreshadowStatus": "buried",
    "suggestedMergeId": null,
    "proposedPatch": null
  },
  {
    "type": "character",
    "title": "林远状态更新",
    "content": "通过入门考核,声望上升",
    "importance": 3,
    "confidence": 0.85,
    "suggestedMergeId": "uuid-of-existing-entry",
    "proposedPatch": {
      "content": "已通过入门考核,同门态度由轻视转为敬畏",
      "importance": 4,
      "lastMentionChapterId": "<chapterId>"
    }
  }
]

类型:五种全做 — character / foreshadow / relationship / location / fact

落库:每条 → knowledge_entriesstatus=pendingsource_chapter_id=chapterIdextraction_confidenceextraction_batch_idmerge_target_id(若有)。

5.3 合并审核 UX(决策 D

场景 UI
mergeTargetId 待审核列表常规展示;采纳 → approve
mergeTargetId 卡片标注「建议更新:{目标标题}」;点击打开 KnowledgeEditorDialog 预填 proposedPatch + 目标条目只读摘要
确认更新 knowledge:approveMerge → patch 目标 approved 条目,删除或标记本 pending 为 rejected
作为新条目 清除 mergeTargetId,保留 pending,用户编辑后采纳

批量「全部采纳高置信度」:仅处理 mergeTargetId IS NULLconfidence >= threshold 的 pending 项。

5.4 IPC 新增

通道 参数 返回
writing:getStats { bookId } WritingStats
knowledge:extractChapter { bookId, chapterId } KnowledgeExtractionResult
knowledge:approveMerge { bookId, pendingId } KnowledgeEntry(更新后的目标)
knowledge:batchApproveHighConfidence { bookId, threshold? } number(采纳条数)

CHAPTER_UPDATE handler 内联调用 ChapterWritingTracker(无需新 IPC)。


6. UI 规格

6.1 驾驶舱(CockpitModal

在现有四卡片下方新增:

  • 今日进度todayWords / dailyGoal 文字 + 细进度条(data-testid="cockpit-today-progress"
  • 连更🔥 {streakDays} 天dailyGoal=0 时隐藏,data-testid="cockpit-streak"
  • 热力图Canvas 52×7 格,365 天;颜色深浅按 word_count 分档(0 / 1999 / 10002999 / ≥3000);今天描边高亮(data-testid="cockpit-heatmap"

6.2 状态栏(EditorLayout #editor-statusbar

dailyWordGoal > 0 且当前有打开书籍:

  • 显示 今日 1234 / 3000 字 + 迷你进度条
  • CSS classgoal-met(≥100%)、goal-near(≥80%
  • data-testid="status-daily-goal"

6.3 知识库(KnowledgePanel

  • 待审核 Tab 顶部:本批抽取分组(按 extractionBatchId 折叠,显示来源章节)
  • 条目卡片:置信度徽章、合并建议标签
  • 工具栏:「全部采纳高置信度」data-testid="knowledge-batch-high-confidence"
  • 合并项:「查看更新建议」data-testid="knowledge-merge-review-{id}"

6.4 抽取入口

  • 章节列表项右键或编辑器菜单:「抽取本章知识」 data-testid="chapter-extract-knowledge"
  • 知识库工具栏:「从当前章抽取」(无选中章时 disabled

6.5 设置(SettingsPage

写作 / AI 分区:

  • knowledgeAutoExtract 开关 data-testid="settings-knowledge-auto-extract"
  • knowledgeExtractConfidenceThreshold 数字输入(0.5–1.0,步进 0.05)data-testid="settings-extract-threshold"

7. 错误处理

场景 处理
AI 抽取 JSON 解析失败 重试一次;仍失败 toast「抽取失败,请稍后重试」,写 console.error
章节正文为空 跳过抽取,toast「章节无内容」
suggestedMergeId 指向已删除条目 视为无合并建议,按新建处理
addToday 扣减后当日 < 0 钳制为 0
成章时抽取进行中 允许并行;同章多次抽取生成新 batchId,旧 pending 保留

8. 测试

8.1 测试 ID

ID 层级 场景 预期
UT-LOG-01 单元 recordDelta 保存 +200 字 当日 +200
UT-LOG-02 单元 recordDelta 删 100 字 当日 -100(不低于 0
UT-LOG-03 单元 supplementOnFinish gap=500 当日 +500finish_supplemented=1
UT-LOG-04 单元 连更 3 天达标 streakDays=3
UT-EXT-01 单元 解析合法抽取 JSON 返回 N 条 ExtractedKnowledgeItem
UT-EXT-02 单元 suggestedMergeId merge_target_id 正确写入
IT-LOG-01 集成 CHAPTER_UPDATE 两次 writing_logs 累计正确
IT-EXT-01 集成 extractChapter 有正文 返回 ≥1 pending
IT-EXT-02 集成 approveMerge 目标 approved 内容更新
IT-EXT-03 集成 抽取 + P6 suggestContext 新采纳条目出现在推荐中
E2E-LOG-01 E2E 写 100 字保存 驾驶舱今日字数更新
E2E-LOG-02 E2E 热力图可见 cockpit-heatmap 存在
E2E-EXT-01 E2E 成章后待审核有抽取项 pending 列表非空
E2E-EXT-02 E2E 手动抽取本章 待审核增加
E2E-EXT-03 E2E 合并建议确认更新 目标条目内容变化

8.2 超时

  • IT-EXT-01 / IT-EXT-02 / IT-EXT-03240s
  • E2E-EXT-01 / E2E-EXT-03300s

8.3 原则

集成/E2E 含 AI 抽取时 禁止 Mock,使用 LM Studio 默认配置。


9. i18n 键(节选)

"cockpit.todayProgress": "今日 {{current}} / {{goal}} 字",
"cockpit.streak": "连更 {{days}} 天",
"cockpit.heatmap": "写作热力图",
"status.dailyGoal": "今日 {{current}} / {{goal}}",
"knowledge.extractChapter": "抽取本章知识",
"knowledge.extractFromCurrent": "从当前章抽取",
"knowledge.batchHighConfidence": "全部采纳高置信度",
"knowledge.mergeSuggest": "建议更新:{{title}}",
"knowledge.approveMerge": "确认更新",
"knowledge.saveAsNew": "作为新条目",
"knowledge.extracting": "正在抽取知识…",
"knowledge.extractFailed": "知识抽取失败,请稍后重试",
"settings.knowledgeAutoExtract": "成章后自动抽取知识",
"settings.extractThreshold": "高置信度阈值"

10. 文件映射

文件 职责
src/main/db/schema-v7.sql snapshots + knowledge 扩展列
src/main/db/migrate.ts v7 迁移
src/main/db/repositories/writing-log.repo.ts 全局 writing_logs CRUD
src/main/db/repositories/chapter-writing-snapshot.repo.ts 每书 snapshot
src/main/services/writing-log.service.ts 日更累加、连更、热力图数据
src/main/services/chapter-writing-tracker.service.ts 差分 + 补计
src/main/services/knowledge-extraction.service.ts AI 抽取
src/main/services/knowledge-extraction-prompt.ts prompt 构建 + JSON 解析
src/main/services/cockpit.service.ts 扩展 WritingStats
src/main/ipc/handlers/writing.handler.ts writing:getStats
src/main/ipc/handlers/knowledge.handler.ts 抽取/合并 IPC
src/main/ipc/handlers/chapter.handler.ts 挂钩 tracker
src/renderer/components/cockpit/WritingHeatmap.tsx Canvas 热力图
src/renderer/components/cockpit/CockpitModal.tsx 扩展布局
src/renderer/components/knowledge/KnowledgePanel.tsx 批次/合并 UI
tests/main/writing-log.test.ts UT-LOG-*
tests/main/knowledge-extraction.test.ts UT-EXT-* / IT-EXT-*
e2e/writing-logs.spec.ts E2E-LOG-*
e2e/knowledge-extraction.spec.ts E2E-EXT-*

11. Spec Coverage Checklist

design/readme 要求 本规格
§6.7 每章自动抽取 + 审核 §5
§6.7 合并/忽略/批量采纳 §5.3
§8 writing_logs + 热力图 + 连更 §3–§4、§6.1
§8 番茄钟/里程碑 排除 §1.4
§9 驾驶舱内嵌分析 热力图 + 今日进度(轻量)
P5 延后「AI 抽取」 本阶段交付
P5 延后 writing_logs 本阶段交付
P6 知识注入上游 §5 + IT-EXT-03

12. 版本与 DoD

  • package.json0.8.0
  • README.md 功能概览追加 P5.2 一行
  • SettingsPage about 版本号更新
  • npm run build && npm run test && npm run test:e2e 全绿
  • LM Studio 集成测试按 §8.2 超时执行

本规格为笔临 P5.2 子项目。角色弧线、关系图谱、导入导出等各自在后续 spec 中增量修订。