@waterwx/dsh-novel-forge 1.4.0 → 1.5.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.
Files changed (49) hide show
  1. package/assets/styles/arcane-thick-3d.webp +0 -0
  2. package/assets/styles/chinese-ink.webp +0 -0
  3. package/assets/styles/clay-stopmotion-3d.webp +0 -0
  4. package/assets/styles/dark-ghibli.webp +0 -0
  5. package/assets/styles/dark-gothic-3d.webp +0 -0
  6. package/assets/styles/film-photo.webp +0 -0
  7. package/assets/styles/guofeng-heavy.webp +0 -0
  8. package/assets/styles/horror-game-3d.webp +0 -0
  9. package/assets/styles/japan-cel-dark.webp +0 -0
  10. package/assets/styles/korean-webtoon.webp +0 -0
  11. package/assets/styles/low-cyberpunk-3d.webp +0 -0
  12. package/assets/styles/nextgen-cg.webp +0 -0
  13. package/assets/styles/noir-film.webp +0 -0
  14. package/assets/styles/openworld-survival.webp +0 -0
  15. package/assets/styles/paper-cut-3d.webp +0 -0
  16. package/assets/styles/pixar-adult-3d.webp +0 -0
  17. package/assets/styles/pop-marvel-2d.webp +0 -0
  18. package/assets/styles/shinkai-anime.webp +0 -0
  19. package/assets/styles/tactical-stealth.webp +0 -0
  20. package/assets/styles/vaporwave-3d.webp +0 -0
  21. package/assets/styles/vhs90.webp +0 -0
  22. package/lib/client.js +2073 -658
  23. package/lib/client.js.map +1 -1
  24. package/lib/index.js +919 -64
  25. package/lib/index.js.map +1 -1
  26. package/lib/types/client/api.d.ts +15 -1
  27. package/lib/types/client/locales.d.ts +4 -2
  28. package/lib/types/client/panel/MangaWorkspace.d.ts +9 -0
  29. package/lib/types/client/panel/NovelPanel.d.ts +1 -1
  30. package/lib/types/client/panel/StoryboardTab.d.ts +13 -0
  31. package/lib/types/client/panel/StyleGallery.d.ts +1 -0
  32. package/lib/types/engine.d.ts +46 -4
  33. package/lib/types/index.d.ts +2 -0
  34. package/lib/types/protocol.d.ts +194 -3
  35. package/lib/types/style-library.d.ts +33 -0
  36. package/package.json +2 -1
  37. package/src/client/api.ts +36 -1
  38. package/src/client/locales.ts +7 -3
  39. package/src/client/panel/ImportModal.tsx +123 -21
  40. package/src/client/panel/MangaWorkspace.tsx +185 -0
  41. package/src/client/panel/NovelPanel.tsx +239 -150
  42. package/src/client/panel/StoryboardTab.tsx +287 -0
  43. package/src/client/panel/StyleGallery.tsx +109 -0
  44. package/src/client/panel/panel.module.css +77 -0
  45. package/src/engine.ts +457 -39
  46. package/src/index.ts +6 -0
  47. package/src/protocol.ts +200 -3
  48. package/src/routes.ts +280 -13
  49. package/src/style-library.ts +78 -0
@@ -16,6 +16,16 @@ export declare class NovelApi {
16
16
  ok: boolean;
17
17
  bookName: string;
18
18
  }>;
19
+ /** 反推大纲:从已写章节正文反向生成全书总纲(NDJSON 流)。 */
20
+ outlineReverse(onFrame: (frame: JobFrame) => void): Promise<void>;
21
+ /** 分镜·导演级:骨架 → 分镜表(镜头级)。 */
22
+ storyboardTable(chapterNo: number, skeleton: import('../protocol.ts').StoryboardSkeleton, styleId?: string, filterId?: string): Promise<import('../protocol.ts').StoryboardTableResponse>;
23
+ /** 漫剧方案管理:create / remove / activate。 */
24
+ manhuaPlans(req: import('../protocol.ts').MangaPlansRequest): Promise<import('../protocol.ts').MangaPlansResponse>;
25
+ /** 分镜·提示词级:分镜表 → 即梦可粘贴视频提示词。 */
26
+ storyboardPrompts(chapterNo: number, table: import('../protocol.ts').StoryboardTable, styleId?: string, filterId?: string): Promise<import('../protocol.ts').StoryboardPromptsResponse>;
27
+ /** 分镜·编剧级:单章 → 剧情骨架(节拍链)。 */
28
+ storyboardSkeleton(chapterNo: number): Promise<import('../protocol.ts').StoryboardSkeletonResponse>;
19
29
  /** 开书想法 → AI 大纲:生成 count 个方案(换批时传 exclude 避开已暂留方向)。 */
20
30
  outlineSuggest(idea: string, count?: number, exclude?: string[]): Promise<import('../protocol.ts').OutlineSuggestResponse>;
21
31
  /** 拆书分析:对已写章节做结构/人物/文风/卖点体检。 */
