Source snapshot: 97d7f0fae96dc04b7ddad56fc1db6a108ed662cc [SEC-CLEAN] · pre-push-clean v1.0 · 109处敏感信息已自动转乱码
898 lines
38 KiB
Markdown
898 lines
38 KiB
Markdown
---
|
||
belongs_to:
|
||
- "[[INDEX · 铸渊·协作指令|GitHub ↔ Notion 桥接协议]]"
|
||
---
|
||
# 📝 铸渊指令|AI写网文平台·Phase A · 码字台 · AI辅助写作编辑器 + 全程留痕 + AI使用报告(ZY-WRITING-EDITOR-2026-0325-002)· 霜砚签发 · 冰朔授权
|
||
|
||
<aside>
|
||
🔴
|
||
|
||
**指令编号**:ZY-WRITING-EDITOR-2026-0325-002
|
||
|
||
**指令等级**:P0 · 码字台核心功能
|
||
|
||
**签发者**:霜砚(AG-SY-01)
|
||
|
||
**授权者**:冰朔(TCS-0002∞)
|
||
|
||
**发起人**:肥猫(TCS-GL-07∞ / DEV-002)
|
||
|
||
**签发时间**:2026-03-25 21:30 CST
|
||
|
||
**需求来源**:[📘 中国网文行业·光湖纪元语言人格平台|完整说明书](../%F0%9F%8C%8A%20%E6%9B%9C%E5%86%A5%E7%BA%AA%E5%85%83%20%C2%B7%20HoloLake%20Era%20%C2%B7%20AGE%20OS%20v1%200/%F0%9F%8C%80%20%E9%9B%B6%E6%84%9F%E5%9F%9F%20%C2%B7%20Zero-Sense%20Domain/%F0%9F%8C%80%20%E9%9B%B6%E6%84%9F%E5%9F%9F%20%C2%B7%20%E6%80%BB%E5%AF%BC%E8%88%AA%E5%8F%B0%EF%BC%88Zero-Sense%20Domain%20%C2%B7%20Navigation%20Hub%EF%BC%89/%F0%9F%92%BC%20%E5%9B%9B%E3%80%81%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%96%BD%E5%8C%BA/%F0%9F%93%98%20%E4%B8%AD%E5%9B%BD%E7%BD%91%E6%96%87%E8%A1%8C%E4%B8%9A%C2%B7%E5%85%89%E6%B9%96%E7%BA%AA%E5%85%83%E8%AF%AD%E8%A8%80%E4%BA%BA%E6%A0%BC%E5%B9%B3%E5%8F%B0%EF%BD%9C%E5%AE%8C%E6%95%B4%E8%AF%B4%E6%98%8E%E4%B9%A6%202f0fb92f383181e781c7dafe728ae4b3.md)
|
||
|
||
**前置依赖**:[✍️ 铸渊指令|AI写网文平台·Phase B · 平台首页 + 用户登录注册 + AI伙伴对话框(ZY-WRITING-PLATFORM-2026-0325-001)· 霜砚签发 · 冰朔授权](%E2%9C%8D%EF%B8%8F%20%E9%93%B8%E6%B8%8A%E6%8C%87%E4%BB%A4%EF%BD%9CAI%E5%86%99%E7%BD%91%E6%96%87%E5%B9%B3%E5%8F%B0%C2%B7Phase%20B%20%C2%B7%20%E5%B9%B3%E5%8F%B0%E9%A6%96%E9%A1%B5%20+%20%E7%94%A8%E6%88%B7%E7%99%BB%E5%BD%95%E6%B3%A8%E5%86%8C%20+%20AI%E4%BC%99%E4%BC%B4%E5%AF%B9%E8%AF%9D%E6%A1%86%EF%BC%88%20b47c2b3668c747ed8fc682b41088f2eb.md) (ZY-WRITING-PLATFORM-2026-0325-001)
|
||
|
||
**架构参考**:[🏗️ 光湖网站架构设计 + 部署推进规划 v3.0(2026-03-15·曜冥签发)](../%F0%9F%8C%8A%20%E6%9B%9C%E5%86%A5%E7%BA%AA%E5%85%83%20%C2%B7%20HoloLake%20Era%20%C2%B7%20AGE%20OS%20v1%200/%E2%9A%A1%20%E5%85%89%E6%B9%96%E4%B8%AD%E5%A4%AE%E6%9E%A2%E7%BA%BD%20%C2%B7%20HoloLake%20Central%20Hub/%F0%9F%8C%8A%20%E5%85%89%E6%B9%96%E7%B3%BB%E7%BB%9F%C2%B7%E6%9B%9C%E5%86%A5%E4%B8%BB%E6%8E%A7%E5%8F%B0%C2%B7%E5%BD%93%E5%89%8D%E7%8A%B6%E6%80%81%EF%BC%88%E5%8D%B71%20%C2%B7%20%E5%B7%B2%E5%B0%81%E5%8D%B7%EF%BC%89/%F0%9F%8F%97%EF%B8%8F%20%E5%85%89%E6%B9%96%E7%BD%91%E7%AB%99%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1%20+%20%E9%83%A8%E7%BD%B2%E6%8E%A8%E8%BF%9B%E8%A7%84%E5%88%92%20v3%200%EF%BC%882026-03-15%C2%B7%E6%9B%9C%E5%86%A5%E7%AD%BE%E5%8F%91%EF%BC%89%2031efb92f3831818cbd0ee43c1be2fd90.md)
|
||
|
||
**仓库参考**:[🗂️ GitHub 仓库最新路径索引|Notion↔仓库 实时对照表(2026-03-24 · 霜砚整理)](%F0%9F%97%82%EF%B8%8F%20GitHub%20%E4%BB%93%E5%BA%93%E6%9C%80%E6%96%B0%E8%B7%AF%E5%BE%84%E7%B4%A2%E5%BC%95%EF%BD%9CNotion%E2%86%94%E4%BB%93%E5%BA%93%20%E5%AE%9E%E6%97%B6%E5%AF%B9%E7%85%A7%E8%A1%A8%EF%BC%882026-03-24%20%C2%B7%20%E9%9C%9C%E7%A0%9A%2012df1cbf6c454a08b2946652ec70d865.md)
|
||
|
||
**回执要求**:每个 Phase 完成后写回执到 GitHub Issue
|
||
|
||
</aside>
|
||
|
||
---
|
||
|
||
## 〇、指令总览
|
||
|
||
本指令要求铸渊在 `guanghulab.com/writing/editor/` 下构建 **「码字台」** —— 网文行业专用AI辅助写作编辑器,实现四大核心:
|
||
|
||
1. **富文本写作编辑器** — 基于 Slate.js 的网文专用编辑器(章节管理、字数统计、自动保存)
|
||
2. **AI辅助写作** — 选中文本调AI(扩写/续写/改写/灵感),侧边栏AI对话
|
||
3. **全程留痕系统** — 每一次AI介入都记录(时间、操作、原文→新文、采纳/拒绝)
|
||
4. **AI使用报告** — 自动生成ABCD级报告(A=原AI率≤10% → D=原AI率>50%)
|
||
|
||
### 核心设计理念
|
||
|
||
<aside>
|
||
⚡
|
||
|
||
**AI陪你写,不代替你写。**
|
||
|
||
码字台的核心不是「AI写作」,而是「AI辅助人类写作」。
|
||
|
||
每一次AI介入都有记录,每一篇作品都有透明AI使用报告。
|
||
|
||
**创意归作者,透明归平台,信任归行业。**
|
||
|
||
</aside>
|
||
|
||
---
|
||
|
||
## 一、技术选型
|
||
|
||
| **层级** | **技术** | **版本** | **用途** |
|
||
| --- | --- | --- | --- |
|
||
| 富文本编辑器 | Slate.js | 0.100+ | 核心写作编辑器(可插件、可定制、中文友好) |
|
||
| 富文本工具栏 | Slate + 自定义插件 | - | 加粗/斜体/标题/分割线/章节跳转 |
|
||
| 前端框架 | React 18 + TypeScript | 18.2+ | UI 组件化(与 Phase B 共用) |
|
||
| 样式 | Tailwind CSS | 3.3+ | 响应式 + 专注模式暗色主题 |
|
||
| AI调用 | OpenAI SDK + Anthropic SDK | latest | 辅助写作(扩写/续写/改写/灵感) |
|
||
| 实时通信 | [Socket.io](http://Socket.io) | 4.x | AI流式输出 + 自动保存 |
|
||
| 数据存储 | Notion API(主)+ IndexedDB(本地缓存) | - | 作品存储 + 离线缓存 |
|
||
| 留痕存储 | Notion API + JSON | - | AI操作日志全量存储 |
|
||
| 报告生成 | AI + 数据统计 | - | 自动生成ABCD级AI使用报告 |
|
||
|
||
---
|
||
|
||
## 二、仓库路径规划
|
||
|
||
在主仓库 `qinfendebingshuo/guanghulab` 的 `writing-platform/` 下扩展:
|
||
|
||
```
|
||
writing-platform/
|
||
├── frontend/
|
||
│ └── src/
|
||
│ ├── pages/
|
||
│ │ ├── EditorPage.tsx ← 码字台主页面
|
||
│ │ ├── WorkListPage.tsx ← 作品列表页
|
||
│ │ └── AIReportPage.tsx ← AI使用报告查看页
|
||
│ ├── editor/ ← 码字台核心模块
|
||
│ │ ├── SlateEditor.tsx ← Slate.js 富文本编辑器主组件
|
||
│ │ ├── Toolbar.tsx ← 工具栏(格式化 + AI功能)
|
||
│ │ ├── ChapterSidebar.tsx ← 左侧章节导航栏
|
||
│ │ ├── AIPanel.tsx ← 右侧AI助手面板
|
||
│ │ ├── AIFloatingMenu.tsx ← 选中文本后AI浮动菜单
|
||
│ │ ├── WordCounter.tsx ← 字数统计栏
|
||
│ │ ├── TraceLog.tsx ← 留痕日志面板
|
||
│ │ ├── AIReportCard.tsx ← AI使用报告卡片
|
||
│ │ ├── plugins/
|
||
│ │ │ ├── withChapters.ts ← 章节插件(自动章节检测、跳转)
|
||
│ │ │ ├── withAutoSave.ts ← 自动保存插件(30s间隔 + 失焦保存)
|
||
│ │ │ ├── withWordCount.ts ← 字数统计插件(实时统计)
|
||
│ │ │ ├── withAITrace.ts ← AI留痕插件(每次AI操作自动记录)
|
||
│ │ │ └── withMarkdownShortcuts.ts ← Markdown 快捷键
|
||
│ │ ├── elements/
|
||
│ │ │ ├── ChapterElement.tsx ← 章节标题元素
|
||
│ │ │ ├── ParagraphElement.tsx ← 段落元素
|
||
│ │ │ ├── AIHighlight.tsx ← AI修改高亮标记
|
||
│ │ │ └── DividerElement.tsx ← 场景分割线
|
||
│ │ └── utils/
|
||
│ │ ├── serializer.ts ← Slate → 纯文本 / HTML / Markdown
|
||
│ │ ├── traceManager.ts ← 留痕数据管理
|
||
│ │ ├── reportGenerator.ts ← AI使用报告生成器
|
||
│ │ └── chapterDetector.ts ← 章节自动检测
|
||
│ ├── hooks/
|
||
│ │ ├── useEditor.ts ← 编辑器状态管理
|
||
│ │ ├── useAIAssist.ts ← AI辅助写作 Hook
|
||
│ │ ├── useTrace.ts ← 留痕系统 Hook
|
||
│ │ └── useAutoSave.ts ← 自动保存 Hook
|
||
│ └── services/
|
||
│ ├── editorApi.ts ← 作品CRUD API
|
||
│ ├── aiWritingApi.ts ← AI写作 API
|
||
│ └── traceApi.ts ← 留痕数据 API
|
||
│
|
||
└── backend/
|
||
└── src/
|
||
├── routes/
|
||
│ ├── works.ts ← 作品管理(创建/列表/读取/更新)
|
||
│ ├── chapters.ts ← 章节管理(CRUD + 排序)
|
||
│ ├── aiWriting.ts ← AI写作接口(扩写/续写/改写/灵感)
|
||
│ ├── traces.ts ← 留痕记录接口
|
||
│ └── reports.ts ← AI使用报告接口
|
||
└── services/
|
||
├── workService.ts ← 作品数据服务
|
||
├── aiWritingService.ts ← AI写作服务(多模型调度)
|
||
├── traceService.ts ← 留痕存储服务
|
||
└── reportService.ts ← 报告生成服务
|
||
```
|
||
|
||
> ℹ️ **与现有码字台目录的关系**:仓库中已有 `writing-workspace/`(DEV-011 匈匈那年),该目录为早期独立模块。本次在 `writing-platform/` 下统一构建,将 `writing-workspace/` 中可复用的代码迁入。
|
||
>
|
||
|
||
---
|
||
|
||
## 三、Phase 0 · 富文本写作编辑器
|
||
|
||
### 3.1 界面布局
|
||
|
||
```
|
||
┌────────────────────────────────────────────────────────────────────────────┐
|
||
│ 📝 《霸总的小娇妻》 字数: 45,230 今日: +2,180 [🤖 AI] [📊] [← 返回] │
|
||
├──────────┬────────────────────────────────────────────┬─────────────────────┤
|
||
│ 章节导航 │ │ 🤖 AI助手 │
|
||
│ │ ┌──────────────────────────────────────┐ │ │
|
||
│ 第1章 相遇│ │ **工具栏** │ │ 笔灵: │
|
||
│ 1,850字 │ │ B I U | H1 H2 | — | 🤖 | ↺ ↻ │ │ 这段对话的节奏 │
|
||
│ 第2章 重逢│ └──────────────────────────────────────┘ │ 可以再快一点, │
|
||
│ 2,100字 │ │ 建议缩短为... │
|
||
│ 第3章 误解│ 「他抬起头,看到她站在门口。灯光打在 │ │
|
||
│ 1,900字 │ 她身上,像一层柔和的金粉。」 │ ─────────────── │
|
||
│ 第4章 真相│ │ 留痕记录 (12) │
|
||
│ 2,300字 │ 「你怎么在这儿?」他的声音有些嘲哑。 │ │ 21:05 扩写 +120字│
|
||
│ ▶ 第5章..│ │ │ 21:03 续写 +85字 │
|
||
│ 580字 │ 「我...」她欲言又止,“ ” │ │ 20:58 改写 38字 │
|
||
│ ✔︎已完结 │ │ │
|
||
│ │ [选中文本后弹出 AI 浮动菜单] │ ─────────────── │
|
||
│ + 新章节 │ ┌────────────────────────┐ │ AI报告概览 │
|
||
│ │ │ ✨扩写 | ✍️续写 | 🔄改写 │ │ 等级: **A** │
|
||
│ │ │ 💡灵感 | 📝摘要 | ❓问笔灵│ │ 原AI率: 8.2% │
|
||
│ │ └────────────────────────┘ │ AI操作: 12次 │
|
||
│ │ │ 采纳率: 75% │
|
||
├──────────┴────────────────────────────────────────────┴─────────────────────┤
|
||
│ 上次保存: 21:08 | 自动保存: 开 | 专注模式: 关 | 快捷键: Ctrl+S 保存 Ctrl+/ 呼AI │
|
||
└────────────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
布局说明:
|
||
|
||
- **左侧 · 章节导航** — 显示所有章节 + 字数 + 当前编辑章节高亮,可拖拽排序
|
||
- **中间 · 编辑区** — 主写作区域,纯净无干扰,类似语雀/Word写作体验
|
||
- **右侧 · AI助手** — AI对话 + 留痕记录 + AI报告概览,可折叠
|
||
- **底部状态栏** — 保存状态 + 专注模式开关 + 快捷键提示
|
||
|
||
### 3.2 Slate.js 编辑器核心配置
|
||
|
||
```tsx
|
||
// editor/SlateEditor.tsx
|
||
import { createEditor, Descendant, Editor, Transforms } from 'slate';
|
||
import { Slate, Editable, withReact } from 'slate-react';
|
||
import { withHistory } from 'slate-history';
|
||
import { withChapters } from './plugins/withChapters';
|
||
import { withAutoSave } from './plugins/withAutoSave';
|
||
import { withWordCount } from './plugins/withWordCount';
|
||
import { withAITrace } from './plugins/withAITrace';
|
||
import { withMarkdownShortcuts } from './plugins/withMarkdownShortcuts';
|
||
|
||
// 自定义元素类型
|
||
type CustomElement =
|
||
| { type: 'chapter-title'; level: number; children: CustomText[] }
|
||
| { type: 'paragraph'; children: CustomText[] }
|
||
| { type: 'scene-divider'; children: CustomText[] }
|
||
| { type: 'ai-highlight'; aiAction: string; traceId: string; children: CustomText[] };
|
||
|
||
type CustomText = {
|
||
text: string;
|
||
bold?: boolean;
|
||
italic?: boolean;
|
||
underline?: boolean;
|
||
aiGenerated?: boolean; // 标记AI生成的文本
|
||
aiTraceId?: string; // 关联留痕ID
|
||
};
|
||
|
||
export function WritingEditor({ workId, chapterId }: Props) {
|
||
const editor = useMemo(() =>
|
||
withMarkdownShortcuts(
|
||
withAITrace(
|
||
withWordCount(
|
||
withAutoSave(
|
||
withChapters(
|
||
withHistory(
|
||
withReact(createEditor())
|
||
)
|
||
), { interval: 30000 } // 30秒自动保存
|
||
)
|
||
)
|
||
)
|
||
), []);
|
||
|
||
const [value, setValue] = useState<Descendant[]>(initialValue);
|
||
|
||
// 加载章节内容
|
||
useEffect(() => {
|
||
loadChapterContent(workId, chapterId).then(content => {
|
||
setValue(content);
|
||
});
|
||
}, [workId, chapterId]);
|
||
|
||
return (
|
||
<Slate editor={editor} initialValue={value} onChange={setValue}>
|
||
<Toolbar />
|
||
<Editable
|
||
className="writing-area prose prose-lg mx-auto max-w-3xl
|
||
font-serif leading-relaxed tracking-wide
|
||
min-h-screen p-8 focus:outline-none"
|
||
placeholder="开始写作..."
|
||
spellCheck={false}
|
||
renderElement={renderElement}
|
||
renderLeaf={renderLeaf}
|
||
onKeyDown={handleKeyDown}
|
||
/>
|
||
</Slate>
|
||
);
|
||
}
|
||
```
|
||
|
||
### 3.3 章节管理系统
|
||
|
||
| **功能** | **实现** | **说明** |
|
||
| --- | --- | --- |
|
||
| 章节列表 | 左侧边栏 ChapterSidebar | 显示全部章节 + 字数 + 编辑状态 |
|
||
| 新建章节 | 点击 + 新章节 | 自动编号(第N章),光标跳到标题 |
|
||
| 章节跳转 | 点击左侧章节名 | 平滑滚动到对应章节 |
|
||
| 章节拖拽排序 | Drag & Drop | 拖拽调整章节顺序,自动更新编号 |
|
||
| 章节状态 | 图标标记 | ✅已完结 / ✍️编辑中 / 📝草稿 |
|
||
| 字数统计 | 实时计算 | 每章字数 + 总字数 + 今日新增 |
|
||
|
||
### 3.4 专注模式
|
||
|
||
点击底部状态栏「专注模式」按钮后:
|
||
|
||
- 隐藏左侧章节栏 + 右侧AI面板
|
||
- 编辑区全屏居中,更宽的写作区域
|
||
- 背景切换为暗色主题(护眼)
|
||
- 快捷键 `Esc` 退出专注模式
|
||
|
||
---
|
||
|
||
## 四、Phase 1 · AI辅助写作
|
||
|
||
### 4.1 AI调用方式
|
||
|
||
作者有三种方式调用AI:
|
||
|
||
**方式一:选中文本 → AI浮动菜单**
|
||
|
||
选中一段文字后,弹出浮动菜单:
|
||
|
||
| **操作** | **图标** | **功能** | **System Prompt 核心** |
|
||
| --- | --- | --- | --- |
|
||
| 扩写 | ✨ | 将选中的文字扩展为更详细的描写 | 将以下内容扩写为更详细生动的描写,保持原文风格和人称视角。输出1.5-2倍字数。 |
|
||
| 续写 | ✍️ | 从选中位置继续写下去 | 根据上文继续写作,保持情节连贯性和人物性格一致性。生成200-500字。 |
|
||
| 改写 | 🔄 | 用不同表达重写选中内容 | 以更优美/更紧凑/更有张力的方式重写以下内容,保持原意不变。 |
|
||
| 灵感 | 💡 | 基于当前内容给出后续情节建议 | 基于以下内容,给出3个不同方向的后续情节建议,每个50字内。 |
|
||
| 摘要 | 📝 | 对选中内容生成摘要 | 用一句话概括以下内容的核心情节。 |
|
||
| 问笔灵 | ❓ | 将选中内容发给AI伙伴讨论 | 跳转到右侧AI面板,携带选中内容作为上下文 |
|
||
|
||
**方式二:快捷键 `Ctrl+/` 呼AI**
|
||
|
||
在光标位置按 `Ctrl+/`,弹出命令面板,输入自由指令:
|
||
|
||
- 「帮我写一段雨景描写」
|
||
- 「这段对话太长,缩短一半」
|
||
- 「给女主加一句内心独白」
|
||
- 「检查这一章有没有前后矛盾」
|
||
|
||
**方式三:右侧AI助手面板**
|
||
|
||
与AI伙伴(笔灵)自由对话,讨论情节、人物、世界观等。对话内容可一键插入编辑器。
|
||
|
||
### 4.2 AI响应流程
|
||
|
||
```
|
||
用户选中文本 + 点击「扩写」
|
||
↓
|
||
前端发送请求:
|
||
{
|
||
action: "expand",
|
||
selectedText: "他抬起头,看到她站在门口。",
|
||
context: {
|
||
chapterContent: "... 前后500字上下文 ...",
|
||
chapterTitle: "第5章 重逢",
|
||
workTitle: "霸总的小娇妻",
|
||
genre: "都市言情",
|
||
wordCountTarget: 3000
|
||
}
|
||
}
|
||
↓
|
||
后端构建完整 prompt + 调AI
|
||
↓
|
||
流式返回结果(SSE / WebSocket)
|
||
↓
|
||
前端在编辑器下方显示AI建议区:
|
||
┌─────────────────────────────────────┐
|
||
│ 🤖 AI建议(扩写) │
|
||
│ │
|
||
│ 他抬起头,看到她站在门口。灯光打在 │
|
||
│ 她身上,像一层柔和的金粉,勾勒出她 │
|
||
│ 纤细的轮廓。她微微侧着头,发丝从肩 │
|
||
│ 头滑落,露出一截白皙的脖颈... │
|
||
│ │
|
||
│ [✅ 采纳] [❌ 拒绝] [🔄 重新生成] │
|
||
└─────────────────────────────────────┘
|
||
↓
|
||
用户点击 [✅ 采纳]
|
||
↓
|
||
AI文本插入编辑器,带 aiGenerated=true 标记
|
||
↓
|
||
同时写入留痕记录
|
||
```
|
||
|
||
### 4.3 AI写作 API
|
||
|
||
```tsx
|
||
// POST /api/writing/ai/assist
|
||
Body: {
|
||
action: "expand" | "continue" | "rewrite" | "inspire" | "summarize" | "freeform",
|
||
selectedText: string, // 选中的文本
|
||
freeformPrompt?: string, // 自由指令(action=freeform时)
|
||
context: {
|
||
chapterId: string,
|
||
chapterContent: string, // 当前章节全文(或截取前吅500字)
|
||
chapterTitle: string,
|
||
workTitle: string,
|
||
genre: string, // 作品类型
|
||
previousChapterSummary?: string // 前一章摘要
|
||
}
|
||
}
|
||
Response (SSE 流式): {
|
||
type: "chunk" | "done",
|
||
content: string, // 每次返回一块文本
|
||
traceId: string, // 留痕ID
|
||
tokenUsage?: { // 完成时返回
|
||
prompt: number,
|
||
completion: number
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4.4 后端 AI 写作服务
|
||
|
||
```tsx
|
||
// services/aiWritingService.ts
|
||
|
||
const WRITING_PROMPTS: Record<string, (ctx: any) => string> = {
|
||
expand: (ctx) => `你是一位专业的${ctx.genre}小说写作助手。
|
||
作品:《${ctx.workTitle}》,当前章节:${ctx.chapterTitle}。
|
||
请将以下内容扩写为更详细生动的描写,保持原文风格和人称视角。
|
||
扩写到原文的1.5-2倍字数。只输出扩写后的文本,不要加任何解释。
|
||
|
||
上下文:
|
||
${ctx.chapterContent}
|
||
|
||
需要扩写的内容:
|
||
${ctx.selectedText}`,
|
||
|
||
continue: (ctx) => `你是一位专业的${ctx.genre}小说写作助手。
|
||
作品:《${ctx.workTitle}》,当前章节:${ctx.chapterTitle}。
|
||
请根据以下内容继续写作,保持情节连贯性和人物性格一致性。
|
||
生成200-500字。只输出续写的文本。
|
||
|
||
当前内容:
|
||
${ctx.chapterContent}
|
||
|
||
从这里继续:
|
||
${ctx.selectedText}`,
|
||
|
||
rewrite: (ctx) => `你是一位专业的${ctx.genre}小说写作助手。
|
||
作品:《${ctx.workTitle}》,当前章节:${ctx.chapterTitle}。
|
||
请以更优美的表达重写以下内容,保持原意不变,字数相近。
|
||
只输出重写后的文本。
|
||
|
||
原文:
|
||
${ctx.selectedText}`,
|
||
|
||
inspire: (ctx) => `你是一位专业的${ctx.genre}小说写作助手。
|
||
作品:《${ctx.workTitle}》,当前章节:${ctx.chapterTitle}。
|
||
基于以下内容,给出3个不同方向的后续情节建议,每个50字内。
|
||
格式:1. … 2. … 3. …
|
||
|
||
当前内容:
|
||
${ctx.selectedText}`,
|
||
|
||
summarize: (ctx) => `用一句话概括以下内容的核心情节:
|
||
${ctx.selectedText}`,
|
||
|
||
freeform: (ctx) => `你是一位专业的${ctx.genre}小说写作助手。
|
||
作品:《${ctx.workTitle}》,当前章节:${ctx.chapterTitle}。
|
||
|
||
当前内容:
|
||
${ctx.chapterContent}
|
||
|
||
作者的指令:
|
||
${ctx.freeformPrompt}
|
||
|
||
相关内容:
|
||
${ctx.selectedText}`
|
||
};
|
||
|
||
export async function* streamAIWriting(params: AIWritingParams) {
|
||
const prompt = WRITING_PROMPTS[params.action](params.context);
|
||
|
||
const stream = await openai.chat.completions.create({
|
||
model: 'gpt-4',
|
||
messages: [
|
||
{ role: 'system', content: prompt },
|
||
{ role: 'user', content: params.selectedText || params.freeformPrompt }
|
||
],
|
||
temperature: 0.8, // 创作类任务略高温度
|
||
max_tokens: 1500,
|
||
stream: true
|
||
});
|
||
|
||
let fullContent = '';
|
||
for await (const chunk of stream) {
|
||
const content = chunk.choices[0]?.delta?.content || '';
|
||
fullContent += content;
|
||
yield { type: 'chunk', content };
|
||
}
|
||
|
||
yield {
|
||
type: 'done',
|
||
content: fullContent,
|
||
tokenUsage: { prompt: 0, completion: 0 } // 从 stream 中提取
|
||
};
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 五、Phase 2 · 全程留痕系统
|
||
|
||
### 5.1 核心原则
|
||
|
||
<aside>
|
||
📌
|
||
|
||
**每一次AI介入,都必须留痕。无例外。**
|
||
|
||
留痕数据是AI使用报告的数据来源,也是平台透明度的基石。
|
||
|
||
作者不能删除留痕,但可以查看全部留痕。
|
||
|
||
</aside>
|
||
|
||
### 5.2 留痕数据结构
|
||
|
||
```tsx
|
||
interface AITrace {
|
||
traceId: string; // 唯一ID
|
||
workId: string; // 作品ID
|
||
chapterId: string; // 章节ID
|
||
userId: string; // 作者ID
|
||
timestamp: string; // ISO时间戳
|
||
action: 'expand' | 'continue' | 'rewrite' | 'inspire' | 'summarize' | 'freeform';
|
||
input: {
|
||
selectedText: string; // 原文(选中的文字)
|
||
prompt?: string; // 自由指令(如有)
|
||
};
|
||
output: {
|
||
generatedText: string; // AI生成的文字
|
||
tokenUsage: {
|
||
prompt: number;
|
||
completion: number;
|
||
};
|
||
};
|
||
decision: 'accepted' | 'rejected' | 'modified' | 'pending';
|
||
finalText?: string; // 如果作者修改了AI建议后采纳,记录最终文本
|
||
wordDelta: number; // 字数变化(+120 表示AI贡献了120字)
|
||
}
|
||
```
|
||
|
||
### 5.3 留痕时机
|
||
|
||
| **事件** | **记录内容** | **decision 状态** |
|
||
| --- | --- | --- |
|
||
| 用户调用AI | 记录 input + output | `pending` |
|
||
| 用户点击 采纳 | 更新 decision | `accepted` |
|
||
| 用户点击 拒绝 | 更新 decision | `rejected` |
|
||
| 用户修改后采纳 | 更新 decision + finalText | `modified` |
|
||
| 用户关闭建议区(未操作) | 更新 decision | `rejected` |
|
||
|
||
### 5.4 留痕显示
|
||
|
||
右侧AI面板的「留痕记录」区域,按时间倒序显示:
|
||
|
||
```
|
||
留痕记录 (12)
|
||
│ 21:05 ✨扩写 +120字 ✅采纳
|
||
│ 21:03 ✍️续写 +85字 ✅采纳
|
||
│ 20:58 🔄改写 38字 ❌拒绝
|
||
│ 20:55 💡灵感 3条 ✅采纳#2
|
||
│ 20:50 ✨扩写 +200字 ✏️修改后采纳
|
||
│ ...
|
||
```
|
||
|
||
点击每条记录可展开查看详情(原文 → AI生成 → 最终采纳)。
|
||
|
||
### 5.5 API
|
||
|
||
```tsx
|
||
// 记录留痕
|
||
POST /api/writing/traces
|
||
Body: { ...AITrace }
|
||
|
||
// 获取章节留痕列表
|
||
GET /api/writing/traces?workId=xxx&chapterId=xxx
|
||
Response: { traces: AITrace[] }
|
||
|
||
// 更新留痕状态(采纳/拒绝)
|
||
PATCH /api/writing/traces/:traceId
|
||
Body: { decision: "accepted" | "rejected" | "modified", finalText?: string }
|
||
```
|
||
|
||
### 5.6 Notion 数据库 — AI留痕表
|
||
|
||
| **字段名** | **类型** | **说明** |
|
||
| --- | --- | --- |
|
||
| 留痕ID | title | 唯一标识 |
|
||
| 作品ID | text | 关联作品 |
|
||
| 章节ID | text | 关联章节 |
|
||
| 作者ID | text | 关联用户 |
|
||
| AI操作类型 | select | expand / continue / rewrite / inspire / summarize / freeform |
|
||
| 原文 | text | 选中的文字 |
|
||
| AI生成文本 | text | AI输出 |
|
||
| 最终文本 | text | 作者修改后的文本(如有) |
|
||
| 决策 | select | accepted / rejected / modified / pending |
|
||
| 字数变化 | number | AI贡献的字数变化 |
|
||
| Token消耗 | number | prompt + completion tokens |
|
||
| 操作时间 | date | 时间戳 |
|
||
|
||
---
|
||
|
||
## 六、Phase 3 · AI使用报告(ABCD级)
|
||
|
||
### 6.1 报告等级定义
|
||
|
||
<aside>
|
||
🏅
|
||
|
||
**ABCD级报告是平台的核心信任机制。**
|
||
|
||
每篇作品自动生成,作者不能修改,编辑和读者都能看到。
|
||
|
||
</aside>
|
||
|
||
| **等级** | **原AI率** | **含义** | **标签颜色** | **说明** |
|
||
| --- | --- | --- | --- | --- |
|
||
| **A** | ≤10% | 几乎全部原创 | 🟢 绿色 | AI仅提供少量灵感或微调,创意完全归作者 |
|
||
| **B** | 10%-30% | AI辅助创作 | 🟡 黄色 | AI提供了部分扩写或辅助,但核心创意和架构归作者 |
|
||
| **C** | 30%-50% | AI深度参与 | 🟠 橙色 | AI参与了大量写作,但作者进行了实质性修改和编辑 |
|
||
| **D** | >50% | AI主导写作 | 🔴 红色 | AI生成了大部分内容,作者贡献较少 |
|
||
|
||
### 6.2 原AI率计算公式
|
||
|
||
```tsx
|
||
// utils/reportGenerator.ts
|
||
|
||
interface AIReportData {
|
||
totalWords: number; // 作品总字数
|
||
aiAcceptedWords: number; // AI生成且被采纳的字数
|
||
aiModifiedWords: number; // AI生成但被修改后采纳的字数
|
||
humanOnlyWords: number; // 纯人类写作的字数
|
||
traces: AITrace[]; // 全部留痕记录
|
||
}
|
||
|
||
function calculateRawAIRate(data: AIReportData): number {
|
||
// 原AI率 = AI采纳字数 / 总字数
|
||
// “修改后采纳”按50%计入AI字数(作者进行了修改,算半个原创)
|
||
const effectiveAIWords = data.aiAcceptedWords + (data.aiModifiedWords * 0.5);
|
||
return Math.round((effectiveAIWords / data.totalWords) * 100 * 10) / 10;
|
||
}
|
||
|
||
function getGrade(rawAIRate: number): 'A' | 'B' | 'C' | 'D' {
|
||
if (rawAIRate <= 10) return 'A';
|
||
if (rawAIRate <= 30) return 'B';
|
||
if (rawAIRate <= 50) return 'C';
|
||
return 'D';
|
||
}
|
||
|
||
function generateReport(data: AIReportData): AIReport {
|
||
const rawAIRate = calculateRawAIRate(data);
|
||
const grade = getGrade(rawAIRate);
|
||
|
||
const traceStats = {
|
||
total: data.traces.length,
|
||
accepted: data.traces.filter(t => t.decision === 'accepted').length,
|
||
rejected: data.traces.filter(t => t.decision === 'rejected').length,
|
||
modified: data.traces.filter(t => t.decision === 'modified').length,
|
||
byAction: {
|
||
expand: data.traces.filter(t => t.action === 'expand').length,
|
||
continue: data.traces.filter(t => t.action === 'continue').length,
|
||
rewrite: data.traces.filter(t => t.action === 'rewrite').length,
|
||
inspire: data.traces.filter(t => t.action === 'inspire').length,
|
||
freeform: data.traces.filter(t => t.action === 'freeform').length,
|
||
}
|
||
};
|
||
|
||
return {
|
||
workId: data.workId,
|
||
grade,
|
||
rawAIRate,
|
||
totalWords: data.totalWords,
|
||
aiContributionWords: data.aiAcceptedWords + data.aiModifiedWords,
|
||
humanWords: data.humanOnlyWords,
|
||
acceptanceRate: Math.round((traceStats.accepted + traceStats.modified) / traceStats.total * 100),
|
||
traceStats,
|
||
generatedAt: new Date().toISOString(),
|
||
// 报告摘要(用AI生成一句话描述)
|
||
summary: `本作品${grade}级,原AI率${rawAIRate}%。共${data.totalWords}字,AI参与${traceStats.total}次,采纳率${traceStats.accepted + traceStats.modified}/${traceStats.total}。`
|
||
};
|
||
}
|
||
```
|
||
|
||
### 6.3 报告展示界面
|
||
|
||
```
|
||
┌─────────────────────────────────────────────┐
|
||
│ AI使用报告 · 《霸总的小娇妻》 │
|
||
├─────────────────────────────────────────────┤
|
||
│ │
|
||
│ ┌─────────────┐ │
|
||
│ │ │ │
|
||
│ │ 🟢 A │ │
|
||
│ │ 8.2% │ │
|
||
│ │ │ │
|
||
│ └─────────────┘ │
|
||
│ 几乎全部原创 │
|
||
│ │
|
||
├─────────────────────────────────────────────┤
|
||
│ 总字数 45,230字 │
|
||
│ 人类原创 41,520字 (91.8%) │
|
||
│ AI贡献 3,710字 (8.2%) │
|
||
├─────────────────────────────────────────────┤
|
||
│ AI操作统计 │
|
||
│ • 总调用: 47次 │
|
||
│ • 扩写: 18次 续写: 12次 改写: 8次 │
|
||
│ • 灵感: 6次 自由指令: 3次 │
|
||
│ • 采纳率: 75% (35/47) │
|
||
│ • 修改后采纳: 8次 │
|
||
├─────────────────────────────────────────────┤
|
||
│ 章节明细 │
|
||
│ 第1章: A(3.2%) 第2章: A(5.1%) │
|
||
│ 第3章: B(12.4%) 第4章: A(7.8%) │
|
||
│ 第5章: A(9.0%) ... │
|
||
├─────────────────────────────────────────────┤
|
||
│ 报告生成时间: 2026-03-25 21:30 │
|
||
│ 本报告由系统自动生成,作者不可修改。 │
|
||
└─────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 6.4 报告 API
|
||
|
||
```tsx
|
||
// 生成/更新作品报告
|
||
POST /api/writing/reports/generate
|
||
Body: { workId: string }
|
||
Response: { report: AIReport }
|
||
|
||
// 获取作品报告
|
||
GET /api/writing/reports/:workId
|
||
Response: { report: AIReport }
|
||
|
||
// 获取章节级别报告
|
||
GET /api/writing/reports/:workId/chapters
|
||
Response: { chapters: ChapterReport[] }
|
||
```
|
||
|
||
---
|
||
|
||
## 七、作品管理
|
||
|
||
### 7.1 作品列表页
|
||
|
||
用户从 Dashboard 点击「开始写作」进入作品列表:
|
||
|
||
```
|
||
┌─────────────────────────────────────────────┐
|
||
│ 📚 我的作品 [+ 新建作品] │
|
||
├─────────────────────────────────────────────┤
|
||
│ │
|
||
│ ┌─────────────────────────────────────┐ │
|
||
│ │ 《霸总的小娇妻》 🟢 A (8.2%) │ │
|
||
│ │ 都市言情 · 20章 · 45,230字 · 连载中 │ │
|
||
│ │ 最后编辑: 10分钟前 │ │
|
||
│ └─────────────────────────────────────┘ │
|
||
│ │
|
||
│ ┌─────────────────────────────────────┐ │
|
||
│ │ 《星辰变》 🟡 B (15.6%) │ │
|
||
│ │ 仙侠奇幻 · 8章 · 18,400字 · 草稿 │ │
|
||
│ │ 最后编辑: 2天前 │ │
|
||
│ └─────────────────────────────────────┘ │
|
||
│ │
|
||
└─────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 7.2 新建作品流程
|
||
|
||
```
|
||
用户点击 [+ 新建作品]
|
||
↓
|
||
弹出表单:
|
||
- 作品名称(必填)
|
||
- 作品类型(选择):都市言情 / 仙侠奇幻 / 悬疑推理 / 科幻 / 历史 / 其他
|
||
- 简介(选填)
|
||
↓
|
||
创建成功 → 自动进入编辑器 → 自动创建「第1章」
|
||
```
|
||
|
||
### 7.3 Notion 数据库 — 作品表
|
||
|
||
| **字段名** | **类型** | **说明** |
|
||
| --- | --- | --- |
|
||
| 作品ID | title | 唯一标识 |
|
||
| 作品名称 | text | 作品标题 |
|
||
| 作者ID | text | 关联用户 |
|
||
| 作品类型 | select | 都市言情 / 仙侠奇幻 / 悬疑推理 / 科幻 / 历史 / 其他 |
|
||
| 总字数 | number | 实时更新 |
|
||
| 章节数 | number | 实时更新 |
|
||
| AI报告等级 | select | A / B / C / D |
|
||
| 原AI率 | number | 百分比 |
|
||
| 状态 | select | 草稿 / 连载中 / 已完结 / 已发布 |
|
||
| 简介 | text | 作品简介 |
|
||
| 创建时间 | date | 创建时间 |
|
||
| 最后编辑 | date | 最后编辑时间 |
|
||
|
||
### 7.4 Notion 数据库 — 章节表
|
||
|
||
| **字段名** | **类型** | **说明** |
|
||
| --- | --- | --- |
|
||
| 章节ID | title | 唯一标识 |
|
||
| 作品ID | text | 关联作品 |
|
||
| 章节标题 | text | 如「第1章 相遇」 |
|
||
| 章节序号 | number | 排序用 |
|
||
| 内容 | text | Slate JSON 序列化存储 |
|
||
| 字数 | number | 本章字数 |
|
||
| 状态 | select | 草稿 / 编辑中 / 已完结 |
|
||
| 最后编辑 | date | 最后保存时间 |
|
||
|
||
---
|
||
|
||
## 八、API 总览
|
||
|
||
| **接口** | **方法** | **功能** | **鉴权** |
|
||
| --- | --- | --- | --- |
|
||
| `/api/writing/works` | GET | 获取我的作品列表 | JWT |
|
||
| `/api/writing/works` | POST | 新建作品 | JWT |
|
||
| `/api/writing/works/:id` | GET | 获取作品详情 | JWT |
|
||
| `/api/writing/works/:id` | PATCH | 更新作品信息 | JWT |
|
||
| `/api/writing/works/:id/chapters` | GET | 获取章节列表 | JWT |
|
||
| `/api/writing/works/:id/chapters` | POST | 新建章节 | JWT |
|
||
| `/api/writing/chapters/:id` | GET | 获取章节内容 | JWT |
|
||
| `/api/writing/chapters/:id` | PUT | 保存章节内容 | JWT |
|
||
| `/api/writing/chapters/:id/order` | PATCH | 调整章节顺序 | JWT |
|
||
| `/api/writing/ai/assist` | POST | AI辅助写作(SSE流) | JWT |
|
||
| `/api/writing/traces` | POST | 记录留痕 | JWT |
|
||
| `/api/writing/traces` | GET | 获取留痕列表 | JWT |
|
||
| `/api/writing/traces/:id` | PATCH | 更新留痕状态 | JWT |
|
||
| `/api/writing/reports/:workId` | GET | 获取AI报告 | JWT |
|
||
| `/api/writing/reports/generate` | POST | 生成/更新报告 | JWT |
|
||
|
||
---
|
||
|
||
## 九、路由规划
|
||
|
||
| **路由** | **页面** | **说明** |
|
||
| --- | --- | --- |
|
||
| `/writing/works` | WorkListPage | 作品列表 |
|
||
| `/writing/editor/:workId` | EditorPage | 码字台(默认打开最后编辑章节) |
|
||
| `/writing/editor/:workId/:chapterId` | EditorPage | 码字台(指定章节) |
|
||
| `/writing/report/:workId` | AIReportPage | AI使用报告详情 |
|
||
|
||
---
|
||
|
||
## 十、快捷键
|
||
|
||
| **快捷键** | **功能** |
|
||
| --- | --- |
|
||
| `Ctrl+S` | 手动保存 |
|
||
| `Ctrl+/` | 呼AI助手(自由指令) |
|
||
| `Ctrl+Shift+E` | 扩写选中文本 |
|
||
| `Ctrl+Shift+W` | 续写 |
|
||
| `Ctrl+Shift+R` | 改写选中文本 |
|
||
| `Ctrl+Z` | 撤销 |
|
||
| `Ctrl+Shift+Z` | 重做 |
|
||
| `Esc` | 退出专注模式 / 关闭AI建议区 |
|
||
| `F11` | 切换专注模式 |
|
||
|
||
---
|
||
|
||
## 十一、验收标准
|
||
|
||
| **验收项** | **标准** |
|
||
| --- | --- |
|
||
| 编辑器可用 | 可流畅输入中文,格式化正常,无卡顿 |
|
||
| 章节管理 | 新建/切换/拖拽排序正常,字数实时统计 |
|
||
| 自动保存 | 30秒自动保存 + 失焦保存,底部状态栏显示保存时间 |
|
||
| AI浮动菜单 | 选中文本后弹出6个AI操作按钮 |
|
||
| AI流式响应 | AI结果流式显示(SSE),不是一次性加载 |
|
||
| 采纳/拒绝 | 采纳后AI文本插入编辑器,拒绝后清除建议区 |
|
||
| 留痕记录 | 每次AI操作自动留痕,右侧面板可查看 |
|
||
| AI报告 | 可生成ABCD级报告,等级和数据正确 |
|
||
| 专注模式 | 切换后全屏写作,暗色主题,Esc退出 |
|
||
| 移动端 | 手机端可编辑(左右侧栏自动收起) |
|
||
| 数据持久化 | 作品/章节/留痕全部存入 Notion 数据库 |
|
||
|
||
---
|
||
|
||
## 十二、执行时序
|
||
|
||
```
|
||
Phase 0: Slate.js编辑器 + 章节管理 + 工具栏 + 自动保存(预计 4h)
|
||
↓
|
||
Phase 1: AI辅助写作(浮动菜单 + SSE流 + 6种Action + 右侧AI面板)(预计 3h)
|
||
↓
|
||
Phase 2: 全程留痕系统(自动记录 + 留痕显示 + Notion存储)(预计 2h)
|
||
↓
|
||
Phase 3: AI使用报告(ABCD计算 + 报告界面 + 作品列表显示)(预计 2h)
|
||
↓
|
||
Phase 4: 作品管理(列表页 + 新建作品 + CRUD API)(预计 1.5h)
|
||
↓
|
||
Phase 5: 前后端联调 + Nginx路由 + 部署(预计 1.5h)
|
||
↓
|
||
→ 预览站测试 → 人类验收 → 正式站上线
|
||
```
|
||
|
||
---
|
||
|
||
## 十三、后续扩展预留
|
||
|
||
本期完成后,后续可扩展(不在本指令范围):
|
||
|
||
- **导出功能** — 导出为 TXT / DOCX / PDF
|
||
- **协作编辑** — 多人实时协作编辑(CRDT)
|
||
- **版本历史** — 每次保存的完整历史记录
|
||
- **模板库** — 网文各类型开头/大纲模板
|
||
- **章节统计** — 写作时间曲线、字数趋势图
|
||
- **多端同步** — 电脑/手机/平板无缝切换
|
||
|
||
---
|
||
|
||
<aside>
|
||
🔏
|
||
|
||
**签发确认**
|
||
|
||
霜砚(AG-SY-01)· Notion 执行 AI 人格体
|
||
|
||
冰朔(TCS-0002∞)· 语言架构师 · 创始人
|
||
|
||
肥猫(TCS-GL-07∞ / DEV-002)· 系统副控 · 需求发起人
|
||
|
||
2026-03-25 21:30 CST
|
||
|
||
**版权**:国作登字-2026-A-00037559
|
||
|
||
**需求来源**:📘 中国网文行业·光湖纪元语言人格平台|完整说明书
|
||
|
||
</aside> |