@waterwx/dsh-novel-forge 1.7.2 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/lib/client.js +3788 -600
- package/lib/client.js.map +1 -1
- package/lib/index.js +1001 -83
- package/lib/index.js.map +1 -1
- package/lib/types/author-assets.d.ts +25 -0
- package/lib/types/client/api.d.ts +18 -0
- package/lib/types/client/panel/AdaptModeView.d.ts +4 -0
- package/lib/types/client/panel/AuthorAssetsView.d.ts +4 -0
- package/lib/types/client/panel/AuthorHome.d.ts +20 -0
- package/lib/types/client/panel/ProgressHomeView.d.ts +5 -0
- package/lib/types/client/panel/SettingsView.d.ts +14 -0
- package/lib/types/client/text.d.ts +9 -0
- package/lib/types/engine.d.ts +24 -1
- package/lib/types/index.d.ts +8 -0
- package/lib/types/protocol.d.ts +206 -10
- package/lib/types/shot-language.d.ts +46 -0
- package/lib/types/story-beat-language.d.ts +35 -0
- package/package.json +4 -2
- package/skills/chapter-batch/SKILL.md +81 -0
- package/src/author-assets.ts +166 -0
- package/src/client/api.ts +41 -0
- package/src/client/mount.tsx._new +97 -0
- package/src/client/mount.tsx._nf +97 -0
- package/src/client/mount.tsx._tmp +97 -0
- package/src/client/panel/AdaptModeView.tsx +204 -0
- package/src/client/panel/AuthorAssetsView.tsx +206 -0
- package/src/client/panel/AuthorHome.tsx +93 -0
- package/src/client/panel/CreateBookView.tsx +4 -0
- package/src/client/panel/ImportModal.tsx +13 -3
- package/src/client/panel/NovelPanel.tsx +48 -16
- package/src/client/panel/ProgressHomeView.tsx +87 -0
- package/src/client/panel/RunPanel.tsx +1 -1
- package/src/client/panel/SceneLibrary.tsx +1 -1
- package/src/client/panel/SettingsView.tsx +285 -0
- package/src/client/panel/ShelfView.tsx +2 -2
- package/src/client/panel/StoryboardTab.tsx +42 -10
- package/src/client/panel/panel.module.css +325 -0
- package/src/client/sidebar-entry.ts +1 -1
- package/src/client/text.ts +28 -0
- package/src/engine.ts +256 -14
- package/src/index.ts +21 -0
- package/src/protocol.ts +218 -10
- package/src/routes.ts +204 -7
- package/src/run.ts +5 -4
- package/src/shot-language.ts +181 -0
- package/src/story-beat-language.ts +130 -0
- package/lib/types/client/panel/RoleVisualPanel.d.ts +0 -15
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 作者资产库/总数据(跨书)— 按作者维度聚合的可复用资产。
|
|
3
|
+
* 与书架同惯例持久化到 ~/.dsh/dsh-novel-forge-author-assets.json。
|
|
4
|
+
* 提供读取/持久化/新增或更新/删除,以及「导入默认」:把书架书的写作资产/角色 +
|
|
5
|
+
* 内置全局库(题材/反AI规则/风格模板/推进模式)批量沉淀成资产条目(默认库)。
|
|
6
|
+
*/
|
|
7
|
+
import type { AuthorAssetLibrary, AuthorStyleAsset } from './protocol.ts';
|
|
8
|
+
/** 作者资产库配置文件路径。 */
|
|
9
|
+
export declare function authorAssetsFile(): string;
|
|
10
|
+
/** 读取作者资产库(不存在/损坏则返回空库,不抛错)。 */
|
|
11
|
+
export declare function loadAuthorAssets(): AuthorAssetLibrary;
|
|
12
|
+
/** 持久化作者资产库。 */
|
|
13
|
+
export declare function saveAuthorAssets(library: AuthorAssetLibrary): void;
|
|
14
|
+
/** 新建一条资产(自动生成 id 与时间戳)。 */
|
|
15
|
+
export declare function createAuthorAsset(input: Omit<AuthorStyleAsset, 'id' | 'createdAt' | 'updatedAt'>): AuthorStyleAsset;
|
|
16
|
+
/** 按 id 更新一条资产;不存在则追加。 */
|
|
17
|
+
export declare function upsertAuthorAsset(input: AuthorStyleAsset): AuthorAssetLibrary;
|
|
18
|
+
/** 删除一条资产;返回更新后的资产库。 */
|
|
19
|
+
export declare function removeAuthorAsset(id: string): AuthorAssetLibrary;
|
|
20
|
+
/**
|
|
21
|
+
* 导入默认:把书架所有书的写作资产/角色 + 内置全局库批量沉淀到作者资产库。
|
|
22
|
+
* 按 `kind:name` 去重(已存在则跳过),不覆盖用户已有条目。
|
|
23
|
+
* @returns 更新后的资产库。
|
|
24
|
+
*/
|
|
25
|
+
export declare function importDefaultAuthorAssets(): AuthorAssetLibrary;
|
|
@@ -184,4 +184,22 @@ export declare class NovelApi {
|
|
|
184
184
|
assistantClear(): Promise<{
|
|
185
185
|
ok: boolean;
|
|
186
186
|
}>;
|
|
187
|
+
/** 作者资产库/总数据:读取跨书可复用资产。 */
|
|
188
|
+
authorAssets(): Promise<import('../protocol.ts').AuthorAssetsResponse>;
|
|
189
|
+
/** 作者资产库:新增/更新一条资产(upsert by id)。 */
|
|
190
|
+
authorAssetsUpsert(asset: import('../protocol.ts').AuthorStyleAsset): Promise<import('../protocol.ts').AuthorAssetsResponse>;
|
|
191
|
+
/** 作者资产库:删除一条资产。 */
|
|
192
|
+
authorAssetsRemove(id: string): Promise<import('../protocol.ts').AuthorAssetsResponse>;
|
|
193
|
+
/** 作者资产库:导入默认(书架书的写作资产/角色 + 内置全局库)批量沉淀。 */
|
|
194
|
+
authorAssetsImportDefault(): Promise<import('../protocol.ts').AuthorAssetsResponse>;
|
|
195
|
+
/** 改编模式 P0:上传全文 → 原文设定卡片 / 可改范围矩阵。 */
|
|
196
|
+
adaptAnalyze(text: string, filePath?: string): Promise<import('../protocol.ts').AdaptAnalyzeResponse>;
|
|
197
|
+
/** 改编模式 P1:确认要改的维度 → 生成映射表/改编规则/联动影响清单。 */
|
|
198
|
+
adaptPropose(req: import('../protocol.ts').AdaptProposeRequest): Promise<import('../protocol.ts').AdaptProposeResponse>;
|
|
199
|
+
/** 改编模式 P2:执行术语替换(全局替换 + 命中统计 + 改编文本预览)。 */
|
|
200
|
+
adaptExecute(req: import('../protocol.ts').AdaptExecuteRequest): Promise<import('../protocol.ts').AdaptExecuteResponse>;
|
|
201
|
+
/** 主题自定义背景:上传图片,服务端存盘并返回可访问 URL。 */
|
|
202
|
+
themeBackgroundUpload(dataUrl: string): Promise<{
|
|
203
|
+
url: string;
|
|
204
|
+
}>;
|
|
187
205
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { NovelApi } from '../api.ts';
|
|
2
|
+
import type { BookshelfSnapshot } from '../../protocol.ts';
|
|
3
|
+
export declare function AuthorHome({ api, shelf, onOpenBook, onReadBook, onAddBook, onImportBook, onOpenSettings, onTheme, onBackground, onOpacity, adaptEnabled }: {
|
|
4
|
+
api: NovelApi;
|
|
5
|
+
shelf: BookshelfSnapshot;
|
|
6
|
+
onOpenBook: (id: string) => void;
|
|
7
|
+
onReadBook: (id: string) => void;
|
|
8
|
+
onAddBook: () => void;
|
|
9
|
+
onImportBook: () => void;
|
|
10
|
+
/** 兼容旧入口:首页设置现为独立设置页,此回调保留但不再使用。 */
|
|
11
|
+
onOpenSettings?: () => void;
|
|
12
|
+
/** 主题/模式/密度变化回调(供面板根容器实时生效)。 */
|
|
13
|
+
onTheme?: (theme: 'liquid' | 'neumorph' | 'macos' | 'clay', mode: 'system' | 'light' | 'dark', density: 'comfort' | 'compact' | 'spacious') => void;
|
|
14
|
+
/** 自定义背景变化回调。 */
|
|
15
|
+
onBackground?: (bg: string | undefined, blur: number) => void;
|
|
16
|
+
/** 玻璃透明度变化回调。 */
|
|
17
|
+
onOpacity?: (n: number) => void;
|
|
18
|
+
/** 是否启用改编模式(默认 false=隐藏入口)。 */
|
|
19
|
+
adaptEnabled?: boolean;
|
|
20
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { NovelApi } from '../api.ts';
|
|
2
|
+
type SettingsTab = 'model' | 'writing' | 'image' | 'files' | 'appearance' | 'background';
|
|
3
|
+
type ThemeMode = 'system' | 'light' | 'dark';
|
|
4
|
+
type ThemeName = 'liquid' | 'neumorph' | 'macos' | 'clay';
|
|
5
|
+
type ThemeDensity = 'comfort' | 'compact' | 'spacious';
|
|
6
|
+
export declare function SettingsView({ api, onTheme, onSettingsTab, onEditorFontSize, onBackground, onOpacity }: {
|
|
7
|
+
api: NovelApi;
|
|
8
|
+
onTheme?: (theme: ThemeName, mode: ThemeMode, density: ThemeDensity) => void;
|
|
9
|
+
onSettingsTab?: (tab: SettingsTab) => void;
|
|
10
|
+
onEditorFontSize?: (n: number) => void;
|
|
11
|
+
onBackground?: (bg: string | undefined, blur: number) => void;
|
|
12
|
+
onOpacity?: (n: number) => void;
|
|
13
|
+
}): import("react").JSX.Element;
|
|
14
|
+
export {};
|
package/lib/types/engine.d.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
export declare const COMPLIANCE_REDLINES: ReadonlyArray<string>;
|
|
14
14
|
import type { Context } from '@deepseek-ai/cordis';
|
|
15
|
-
import type { AuditIssue, AuthorReview, BreakdownResponse, ChapterPlan, Foreshadow, NovelConfig, OutlineCandidate, Plotline, PlotlineHealthReport, PlotlinePlan, ProjectState, ReviewReport, RoleRecord, RoleStatusCard, SceneCard, StoryBible, StoryboardSkeleton, StoryboardTable, StoryboardPrompt, MangaRoleCandidate, Volume, WorldState } from './protocol.ts';
|
|
15
|
+
import type { AdaptationDimension, AdaptAnalyzeResponse, AdaptationMapping, AdaptProposeResponse, AuditIssue, AuthorReview, BreakdownResponse, ChapterPlan, Foreshadow, NovelConfig, OutlineCandidate, Plotline, PlotlineHealthReport, PlotlinePlan, ProjectState, ReviewReport, RoleRecord, RoleStatusCard, SceneCard, StoryBible, StoryboardSkeleton, StoryboardTable, StoryboardPrompt, MangaRoleCandidate, Volume, WorldState } from './protocol.ts';
|
|
16
16
|
/** Project state file name inside the output dir. */
|
|
17
17
|
export declare const PROJECT_FILE = "novel-project.json";
|
|
18
18
|
/** Chapter output file name, e.g. 第001章_开篇.md */
|
|
@@ -217,6 +217,29 @@ export declare function generateStoryboardSkeleton(ctx: Context, config: NovelCo
|
|
|
217
217
|
* 两阶段:分批提取章节事件摘要 → 汇总生成大纲。不修改章节/设定,只返回大纲文本。
|
|
218
218
|
*/
|
|
219
219
|
export declare function reverseOutlineFromChapters(ctx: Context, config: NovelConfig, project: ProjectState, outputDir: string, onProgress?: (done: number, total: number, phase: string) => void): Promise<string>;
|
|
220
|
+
/**
|
|
221
|
+
* 改编模式 P0:全文分析 → 原文设定卡片 / 可改范围矩阵。
|
|
222
|
+
* 拆章统计 + 取样正文,让 LLM 一次输出结构化 JSON:
|
|
223
|
+
* { bookName, outline, dimensions: [{key,title,mutability,current,evidence,candidates,impact,risk}] }。
|
|
224
|
+
*/
|
|
225
|
+
export declare function analyzeAdaptation(ctx: Context, config: NovelConfig, text: string): Promise<AdaptAnalyzeResponse>;
|
|
226
|
+
/** 改编方案:由用户勾选的维度与新值,生成 LLM 映射表/规则/影响清单。 */
|
|
227
|
+
export declare function proposeAdaptation(ctx: Context, config: NovelConfig, text: string, selections: Array<{
|
|
228
|
+
key: string;
|
|
229
|
+
title: string;
|
|
230
|
+
current: string;
|
|
231
|
+
target: string;
|
|
232
|
+
mutability: string;
|
|
233
|
+
}>, dimensions?: AdaptationDimension[]): Promise<AdaptProposeResponse>;
|
|
234
|
+
/** 剧本术语替换执行:按映射表做精确替换并统计命中。 */
|
|
235
|
+
export declare function applyAdaptationReplacements(text: string, mappings: AdaptationMapping[]): {
|
|
236
|
+
adaptedText: string;
|
|
237
|
+
hits: Array<{
|
|
238
|
+
source: string;
|
|
239
|
+
target: string;
|
|
240
|
+
count: number;
|
|
241
|
+
}>;
|
|
242
|
+
};
|
|
220
243
|
/**
|
|
221
244
|
* 摘要 + 事实抽取合并为一次 LLM 调用(省一次调用与一次正文输入,
|
|
222
245
|
* 批量生成时整体开销约省 25%)。
|
package/lib/types/index.d.ts
CHANGED
|
@@ -57,6 +57,14 @@ export interface Config {
|
|
|
57
57
|
imageApiModel?: string;
|
|
58
58
|
/** 是否启用豆包生图(旧字段,兼容迁移用)。 */
|
|
59
59
|
imageApiEnabled?: boolean;
|
|
60
|
+
/** 自定义背景图(URL / dataURL / 服务端路径引用)。 */
|
|
61
|
+
themeBackground?: string;
|
|
62
|
+
/** 自定义背景遮罩/模糊强度 0-80。 */
|
|
63
|
+
themeBackgroundBlur?: number;
|
|
64
|
+
/** 玻璃透明度 0-100(100=当前原样)。 */
|
|
65
|
+
themeOpacity?: number;
|
|
66
|
+
/** 是否启用改编模式(默认关闭)。 */
|
|
67
|
+
enableAdaptMode?: boolean;
|
|
60
68
|
}
|
|
61
69
|
export declare const Config: z<Config>;
|
|
62
70
|
/** Model-facing announcement: plugin presence, capabilities, and limits. */
|
package/lib/types/protocol.d.ts
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* state file format, and the NDJSON generation stream frames all live here so
|
|
5
5
|
* both halves spell exactly one vocabulary.
|
|
6
6
|
*/
|
|
7
|
+
import type { ShotSizeId, CameraMoveId, CompositionId, LightingId } from './shot-language.ts';
|
|
8
|
+
import type { StoryFunctionId, EmotionId } from './story-beat-language.ts';
|
|
7
9
|
/** The /api/dsh-novel-forge route family (same-origin, loopback-fenced). */
|
|
8
10
|
export declare const NOVEL_API: {
|
|
9
11
|
readonly status: "/api/dsh-novel-forge/status";
|
|
@@ -102,6 +104,24 @@ export declare const NOVEL_API: {
|
|
|
102
104
|
readonly runStatus: "/api/dsh-novel-forge/run/status";
|
|
103
105
|
readonly config: "/api/dsh-novel-forge/config";
|
|
104
106
|
readonly openFolder: "/api/dsh-novel-forge/open-folder";
|
|
107
|
+
/** 作者资产库/总数据:读取个人跨书资产(笔法/红线/套路/角色模板/世界观模板)。 */
|
|
108
|
+
readonly authorAssets: "/api/dsh-novel-forge/author-assets";
|
|
109
|
+
/** 作者资产库:新增/更新一条资产(upsert by id)。 */
|
|
110
|
+
readonly authorAssetsUpsert: "/api/dsh-novel-forge/author-assets/upsert";
|
|
111
|
+
/** 作者资产库:删除一条资产。 */
|
|
112
|
+
readonly authorAssetsRemove: "/api/dsh-novel-forge/author-assets/remove";
|
|
113
|
+
/** 作者资产库:导入默认(书架书的写作资产/角色 + 内置全局库)批量沉淀。 */
|
|
114
|
+
readonly authorAssetsImportDefault: "/api/dsh-novel-forge/author-assets/import-default";
|
|
115
|
+
/** 改编模式:上传全文 → 分析 → 原文设定卡片/可改范围矩阵。 */
|
|
116
|
+
readonly adaptAnalyze: "/api/dsh-novel-forge/adapt/analyze";
|
|
117
|
+
/** 改编模式:确认要改的维度 → 生成映射表/改编规则/联动影响清单。 */
|
|
118
|
+
readonly adaptPropose: "/api/dsh-novel-forge/adapt/propose";
|
|
119
|
+
/** 改编模式:执行术语替换(全局替换 + 命中统计 + 改编文本预览)。 */
|
|
120
|
+
readonly adaptExecute: "/api/dsh-novel-forge/adapt/execute";
|
|
121
|
+
/** 主题自定义背景:上传图片(POST,存盘并返回服务端 URL)。 */
|
|
122
|
+
readonly themeBackgroundUpload: "/api/dsh-novel-forge/theme/background";
|
|
123
|
+
/** 主题自定义背景:读取已上传文件(GET prefix,/theme/background/<name>)。 */
|
|
124
|
+
readonly themeBackgroundGet: "/api/dsh-novel-forge/theme/background";
|
|
105
125
|
};
|
|
106
126
|
/** 书架:一本书的条目。 */
|
|
107
127
|
export interface BookEntry {
|
|
@@ -208,10 +228,10 @@ export interface StoryboardBeat {
|
|
|
208
228
|
id: string;
|
|
209
229
|
/** 事件一句话(发生了什么)。 */
|
|
210
230
|
event: string;
|
|
211
|
-
/**
|
|
212
|
-
emotion:
|
|
213
|
-
/**
|
|
214
|
-
function:
|
|
231
|
+
/** 情绪走向(情绪词 id 数组,来自 story-beat-language 词库,链式)。 */
|
|
232
|
+
emotion: EmotionId[];
|
|
233
|
+
/** 叙事功能(枚举 id,来自 story-beat-language 词库)。 */
|
|
234
|
+
function: StoryFunctionId;
|
|
215
235
|
/** 因果:承接上一节拍的原因(可选)。 */
|
|
216
236
|
cause?: string;
|
|
217
237
|
}
|
|
@@ -239,10 +259,12 @@ export interface StoryboardShot {
|
|
|
239
259
|
id: string;
|
|
240
260
|
/** 挂载的节拍 id(骨架中的 b1…)。 */
|
|
241
261
|
beatId: string;
|
|
242
|
-
/**
|
|
243
|
-
shot:
|
|
244
|
-
/**
|
|
245
|
-
camera:
|
|
262
|
+
/** 景别(枚举 id,来自 shot-language 词库)。 */
|
|
263
|
+
shot: ShotSizeId;
|
|
264
|
+
/** 机位与运镜(枚举 id 数组,来自 shot-language 词库)。 */
|
|
265
|
+
camera: CameraMoveId[];
|
|
266
|
+
/** 构图(可选,枚举 id)。 */
|
|
267
|
+
composition?: CompositionId;
|
|
246
268
|
/** 时长(秒,1-12)。 */
|
|
247
269
|
duration: number;
|
|
248
270
|
/** 画面内容:角色动作 + 表情 + 服装/标志物。 */
|
|
@@ -251,8 +273,8 @@ export interface StoryboardShot {
|
|
|
251
273
|
line: string;
|
|
252
274
|
/** 音效(无则空字符串)。 */
|
|
253
275
|
sound: string;
|
|
254
|
-
/**
|
|
255
|
-
light:
|
|
276
|
+
/** 光效(枚举 id 数组,来自 shot-language 词库)。 */
|
|
277
|
+
light: LightingId[];
|
|
256
278
|
/** 承接上一镜头结尾状态(位置/动作/情绪/服装)。 */
|
|
257
279
|
prevState: string;
|
|
258
280
|
/** 本镜头结束状态。 */
|
|
@@ -1171,6 +1193,14 @@ export interface NovelConfig {
|
|
|
1171
1193
|
imageApiModel?: string;
|
|
1172
1194
|
/** 是否启用生图(= 存在启用条目)。 */
|
|
1173
1195
|
imageApiEnabled?: boolean;
|
|
1196
|
+
/** 自定义背景图(URL 或 dataURL 或服务端路径引用;空 = 使用主题默认背景)。 */
|
|
1197
|
+
themeBackground?: string;
|
|
1198
|
+
/** 自定义背景遮罩/模糊强度 0-80(0 = 不遮罩)。 */
|
|
1199
|
+
themeBackgroundBlur?: number;
|
|
1200
|
+
/** 玻璃透明度 0-100(100=当前原样,越小越透,新拟态/黏土可见背景图)。 */
|
|
1201
|
+
themeOpacity?: number;
|
|
1202
|
+
/** 是否启用改编模式(默认关闭;发布后开启)。 */
|
|
1203
|
+
enableAdaptMode?: boolean;
|
|
1174
1204
|
}
|
|
1175
1205
|
/** GET /status response. */
|
|
1176
1206
|
export interface StatusResponse {
|
|
@@ -1408,6 +1438,13 @@ export interface ConfigPatch {
|
|
|
1408
1438
|
imageApiKey?: string;
|
|
1409
1439
|
imageApiModel?: string;
|
|
1410
1440
|
imageApiEnabled?: boolean;
|
|
1441
|
+
/** 自定义背景图(URL / dataURL / 服务端路径引用)。 */
|
|
1442
|
+
themeBackground?: string;
|
|
1443
|
+
/** 自定义背景遮罩/模糊强度 0-80。 */
|
|
1444
|
+
themeBackgroundBlur?: number;
|
|
1445
|
+
/** 玻璃透明度 0-100(100=当前原样)。 */
|
|
1446
|
+
themeOpacity?: number;
|
|
1447
|
+
enableAdaptMode?: boolean;
|
|
1411
1448
|
/** 生图模型库(完整替换保存)。 */
|
|
1412
1449
|
imageModels?: ImageModelConfig[];
|
|
1413
1450
|
}
|
|
@@ -1569,3 +1606,162 @@ export interface StyleEngineRequest {
|
|
|
1569
1606
|
/** 资产名(可选,默认「风格资产 N」)。 */
|
|
1570
1607
|
name?: string;
|
|
1571
1608
|
}
|
|
1609
|
+
/** 作者资产库中一条可跨书复用的资产(笔法/红线/套路/角色模板/世界观模板等)。 */
|
|
1610
|
+
export interface AuthorStyleAsset {
|
|
1611
|
+
/** 稳定 id(本地唯一)。 */
|
|
1612
|
+
id: string;
|
|
1613
|
+
/** 资产名(如「短句快节奏爽文风」「林越式痞坏角色」)。 */
|
|
1614
|
+
name: string;
|
|
1615
|
+
/** 资产类型。 */
|
|
1616
|
+
kind: 'style' | 'antiAi' | 'progression' | 'genre' | 'roleTemplate' | 'worldTemplate' | 'custom';
|
|
1617
|
+
/** 一句话摘要。 */
|
|
1618
|
+
summary: string;
|
|
1619
|
+
/** 资产正文内容(按 kind 约定解读的文本/JSON 描述)。 */
|
|
1620
|
+
content: string;
|
|
1621
|
+
/** 结构化载荷(角色模板/世界观模板等可结构化字段;缺省为 null)。 */
|
|
1622
|
+
structured?: Record<string, unknown>;
|
|
1623
|
+
/** 来源书名(哪本书提炼/收藏而来)。 */
|
|
1624
|
+
sourceBooks: string[];
|
|
1625
|
+
/** 标签。 */
|
|
1626
|
+
tags: string[];
|
|
1627
|
+
/** 来源样本文本(可选)。 */
|
|
1628
|
+
sourceText?: string;
|
|
1629
|
+
/** 创建时间。 */
|
|
1630
|
+
createdAt: string;
|
|
1631
|
+
/** 更新时间。 */
|
|
1632
|
+
updatedAt: string;
|
|
1633
|
+
}
|
|
1634
|
+
/** 作者资产库(跨书总数据):按作者维度聚合的可复用资产。 */
|
|
1635
|
+
export interface AuthorAssetLibrary {
|
|
1636
|
+
/** 货架版本,便于未来迁移。 */
|
|
1637
|
+
version: 1;
|
|
1638
|
+
items: AuthorStyleAsset[];
|
|
1639
|
+
}
|
|
1640
|
+
/** GET /author-assets 响应。 */
|
|
1641
|
+
export interface AuthorAssetsResponse {
|
|
1642
|
+
assets: AuthorAssetLibrary;
|
|
1643
|
+
}
|
|
1644
|
+
/** POST /author-assets/upsert 请求:新增或按 id 更新一条资产。 */
|
|
1645
|
+
export interface AuthorAssetUpsertRequest {
|
|
1646
|
+
asset: AuthorStyleAsset;
|
|
1647
|
+
}
|
|
1648
|
+
/** POST /author-assets/remove 请求:删除一条资产。 */
|
|
1649
|
+
export interface AuthorAssetRemoveRequest {
|
|
1650
|
+
id: string;
|
|
1651
|
+
}
|
|
1652
|
+
/** 改编可改范围的单个维度(矩阵的一行)。 */
|
|
1653
|
+
export interface AdaptationDimension {
|
|
1654
|
+
/** 维度 key(如 realm/name/goldenFinger…)。 */
|
|
1655
|
+
key: string;
|
|
1656
|
+
/** 维度名(如「大世界」「修为体系」「主角名」「金手指」)。 */
|
|
1657
|
+
title: string;
|
|
1658
|
+
/** 可改度:保留 / 可改影响大 / 可改影响小 / 可自由改 / 仅视觉包装。 */
|
|
1659
|
+
mutability: 'locked' | 'big' | 'small' | 'free' | 'visual';
|
|
1660
|
+
/** 原文当前值(从正文提炼,附证据)。 */
|
|
1661
|
+
current: string;
|
|
1662
|
+
/** 该值在正文中的出现证据(章节/频次,可空)。 */
|
|
1663
|
+
evidence?: string;
|
|
1664
|
+
/** AI 建议的候选新值(可空)。 */
|
|
1665
|
+
candidates?: string[];
|
|
1666
|
+
/** 联动影响说明(改了会影响哪些章节/角色/伏笔/术语)。 */
|
|
1667
|
+
impact: string;
|
|
1668
|
+
/** 风险评级。 */
|
|
1669
|
+
risk: 'high' | 'medium' | 'low';
|
|
1670
|
+
}
|
|
1671
|
+
/** POST /adapt/analyze 请求:上传全文做改编分析。 */
|
|
1672
|
+
export interface AdaptAnalyzeRequest {
|
|
1673
|
+
/** 全文文本(优先)。 */
|
|
1674
|
+
text: string;
|
|
1675
|
+
/** 或服务器端全文文件路径。 */
|
|
1676
|
+
filePath?: string;
|
|
1677
|
+
}
|
|
1678
|
+
/** POST /adapt/analyze 响应。 */
|
|
1679
|
+
export interface AdaptAnalyzeResponse {
|
|
1680
|
+
/** 识别书名(文件名推断或正文首行)。 */
|
|
1681
|
+
bookName: string;
|
|
1682
|
+
/** 拆出的章节数。 */
|
|
1683
|
+
chapters: number;
|
|
1684
|
+
/** 反推的初始大纲(可空)。 */
|
|
1685
|
+
outline?: string;
|
|
1686
|
+
/** 可改范围矩阵。 */
|
|
1687
|
+
dimensions: AdaptationDimension[];
|
|
1688
|
+
/** 分析消耗说明。 */
|
|
1689
|
+
note?: string;
|
|
1690
|
+
}
|
|
1691
|
+
/** 一条改编映射(原值 → 新值)。 */
|
|
1692
|
+
export interface AdaptationMapping {
|
|
1693
|
+
/** 原值(如「林尘」「练气」「青云宗」)。 */
|
|
1694
|
+
source: string;
|
|
1695
|
+
/** 新值(如「楚风」「凝元」「天渊阁」)。 */
|
|
1696
|
+
target: string;
|
|
1697
|
+
/** 适用范围。 */
|
|
1698
|
+
scope: 'name' | 'realm' | 'faction' | 'term' | 'other';
|
|
1699
|
+
/** 说明(可空)。 */
|
|
1700
|
+
note?: string;
|
|
1701
|
+
}
|
|
1702
|
+
/** 改编规则:哪些必须保留、哪些允许改、一致性约束。 */
|
|
1703
|
+
export interface AdaptationRules {
|
|
1704
|
+
/** 必须保留的要素(骨架/人物动机/伏笔逻辑/爽点结构…)。 */
|
|
1705
|
+
preserve: string[];
|
|
1706
|
+
/** 允许改变的要素。 */
|
|
1707
|
+
change: string[];
|
|
1708
|
+
/** 改编红线/一致性要求。 */
|
|
1709
|
+
constraints: string[];
|
|
1710
|
+
}
|
|
1711
|
+
/** 一组改编方案(映射表 + 规则 + 联动影响清单)。 */
|
|
1712
|
+
export interface AdaptationProposal {
|
|
1713
|
+
/** 映射表(原→新)。 */
|
|
1714
|
+
mappings: AdaptationMapping[];
|
|
1715
|
+
/** 改编规则。 */
|
|
1716
|
+
rules: AdaptationRules;
|
|
1717
|
+
/** 联动影响清单。 */
|
|
1718
|
+
impacts: Array<{
|
|
1719
|
+
item: string;
|
|
1720
|
+
detail: string;
|
|
1721
|
+
risk: 'high' | 'medium' | 'low';
|
|
1722
|
+
chapters?: number[];
|
|
1723
|
+
}>;
|
|
1724
|
+
}
|
|
1725
|
+
/** POST /adapt/propose 请求:由用户勾选的维度 + 新值生成改编方案。 */
|
|
1726
|
+
export interface AdaptProposeRequest {
|
|
1727
|
+
/** 原文全文(复用,便于 LLM 核对联动影响)。 */
|
|
1728
|
+
text: string;
|
|
1729
|
+
/** 用户确认要改的维度(含原值与新值)。 */
|
|
1730
|
+
selections: Array<{
|
|
1731
|
+
key: string;
|
|
1732
|
+
title: string;
|
|
1733
|
+
current: string;
|
|
1734
|
+
target: string;
|
|
1735
|
+
mutability: string;
|
|
1736
|
+
}>;
|
|
1737
|
+
/** 若已分析过,可携带完整矩阵作为上下文。 */
|
|
1738
|
+
dimensions?: AdaptationDimension[];
|
|
1739
|
+
}
|
|
1740
|
+
/** POST /adapt/propose 响应。 */
|
|
1741
|
+
export interface AdaptProposeResponse {
|
|
1742
|
+
proposal: AdaptationProposal;
|
|
1743
|
+
}
|
|
1744
|
+
/** POST /adapt/execute 请求:执行改编(首版为术语替换)。 */
|
|
1745
|
+
export interface AdaptExecuteRequest {
|
|
1746
|
+
/** 原文全文。 */
|
|
1747
|
+
text: string;
|
|
1748
|
+
/** 改编映射表。 */
|
|
1749
|
+
mappings: AdaptationMapping[];
|
|
1750
|
+
/** 改编规则(可选,后续逐章改写使用;替换模式暂不依赖)。 */
|
|
1751
|
+
rules?: AdaptationRules;
|
|
1752
|
+
/** 执行模式:首版仅 replace(术语替换)。 */
|
|
1753
|
+
mode?: 'replace' | 'rewrite';
|
|
1754
|
+
}
|
|
1755
|
+
/** POST /adapt/execute 响应。 */
|
|
1756
|
+
export interface AdaptExecuteResponse {
|
|
1757
|
+
/** 改编后的全文。 */
|
|
1758
|
+
adaptedText: string;
|
|
1759
|
+
/** 执行的映射数。 */
|
|
1760
|
+
mappings: number;
|
|
1761
|
+
/** 命中统计:每条映射的替换次数。 */
|
|
1762
|
+
hits: Array<{
|
|
1763
|
+
source: string;
|
|
1764
|
+
target: string;
|
|
1765
|
+
count: number;
|
|
1766
|
+
}>;
|
|
1767
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 镜头语言词库(分镜规范化基准)。
|
|
3
|
+
* 分镜表的 shot/camera/composition/light 字段统一从这里取值(英文 id),
|
|
4
|
+
* 生成提示词时用 zh 中文词块;适配英文平台时用 en。
|
|
5
|
+
* 目的:让"景别/运镜/构图/光效"有标准词表,避免 LLM 自由发挥导致漂移。
|
|
6
|
+
*/
|
|
7
|
+
/** 景别。 */
|
|
8
|
+
export type ShotSizeId = 'extreme_wide' | 'wide' | 'full' | 'medium' | 'medium_close' | 'close' | 'extreme_close' | 'big_extreme_close';
|
|
9
|
+
/** 运镜/机位。 */
|
|
10
|
+
export type CameraMoveId = 'static' | 'dolly_in' | 'dolly_out' | 'pan_left' | 'pan_right' | 'track_left' | 'track_right' | 'follow' | 'pedestal_up' | 'pedestal_down' | 'orbit' | 'handheld' | 'low_angle' | 'high_angle' | 'over_shoulder';
|
|
11
|
+
/** 构图。 */
|
|
12
|
+
export type CompositionId = 'rule_of_thirds' | 'center' | 'leading_line' | 'foreground' | 'low' | 'overhead' | 'symmetry';
|
|
13
|
+
/** 光效。 */
|
|
14
|
+
export type LightingId = 'front' | 'side' | 'back' | 'top' | 'rembrandt' | 'neon' | 'hard' | 'soft' | 'mood' | 'contrast';
|
|
15
|
+
export interface ShotLangEntry<T extends string> {
|
|
16
|
+
id: T;
|
|
17
|
+
/** 中文(提示词/展示用)。 */
|
|
18
|
+
zh: string;
|
|
19
|
+
/** 英文(英文平台适配用)。 */
|
|
20
|
+
en: string;
|
|
21
|
+
/** 一句话说明(下拉/卡片)。 */
|
|
22
|
+
hint: string;
|
|
23
|
+
}
|
|
24
|
+
export declare const SHOT_SIZES: readonly ShotLangEntry<ShotSizeId>[];
|
|
25
|
+
export declare const CAMERA_MOVES: readonly ShotLangEntry<CameraMoveId>[];
|
|
26
|
+
export declare const COMPOSITIONS: readonly ShotLangEntry<CompositionId>[];
|
|
27
|
+
export declare const LIGHTINGS: readonly ShotLangEntry<LightingId>[];
|
|
28
|
+
export interface ShotLanguage {
|
|
29
|
+
shot?: ShotSizeId;
|
|
30
|
+
camera: CameraMoveId[];
|
|
31
|
+
composition?: CompositionId;
|
|
32
|
+
light: LightingId[];
|
|
33
|
+
}
|
|
34
|
+
/** 从中文文本归一化到景别(处理旧数据/LLM 口语)。未知回退 medium。 */
|
|
35
|
+
export declare function normalizeShotSize(text: string | undefined): ShotSizeId;
|
|
36
|
+
/** 从中文文本归一化到运镜列表。 */
|
|
37
|
+
export declare function normalizeCameras(text: string | undefined): CameraMoveId[];
|
|
38
|
+
/** 从中文文本归一化到构图(可选)。 */
|
|
39
|
+
export declare function normalizeComposition(text: string | undefined): CompositionId | undefined;
|
|
40
|
+
/** 从中文文本归一化到光效列表。 */
|
|
41
|
+
export declare function normalizeLightings(text: string | undefined): LightingId[];
|
|
42
|
+
/** 取词条中文(ZHs 合并句子)。 */
|
|
43
|
+
export declare function sizeZh(id: ShotSizeId | undefined): string;
|
|
44
|
+
export declare function cameraZh(ids: CameraMoveId[] | undefined): string;
|
|
45
|
+
export declare function compoZh(id: CompositionId | undefined): string;
|
|
46
|
+
export declare function lightZh(ids: LightingId[] | undefined): string;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 编剧词库(剧情骨架规范化基准)。
|
|
3
|
+
* 骨架的 function(叙事功能)与 emotion(情绪走向)统一从这里取值(英文 id),
|
|
4
|
+
* 生成提示词/展示时用 zh 中文。
|
|
5
|
+
* 目的:让"叙事功能/情绪"有标准词表,避免 LLM 自由发挥导致情绪链漂移。
|
|
6
|
+
*/
|
|
7
|
+
/** 叙事功能(对应节拍在剧情中的作用)。 */
|
|
8
|
+
export type StoryFunctionId = 'exposition' | 'conflict' | 'turn' | 'climax' | 'resolve' | 'foreshadow' | 'character';
|
|
9
|
+
/** 情绪词(低→高能量的情绪阶,角色在节拍中的主要情绪点)。 */
|
|
10
|
+
export type EmotionId = 'calm' | 'indifferent' | 'expectant' | 'curious' | 'alert' | 'suppressed' | 'enduring' | 'worried' | 'irritable' | 'uneasy' | 'terrified' | 'angry' | 'collapsing' | 'resolute' | 'grieved' | 'relieved' | 'bittersweet' | 'triumphant' | 'reborn' | 'numb';
|
|
11
|
+
export interface BeatLangEntry<T extends string> {
|
|
12
|
+
id: T;
|
|
13
|
+
/** 中文(展示用)。 */
|
|
14
|
+
zh: string;
|
|
15
|
+
/** 英文(英文平台适配用)。 */
|
|
16
|
+
en: string;
|
|
17
|
+
/** 一句话说明。 */
|
|
18
|
+
hint: string;
|
|
19
|
+
}
|
|
20
|
+
/** 叙事功能词表。 */
|
|
21
|
+
export declare const STORY_FUNCTIONS: readonly BeatLangEntry<StoryFunctionId>[];
|
|
22
|
+
/** 情绪词表(按能量/阶段排序)。 */
|
|
23
|
+
export declare const EMOTIONS: readonly BeatLangEntry<EmotionId>[];
|
|
24
|
+
export interface StoryBeatLanguage {
|
|
25
|
+
function: StoryFunctionId;
|
|
26
|
+
emotion: EmotionId[];
|
|
27
|
+
}
|
|
28
|
+
/** 从中文归一化叙事功能(未知回退 exposition)。 */
|
|
29
|
+
export declare function normalizeStoryFunction(text: string | undefined): StoryFunctionId;
|
|
30
|
+
/** 从中文文本归一化情绪词列表(可含→箭头链)。 */
|
|
31
|
+
export declare function normalizeEmotions(text: string | undefined): EmotionId[];
|
|
32
|
+
/** 叙事功能中文。 */
|
|
33
|
+
export declare function functionZh(id: StoryFunctionId | undefined): string;
|
|
34
|
+
/** 情绪中文(箭头连接)。 */
|
|
35
|
+
export declare function emotionZh(ids: EmotionId[] | undefined): string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@waterwx/dsh-novel-forge",
|
|
3
3
|
"description": "AI 编译小说工作台 for the dsh web GUI: import a novel outline (docx/text), plan chapters with LLM, generate chapter by chapter (3000-4000 chars each), and save every chapter as Markdown into your chosen output folder.",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.8.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": "^22.19.0 || >=24.0.0"
|
|
@@ -80,9 +80,9 @@
|
|
|
80
80
|
"lib/**/*.js",
|
|
81
81
|
"lib/**/*.js.map",
|
|
82
82
|
"lib/**/*.d.ts",
|
|
83
|
-
"lib/**/*.d.ts.map",
|
|
84
83
|
"src",
|
|
85
84
|
"assets/styles",
|
|
85
|
+
"skills",
|
|
86
86
|
"scripts/patch-schemastery.mjs",
|
|
87
87
|
"cordis.patch.yml",
|
|
88
88
|
"README.md"
|
|
@@ -95,6 +95,8 @@
|
|
|
95
95
|
"watch": "tsdown --watch",
|
|
96
96
|
"typecheck": "tsc --noEmit",
|
|
97
97
|
"check:styles": "node scripts/check-theme-sizes.mjs",
|
|
98
|
+
"release": "node scripts/release.mjs",
|
|
99
|
+
"release:dry": "node scripts/release.mjs --dry-run",
|
|
98
100
|
"test": "vitest run"
|
|
99
101
|
}
|
|
100
102
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: novel-forge-chapter-batch
|
|
3
|
+
description: 批量生成小说章节并值守处理审稿未过的章节。当用户说「生成 N 章」「连写」「批量生成」「继续写章节」「值守处理未过章节」时使用。依赖 dsh-novel-forge 插件(http://127.0.0.1:3080/api/dsh-novel-forge/*)。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 小说章节批量生产与值守处理
|
|
7
|
+
|
|
8
|
+
把「批量生成章节 + 审稿未过处理」固化为可复现流程。所有操作通过 dsh-novel-forge 的 HTTP API 执行。
|
|
9
|
+
|
|
10
|
+
## 0. 值守纪律(最高优先级,违反即空转)
|
|
11
|
+
|
|
12
|
+
1. **启动后台任务后立即停下,不轮询、不连续 wait、不做无意义动作**——后台任务(批量生成/处理)由运行时在完成时自动通知。
|
|
13
|
+
2. 只有收到「任务完成」通知或用户新消息时,才继续下一步(读结果 → 处理未过 → 汇报)。
|
|
14
|
+
3. 等待期间可以做「与当前任务无关」的其他有用工作(如用户提出的其他问题、代码改进),但不得为等任务而空转。
|
|
15
|
+
4. 任务因 web 重启中断时:等用户确认或检测到 3080 恢复后,复位卡死章节(generating/error → reset)再续跑,并向用户说明中断原因。
|
|
16
|
+
|
|
17
|
+
## 1. 前置检查(每次必做)
|
|
18
|
+
|
|
19
|
+
1. 确认服务在跑:`GET /api/dsh-novel-forge/status` 返回 200,读 `project.chapters` 数量与书名。
|
|
20
|
+
2. 确认目标章节状态:列出 `pending`(待生成)章节号区间,避免重复生成已 approved/rejected 的章。
|
|
21
|
+
3. **串行执行,禁止并行写 project.json**——多个脚本同时调 API 会造成状态互相覆盖(实测教训:第 166 章曾被并发回滚成 rejected)。
|
|
22
|
+
|
|
23
|
+
## 2. 批量生成
|
|
24
|
+
|
|
25
|
+
对目标章节区间(如 181-205)逐章串行调用:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
POST /api/dsh-novel-forge/generate
|
|
29
|
+
{ "chapterNo": N, "skipReview": false }
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- `skipReview: false` 走完整质量门(生成 → 摘要+编年录 → AI 审稿 → 作者复盘)。
|
|
33
|
+
- 响应为 NDJSON 流;找 `{"type":"review","report":{...}}` 帧取 `score`/`passed`。
|
|
34
|
+
- 每章 2-5 分钟;失败自动重试 1 次(间隔 3 秒)。
|
|
35
|
+
- 预估总时长并告知用户(25 章 ≈ 45-75 分钟),放后台跑,期间可并行做别的(只读操作不受影响)。
|
|
36
|
+
- 推荐用 Node 脚本(fetch + 逐章循环),避免 PowerShell 的引号/UTF-8 转义坑;脚本用完删除。
|
|
37
|
+
|
|
38
|
+
## 2. 未过章节处理(分级策略)
|
|
39
|
+
|
|
40
|
+
生成完成后汇总:通过 / 未过(rejected)/ 失败(error)。对未过章按此分级:
|
|
41
|
+
|
|
42
|
+
### A. 无 high(全是 medium/low 主观项)→ 豁免通过
|
|
43
|
+
```
|
|
44
|
+
POST /api/dsh-novel-forge/chapter/approve { "chapterNo": N }
|
|
45
|
+
```
|
|
46
|
+
主观项(套话/节奏/比喻/心理描写)不值得逐章磨,直接通过。
|
|
47
|
+
|
|
48
|
+
### B. 有 high 且问题明确(逻辑/设定/时间线/用词)→ 按意见修订 + 验证模式
|
|
49
|
+
1. 取 review 的 high(无 high 取前 3 条 medium),拼指令:
|
|
50
|
+
`按审稿意见修订(优先处理):\n[severity] item → suggestion`
|
|
51
|
+
2. `POST /rewrite` `{ chapterNo, instructions }` → 产出 pendingDraft
|
|
52
|
+
3. **验证模式**:`POST /chapter/check` `{ chapterNo, text: draft, previousReport: review }`——携带上一轮报告,LLM 只核对原意见是否解决 + 只挑新增 high,不全新找茬
|
|
53
|
+
4. 判定:`passed || issues 全非 high` → 可接受
|
|
54
|
+
5. 可接受 → `POST /draft/apply` `{ chapterNo, report: { score: max(score,70), passed: true, issues: [], ... } }` 落盘为 approved
|
|
55
|
+
6. 不可接受 → 看剩余 high 是否明确可修 → 第二轮修订(指令更精确,如「把第 141 章的养伤时间线统一为七天」)→ 再验证
|
|
56
|
+
7. **每章最多修订 2 轮**,仍不过 → 保留草稿,标记「待人工」,不硬来
|
|
57
|
+
|
|
58
|
+
### C. 有 high 但结构性(修订改不好,如逻辑矛盾被坐实)→ 重新生成
|
|
59
|
+
- `POST /draft/discard` 清草稿 → `POST /generate` 整章重写
|
|
60
|
+
- 重新生成后若只剩主观项 → 走 A 豁免
|
|
61
|
+
|
|
62
|
+
### D. error 状态(无审稿、chars 丢失)→ 重置重生成
|
|
63
|
+
- `POST /chapter/reset` `{ chapterNo }` → `POST /generate`
|
|
64
|
+
|
|
65
|
+
### 特殊注意
|
|
66
|
+
- **approved 但 review 有 high**:已通过状态保留,不折腾(high 可能已被正文处理或审稿误标)。
|
|
67
|
+
- **修订指令越精确越有效**:具体数字/行为(如「茶梗尺寸统一为半截指节」)一次就过;泛泛的「修正矛盾」容易改不到位。
|
|
68
|
+
|
|
69
|
+
## 3. 收尾
|
|
70
|
+
|
|
71
|
+
1. 最终验证:`GET /status` 读目标区间全部 approved。
|
|
72
|
+
2. 可选:对涉及剧情的章节刷新剧情线进度(`POST /plotlines` `{ op:'refresh', id }`)——注意刷新函数只读最近 8 章摘要,早期章节的线可能刷不准,必要时手动 update progress + link 章节。
|
|
73
|
+
3. 向用户汇报:通过/未过/失败数量 + 每章处理方式 + 遗留待人工项。
|
|
74
|
+
|
|
75
|
+
## 4. 已知陷阱(血泪教训)
|
|
76
|
+
|
|
77
|
+
- **并发写 project.json 会互相覆盖**——多个生成/处理任务必须串行。
|
|
78
|
+
- **rewrite 的草稿可能不落盘**(偶发 500 或时序)——应用前检查 `pendingDraft` 是否存在,不存在则重跑 rewrite。
|
|
79
|
+
- **PowerShell 调 API 的引号/中文转义是坑**——统一用 Node 脚本。
|
|
80
|
+
- **status 接口会做数据快照**——以磁盘 novel-project.json 为准复核关键状态。
|
|
81
|
+
- **验证模式 500 偶发**——重试一次即可(LLM 瞬时错误)。
|