@@ -118,8 +128,12 @@ export declare class NovelApi {
118
128
  bookRemove(id: string): Promise<import('../protocol.ts').BookshelfSnapshot>;
119
129
  /** 导入已有项目目录(Mode A):校验 novel-project.json,登记/激活书架。 */
120
130
  bookImportDir(outputDir: string): Promise<import('../protocol.ts').BookImportDirResponse>;
121
- /** 导入 txt/md 全本(Mode B):拆章建项目并登记书架。 */
131
+ /** 导入 txt/md 全本(Mode B):服务器本地文件路径模式。 */
122
132
  bookImportText(filePath: string, outputDir?: string): Promise<import('../protocol.ts').BookImportTextResponse>;
133
+ /** 拆章预览(浏览器上传全文,不落盘):返回识别到的章节与跳过清单。 */
134
+ bookImportTextPreview(text: string, fileName?: string): Promise<import('../protocol.ts').BookImportTextPreviewResponse>;
135
+ /** 导入 txt/md 全本(Mode B):浏览器上传全文内容模式。 */
136
+ bookImportTextContent(text: string, fileName: string, outputDir?: string): Promise<import('../protocol.ts').BookImportTextResponse>;
123
137
  /** 生产单:启动批量生产(区间或新增 N 章;计划不足自动补)。 */
124
138
  runStart(req: import('../protocol.ts').RunStartRequest): Promise<import('../protocol.ts').RunState>;
125
139
  /** 生产单控制:pause / resume / stop。 */
@@ -143,12 +143,14 @@ export declare const zh: {
143
143
  readonly 'settings.model': "模型";
144
144
  readonly 'settings.modelCustom': "自定义…";
145
145
  readonly 'settings.modelCustomPlaceholder': "输入任意模型 id";
146
- readonly 'settings.reasoningEffort': "思考强度 (reasoningEffort)";
146
+ readonly 'settings.reasoningEffort': "写作类任务思考强度 (reasoningEffort)";
147
+ readonly 'settings.reasoningHint': "章节生成/润色/重写/审稿等写作任务使用;关掉更省更快。";
148
+ readonly 'settings.analysisReasoning': "分析类任务思考强度(提炼/拆书/反推大纲)";
149
+ readonly 'settings.analysisReasoningHint': "角色/场景/道藏提炼、拆书、反推大纲等一次性分析任务默认 low,保证质量,不受上面写作档位影响。";
147
150
  readonly 'settings.reasoning.off': "off · 关闭思考(推荐日常写文)";
148
151
  readonly 'settings.reasoning.low': "low · 低思考";
149
152
  readonly 'settings.reasoning.high': "high · 高思考";
150
153
  readonly 'settings.reasoning.max': "max · 最高思考(质检/推演)";
151
- readonly 'settings.reasoningHint': "off 最快最省;high/max 更慢更贵但推理更强";
152
154
  readonly 'settings.theme': "主题";
153
155
  readonly 'settings.themeLiquid': "iOS 液态玻璃(绿)";
154
156
  readonly 'settings.themeClassic': "经典毛玻璃(蓝)";
@@ -0,0 +1,9 @@
1
+ import type { NovelApi } from '../api.ts';
2
+ import type { ChapterPlan, ProjectState } from '../../protocol.ts';
3
+ export declare function MangaWorkspace({ api, project, chapters, onProjectChanged, }: {
4
+ api: NovelApi;
5
+ project: ProjectState | null;
6
+ chapters: ChapterPlan[];
7
+ /** 方案变更已持久化后触发(刷新项目)。 */
8
+ onProjectChanged?: () => void | Promise<void>;
9
+ }): import("react").JSX.Element;
@@ -1,7 +1,7 @@
1
1
  import type { NovelApi } from '../api.ts';
2
2
  import type { PanelController } from './controller.ts';
3
3
  /** The panel's tab identifiers. */
4
- export type NovelTab = 'workflow' | 'overview' | 'blurb' | 'plan' | 'bible' | 'world' | 'foreshadow' | 'assistant' | 'settings' | 'characters' | 'roles' | 'facts' | 'plotlines' | 'reviews' | 'progress' | 'breakdown' | 'roleImage' | 'scenes' | 'assetsGenre' | 'assetsProgression' | 'assetsTemplates' | 'assetsRules' | 'assetsStyle' | 'run' | 'book' | 'assets';
4
+ export type NovelTab = 'workflow' | 'overview' | 'blurb' | 'plan' | 'bible' | 'world' | 'foreshadow' | 'assistant' | 'settings' | 'characters' | 'roles' | 'facts' | 'plotlines' | 'reviews' | 'progress' | 'breakdown' | 'roleImage' | 'scenes' | 'assetsGenre' | 'assetsProgression' | 'assetsTemplates' | 'assetsRules' | 'assetsStyle' | 'run' | 'manhua' | 'styleLib' | 'book' | 'assets';
5
5
  /** Panel shell props. */
6
6
  export interface NovelPanelProps {
7
7
  /** The panel state owner (open/close/toggle). */
@@ -0,0 +1,13 @@
1
+ import type { NovelApi } from '../api.ts';
2
+ import type { ChapterPlan, ProjectState } from '../../protocol.ts';
3
+ export declare function StoryboardTab({ api, project, chapters, onProjectChanged, styleId, filterId, }: {
4
+ api: NovelApi;
5
+ project: ProjectState | null;
6
+ chapters: ChapterPlan[];
7
+ /** 生成成功且已持久化后触发(刷新项目,切章/重进可恢复)。 */
8
+ onProjectChanged?: () => void | Promise<void>;
9
+ /** 漫剧基底风格 id(画面措辞随风格)。 */
10
+ styleId?: string;
11
+ /** 可选滤镜风格 id。 */
12
+ filterId?: string;
13
+ }): import("react").JSX.Element;
@@ -0,0 +1 @@
1
+ export declare function StyleGallery(): import("react").JSX.Element;
@@ -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, Volume, WorldState } from './protocol.ts';
15
+ import type { AuditIssue, AuthorReview, BreakdownResponse, ChapterPlan, Foreshadow, NovelConfig, OutlineCandidate, Plotline, PlotlineHealthReport, PlotlinePlan, ProjectState, ReviewReport, RoleRecord, RoleStatusCard, SceneCard, StoryBible, StoryboardSkeleton, StoryboardTable, StoryboardPrompt, 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 */
@@ -71,7 +71,28 @@ export declare function refreshPlotlineProgress(ctx: Context, config: NovelConfi
71
71
  export declare function extractRoles(ctx: Context, config: NovelConfig, project: ProjectState): Promise<RoleRecord[]>;
72
72
  /** ✨ AI 从全书提炼场景库:正文/编年录 → 高频重要场景的结构化视觉锚点。 */
73
73
  export declare function extractScenes(ctx: Context, config: NovelConfig, project: ProjectState): Promise<SceneCard[]>;
74
- /** 从 txt/md 全本拆分章节并建立项目:正文落盘为章节文件,status=written(待审稿)。 */
74
+ /** 从 txt/md 全本文本拆章(纯逻辑,不落盘):识别章节头、剥离重复标题、去重、排序并统一重新编号。 */
75
+ export declare function splitBookText(raw: string): Array<{
76
+ no: number;
77
+ title: string;
78
+ body: string;
79
+ }>;
80
+ /** 拆章预览(不落盘):章节编号/标题/字数 + 跳过清单。 */
81
+ export declare function previewBookText(raw: string): {
82
+ chapters: Array<{
83
+ no: number;
84
+ title: string;
85
+ chars: number;
86
+ }>;
87
+ skipped: string[];
88
+ };
89
+ /** 从全本文本导入(浏览器上传 / 服务器文件共用):建项目、写章节文件、保存。 */
90
+ export declare function importBookTextFromText(raw: string, outputDir: string, bookName: string): {
91
+ bookName: string;
92
+ chapters: number;
93
+ skipped: string[];
94
+ };
95
+ /** 从 txt/md 全本文件导入:编码自适应读取后拆章建项目,status=written(待审稿)。 */
75
96
  export declare function importBookText(filePath: string, outputDir: string): {
76
97
  bookName: string;
77
98
  chapters: number;
@@ -92,12 +113,12 @@ export interface RoleVisualPrompt {
92
113
  * 为单个角色提炼「动漫形象描述词」:扫描该角色出场的已写章节正文,
93
114
  * 截取含外貌描写的段落,交给 LLM 提炼中文描述 + 英文绘图标签。
94
115
  */
95
- export declare function extractRoleVisual(ctx: Context, config: NovelConfig, project: ProjectState, outputDir: string, roleName: string): Promise<RoleVisualPrompt>;
116
+ export declare function extractRoleVisual(ctx: Context, config: NovelConfig, project: ProjectState, outputDir: string, roleName: string, styleId?: string, filterId?: string): Promise<RoleVisualPrompt>;
96
117
  /**
97
118
  * 角色四类生图提示词精修包(promptKit):以锚点 + 表情清单 + 视觉规则为输入,
98
119
  * LLM 产出 立绘/四视图/表情×N/细节 四套 zh+en 提示词(比前端拼装更精炼)。
99
120
  */
100
- export declare function generateRolePromptKit(ctx: Context, config: NovelConfig, project: ProjectState, roleName: string): Promise<RoleRecord['promptKit']>;
121
+ export declare function generateRolePromptKit(ctx: Context, config: NovelConfig, project: ProjectState, roleName: string, styleId?: string, filterId?: string): Promise<RoleRecord['promptKit']>;
101
122
  /** ✨ 从道藏/红线提炼「视觉世界观规则」:生图/生视频必须遵守的设定纠偏(如"商品=人,禁止常规超市商品")。 */
102
123
  export declare function extractVisualRules(ctx: Context, config: NovelConfig, project: ProjectState): Promise<string[]>;
103
124
  /**
@@ -161,6 +182,27 @@ export declare function generateChapterStream(ctx: Context, config: NovelConfig,
161
182
  }, void, unknown>;
162
183
  /** Generate a chapter summary (narrative memory). */
163
184
  export declare function summarizeChapter(ctx: Context, config: NovelConfig, project: ProjectState, outputDir: string, chapterNo: number): Promise<string>;
185
+ /**
186
+ * 分镜·导演级:剧情骨架 → 分镜表(镜头级)。
187
+ * 只做画面层:景别/机位运镜/时长/画面/台词/音效/光效 + 状态连续;禁止改剧情(骨架只读)。
188
+ */
189
+ export declare function generateStoryboardTable(ctx: Context, config: NovelConfig, project: ProjectState, outputDir: string, chapterNo: number, skeleton: StoryboardSkeleton, styleId?: string, filterId?: string): Promise<StoryboardTable>;
190
+ /**
191
+ * 分镜·提示词级:分镜表 → 即梦可粘贴视频提示词。
192
+ * 每镜头一段:风格词块(基底+滤镜)+ 画面内容(角色动作/服装标志物)+ 机位运镜 + 光效。
193
+ * 提示词聚焦画面与镜头(视频模型无音频,台词/音效不注入)。
194
+ */
195
+ export declare function generateStoryboardPrompts(ctx: Context, config: NovelConfig, project: ProjectState, outputDir: string, chapterNo: number, table: StoryboardTable, styleId?: string, filterId?: string): Promise<StoryboardPrompt[]>;
196
+ /**
197
+ * 分镜·编剧级:单章 → 剧情骨架(节拍链)。
198
+ * 只做故事层(事件/情绪/功能/因果),不做画面;导演级分镜在其上展开。
199
+ */
200
+ export declare function generateStoryboardSkeleton(ctx: Context, config: NovelConfig, project: ProjectState, outputDir: string, chapterNo: number): Promise<StoryboardSkeleton>;
201
+ /**
202
+ * 反向推大纲:从已写章节正文反推出全书总纲(分卷 + 章节要点 + 主线/人物弧线/伏笔清单)。
203
+ * 两阶段:分批提取章节事件摘要 → 汇总生成大纲。不修改章节/设定,只返回大纲文本。
204
+ */
205
+ export declare function reverseOutlineFromChapters(ctx: Context, config: NovelConfig, project: ProjectState, outputDir: string, onProgress?: (done: number, total: number, phase: string) => void): Promise<string>;
164
206
  /**
165
207
  * 摘要 + 事实抽取合并为一次 LLM 调用(省一次调用与一次正文输入,
166
208
  * 批量生成时整体开销约省 25%)。
@@ -35,6 +35,8 @@ export interface Config {
35
35
  model?: string;
36
36
  /** LLM reasoning effort (off/low/high/max). */
37
37
  reasoningEffort?: 'off' | 'low' | 'high' | 'max';
38
+ /** 分析类任务(提炼/拆书/反推大纲等)的推理档位;默认 low。 */
39
+ analysisReasoning?: 'off' | 'low' | 'high' | 'max';
38
40
  /** Target characters per chapter. */
39
41
  chapterChars?: number;
40
42
  /** Max output tokens per chapter call. */
@@ -39,6 +39,16 @@ export declare const NOVEL_API: {
39
39
  readonly bookshelfImportDir: "/api/dsh-novel-forge/bookshelf/import-dir";
40
40
  /** 导入 txt/md 全本:拆章建项目并登记书架。 */
41
41
  readonly bookshelfImportText: "/api/dsh-novel-forge/bookshelf/import-text";
42
+ /** 导入 txt/md 全本:拆章预览(不落盘)。 */
43
+ readonly bookshelfImportTextPreview: "/api/dsh-novel-forge/bookshelf/import-text/preview";
44
+ /** 漫剧方案管理:create/remove/activate。 */
45
+ readonly manhuaPlans: "/api/dsh-novel-forge/manhua/plans";
46
+ /** 分镜·编剧级:单章 → 剧情骨架(节拍链)。 */
47
+ readonly storyboardSkeleton: "/api/dsh-novel-forge/storyboard/skeleton";
48
+ /** 分镜·导演级:骨架 → 分镜表(镜头级)。 */
49
+ readonly storyboardTable: "/api/dsh-novel-forge/storyboard/table";
50
+ /** 分镜·提示词级:分镜表 → 即梦可粘贴视频提示词。 */
51
+ readonly storyboardPrompts: "/api/dsh-novel-forge/storyboard/prompts";
42
52
  /** 重置项目(可选携带新大纲):清空设定/卷/章节/伏笔/资产/事实库。 */
43
53
  readonly reset: "/api/dsh-novel-forge/reset";
44
54
  /** 全书一致性质检:LLM 扫描已生成章节,输出矛盾问题清单。 */
@@ -73,6 +83,8 @@ export declare const NOVEL_API: {
73
83
  readonly sensitiveCheck: "/api/dsh-novel-forge/sensitive-check";
74
84
  /** 开书想法 → AI 补全大纲:输入一句话想法,生成 2-3 个可选大纲方案。 */
75
85
  readonly outlineSuggest: "/api/dsh-novel-forge/outline/suggest";
86
+ /** 反推大纲:从已写章节正文反向生成全书总纲(NDJSON 流)。 */
87
+ readonly outlineReverse: "/api/dsh-novel-forge/outline/reverse";
76
88
  /** 拆书分析:对已写章节做结构/人物/文风/卖点四维体检(两阶段:源笔记→分节分析)。 */
77
89
  readonly breakdown: "/api/dsh-novel-forge/breakdown";
78
90
  /** 漫剧分镜生成:章节 → 角色锚点 + 分镜表(可适配豆包/Seedance/SD)。 */
@@ -143,10 +155,17 @@ export interface BookImportDirResponse {
143
155
  /** true = 目录已在书架中(本次为重新激活)。 */
144
156
  existed: boolean;
145
157
  }
146
- /** POST /bookshelf/import-text 请求:导入 txt/md 全本。 */
158
+ /** POST /bookshelf/import-text 请求:导入 txt/md 全本。两种模式二选一:
159
+ * - filePath:服务器本地文件路径;
160
+ * - text + fileName:浏览器上传的全文内容(fileName 用于推断书名)。
161
+ */
147
162
  export interface BookImportTextRequest {
148
- /** 源文件绝对路径(txt 或 md)。 */
149
- filePath: string;
163
+ /** 模式一:源文件绝对路径(txt 或 md)。 */
164
+ filePath?: string;
165
+ /** 模式二:浏览器上传的全文内容。 */
166
+ text?: string;
167
+ /** 模式二:原文件名(txt/md),用于推断书名与显示。 */
168
+ fileName?: string;
150
169
  /** 输出目录;缺省为 ~/.dsh/novels/书名。 */
151
170
  outputDir?: string;
152
171
  }
@@ -160,6 +179,158 @@ export interface BookImportTextResponse {
160
179
  /** 登记后的书架条目。 */
161
180
  book: BookEntry;
162
181
  }
182
+ /** POST /bookshelf/import-text/preview 请求:上传全文做拆章预览(不落盘)。 */
183
+ export interface BookImportTextPreviewRequest {
184
+ text: string;
185
+ /** 原文件名(txt/md),用于推断书名。 */
186
+ fileName?: string;
187
+ }
188
+ /** POST /bookshelf/import-text/preview 响应。 */
189
+ export interface BookImportTextPreviewResponse {
190
+ /** 预计书名(fileName 去扩展名)。 */
191
+ bookName: string;
192
+ /** 识别出的章节(已按正文长度过滤过短章节)。 */
193
+ chapters: Array<{
194
+ no: number;
195
+ title: string;
196
+ chars: number;
197
+ }>;
198
+ /** 因内容过短被跳过的章节标题列表。 */
199
+ skipped: string[];
200
+ }
201
+ /** 分镜·编剧级:剧情骨架中的一节拍。 */
202
+ export interface StoryboardBeat {
203
+ /** 节拍 id(如 b1、b2)。 */
204
+ id: string;
205
+ /** 事件一句话(发生了什么)。 */
206
+ event: string;
207
+ /** 情绪走向(如 压抑→隐忍→惊惧)。 */
208
+ emotion: string;
209
+ /** 叙事功能:铺垫/冲突/转折/高潮/收束/伏笔/人物塑造。 */
210
+ function: string;
211
+ /** 因果:承接上一节拍的原因(可选)。 */
212
+ cause?: string;
213
+ }
214
+ /** 分镜·编剧级:单章剧情骨架。 */
215
+ export interface StoryboardSkeleton {
216
+ chapterNo: number;
217
+ /** 本章弧线一句话(起承转合)。 */
218
+ arc: string;
219
+ /** 剧情节拍链(时间顺序,因果连贯)。 */
220
+ beats: StoryboardBeat[];
221
+ }
222
+ /** POST /storyboard/skeleton 请求:生成单章剧情骨架。 */
223
+ export interface StoryboardSkeletonRequest {
224
+ chapterNo: number;
225
+ }
226
+ /** POST /storyboard/skeleton 响应。 */
227
+ export interface StoryboardSkeletonResponse {
228
+ skeleton: StoryboardSkeleton;
229
+ }
230
+ /** 分镜·导演级:一个镜头。 */
231
+ export interface StoryboardShot {
232
+ /** 镜头 id(如 s1、s2)。 */
233
+ id: string;
234
+ /** 挂载的节拍 id(骨架中的 b1…)。 */
235
+ beatId: string;
236
+ /** 景别:远景/全景/中景/近景/特写。 */
237
+ shot: string;
238
+ /** 机位与运镜(如 低机位仰拍 + 缓慢推近)。 */
239
+ camera: string;
240
+ /** 时长(秒,1-12)。 */
241
+ duration: number;
242
+ /** 画面内容:角色动作 + 表情 + 服装/标志物。 */
243
+ visual: string;
244
+ /** 台词/旁白(无则空字符串)。 */
245
+ line: string;
246
+ /** 音效(无则空字符串)。 */
247
+ sound: string;
248
+ /** 光效(如 雨夜顶光 + 手机屏幕冷光)。 */
249
+ light: string;
250
+ /** 承接上一镜头结尾状态(位置/动作/情绪/服装)。 */
251
+ prevState: string;
252
+ /** 本镜头结束状态。 */
253
+ nextState: string;
254
+ }
255
+ /** 分镜·导演级:单章分镜表。 */
256
+ export interface StoryboardTable {
257
+ chapterNo: number;
258
+ shots: StoryboardShot[];
259
+ }
260
+ /** POST /storyboard/table 请求:骨架 → 分镜表。 */
261
+ export interface StoryboardTableRequest {
262
+ chapterNo: number;
263
+ /** 编剧级骨架(前端已生成/编辑后的版本)。 */
264
+ skeleton: StoryboardSkeleton;
265
+ /** 漫剧方案基底风格 id(style-library);提供时按风格措辞画面描述。 */
266
+ styleId?: string;
267
+ /** 可选滤镜风格 id(stackable)。 */
268
+ filterId?: string;
269
+ }
270
+ /** POST /storyboard/table 响应。 */
271
+ export interface StoryboardTableResponse {
272
+ table: StoryboardTable;
273
+ }
274
+ /** 分镜·提示词级:一个镜头的即梦视频提示词。 */
275
+ export interface StoryboardPrompt {
276
+ /** 对应镜头 id(s1…)。 */
277
+ shotId: string;
278
+ /** 即梦/视频模型可粘贴的中文提示词(画面+运镜+光效+风格词块)。 */
279
+ text: string;
280
+ }
281
+ /** 分镜持久化:单章的分镜产出(骨架 + 分镜表 + 视频提示词,可分别存在)。 */
282
+ export interface ChapterStoryboard {
283
+ chapterNo: number;
284
+ skeleton?: StoryboardSkeleton;
285
+ table?: StoryboardTable;
286
+ prompts?: StoryboardPrompt[];
287
+ updatedAt: string;
288
+ }
289
+ /** POST /storyboard/prompts 请求:分镜表 → 视频提示词。 */
290
+ export interface StoryboardPromptsRequest {
291
+ chapterNo: number;
292
+ /** 分镜表(前端已生成的镜头列表)。 */
293
+ table: StoryboardTable;
294
+ /** 基底风格 id。 */
295
+ styleId?: string;
296
+ /** 可选滤镜风格 id。 */
297
+ filterId?: string;
298
+ }
299
+ /** POST /storyboard/prompts 响应。 */
300
+ export interface StoryboardPromptsResponse {
301
+ prompts: StoryboardPrompt[];
302
+ }
303
+ /** 漫剧方案:同一本书的多套视觉演绎(基底风格 + 可选滤镜)。 */
304
+ export interface MangaPlan {
305
+ /** 方案 id。 */
306
+ id: string;
307
+ /** 方案名(如《保质期》3D 皮克斯版)。 */
308
+ name: string;
309
+ /** 基底风格 id(style-library 中非 stackable 风格)。 */
310
+ styleId: string;
311
+ /** 可选滤镜风格 id(style-library 中 stackable 风格)。 */
312
+ filterId?: string;
313
+ /** 是否激活(分镜/角色图生成时使用)。 */
314
+ active: boolean;
315
+ createdAt: string;
316
+ updatedAt: string;
317
+ }
318
+ /** POST /manhua/plans 请求:漫剧方案管理。 */
319
+ export interface MangaPlansRequest {
320
+ op: 'create' | 'remove' | 'activate';
321
+ /** create:方案名。 */
322
+ name?: string;
323
+ /** create:基底风格 id。 */
324
+ styleId?: string;
325
+ /** create:可选滤镜风格 id。 */
326
+ filterId?: string;
327
+ /** remove/activate:方案 id。 */
328
+ id?: string;
329
+ }
330
+ /** POST /manhua/plans 响应。 */
331
+ export interface MangaPlansResponse {
332
+ plans: MangaPlan[];
333
+ }
163
334
  /** Chapter lifecycle states (the writing pipeline's state machine). */
164
335
  export type ChapterStatus = 'pending' | 'generating' | 'written' | 'reviewing' | 'approved' | 'rejected' | 'error';
165
336
  /** One chapter in the plan. */
@@ -644,6 +815,10 @@ export interface RolesRequest {
644
815
  label?: string;
645
816
  /** op='imageGenerate' 时的漫画风格预设 id(用于统一角色图与漫画页风格)。 */
646
817
  style?: string;
818
+ /** op='visual' / op='promptKit' 时的漫剧基底风格 id(角色图按方案风格重出)。 */
819
+ styleId?: string;
820
+ /** op='visual' / op='promptKit' 时的可选滤镜风格 id。 */
821
+ filterId?: string;
647
822
  }
648
823
  /** POST /roles 响应。 */
649
824
  export interface RolesResponse {
@@ -775,6 +950,10 @@ export interface ProjectState {
775
950
  scenes?: SceneCard[];
776
951
  /** 视觉世界观规则(生图/生视频必须遵守,从道藏提炼,注入所有提示词)。 */
777
952
  visualRules?: string[];
953
+ /** 分镜工作台产出(骨架/分镜表,按章持久化,刷新/切换不丢)。 */
954
+ storyboards?: ChapterStoryboard[];
955
+ /** 漫剧方案列表(同一本书的多套视觉演绎:基底风格 + 可选滤镜)。 */
956
+ mangaPlans?: MangaPlan[];
778
957
  /** 人物志:角色当前状态聚合结果(从编年录刷新后存档,打开页面直接显示)。 */
779
958
  roleStatus?: RoleStatusCard[];
780
959
  /** 漫剧分镜结果缓存:章号 → 分镜(持久化,刷新不丢)。 */
@@ -796,6 +975,8 @@ export interface NovelConfig {
796
975
  model: string;
797
976
  /** LLM reasoning effort: off = no thinking; low/high/max = thinking intensity. */
798
977
  reasoningEffort: 'off' | 'low' | 'high' | 'max';
978
+ /** 分析类任务(提炼/拆书/反推大纲等)的推理档位;默认 low,不受上面写作档位影响。 */
979
+ analysisReasoning: 'off' | 'low' | 'high' | 'max';
799
980
  /** Target characters per chapter. */
800
981
  chapterChars: number;
801
982
  /** Max output tokens per chapter call. */
@@ -961,6 +1142,15 @@ export type JobFrame = {
961
1142
  no: number;
962
1143
  chars: number;
963
1144
  draft: string;
1145
+ } | {
1146
+ type: 'outline-progress';
1147
+ done: number;
1148
+ total: number;
1149
+ phase: string;
1150
+ } | {
1151
+ type: 'outline-done';
1152
+ outline: string;
1153
+ chars: number;
964
1154
  } | {
965
1155
  type: 'error';
966
1156
  no: number;
@@ -1032,6 +1222,7 @@ export interface ConfigPatch {
1032
1222
  provider?: string;
1033
1223
  model?: string;
1034
1224
  reasoningEffort?: 'off' | 'low' | 'high' | 'max';
1225
+ analysisReasoning?: 'off' | 'low' | 'high' | 'max';
1035
1226
  chapterChars?: number;
1036
1227
  maxTokens?: number;
1037
1228
  reviewPassScore?: number;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * 风格库(内置模板):漫剧方案的视觉基底 + 可叠加滤镜。
3
+ * 字段来自通用风格模板(豆包整理),keywords 即风格前缀词块,生成时直接套用。
4
+ */
5
+ export type StyleCategory = '3d' | 'game' | '2d' | 'film' | 'craft';
6
+ export interface ArtStyle {
7
+ id: string;
8
+ /** 风格名(用户可见)。 */
9
+ name: string;
10
+ category: StyleCategory;
11
+ /** 特点一句话(卡片展示)。 */
12
+ traits: string;
13
+ /** 风格关键词/前缀(生成角色图/视频提示词时套用)。 */
14
+ keywords: string;
15
+ /** 是否可作为滤镜叠加在基底风格之上(影视实验类;缺省 false)。 */
16
+ stackable?: boolean;
17
+ /** 默认推荐排序权重(0-1,推荐池排序参考)。 */
18
+ weight?: number;
19
+ }
20
+ export declare const STYLE_CATEGORIES: ReadonlyArray<{
21
+ id: StyleCategory;
22
+ label: string;
23
+ icon: string;
24
+ desc: string;
25
+ }>;
26
+ /** 内置风格模板(18 个)。 */
27
+ export declare const STYLE_LIBRARY: ArtStyle[];
28
+ /** 按分类取风格。 */
29
+ export declare function stylesByCategory(category: StyleCategory): ArtStyle[];
30
+ /** 取单个风格(未找到返回 undefined)。 */
31
+ export declare function findStyle(id: string): ArtStyle | undefined;
32
+ /** 按基底 + 滤镜拼接风格关键词(角色图/分镜/视频提示词共用;缺省回退 3D 动漫)。 */
33
+ export declare function styleKeywords(styleId?: string, filterId?: string): 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.0",
4
+ "version": "1.5.0",
5
5
  "type": "module",
6
6
  "engines": {
7
7
  "node": "^22.19.0 || >=24.0.0"
@@ -81,6 +81,7 @@
81
81
  "lib/**/*.d.ts",
82
82
  "lib/**/*.d.ts.map",
83
83
  "src",
84
+ "assets/styles",
84
85
  "scripts/patch-schemastery.mjs",
85
86
  "cordis.patch.yml",
86
87
  "README.md"
package/src/client/api.ts CHANGED
@@ -75,6 +75,31 @@ export class NovelApi {
75
75
  return postJson<{ ok: boolean; bookName: string }>(NOVEL_API.saveOutline, { text })
76
76
  }
77
77
 
78
+ /** 反推大纲:从已写章节正文反向生成全书总纲(NDJSON 流)。 */
79
+ async outlineReverse(onFrame: (frame: JobFrame) => void): Promise<void> {
80
+ await this.streamJob(NOVEL_API.outlineReverse, {}, onFrame)
81
+ }
82
+
83
+ /** 分镜·导演级:骨架 → 分镜表(镜头级)。 */
84
+ async storyboardTable(chapterNo: number, skeleton: import('../protocol.ts').StoryboardSkeleton, styleId?: string, filterId?: string): Promise<import('../protocol.ts').StoryboardTableResponse> {
85
+ return postJson<import('../protocol.ts').StoryboardTableResponse>(NOVEL_API.storyboardTable, { chapterNo, skeleton, styleId, filterId })
86
+ }
87
+
88
+ /** 漫剧方案管理:create / remove / activate。 */
89
+ async manhuaPlans(req: import('../protocol.ts').MangaPlansRequest): Promise<import('../protocol.ts').MangaPlansResponse> {
90
+ return postJson<import('../protocol.ts').MangaPlansResponse>(NOVEL_API.manhuaPlans, req)
91
+ }
92
+
93
+ /** 分镜·提示词级:分镜表 → 即梦可粘贴视频提示词。 */
94
+ async storyboardPrompts(chapterNo: number, table: import('../protocol.ts').StoryboardTable, styleId?: string, filterId?: string): Promise<import('../protocol.ts').StoryboardPromptsResponse> {
95
+ return postJson<import('../protocol.ts').StoryboardPromptsResponse>(NOVEL_API.storyboardPrompts, { chapterNo, table, styleId, filterId })
96
+ }
97
+
98
+ /** 分镜·编剧级:单章 → 剧情骨架(节拍链)。 */
99
+ async storyboardSkeleton(chapterNo: number): Promise<import('../protocol.ts').StoryboardSkeletonResponse> {
100
+ return postJson<import('../protocol.ts').StoryboardSkeletonResponse>(NOVEL_API.storyboardSkeleton, { chapterNo })
101
+ }
102
+
78
103
  /** 开书想法 → AI 大纲:生成 count 个方案(换批时传 exclude 避开已暂留方向)。 */
79
104
  async outlineSuggest(idea: string, count?: number, exclude?: string[]): Promise<import('../protocol.ts').OutlineSuggestResponse> {
80
105
  return postJson<import('../protocol.ts').OutlineSuggestResponse>(NOVEL_API.outlineSuggest, { idea, count, exclude })
@@ -259,11 +284,21 @@ export class NovelApi {
259
284
  return postJson<import('../protocol.ts').BookImportDirResponse>(NOVEL_API.bookshelfImportDir, { outputDir })
260
285
  }
261
286
 
262
- /** 导入 txt/md 全本(Mode B):拆章建项目并登记书架。 */
287
+ /** 导入 txt/md 全本(Mode B):服务器本地文件路径模式。 */
263
288
  async bookImportText(filePath: string, outputDir?: string): Promise<import('../protocol.ts').BookImportTextResponse> {
264
289
  return postJson<import('../protocol.ts').BookImportTextResponse>(NOVEL_API.bookshelfImportText, { filePath, outputDir })
265
290
  }
266
291
 
292
+ /** 拆章预览(浏览器上传全文,不落盘):返回识别到的章节与跳过清单。 */
293
+ async bookImportTextPreview(text: string, fileName?: string): Promise<import('../protocol.ts').BookImportTextPreviewResponse> {
294
+ return postJson<import('../protocol.ts').BookImportTextPreviewResponse>(NOVEL_API.bookshelfImportTextPreview, { text, fileName })
295
+ }
296
+
297
+ /** 导入 txt/md 全本(Mode B):浏览器上传全文内容模式。 */
298
+ async bookImportTextContent(text: string, fileName: string, outputDir?: string): Promise<import('../protocol.ts').BookImportTextResponse> {
299
+ return postJson<import('../protocol.ts').BookImportTextResponse>(NOVEL_API.bookshelfImportText, { text, fileName, outputDir })
300
+ }
301
+
267
302
  /** 生产单:启动批量生产(区间或新增 N 章;计划不足自动补)。 */
268
303
  async runStart(req: import('../protocol.ts').RunStartRequest): Promise<import('../protocol.ts').RunState> {
269
304
  return postJson<import('../protocol.ts').RunState>(NOVEL_API.runStart, req)
@@ -144,12 +144,14 @@ export const zh = {
144
144
  'settings.model': '模型',
145
145
  'settings.modelCustom': '自定义…',
146
146
  'settings.modelCustomPlaceholder': '输入任意模型 id',
147
- 'settings.reasoningEffort': '思考强度 (reasoningEffort)',
147
+ 'settings.reasoningEffort': '写作类任务思考强度 (reasoningEffort)',
148
+ 'settings.reasoningHint': '章节生成/润色/重写/审稿等写作任务使用;关掉更省更快。',
149
+ 'settings.analysisReasoning': '分析类任务思考强度(提炼/拆书/反推大纲)',
150
+ 'settings.analysisReasoningHint': '角色/场景/道藏提炼、拆书、反推大纲等一次性分析任务默认 low,保证质量,不受上面写作档位影响。',
148
151
  'settings.reasoning.off': 'off · 关闭思考(推荐日常写文)',
149
152
  'settings.reasoning.low': 'low · 低思考',
150
153
  'settings.reasoning.high': 'high · 高思考',
151
154
  'settings.reasoning.max': 'max · 最高思考(质检/推演)',
152
- 'settings.reasoningHint': 'off 最快最省;high/max 更慢更贵但推理更强',
153
155
  'settings.theme': '主题',
154
156
  'settings.themeLiquid': 'iOS 液态玻璃(绿)',
155
157
  'settings.themeClassic': '经典毛玻璃(蓝)',
@@ -295,7 +297,9 @@ export const en: Record<string, string> = {
295
297
  'settings.model': 'Model',
296
298
  'settings.modelCustom': 'Custom…',
297
299
  'settings.modelCustomPlaceholder': 'Type any model id',
298
- 'settings.reasoningEffort': 'Reasoning effort',
300
+ 'settings.reasoningEffort': 'Writing-task reasoning effort',
301
+ 'settings.analysisReasoning': 'Analysis-task reasoning (extract / breakdown / reverse outline)',
302
+ 'settings.analysisReasoningHint': 'One-off analysis tasks (roles/scenes/bible extract, breakdown, reverse outline) default to low; not affected by the writing-level switch.',
299
303
  'settings.reasoning.off': 'off · no thinking (recommended)',
300
304
  'settings.reasoning.low': 'low',
301
305
  'settings.reasoning.high': 'high',