@waterwx/dsh-novel-forge 1.1.9 → 1.2.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.
@@ -141,6 +141,14 @@ export declare const zh: {
141
141
  readonly 'settings.outputDir': "输出目录";
142
142
  readonly 'settings.provider': "模型提供商";
143
143
  readonly 'settings.model': "模型";
144
+ readonly 'settings.modelCustom': "自定义…";
145
+ readonly 'settings.modelCustomPlaceholder': "输入任意模型 id";
146
+ readonly 'settings.reasoningEffort': "思考强度 (reasoningEffort)";
147
+ readonly 'settings.reasoning.off': "off · 关闭思考(推荐日常写文)";
148
+ readonly 'settings.reasoning.low': "low · 低思考";
149
+ readonly 'settings.reasoning.high': "high · 高思考";
150
+ readonly 'settings.reasoning.max': "max · 最高思考(质检/推演)";
151
+ readonly 'settings.reasoningHint': "off 最快最省;high/max 更慢更贵但推理更强";
144
152
  readonly 'settings.theme': "主题";
145
153
  readonly 'settings.themeLiquid': "iOS 液态玻璃(绿)";
146
154
  readonly 'settings.themeClassic': "经典毛玻璃(蓝)";
@@ -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' | 'storyboard' | 'assetsGenre' | 'assetsProgression' | 'assetsTemplates' | 'assetsRules' | 'assetsStyle' | 'run';
4
+ export type NovelTab = 'workflow' | 'overview' | 'blurb' | 'plan' | 'bible' | 'world' | 'foreshadow' | 'assistant' | 'settings' | 'characters' | 'roles' | 'facts' | 'plotlines' | 'reviews' | 'progress' | 'breakdown' | 'storyboard' | 'assetsGenre' | 'assetsProgression' | 'assetsTemplates' | 'assetsRules' | 'assetsStyle' | 'run' | 'book' | 'assets';
5
5
  /** Panel shell props. */
6
6
  export interface NovelPanelProps {
7
7
  /** The panel state owner (open/close/toggle). */
@@ -174,7 +174,7 @@ export declare function markForeshadowPlanted(project: ProjectState, outputDir:
174
174
  */
175
175
  export declare function extractFacts(ctx: Context, config: NovelConfig, project: ProjectState, outputDir: string, chapterNo: number): Promise<number>;
176
176
  /** 全书一致性质检:LLM 分批扫描已生成章节 + 设定 + 事实库,聚合矛盾清单。 */
177
- export declare function auditBook(ctx: Context, config: NovelConfig, project: ProjectState, outputDir: string): Promise<AuditIssue[]>;
177
+ export declare function auditBook(ctx: Context, config: NovelConfig, project: ProjectState, outputDir: string, onProgress?: (completedBatches: number, totalBatches: number) => void): Promise<AuditIssue[]>;
178
178
  /** 小说简介:AI 生成或按已写开头补全(面向读者的作品门面)。 */
179
179
  export declare function generateBlurb(ctx: Context, config: NovelConfig, project: ProjectState, partial?: string): Promise<string>;
180
180
  /**
@@ -33,6 +33,8 @@ export interface Config {
33
33
  provider?: string;
34
34
  /** LLM model id. */
35
35
  model?: string;
36
+ /** LLM reasoning effort (off/low/high/max). */
37
+ reasoningEffort?: 'off' | 'low' | 'high' | 'max';
36
38
  /** Target characters per chapter. */
37
39
  chapterChars?: number;
38
40
  /** Max output tokens per chapter call. */
@@ -285,6 +285,26 @@ export interface AuditResponse {
285
285
  /** 质检时间。 */
286
286
  auditedAt: string;
287
287
  }
288
+ /** 全书质检的实时状态(通过 /status 暴露给面板/外部读取)。 */
289
+ export interface AuditStatus {
290
+ status: 'idle' | 'running' | 'done' | 'error';
291
+ /** 开始时间(ISO)。 */
292
+ startedAt?: string;
293
+ /** 结束时间(ISO)。 */
294
+ finishedAt?: string;
295
+ /** 总批次数(0 = 尚未开始/无章节)。 */
296
+ totalBatches: number;
297
+ /** 已完成批次数。 */
298
+ completedBatches: number;
299
+ /** 参与质检的章节数。 */
300
+ auditedChapters?: number;
301
+ /** 发现的问题数(done 后有效)。 */
302
+ issuesCount?: number;
303
+ /** 最近一次质检的问题清单(done 后有效;error 时为空)。 */
304
+ issues?: AuditIssue[];
305
+ /** 失败信息(error 时有效)。 */
306
+ error?: string;
307
+ }
288
308
  /** 一条剧情线(主线/支线/人物线/悬念线)。 */
289
309
  export interface Plotline {
290
310
  /** 稳定 id。 */
@@ -712,6 +732,8 @@ export interface NovelConfig {
712
732
  provider: string;
713
733
  /** LLM model id (e.g. deepseek-v4-flash). */
714
734
  model: string;
735
+ /** LLM reasoning effort: off = no thinking; low/high/max = thinking intensity. */
736
+ reasoningEffort: 'off' | 'low' | 'high' | 'max';
715
737
  /** Target characters per chapter. */
716
738
  chapterChars: number;
717
739
  /** Max output tokens per chapter call. */
@@ -732,6 +754,8 @@ export interface StatusResponse {
732
754
  project?: ProjectState;
733
755
  /** Chapter files already on disk (basenames, sorted). */
734
756
  generatedFiles: string[];
757
+ /** 全书质检实时状态(用于面板/外部读取进度)。 */
758
+ audit?: AuditStatus;
735
759
  }
736
760
  /** 生产单状态(生产单 = 区间批量生产执行器:计划补足 + 逐章生成 + 被拒分级处理)。 */
737
761
  export interface RunState {
@@ -939,6 +963,7 @@ export interface ConfigPatch {
939
963
  outputDir?: string;
940
964
  provider?: string;
941
965
  model?: string;
966
+ reasoningEffort?: 'off' | 'low' | 'high' | 'max';
942
967
  chapterChars?: number;
943
968
  maxTokens?: number;
944
969
  reviewPassScore?: number;
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.1.9",
4
+ "version": "1.2.0",
5
5
  "type": "module",
6
6
  "engines": {
7
7
  "node": "^22.19.0 || >=24.0.0"
@@ -142,6 +142,14 @@ export const zh = {
142
142
  'settings.outputDir': '输出目录',
143
143
  'settings.provider': '模型提供商',
144
144
  'settings.model': '模型',
145
+ 'settings.modelCustom': '自定义…',
146
+ 'settings.modelCustomPlaceholder': '输入任意模型 id',
147
+ 'settings.reasoningEffort': '思考强度 (reasoningEffort)',
148
+ 'settings.reasoning.off': 'off · 关闭思考(推荐日常写文)',
149
+ 'settings.reasoning.low': 'low · 低思考',
150
+ 'settings.reasoning.high': 'high · 高思考',
151
+ 'settings.reasoning.max': 'max · 最高思考(质检/推演)',
152
+ 'settings.reasoningHint': 'off 最快最省;high/max 更慢更贵但推理更强',
145
153
  'settings.theme': '主题',
146
154
  'settings.themeLiquid': 'iOS 液态玻璃(绿)',
147
155
  'settings.themeClassic': '经典毛玻璃(蓝)',
@@ -285,6 +293,14 @@ export const en: Record<string, string> = {
285
293
  'settings.outputDir': 'Output directory',
286
294
  'settings.provider': 'Provider',
287
295
  'settings.model': 'Model',
296
+ 'settings.modelCustom': 'Custom…',
297
+ 'settings.modelCustomPlaceholder': 'Type any model id',
298
+ 'settings.reasoningEffort': 'Reasoning effort',
299
+ 'settings.reasoning.off': 'off · no thinking (recommended)',
300
+ 'settings.reasoning.low': 'low',
301
+ 'settings.reasoning.high': 'high',
302
+ 'settings.reasoning.max': 'max (audit/reasoning)',
303
+ 'settings.reasoningHint': 'off is fastest/cheapest; high/max are slower and stronger',
288
304
  'settings.theme': 'Theme',
289
305
  'settings.themeLiquid': 'iOS Liquid Glass (green)',
290
306
  'settings.themeClassic': 'Classic frosted (blue)',
@@ -206,6 +206,10 @@ export function AssetsTab({ api, initialTab = 'genre' }: AssetsTabProps) {
206
206
 
207
207
  return (
208
208
  <div style={{ display: 'flex', flexDirection: 'column', gap: 12, flex: 1, minHeight: 0 }}>
209
+ <div className={css.row} style={{ justifyContent: 'space-between', flexWrap: 'wrap' }}>
210
+ <span className={css.cardTitle} style={{ fontSize: 17, fontWeight: 700 }}>🧰 创作资产</span>
211
+ <span className={css.meta}>题材基底 / 推进模式 / 笔法帖 / 文戒 / 心法</span>
212
+ </div>
209
213
  {error !== '' && <div className={css.card} style={{ borderColor: 'var(--nf-error)' }}><span style={{ color: 'var(--nf-error)' }}>{tt('common.error')}: {error}</span></div>}
210
214
  {notice !== '' && <div className={css.card}><span style={{ color: 'var(--nf-success)' }}>{notice}</span></div>}
211
215
 
@@ -235,6 +239,21 @@ export function AssetsTab({ api, initialTab = 'genre' }: AssetsTabProps) {
235
239
  </div>
236
240
  </div>
237
241
 
242
+ {/* 子页签:题材基底 / 推进模式 / 笔法帖 / 文戒 / 心法 */}
243
+ <div className={css.row} style={{ flexWrap: 'wrap', gap: 6 }}>
244
+ {SUB_TABS.map(t => (
245
+ <button
246
+ key={t.id}
247
+ type="button"
248
+ className={`${css.button} ${assetTab === t.id ? css.buttonPrimary : ''}`}
249
+ style={{ fontSize: 14, flex: 1 }}
250
+ onClick={() => { setAssetTab(t.id) }}
251
+ >
252
+ {t.label}
253
+ </button>
254
+ ))}
255
+ </div>
256
+
238
257
  {/* 题材基底库 */}
239
258
  {assetTab === 'genre' && (
240
259
  <div className={css.card}>