dsh-novel-generator 0.1.36 → 0.1.38
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 +6 -2
- package/client.js +13 -1
- package/index.js +10 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -98,12 +98,16 @@ dsh plugin --profile web add dsh-novel-generator
|
|
|
98
98
|
|
|
99
99
|
## 章节故事页
|
|
100
100
|
|
|
101
|
-
-
|
|
101
|
+
- 正文可以直接编辑、保存;工具条上还有三个按钮:
|
|
102
102
|
- **「同步章节大纲」**:确认后把当前正文交给模型,**按这一章的实际内容重算整份大纲**——故事梗概、故事时间长度(天)、章节最低字数、章节最多字数、梗概最低字数,然后直接保存覆盖旧大纲(正文不动)。
|
|
103
103
|
- 字数范围一定会把正文实际字数包在里面;梗概下限不会超过新梗概本身的长度。
|
|
104
104
|
- 时间长度只有在不破坏时间线时才会改:末章可以直接改;后面还有章节时,只有「下一章起始日 = 本章起始日 + 新时长」才采纳,否则保留原时长并在提示里说明模型建议值。
|
|
105
|
+
- **「提取行文风格」**:模型读这一章,提炼视角与人称、句式、用词、节奏、描写比例,输出条目式说明(≤600 字)。
|
|
106
|
+
- 分析期间整个工坊被锁定,无法点别的按钮;正文不足 300 字时按钮不可点,接口也返回 400。
|
|
107
|
+
- 完成后弹面板:只读文本 + 「复制」(贴到作品列表的「前置」里)+ 「写入前置」。
|
|
108
|
+
- 「写入前置」会先弹确认,**明确告知要用 AI 整理**:模型把这段风格与你现有前置合并成一段统一的写作约束(≤2000 字)后保存为本书前置,覆盖旧的那份。
|
|
105
109
|
- **「AI 修改」**:填入修改意见后,模型按意见重写整章,结果只放进编辑区、不自动保存。
|
|
106
|
-
-
|
|
110
|
+
- 正文为空时按钮不可点,接口也会拒绝(400);修改意见为空同样拒绝。
|
|
107
111
|
|
|
108
112
|
## 章节大纲页
|
|
109
113
|
|
package/client.js
CHANGED
|
@@ -166,6 +166,7 @@ body[data-ds-dark-theme] .dsn-shell{color-scheme:dark}
|
|
|
166
166
|
border:1px solid var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}
|
|
167
167
|
.dsn-note{margin:0;padding:8px 12px;border-radius:10px;font-size:12px;
|
|
168
168
|
border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1)}
|
|
169
|
+
.dsn-note-row{display:flex;align-items:center;gap:10px;justify-content:space-between}
|
|
169
170
|
.dsn-empty{padding:32px;text-align:center;color:var(--dsw-alias-label-secondary);font-size:13px}
|
|
170
171
|
.dsn-toast{position:absolute;top:58px;left:50%;transform:translateX(-50%);z-index:30;
|
|
171
172
|
padding:8px 16px;border-radius:999px;font-size:12px;border-left:3px solid var(--dsw-alias-state-success-primary);
|
|
@@ -1576,7 +1577,18 @@ body[data-ds-dark-theme] .dsn-shell{color-scheme:dark}
|
|
|
1576
1577
|
? h('div', { className: 'dsn-empty' }, t('还没有章节。点右上角「+ 新建章节」开始第一章。', "No chapters yet. Use \"+ New chapter\" at the top right to start the first one."))
|
|
1577
1578
|
: h(React.Fragment, null,
|
|
1578
1579
|
h('div', { className: 'dsn-editor' },
|
|
1579
|
-
!chapter.outline
|
|
1580
|
+
!chapter.outline
|
|
1581
|
+
? (String(text || '').trim() === ''
|
|
1582
|
+
? h('div', { className: 'dsn-note' }, t('这一章还没有章节大纲:先去「章节大纲」填写,再回来生成正文。', 'This chapter has no outline yet — fill one in under "Outline", then generate from there.'))
|
|
1583
|
+
: h('div', { className: 'dsn-note dsn-note-row' },
|
|
1584
|
+
h('span', null, t('这一章是导入的,没有章节大纲记录:点「同步章节大纲」会根据正文生成梗概与字数范围。', 'This chapter came from an import and has no outline recorded — “Sync outline” builds one from the text.')),
|
|
1585
|
+
h('button', {
|
|
1586
|
+
className: 'dsn-btn ghost',
|
|
1587
|
+
type: 'button',
|
|
1588
|
+
disabled: saving || Boolean(summarizing),
|
|
1589
|
+
onClick: onSummarize,
|
|
1590
|
+
}, t('现在同步', 'Sync now'))))
|
|
1591
|
+
: null,
|
|
1580
1592
|
h('textarea', {
|
|
1581
1593
|
className: 'dsn-textarea dsn-story',
|
|
1582
1594
|
value: text,
|
package/index.js
CHANGED
|
@@ -1499,7 +1499,7 @@ async function bootstrap(ctx, root) {
|
|
|
1499
1499
|
}
|
|
1500
1500
|
}
|
|
1501
1501
|
return {
|
|
1502
|
-
revision: '2026-10-
|
|
1502
|
+
revision: '2026-10-29.1',
|
|
1503
1503
|
projects,
|
|
1504
1504
|
models: {
|
|
1505
1505
|
default: modelCatalog.default || null,
|
|
@@ -2017,7 +2017,6 @@ async function updatePreset(ctx, root, body) {
|
|
|
2017
2017
|
* the four numbers the outline records, all measured from this one chapter.
|
|
2018
2018
|
*/
|
|
2019
2019
|
function syncOutlinePrompt(project, chapter, prose) {
|
|
2020
|
-
const span = chapterWindow(project, chapter);
|
|
2021
2020
|
const chars = wordCount(prose);
|
|
2022
2021
|
const lines = [];
|
|
2023
2022
|
lines.push('你是这部小说的编辑。作者已经写完了下面这一章,请据此同步它的章节大纲。');
|
|
@@ -2026,13 +2025,17 @@ function syncOutlinePrompt(project, chapter, prose) {
|
|
|
2026
2025
|
lines.push('');
|
|
2027
2026
|
lines.push('各项含义:');
|
|
2028
2027
|
lines.push('- synopsis:这一章的故事梗概,写清起因、经过、转折、结果,供后续章节与世界观使用;300 字以内,纯文本。');
|
|
2029
|
-
lines.push(
|
|
2028
|
+
lines.push('- durationDays:这段剧情在故事内部推进了几天,整数 1–365。');
|
|
2029
|
+
lines.push(' 只看正文里的时间线索(清晨到入夜、翌日、过了三日、雨下到第几天……)来数;');
|
|
2030
|
+
lines.push(' 正文没有时间线索时按事件密度估计:一场连续场景通常算 1 天,跨几次昼夜就往上加;');
|
|
2031
|
+
lines.push(' 大多数章节在 1–7 天之间,只有正文明确跨越更久时才写更大的数。');
|
|
2032
|
+
lines.push(' 不要参考任何已有设定或历史记录,完全按这段正文判断,不要沿用「原来记了多少天」。');
|
|
2030
2033
|
lines.push(`- minWords / maxWords:这一章应有的字数下限与上限,整数;本章正文实际 ${chars} 字,范围应当把 ${chars} 包在里面。`);
|
|
2031
2034
|
lines.push('- synopsisMinChars:上面这段梗概算「合格」的最低字数,整数 20–400,取梗概长度的八成左右。');
|
|
2032
2035
|
lines.push('');
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
lines.push(`【本章】第 ${chapter.index + 1} 章 ${chapter.title || ''}
|
|
2036
|
+
// No time span and no preface here: this is a measurement of the text, and
|
|
2037
|
+
// either would hand the model the answer it is supposed to derive.
|
|
2038
|
+
lines.push(`【本章】第 ${chapter.index + 1} 章 ${chapter.title || ''}`);
|
|
2036
2039
|
lines.push(`【正文】(共 ${chars} 字,不含空白)`);
|
|
2037
2040
|
lines.push(prose);
|
|
2038
2041
|
return lines.join('\n');
|
|
@@ -2454,7 +2457,6 @@ const STYLE_MIN_CHARS = 300;
|
|
|
2454
2457
|
const STYLE_MAX_CHARS = 600;
|
|
2455
2458
|
|
|
2456
2459
|
function styleExtractPrompt(project, chapter, prose) {
|
|
2457
|
-
const span = chapterWindow(project, chapter);
|
|
2458
2460
|
const lines = [];
|
|
2459
2461
|
lines.push('你是这部小说的文字编辑。请从下面这段正文里提取这篇小说的行文风格,写成可以直接当作「写作约束」使用的条目。');
|
|
2460
2462
|
lines.push('');
|
|
@@ -2471,7 +2473,7 @@ function styleExtractPrompt(project, chapter, prose) {
|
|
|
2471
2473
|
lines.push('- 不要出现「这段文字」「作者」之类的话,也不要评价好坏;');
|
|
2472
2474
|
lines.push(`- 全文不超过 ${STYLE_MAX_CHARS} 字,宁可少写几条也要写得可执行。`);
|
|
2473
2475
|
lines.push('');
|
|
2474
|
-
lines.push(`【本章】第 ${chapter.index + 1} 章 ${chapter.title || ''}
|
|
2476
|
+
lines.push(`【本章】第 ${chapter.index + 1} 章 ${chapter.title || ''}`);
|
|
2475
2477
|
lines.push('【正文】');
|
|
2476
2478
|
lines.push(prose);
|
|
2477
2479
|
return lines.join('\n');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-novel-generator",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.38",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Novel studio for DeepSeek Harness: a draggable story timeline, world snapshots, chapter outlines, and chapters written by the work's own agent.",
|
|
6
6
|
"license": "MIT",
|