@waterwx/dsh-novel-forge 1.6.0 → 1.7.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/lib/client.js +35487 -745
- package/lib/client.js.map +1 -1
- package/lib/index.js +111 -12
- package/lib/index.js.map +1 -1
- package/lib/types/client/api.d.ts +1 -0
- package/lib/types/client/panel/MangaWorkspace.d.ts +6 -4
- package/lib/types/client/panel/RoleVisualPanel.d.ts +5 -3
- package/lib/types/client/panel/SceneLibrary.d.ts +1 -1
- package/lib/types/client/panel/StoryboardTab.d.ts +1 -1
- package/lib/types/engine.d.ts +8 -1
- package/lib/types/index.d.ts +6 -4
- package/lib/types/protocol.d.ts +47 -3
- package/package.json +99 -98
- package/src/client/api.ts +4 -0
- package/src/client/panel/MangaWorkspace.tsx +7 -3
- package/src/client/panel/NovelPanel.tsx +389 -231
- package/src/client/panel/RoleVisualPanel.tsx +23 -6
- package/src/client/panel/RunPanel.tsx +1 -1
- package/src/client/panel/SceneLibrary.tsx +1 -1
- package/src/client/panel/ShelfView.tsx +28 -35
- package/src/client/panel/StoryboardTab.tsx +1 -1
- package/src/client/panel/panel.module.css +407 -23
- package/src/engine.ts +48 -8
- package/src/index.ts +37 -6
- package/src/protocol.ts +50 -3
- package/src/routes.ts +26 -1
package/src/index.ts
CHANGED
|
@@ -15,7 +15,7 @@ import z from 'schemastery'
|
|
|
15
15
|
import type {} from '@deepseek-ai/dsh-host-webserver'
|
|
16
16
|
import type {} from '@deepseek-ai/dsh-llm'
|
|
17
17
|
import type {} from '@deepseek-ai/dsh-system-prompt'
|
|
18
|
-
import type { ConfigPatch, NovelConfig } from './protocol.ts'
|
|
18
|
+
import type { ConfigPatch, ImageModelConfig, NovelConfig } from './protocol.ts'
|
|
19
19
|
import { makeRoutes } from './routes.ts'
|
|
20
20
|
import { activeBookOutputDir } from './bookshelf.ts'
|
|
21
21
|
|
|
@@ -62,11 +62,13 @@ export interface Config {
|
|
|
62
62
|
autoAuthorReview?: boolean
|
|
63
63
|
/** 修订/润色产出草稿后自动附带一次 AI 审查(默认开,可在设置页关闭省 token)。 */
|
|
64
64
|
autoReviewAfterRevise?: boolean
|
|
65
|
-
/**
|
|
65
|
+
/** 生图模型库(多套并存,启用一条生效)。 */
|
|
66
|
+
imageModels?: ImageModelConfig[]
|
|
67
|
+
/** 豆包/Seedream 生图 API Key(旧字段,兼容迁移用)。 */
|
|
66
68
|
imageApiKey?: string
|
|
67
|
-
/** 豆包/Seedream 生图模型 ID
|
|
69
|
+
/** 豆包/Seedream 生图模型 ID(旧字段,兼容迁移用)。 */
|
|
68
70
|
imageApiModel?: string
|
|
69
|
-
/**
|
|
71
|
+
/** 是否启用豆包生图(旧字段,兼容迁移用)。 */
|
|
70
72
|
imageApiEnabled?: boolean
|
|
71
73
|
}
|
|
72
74
|
|
|
@@ -85,6 +87,14 @@ export const Config: z<Config> = z.object({
|
|
|
85
87
|
autoReview: z.boolean().default(true),
|
|
86
88
|
autoAuthorReview: z.boolean().default(true),
|
|
87
89
|
autoReviewAfterRevise: z.boolean().default(true),
|
|
90
|
+
imageModels: z.array(z.object({
|
|
91
|
+
id: z.string().default(''),
|
|
92
|
+
name: z.string().default(''),
|
|
93
|
+
baseURL: z.string().default(''),
|
|
94
|
+
apiKey: z.string().default(''),
|
|
95
|
+
model: z.string().default(''),
|
|
96
|
+
enabled: z.boolean().default(false),
|
|
97
|
+
})).default([]),
|
|
88
98
|
imageApiKey: z.string().default(''),
|
|
89
99
|
imageApiModel: z.string().default(''),
|
|
90
100
|
imageApiEnabled: z.boolean().default(false),
|
|
@@ -126,12 +136,33 @@ export function resolveConfig(value: Partial<Config> | undefined): NovelConfig {
|
|
|
126
136
|
autoReview: value?.autoReview ?? DEFAULT_AUTO_REVIEW,
|
|
127
137
|
autoAuthorReview: value?.autoAuthorReview ?? DEFAULT_AUTO_AUTHOR_REVIEW,
|
|
128
138
|
autoReviewAfterRevise: value?.autoReviewAfterRevise ?? DEFAULT_AUTO_REVIEW_AFTER_REVISE,
|
|
129
|
-
|
|
130
|
-
|
|
139
|
+
// 生图模型库:只有「从未保存过 imageModels」时才用旧配置迁移一条(豆包默认地址);
|
|
140
|
+
// 已保存为空数组 = 用户主动删光,保持空,不再复活。
|
|
141
|
+
imageModels: value?.imageModels !== undefined
|
|
142
|
+
? value.imageModels
|
|
143
|
+
: (value?.imageApiKey !== undefined && value.imageApiKey !== ''
|
|
144
|
+
? [{ id: 'img-legacy', name: '豆包(旧配置)', baseURL: DEFAULT_IMAGE_BASE, apiKey: value.imageApiKey, model: value.imageApiModel ?? '', enabled: true }]
|
|
145
|
+
: []),
|
|
146
|
+
// 运行时生效值 = 启用条目(兼容旧代码读取 imageApiKey/imageApiModel/imageApiEnabled)。
|
|
147
|
+
imageBaseUrl: (() => {
|
|
148
|
+
const active = (value?.imageModels ?? []).find(m => m.enabled) ?? (value?.imageModels ?? [])[0]
|
|
149
|
+
return active?.baseURL !== undefined && active.baseURL !== '' ? active.baseURL : (value?.imageApiKey !== undefined && value.imageApiKey !== '' ? DEFAULT_IMAGE_BASE : undefined)
|
|
150
|
+
})(),
|
|
151
|
+
imageApiKey: (() => {
|
|
152
|
+
const active = (value?.imageModels ?? []).find(m => m.enabled) ?? (value?.imageModels ?? [])[0]
|
|
153
|
+
return active?.apiKey ?? value?.imageApiKey
|
|
154
|
+
})(),
|
|
155
|
+
imageApiModel: (() => {
|
|
156
|
+
const active = (value?.imageModels ?? []).find(m => m.enabled) ?? (value?.imageModels ?? [])[0]
|
|
157
|
+
return active?.model ?? value?.imageApiModel
|
|
158
|
+
})(),
|
|
131
159
|
imageApiEnabled: value?.imageApiEnabled ?? false,
|
|
132
160
|
}
|
|
133
161
|
}
|
|
134
162
|
|
|
163
|
+
/** 生图默认接口地址(豆包 ark,OpenAI 兼容)。 */
|
|
164
|
+
const DEFAULT_IMAGE_BASE = 'https://ark.cn-beijing.volces.com/api/v3'
|
|
165
|
+
|
|
135
166
|
/**
|
|
136
167
|
* Mount the routes and announcement.
|
|
137
168
|
* @param ctx - host plugin context carrying webServer/llm/systemPrompt.
|
package/src/protocol.ts
CHANGED
|
@@ -50,6 +50,8 @@ export const NOVEL_API = {
|
|
|
50
50
|
storyboardTable: '/api/dsh-novel-forge/storyboard/table',
|
|
51
51
|
/** 分镜·提示词级:分镜表 → 即梦可粘贴视频提示词。 */
|
|
52
52
|
storyboardPrompts: '/api/dsh-novel-forge/storyboard/prompts',
|
|
53
|
+
/** 生图接口连通性测试(设置页每个模型条目用)。 */
|
|
54
|
+
imageTest: '/api/dsh-novel-forge/image-test',
|
|
53
55
|
/** 重置项目(可选携带新大纲):清空设定/卷/章节/伏笔/资产/事实库。 */
|
|
54
56
|
reset: '/api/dsh-novel-forge/reset',
|
|
55
57
|
/** 全书一致性质检:LLM 扫描已生成章节,输出矛盾问题清单。 */
|
|
@@ -875,12 +877,35 @@ export interface RolesRequest {
|
|
|
875
877
|
label?: string
|
|
876
878
|
/** op='imageGenerate' 时的漫画风格预设 id(用于统一角色图与漫画页风格)。 */
|
|
877
879
|
style?: string
|
|
880
|
+
/** op='imageGenerate' 时指定生图模型库条目 id(缺省用启用条目)。 */
|
|
881
|
+
modelId?: string
|
|
878
882
|
/** op='visual' / op='promptKit' 时的漫剧基底风格 id(角色图按方案风格重出)。 */
|
|
879
883
|
styleId?: string
|
|
880
884
|
/** op='visual' / op='promptKit' 时的可选滤镜风格 id。 */
|
|
881
885
|
filterId?: string
|
|
882
886
|
}
|
|
883
887
|
|
|
888
|
+
/** POST /image-test 请求:测一个生图接口的连通性与延迟(不落盘)。 */
|
|
889
|
+
export interface ImageTestRequest {
|
|
890
|
+
/** OpenAI 兼容生图接口地址。 */
|
|
891
|
+
baseURL: string
|
|
892
|
+
/** API Key。 */
|
|
893
|
+
apiKey: string
|
|
894
|
+
/** 模型 id(顺带校验是否在接口模型列表里,可选)。 */
|
|
895
|
+
model?: string
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
/** POST /image-test 响应。 */
|
|
899
|
+
export interface ImageTestResponse {
|
|
900
|
+
ok: boolean
|
|
901
|
+
/** 连通延迟(毫秒)。 */
|
|
902
|
+
ms?: number
|
|
903
|
+
/** 失败原因。 */
|
|
904
|
+
message?: string
|
|
905
|
+
/** 模型 id 是否出现在接口的模型列表(探测成功时才有)。 */
|
|
906
|
+
modelFound?: boolean
|
|
907
|
+
}
|
|
908
|
+
|
|
884
909
|
/** POST /roles 响应。 */
|
|
885
910
|
export interface RolesResponse {
|
|
886
911
|
roles: RoleRecord[]
|
|
@@ -1038,6 +1063,22 @@ export interface ProjectState {
|
|
|
1038
1063
|
updatedAt: string
|
|
1039
1064
|
}
|
|
1040
1065
|
|
|
1066
|
+
/** 生图模型配置(模型库条目,可多套并存,启用一条生效)。 */
|
|
1067
|
+
export interface ImageModelConfig {
|
|
1068
|
+
/** 条目 id(本地唯一)。 */
|
|
1069
|
+
id: string
|
|
1070
|
+
/** 展示名(如「豆包 Seedream」「即梦」)。 */
|
|
1071
|
+
name: string
|
|
1072
|
+
/** OpenAI 兼容生图接口地址(如 https://ark.cn-beijing.volces.com/api/v3)。 */
|
|
1073
|
+
baseURL: string
|
|
1074
|
+
/** API Key。 */
|
|
1075
|
+
apiKey: string
|
|
1076
|
+
/** 生图模型 id(如 doubao-seedream-5-0-pro-260628)。 */
|
|
1077
|
+
model: string
|
|
1078
|
+
/** 是否启用(同时只启用一条)。 */
|
|
1079
|
+
enabled: boolean
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1041
1082
|
/** Runtime config surface exposed to the panel (subset of plugin Config). */
|
|
1042
1083
|
export interface NovelConfig {
|
|
1043
1084
|
/** Absolute path of the default docx outline to load. */
|
|
@@ -1064,11 +1105,15 @@ export interface NovelConfig {
|
|
|
1064
1105
|
autoAuthorReview: boolean
|
|
1065
1106
|
/** 修订/润色产出草稿后是否自动附带一次 AI 审查(工作区显示新稿评分与剩余问题)。 */
|
|
1066
1107
|
autoReviewAfterRevise: boolean
|
|
1067
|
-
/**
|
|
1108
|
+
/** 生图模型库(多套并存,启用一条生效;旧 imageApiKey/imageApiModel 自动迁移为一条)。 */
|
|
1109
|
+
imageModels?: ImageModelConfig[]
|
|
1110
|
+
/** 运行时生效的生图接口地址(= 启用条目,兼容旧代码读取)。 */
|
|
1111
|
+
imageBaseUrl?: string
|
|
1112
|
+
/** 运行时生效的生图 API Key(= 启用条目,兼容旧代码读取)。 */
|
|
1068
1113
|
imageApiKey?: string
|
|
1069
|
-
/**
|
|
1114
|
+
/** 运行时生效的生图模型 id(= 启用条目,兼容旧代码读取)。 */
|
|
1070
1115
|
imageApiModel?: string
|
|
1071
|
-
/**
|
|
1116
|
+
/** 是否启用生图(= 存在启用条目)。 */
|
|
1072
1117
|
imageApiEnabled?: boolean
|
|
1073
1118
|
}
|
|
1074
1119
|
|
|
@@ -1286,6 +1331,8 @@ export interface ConfigPatch {
|
|
|
1286
1331
|
imageApiKey?: string
|
|
1287
1332
|
imageApiModel?: string
|
|
1288
1333
|
imageApiEnabled?: boolean
|
|
1334
|
+
/** 生图模型库(完整替换保存)。 */
|
|
1335
|
+
imageModels?: ImageModelConfig[]
|
|
1289
1336
|
}
|
|
1290
1337
|
|
|
1291
1338
|
// ------------------------------------------------------------ assistant
|
package/src/routes.ts
CHANGED
|
@@ -95,6 +95,8 @@ import {
|
|
|
95
95
|
type StoryboardTableRequest,
|
|
96
96
|
type StoryboardTableResponse,
|
|
97
97
|
type StoryboardPromptsRequest,
|
|
98
|
+
type ImageTestRequest,
|
|
99
|
+
type ImageTestResponse,
|
|
98
100
|
type StoryboardPromptsResponse,
|
|
99
101
|
type StyleEngineRequest,
|
|
100
102
|
type SummaryRequest,
|
|
@@ -146,6 +148,7 @@ import {
|
|
|
146
148
|
reverseOutlineFromChapters,
|
|
147
149
|
breakdownBook,
|
|
148
150
|
generateRoleReferenceImage,
|
|
151
|
+
testImageEndpoint,
|
|
149
152
|
generateStoryboardSkeleton,
|
|
150
153
|
generateStoryboardTable,
|
|
151
154
|
generateStoryboardPrompts,
|
|
@@ -1854,7 +1857,7 @@ export function makeRoutes(deps: NovelRoutesDeps): WebRoute[] {
|
|
|
1854
1857
|
return
|
|
1855
1858
|
}
|
|
1856
1859
|
try {
|
|
1857
|
-
const imageUrl = await generateRoleReferenceImage(ctx, config, project, config.outputDir, name, body?.style ?? '')
|
|
1860
|
+
const imageUrl = await generateRoleReferenceImage(ctx, config, project, config.outputDir, name, body?.style ?? '', body?.modelId)
|
|
1858
1861
|
project.updatedAt = new Date().toISOString()
|
|
1859
1862
|
saveProject(config.outputDir, project)
|
|
1860
1863
|
writeJson(res, 200, { roles: project.roles, imageUrl } satisfies RolesResponse)
|
|
@@ -2192,6 +2195,27 @@ export function makeRoutes(deps: NovelRoutesDeps): WebRoute[] {
|
|
|
2192
2195
|
},
|
|
2193
2196
|
}
|
|
2194
2197
|
|
|
2198
|
+
// --------------------------------------------------------- image-test
|
|
2199
|
+
/** 生图接口连通性测试:GET {baseURL}/models + 计时(设置页模型条目用)。 */
|
|
2200
|
+
const imageTestRoute: WebRoute = {
|
|
2201
|
+
kind: 'exact',
|
|
2202
|
+
path: NOVEL_API.imageTest,
|
|
2203
|
+
handler: async (req, res) => {
|
|
2204
|
+
if (!guard(req, res, 'POST')) return
|
|
2205
|
+
const body = await readJsonBody<ImageTestRequest>(req)
|
|
2206
|
+
if (body?.baseURL === undefined || body?.apiKey === undefined) {
|
|
2207
|
+
writeJson(res, 400, { error: 'baseURL 与 apiKey 必填' })
|
|
2208
|
+
return
|
|
2209
|
+
}
|
|
2210
|
+
try {
|
|
2211
|
+
const result = await testImageEndpoint(body.baseURL, body.apiKey, body.model)
|
|
2212
|
+
writeJson(res, 200, result satisfies ImageTestResponse)
|
|
2213
|
+
} catch (error) {
|
|
2214
|
+
writeJson(res, 500, { error: `测试失败:${(error as Error).message}` })
|
|
2215
|
+
}
|
|
2216
|
+
},
|
|
2217
|
+
}
|
|
2218
|
+
|
|
2195
2219
|
// ---------------------------------------------------- storyboard table
|
|
2196
2220
|
/** 分镜·导演级:骨架 → 分镜表(镜头级)。 */
|
|
2197
2221
|
const storyboardTableRoute: WebRoute = {
|
|
@@ -2576,6 +2600,7 @@ export function makeRoutes(deps: NovelRoutesDeps): WebRoute[] {
|
|
|
2576
2600
|
manhuaPlansRoute,
|
|
2577
2601
|
styleImageRoute,
|
|
2578
2602
|
storyboardSkeletonRoute,
|
|
2603
|
+
imageTestRoute,
|
|
2579
2604
|
storyboardTableRoute,
|
|
2580
2605
|
storyboardPromptsRoute,
|
|
2581
2606
|
breakdownRoute,
|