@waterwx/dsh-novel-forge 0.1.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/LICENSE +202 -0
- package/README.md +180 -0
- package/cordis.patch.yml +13 -0
- package/lib/client.js +3924 -0
- package/lib/client.js.map +1 -0
- package/lib/index.js +3120 -0
- package/lib/index.js.map +1 -0
- package/lib/types/assets.d.ts +35 -0
- package/lib/types/assistant.d.ts +43 -0
- package/lib/types/bookshelf.d.ts +35 -0
- package/lib/types/client/api.d.ts +68 -0
- package/lib/types/client/docx.d.ts +15 -0
- package/lib/types/client/index.d.ts +14 -0
- package/lib/types/client/locales.d.ts +139 -0
- package/lib/types/client/mount.d.ts +9 -0
- package/lib/types/client/panel/AssetsTab.d.ts +7 -0
- package/lib/types/client/panel/AssistantTab.d.ts +7 -0
- package/lib/types/client/panel/BookshelfBar.d.ts +11 -0
- package/lib/types/client/panel/NovelPanel.d.ts +13 -0
- package/lib/types/client/panel/controller.d.ts +19 -0
- package/lib/types/client/panel/helpers.d.ts +8 -0
- package/lib/types/client/sidebar-entry.d.ts +13 -0
- package/lib/types/docx.d.ts +19 -0
- package/lib/types/engine.d.ts +95 -0
- package/lib/types/index.d.ts +55 -0
- package/lib/types/protocol.d.ts +521 -0
- package/lib/types/routes.d.ts +29 -0
- package/package.json +105 -0
- package/src/assets.ts +518 -0
- package/src/assistant.ts +547 -0
- package/src/bookshelf.ts +137 -0
- package/src/client/api.ts +254 -0
- package/src/client/css-modules.d.ts +8 -0
- package/src/client/docx.ts +69 -0
- package/src/client/index.ts +34 -0
- package/src/client/locales.ts +271 -0
- package/src/client/mount.tsx +97 -0
- package/src/client/panel/AssetsTab.tsx +341 -0
- package/src/client/panel/AssistantTab.tsx +188 -0
- package/src/client/panel/BookshelfBar.tsx +116 -0
- package/src/client/panel/NovelPanel.tsx +990 -0
- package/src/client/panel/controller.ts +45 -0
- package/src/client/panel/helpers.ts +17 -0
- package/src/client/panel/panel.module.css +894 -0
- package/src/client/sidebar-entry.ts +122 -0
- package/src/docx.ts +83 -0
- package/src/engine.ts +1019 -0
- package/src/index.ts +184 -0
- package/src/protocol.ts +539 -0
- package/src/routes.ts +955 -0
package/src/protocol.ts
ADDED
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-novel-forge — shared protocol between the host half (Node) and the
|
|
3
|
+
* browser half (web GUI). Route paths, request/response shapes, the project
|
|
4
|
+
* state file format, and the NDJSON generation stream frames all live here so
|
|
5
|
+
* both halves spell exactly one vocabulary.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** The /api/dsh-novel-forge route family (same-origin, loopback-fenced). */
|
|
9
|
+
export const NOVEL_API = {
|
|
10
|
+
status: '/api/dsh-novel-forge/status',
|
|
11
|
+
loadOutline: '/api/dsh-novel-forge/load-outline',
|
|
12
|
+
saveOutline: '/api/dsh-novel-forge/save-outline',
|
|
13
|
+
plan: '/api/dsh-novel-forge/plan',
|
|
14
|
+
volumes: '/api/dsh-novel-forge/volumes',
|
|
15
|
+
bible: '/api/dsh-novel-forge/bible',
|
|
16
|
+
assets: '/api/dsh-novel-forge/assets',
|
|
17
|
+
styleEngine: '/api/dsh-novel-forge/style-engine',
|
|
18
|
+
generate: '/api/dsh-novel-forge/generate',
|
|
19
|
+
review: '/api/dsh-novel-forge/review',
|
|
20
|
+
rewrite: '/api/dsh-novel-forge/rewrite',
|
|
21
|
+
polish: '/api/dsh-novel-forge/polish',
|
|
22
|
+
summary: '/api/dsh-novel-forge/summary',
|
|
23
|
+
foreshadow: '/api/dsh-novel-forge/foreshadow',
|
|
24
|
+
exportBook: '/api/dsh-novel-forge/export',
|
|
25
|
+
chapter: '/api/dsh-novel-forge/chapter',
|
|
26
|
+
assistant: '/api/dsh-novel-forge/assistant',
|
|
27
|
+
assistantHistory: '/api/dsh-novel-forge/assistant-history',
|
|
28
|
+
bookshelf: '/api/dsh-novel-forge/bookshelf',
|
|
29
|
+
config: '/api/dsh-novel-forge/config',
|
|
30
|
+
openFolder: '/api/dsh-novel-forge/open-folder',
|
|
31
|
+
} as const
|
|
32
|
+
|
|
33
|
+
/** 书架:一本书的条目。 */
|
|
34
|
+
export interface BookEntry {
|
|
35
|
+
/** 稳定 id。 */
|
|
36
|
+
id: string
|
|
37
|
+
/** 书名。 */
|
|
38
|
+
bookName: string
|
|
39
|
+
/** 该书输出目录(独立项目目录)。 */
|
|
40
|
+
outputDir: string
|
|
41
|
+
/** 创建时间。 */
|
|
42
|
+
createdAt: string
|
|
43
|
+
/** 最后活动时间。 */
|
|
44
|
+
updatedAt: string
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** 书架快照(含每本书的进度摘要)。 */
|
|
48
|
+
export interface BookshelfSnapshot {
|
|
49
|
+
books: Array<BookEntry & { done: number; total: number; hasProject: boolean }>
|
|
50
|
+
/** 当前激活的书 id(无则 null)。 */
|
|
51
|
+
activeBookId: string | null
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** POST /bookshelf 请求:创建新书。 */
|
|
55
|
+
export interface BookCreateRequest {
|
|
56
|
+
bookName: string
|
|
57
|
+
outputDir?: string
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** POST /bookshelf/activate 请求:切换当前书。 */
|
|
61
|
+
export interface BookActivateRequest {
|
|
62
|
+
id: string
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** POST /bookshelf/remove 请求:移除书架条目。 */
|
|
66
|
+
export interface BookRemoveRequest {
|
|
67
|
+
id: string
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Chapter lifecycle states (the writing pipeline's state machine). */
|
|
71
|
+
export type ChapterStatus =
|
|
72
|
+
| 'pending' // planned, not started
|
|
73
|
+
| 'generating' // LLM writing right now
|
|
74
|
+
| 'written' // body on disk, awaiting review
|
|
75
|
+
| 'reviewing' // review in progress
|
|
76
|
+
| 'approved' // passed review (or user-approved)
|
|
77
|
+
| 'rejected' // review found problems
|
|
78
|
+
| 'error' // generation failed
|
|
79
|
+
|
|
80
|
+
/** One chapter in the plan. */
|
|
81
|
+
export interface ChapterPlan {
|
|
82
|
+
/** 1-based chapter number (stable identity; files are named from it). */
|
|
83
|
+
no: number
|
|
84
|
+
/** Volume this chapter belongs to (1-based; 0 = unassigned). */
|
|
85
|
+
volume: number
|
|
86
|
+
/** Chapter title, decided by the LLM plan step. */
|
|
87
|
+
title: string
|
|
88
|
+
/** Story beats / plot points for this chapter (model-facing guidance). */
|
|
89
|
+
beats: string
|
|
90
|
+
/** Target character count (defaults to the configured chapter size). */
|
|
91
|
+
targetChars: number
|
|
92
|
+
/** Generation/review state. */
|
|
93
|
+
status: ChapterStatus
|
|
94
|
+
/** Actual character count once generated. */
|
|
95
|
+
chars?: number
|
|
96
|
+
/** Failure message when status is 'error'. */
|
|
97
|
+
error?: string
|
|
98
|
+
/** Output file name once generated (relative to the output dir). */
|
|
99
|
+
file?: string
|
|
100
|
+
/** LLM summary of the chapter (narrative memory for later chapters). */
|
|
101
|
+
summary?: string
|
|
102
|
+
/** Latest review report (present once reviewed). */
|
|
103
|
+
review?: ReviewReport
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** One review finding. */
|
|
107
|
+
export interface ReviewIssue {
|
|
108
|
+
/** Severity: high = must fix, medium = should fix, low = suggestion. */
|
|
109
|
+
severity: 'high' | 'medium' | 'low'
|
|
110
|
+
/** What the problem is. */
|
|
111
|
+
item: string
|
|
112
|
+
/** Concrete suggestion for fixing it. */
|
|
113
|
+
suggestion: string
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** AI review report for one chapter. */
|
|
117
|
+
export interface ReviewReport {
|
|
118
|
+
/** Overall score 0-100. */
|
|
119
|
+
score: number
|
|
120
|
+
/** Pass threshold (config; 70 default). */
|
|
121
|
+
passed: boolean
|
|
122
|
+
/** One-line verdict. */
|
|
123
|
+
verdict: string
|
|
124
|
+
/** Individual findings. */
|
|
125
|
+
issues: ReviewIssue[]
|
|
126
|
+
/** When the review ran. */
|
|
127
|
+
reviewedAt: string
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** A volume of the book. */
|
|
131
|
+
export interface Volume {
|
|
132
|
+
/** 1-based volume number. */
|
|
133
|
+
no: number
|
|
134
|
+
/** Volume title. */
|
|
135
|
+
title: string
|
|
136
|
+
/** Volume positioning / summary. */
|
|
137
|
+
summary: string
|
|
138
|
+
/** First chapter number of this volume. */
|
|
139
|
+
chapterStart: number
|
|
140
|
+
/** Last chapter number (inclusive). */
|
|
141
|
+
chapterEnd: number
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** A character card from the story bible. */
|
|
145
|
+
export interface CharacterCard {
|
|
146
|
+
name: string
|
|
147
|
+
role: 'protagonist' | 'supporting' | 'antagonist' | 'other'
|
|
148
|
+
/** Personality / traits (short lines). */
|
|
149
|
+
traits: string[]
|
|
150
|
+
/** Goals and motivations. */
|
|
151
|
+
goals: string
|
|
152
|
+
/** Key relations to other characters. */
|
|
153
|
+
relations: string
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** The structured story bible (worldbuilding extracted from the outline). */
|
|
157
|
+
export interface StoryBible {
|
|
158
|
+
/** Genre + tone tags. */
|
|
159
|
+
genre: string
|
|
160
|
+
/** Worldbuilding rules (power system, geography, factions...). */
|
|
161
|
+
worldRules: string[]
|
|
162
|
+
/** Character cards. */
|
|
163
|
+
characters: CharacterCard[]
|
|
164
|
+
/** Writing red lines (forbidden content / must-avoid tropes). */
|
|
165
|
+
redLines: string[]
|
|
166
|
+
/** Style guidance (pacing, pov, tone). */
|
|
167
|
+
style: string[]
|
|
168
|
+
/** When the bible was generated. */
|
|
169
|
+
generatedAt?: string
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** A planted/active/resolved foreshadowing thread. */
|
|
173
|
+
export interface Foreshadow {
|
|
174
|
+
/** Stable id. */
|
|
175
|
+
id: string
|
|
176
|
+
/** What the foreshadow is. */
|
|
177
|
+
description: string
|
|
178
|
+
/** Chapter where it was planted (undefined = planned). */
|
|
179
|
+
plantedChapter?: number
|
|
180
|
+
/** Chapter where it should be paid off. */
|
|
181
|
+
targetChapter?: number
|
|
182
|
+
/** Lifecycle state. */
|
|
183
|
+
status: 'planned' | 'planted' | 'progressing' | 'resolved' | 'abandoned'
|
|
184
|
+
/** Resolution note when resolved. */
|
|
185
|
+
resolvedNote?: string
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** The persisted project: outline + bible + plan + progress. */
|
|
189
|
+
export interface ProjectState {
|
|
190
|
+
/** Book title (first non-empty line of the outline, usually). */
|
|
191
|
+
bookName: string
|
|
192
|
+
/** Full outline text (docx-extracted or pasted). */
|
|
193
|
+
outline: string
|
|
194
|
+
/** Source outline path when loaded from a docx. */
|
|
195
|
+
outlinePath?: string
|
|
196
|
+
/** Structured story bible (worldbuilding), if generated. */
|
|
197
|
+
bible?: StoryBible
|
|
198
|
+
/** Volumes, if planned. */
|
|
199
|
+
volumes?: Volume[]
|
|
200
|
+
/** Chapter plan. */
|
|
201
|
+
chapters: ChapterPlan[]
|
|
202
|
+
/** Foreshadowing threads. */
|
|
203
|
+
foreshadows: Foreshadow[]
|
|
204
|
+
/** 写作资产(题材基底/推进模式/反AI规则/写法资产)。 */
|
|
205
|
+
assets?: ProjectAssets
|
|
206
|
+
/** ISO timestamps. */
|
|
207
|
+
createdAt: string
|
|
208
|
+
updatedAt: string
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** Runtime config surface exposed to the panel (subset of plugin Config). */
|
|
212
|
+
export interface NovelConfig {
|
|
213
|
+
/** Absolute path of the default docx outline to load. */
|
|
214
|
+
outlinePath: string
|
|
215
|
+
/** Absolute output directory for chapters + project state. */
|
|
216
|
+
outputDir: string
|
|
217
|
+
/** LLM provider route (e.g. deepseek-official). */
|
|
218
|
+
provider: string
|
|
219
|
+
/** LLM model id (e.g. deepseek-v4-flash). */
|
|
220
|
+
model: string
|
|
221
|
+
/** Target characters per chapter. */
|
|
222
|
+
chapterChars: number
|
|
223
|
+
/** Max output tokens per chapter call. */
|
|
224
|
+
maxTokens: number
|
|
225
|
+
/** Review pass threshold (0-100). */
|
|
226
|
+
reviewPassScore: number
|
|
227
|
+
/** Whether generation auto-runs review after writing. */
|
|
228
|
+
autoReview: boolean
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** GET /status response. */
|
|
232
|
+
export interface StatusResponse {
|
|
233
|
+
config: NovelConfig
|
|
234
|
+
/** The persisted project, when one exists in the output dir. */
|
|
235
|
+
project?: ProjectState
|
|
236
|
+
/** Chapter files already on disk (basenames, sorted). */
|
|
237
|
+
generatedFiles: string[]
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/** POST /load-outline request: either a docx path or raw text. */
|
|
241
|
+
export interface LoadOutlineRequest {
|
|
242
|
+
/** Absolute docx path; defaults to the configured outline path. */
|
|
243
|
+
path?: string
|
|
244
|
+
/** Raw outline text (takes precedence over path when present). */
|
|
245
|
+
text?: string
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** POST /load-outline response. */
|
|
249
|
+
export interface LoadOutlineResponse {
|
|
250
|
+
outline: string
|
|
251
|
+
bookName: string
|
|
252
|
+
chars: number
|
|
253
|
+
path?: string
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** POST /plan request. */
|
|
257
|
+
export interface PlanRequest {
|
|
258
|
+
/** Outline to plan from; defaults to the persisted project's outline. */
|
|
259
|
+
outline?: string
|
|
260
|
+
/** Number of chapters to plan (default: 30). */
|
|
261
|
+
chapterCount?: number
|
|
262
|
+
/** Volume to plan (1-based); when given, plans only that volume's chapters. */
|
|
263
|
+
volume?: number
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/** POST /plan response. */
|
|
267
|
+
export interface PlanResponse {
|
|
268
|
+
chapters: ChapterPlan[]
|
|
269
|
+
volumes?: Volume[]
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** POST /volumes request/response. */
|
|
273
|
+
export interface VolumesRequest {
|
|
274
|
+
/** Outline to split into volumes; defaults to the project outline. */
|
|
275
|
+
outline?: string
|
|
276
|
+
}
|
|
277
|
+
export interface VolumesResponse {
|
|
278
|
+
volumes: Volume[]
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/** POST /bible request/response. */
|
|
282
|
+
export interface BibleRequest {
|
|
283
|
+
/** Outline to extract from; defaults to the project outline. */
|
|
284
|
+
outline?: string
|
|
285
|
+
}
|
|
286
|
+
export interface BibleResponse {
|
|
287
|
+
bible: StoryBible
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/** POST /generate request: one chapter of the current project. */
|
|
291
|
+
export interface GenerateRequest {
|
|
292
|
+
chapterNo: number
|
|
293
|
+
/** When true, skips the auto-review step. */
|
|
294
|
+
skipReview?: boolean
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/** One NDJSON frame of a generation/review/rewrite stream. */
|
|
298
|
+
export type JobFrame =
|
|
299
|
+
| { type: 'start'; no: number; title: string }
|
|
300
|
+
| { type: 'delta'; text: string }
|
|
301
|
+
| { type: 'progress'; chars: number }
|
|
302
|
+
| { type: 'done'; no: number; file: string; chars: number; title: string }
|
|
303
|
+
| { type: 'review'; no: number; report: ReviewReport }
|
|
304
|
+
| { type: 'rewritten'; no: number; file: string; chars: number }
|
|
305
|
+
| { type: 'error'; no: number; message: string }
|
|
306
|
+
|
|
307
|
+
/** POST /review request: review one written chapter. */
|
|
308
|
+
export interface ReviewRequest {
|
|
309
|
+
chapterNo: number
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/** POST /rewrite request: rewrite one chapter (optionally per review issues). */
|
|
313
|
+
export interface RewriteRequest {
|
|
314
|
+
chapterNo: number
|
|
315
|
+
/** Free-form instructions; defaults to fixing the review's high issues. */
|
|
316
|
+
instructions?: string
|
|
317
|
+
/**
|
|
318
|
+
* 局部修订:正文中的一段原文(无需完全精确,取一个自然段内的片段即可)。
|
|
319
|
+
* 提供时只重写该段,其余正文保持不变;不提供时整章重写。
|
|
320
|
+
*/
|
|
321
|
+
target?: string
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/** POST /polish request: de-AI-ify one chapter. */
|
|
325
|
+
export interface PolishRequest {
|
|
326
|
+
chapterNo: number
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/** POST /summary request: (re)generate a chapter summary. */
|
|
330
|
+
export interface SummaryRequest {
|
|
331
|
+
chapterNo: number
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/** POST /foreshadow request: create, update, or AI-suggest foreshadows. */
|
|
335
|
+
export interface ForeshadowRequest {
|
|
336
|
+
/** When true, runs the LLM suggestion pass (ignores other fields). */
|
|
337
|
+
suggest?: boolean
|
|
338
|
+
/** When given, updates that foreshadow instead of creating one. */
|
|
339
|
+
id?: string
|
|
340
|
+
description?: string
|
|
341
|
+
plantedChapter?: number
|
|
342
|
+
targetChapter?: number
|
|
343
|
+
status?: Foreshadow['status']
|
|
344
|
+
resolvedNote?: string
|
|
345
|
+
}
|
|
346
|
+
export interface ForeshadowResponse {
|
|
347
|
+
foreshadows: Foreshadow[]
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/** GET /chapter response. */
|
|
351
|
+
export interface ChapterResponse {
|
|
352
|
+
no: number
|
|
353
|
+
title: string
|
|
354
|
+
markdown: string
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/** POST /export request/response. */
|
|
358
|
+
export interface ExportRequest {
|
|
359
|
+
format: 'txt' | 'md'
|
|
360
|
+
}
|
|
361
|
+
export interface ExportResponse {
|
|
362
|
+
file: string
|
|
363
|
+
chars: number
|
|
364
|
+
chapters: number
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/** POST /config request: patch any subset of the runtime config. */
|
|
368
|
+
export interface ConfigPatch {
|
|
369
|
+
outlinePath?: string
|
|
370
|
+
outputDir?: string
|
|
371
|
+
provider?: string
|
|
372
|
+
model?: string
|
|
373
|
+
chapterChars?: number
|
|
374
|
+
maxTokens?: number
|
|
375
|
+
reviewPassScore?: number
|
|
376
|
+
autoReview?: boolean
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// ------------------------------------------------------------ assistant
|
|
380
|
+
|
|
381
|
+
/** One assistant conversation message (persisted per project). */
|
|
382
|
+
export interface AssistantMessage {
|
|
383
|
+
role: 'user' | 'assistant' | 'tool'
|
|
384
|
+
/** Message text (tool messages carry the tool result). */
|
|
385
|
+
content: string
|
|
386
|
+
/** ISO timestamp. */
|
|
387
|
+
ts: string
|
|
388
|
+
/** For tool messages: which tool ran. */
|
|
389
|
+
tool?: string
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/** POST /assistant request: one user turn. */
|
|
393
|
+
export interface AssistantRequest {
|
|
394
|
+
message: string
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/** One NDJSON frame of the assistant stream. */
|
|
398
|
+
export type AssistantFrame =
|
|
399
|
+
| { type: 'delta'; text: string }
|
|
400
|
+
| { type: 'tool'; name: string; status: 'start' | 'done' | 'error'; detail?: string }
|
|
401
|
+
/** Live output while a tool runs (e.g. chapter text being generated). */
|
|
402
|
+
| { type: 'toolDelta'; name: string; text: string }
|
|
403
|
+
| { type: 'done' }
|
|
404
|
+
| { type: 'error'; message: string }
|
|
405
|
+
|
|
406
|
+
/** GET /assistant-history response. */
|
|
407
|
+
export interface AssistantHistoryResponse {
|
|
408
|
+
messages: AssistantMessage[]
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// ---------------------------------------------------------- writing assets
|
|
412
|
+
|
|
413
|
+
/** 题材基底库:一本书属于哪个阅读市场。树形(题材→子题材→下级)。 */
|
|
414
|
+
export interface GenreNode {
|
|
415
|
+
/** 题材名称(标签,如「仙侠修真」「都市异能」)。 */
|
|
416
|
+
name: string
|
|
417
|
+
/** 题材特征、常见爽点、叙事重心或读者期待。 */
|
|
418
|
+
description: string
|
|
419
|
+
/** 子题材。 */
|
|
420
|
+
children: GenreNode[]
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/** 推进模式库:读者为什么继续看下一章。 */
|
|
424
|
+
export interface ProgressionMode {
|
|
425
|
+
/** 模式名称(如「升级变强」「经营扩张」「解谜揭露」)。 */
|
|
426
|
+
name: string
|
|
427
|
+
/** 核心驱动力:靠什么制造追读动力。 */
|
|
428
|
+
driver: string
|
|
429
|
+
/** 读者期待:每隔几章获得什么变化或回报。 */
|
|
430
|
+
readerExpectation: string
|
|
431
|
+
/** 常见兑现方式(爽点如何落地)。 */
|
|
432
|
+
payoffs: string[]
|
|
433
|
+
/** 节奏风险:最怕什么(重复升级、冲突变弱、谜题拖太久…)。 */
|
|
434
|
+
risks: string[]
|
|
435
|
+
/** 主模式或辅助模式。 */
|
|
436
|
+
primary: boolean
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/** 反 AI 规则:一条「要避免的问题 + 修正方向」。 */
|
|
440
|
+
export interface AntiAiRule {
|
|
441
|
+
/** 规则名(如「禁止解释型心理描写」「AI 高频套话」)。 */
|
|
442
|
+
name: string
|
|
443
|
+
/** 要避免的表达问题,具体可检查。 */
|
|
444
|
+
avoid: string
|
|
445
|
+
/** 推荐修正方向。 */
|
|
446
|
+
fix: string
|
|
447
|
+
/** 命中即告警的具体表达模式(用于审稿逐条核对与去 AI 味检测)。 */
|
|
448
|
+
detectPatterns?: string[]
|
|
449
|
+
/** 是否内置全局规则(内置规则随插件发布,项目规则为用户自定义)。 */
|
|
450
|
+
builtin?: boolean
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/** 预置写法模板(来自 AI-Novel-Writing-Assistant 内置数据,一键绑定无需样本文本)。 */
|
|
454
|
+
export interface StyleTemplate {
|
|
455
|
+
/** 模板 key(如 power-up-escalation)。 */
|
|
456
|
+
key: string
|
|
457
|
+
/** 模板名(如「爽文递进推进流」)。 */
|
|
458
|
+
name: string
|
|
459
|
+
/** 模板说明。 */
|
|
460
|
+
description: string
|
|
461
|
+
/** 分类(如「爽文流」「悬疑流」)。 */
|
|
462
|
+
category: string
|
|
463
|
+
/** 适用题材。 */
|
|
464
|
+
applicableGenres: string[]
|
|
465
|
+
/** 叙述规则。 */
|
|
466
|
+
proseRules: string[]
|
|
467
|
+
/** 角色/台词规则。 */
|
|
468
|
+
dialogueRules: string[]
|
|
469
|
+
/** 语言规则。 */
|
|
470
|
+
languageRules: string[]
|
|
471
|
+
/** 节奏规则。 */
|
|
472
|
+
rhythmRules: string[]
|
|
473
|
+
/** 该模板默认绑定的反 AI 规则 key(内置规则名)。 */
|
|
474
|
+
defaultAntiAiRuleKeys: string[]
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/** 写法引擎:从样本文本提取的叙事风格资产。 */
|
|
478
|
+
export interface StyleAsset {
|
|
479
|
+
/** 资产名(如「林越式痞坏」「冷峻猎手风」)。 */
|
|
480
|
+
name: string
|
|
481
|
+
/** 叙述视角与句式节奏。 */
|
|
482
|
+
proseRules: string[]
|
|
483
|
+
/** 角色台词风格。 */
|
|
484
|
+
dialogueRules: string[]
|
|
485
|
+
/** 描写密度与情绪表达。 */
|
|
486
|
+
descriptionRules: string[]
|
|
487
|
+
/** 表达边界(不要做什么)。 */
|
|
488
|
+
boundaries: string[]
|
|
489
|
+
/** 来源样本文本(可空)。 */
|
|
490
|
+
sourceText?: string
|
|
491
|
+
/** 创建时间。 */
|
|
492
|
+
createdAt: string
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/** 项目写作资产(题材基底 + 推进模式 + 反 AI 规则 + 写法资产)。 */
|
|
496
|
+
export interface ProjectAssets {
|
|
497
|
+
/** 本书选用的题材(可以是题材基底库中某节点名)。 */
|
|
498
|
+
genre?: GenreNode
|
|
499
|
+
/** 主推进模式。 */
|
|
500
|
+
primaryProgression?: ProgressionMode
|
|
501
|
+
/** 辅助推进模式。 */
|
|
502
|
+
auxiliaryProgressions: ProgressionMode[]
|
|
503
|
+
/** 生效的反 AI 规则(内置 + 自定义)。 */
|
|
504
|
+
antiAiRules: AntiAiRule[]
|
|
505
|
+
/** 绑定的写法资产。 */
|
|
506
|
+
styleAssets: StyleAsset[]
|
|
507
|
+
/** 资产更新时间。 */
|
|
508
|
+
updatedAt?: string
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/** GET /assets response(含全局题材库与反 AI 规则库)。 */
|
|
512
|
+
export interface AssetsResponse {
|
|
513
|
+
projectAssets: ProjectAssets
|
|
514
|
+
/** 全局题材基底库(可复用资产,跨书)。 */
|
|
515
|
+
genreLibrary: GenreNode[]
|
|
516
|
+
/** 全局反 AI 规则库(内置默认规则)。 */
|
|
517
|
+
antiAiLibrary: AntiAiRule[]
|
|
518
|
+
/** 预置写法模板(一键绑定,无需样本文本)。 */
|
|
519
|
+
styleTemplates: StyleTemplate[]
|
|
520
|
+
/** 内置推进模式候选。 */
|
|
521
|
+
progressionLibrary: ProgressionMode[]
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/** POST /assets request:更新项目写作资产(部分字段可选)。 */
|
|
525
|
+
export interface AssetsPatch {
|
|
526
|
+
genre?: GenreNode
|
|
527
|
+
primaryProgression?: ProgressionMode
|
|
528
|
+
auxiliaryProgressions?: ProgressionMode[]
|
|
529
|
+
antiAiRules?: AntiAiRule[]
|
|
530
|
+
styleAssets?: StyleAsset[]
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/** POST /style-engine request:从样本文本提取写法资产。 */
|
|
534
|
+
export interface StyleEngineRequest {
|
|
535
|
+
/** 样本文本(风格来源)。 */
|
|
536
|
+
sampleText: string
|
|
537
|
+
/** 资产名(可选,默认「风格资产 N」)。 */
|
|
538
|
+
name?: string
|
|
539
|
+
}
|