@whispering233/ai-editor-server 0.0.52 → 0.0.54
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/client-dist/assets/{index-Dim9IXQC.css → index-B2op0r9o.css} +1 -1
- package/client-dist/assets/index-Bgk8dcAm.js +627 -0
- package/client-dist/index.html +2 -2
- package/dist/backup.d.ts +37 -44
- package/dist/backup.d.ts.map +1 -1
- package/dist/backup.js +55 -201
- package/dist/backup.js.map +1 -1
- package/dist/cloud/auto-push.d.ts +3 -3
- package/dist/cloud/auto-push.d.ts.map +1 -1
- package/dist/cloud/auto-push.js +7 -6
- package/dist/cloud/auto-push.js.map +1 -1
- package/dist/cloud/state.d.ts +6 -0
- package/dist/cloud/state.d.ts.map +1 -1
- package/dist/cloud/state.js +25 -0
- package/dist/cloud/state.js.map +1 -1
- package/dist/cloud/sync.d.ts +4 -6
- package/dist/cloud/sync.d.ts.map +1 -1
- package/dist/cloud/sync.js +8 -23
- package/dist/cloud/sync.js.map +1 -1
- package/dist/decompose/batching.d.ts +20 -0
- package/dist/decompose/batching.d.ts.map +1 -0
- package/dist/decompose/batching.js +29 -0
- package/dist/decompose/batching.js.map +1 -0
- package/dist/decompose/extract.d.ts +44 -0
- package/dist/decompose/extract.d.ts.map +1 -0
- package/dist/decompose/extract.js +246 -0
- package/dist/decompose/extract.js.map +1 -0
- package/dist/decompose/job.d.ts +91 -0
- package/dist/decompose/job.d.ts.map +1 -0
- package/dist/decompose/job.js +289 -0
- package/dist/decompose/job.js.map +1 -0
- package/dist/decompose/llm.d.ts +68 -0
- package/dist/decompose/llm.d.ts.map +1 -0
- package/dist/decompose/llm.js +181 -0
- package/dist/decompose/llm.js.map +1 -0
- package/dist/decompose/merge-write.d.ts +75 -0
- package/dist/decompose/merge-write.d.ts.map +1 -0
- package/dist/decompose/merge-write.js +670 -0
- package/dist/decompose/merge-write.js.map +1 -0
- package/dist/decompose/merge.d.ts +156 -0
- package/dist/decompose/merge.d.ts.map +1 -0
- package/dist/decompose/merge.js +266 -0
- package/dist/decompose/merge.js.map +1 -0
- package/dist/decompose/report.d.ts +57 -0
- package/dist/decompose/report.d.ts.map +1 -0
- package/dist/decompose/report.js +127 -0
- package/dist/decompose/report.js.map +1 -0
- package/dist/decompose/runner.d.ts +143 -0
- package/dist/decompose/runner.d.ts.map +1 -0
- package/dist/decompose/runner.js +520 -0
- package/dist/decompose/runner.js.map +1 -0
- package/dist/decompose/split.d.ts +89 -0
- package/dist/decompose/split.d.ts.map +1 -0
- package/dist/decompose/split.js +556 -0
- package/dist/decompose/split.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/last-project.d.ts +5 -0
- package/dist/last-project.d.ts.map +1 -1
- package/dist/last-project.js +18 -0
- package/dist/last-project.js.map +1 -1
- package/dist/middleware/error.d.ts +1 -1
- package/dist/middleware/error.d.ts.map +1 -1
- package/dist/middleware/error.js +9 -0
- package/dist/middleware/error.js.map +1 -1
- package/dist/middleware/project.d.ts +4 -3
- package/dist/middleware/project.d.ts.map +1 -1
- package/dist/middleware/project.js +40 -2
- package/dist/middleware/project.js.map +1 -1
- package/dist/routes/chat.d.ts.map +1 -1
- package/dist/routes/chat.js +28 -3
- package/dist/routes/chat.js.map +1 -1
- package/dist/routes/cloud.d.ts.map +1 -1
- package/dist/routes/cloud.js +168 -11
- package/dist/routes/cloud.js.map +1 -1
- package/dist/routes/decompose.d.ts +26 -0
- package/dist/routes/decompose.d.ts.map +1 -0
- package/dist/routes/decompose.js +453 -0
- package/dist/routes/decompose.js.map +1 -0
- package/dist/routes/project.d.ts +22 -0
- package/dist/routes/project.d.ts.map +1 -1
- package/dist/routes/project.js +143 -9
- package/dist/routes/project.js.map +1 -1
- package/package.json +5 -5
- package/client-dist/assets/index-JrTZv8BF.js +0 -621
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { DecomposeBatchResult } from "@whispering233/ai-editor-shared";
|
|
2
|
+
/** 章摘要长度上限(写入 outline 节点 `summary`,会被聚焦章注入使用——见 20-context.md §2) */
|
|
3
|
+
export declare const DECOMPOSE_CHAPTER_SUMMARY_MAX_CHARS = 200;
|
|
4
|
+
/** 实体 `description` 长度上限 */
|
|
5
|
+
export declare const DECOMPOSE_DESCRIPTION_MAX_CHARS = 300;
|
|
6
|
+
/** 人物 `motivation` 长度上限 */
|
|
7
|
+
export declare const DECOMPOSE_MOTIVATION_MAX_CHARS = 200;
|
|
8
|
+
/** 人物 `personality` 条数上限 */
|
|
9
|
+
export declare const DECOMPOSE_PERSONALITY_MAX_ITEMS = 6;
|
|
10
|
+
/** 每章人物条数上限 */
|
|
11
|
+
export declare const DECOMPOSE_CHAPTER_MAX_CHARACTERS = 12;
|
|
12
|
+
/** 每章设定条数上限 */
|
|
13
|
+
export declare const DECOMPOSE_CHAPTER_MAX_SETTINGS = 8;
|
|
14
|
+
/** 每章地点条数上限 */
|
|
15
|
+
export declare const DECOMPOSE_CHAPTER_MAX_LOCATIONS = 8;
|
|
16
|
+
/** 每章关系条数上限 */
|
|
17
|
+
export declare const DECOMPOSE_CHAPTER_MAX_RELATIONS = 12;
|
|
18
|
+
/**
|
|
19
|
+
* 关系类型白名单 = 「AI 可产出」的 shared `RELATION_TYPES` 子集(docs/design/60-decompose.md §5)。
|
|
20
|
+
* **不给全量**:`plants` / `advances` / `resolves` 锚定伏笔、`appears_in` / `occurs_at` / `occurs_in`
|
|
21
|
+
* 锚定大纲节点与时间轴、`depends_on` / `involves` / `plot_edge` 属伏笔与画布——这些都是**创作期**由用户
|
|
22
|
+
* 决定的语义,从正文里猜必然错位(模型会把「提到了地点」写成 `occurs_at`)。剩下的结构关系
|
|
23
|
+
* (`belongs_to` / `owns` / `masters`)与人物关系(含 `kills`)才是正文能可靠支撑的。
|
|
24
|
+
* 白名单外一律丢弃:不猜测、不映射到「近似类型」。
|
|
25
|
+
* `satisfies readonly RelationType[]`:类型写错字(不在 shared `RELATION_TYPES`)编译期报红,
|
|
26
|
+
* 否则白名单里的错字会让该关系被静默丢弃。
|
|
27
|
+
*/
|
|
28
|
+
export declare const DECOMPOSE_RELATION_TYPES: readonly ["ally", "rival", "mentor", "family", "kills", "belongs_to", "owns", "masters"];
|
|
29
|
+
export type DecomposeRelationType = (typeof DECOMPOSE_RELATION_TYPES)[number];
|
|
30
|
+
/** 归一结果:干净批结果 + 截断/丢弃记录(调用方负责写日志) */
|
|
31
|
+
export interface ExtractionNormalization {
|
|
32
|
+
result: DecomposeBatchResult;
|
|
33
|
+
discarded: string[];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 校验与归一一批抽取结果。
|
|
37
|
+
*
|
|
38
|
+
* - `expectedChapterIndexes` = 本批应覆盖的章序(1-based 文件位置序),来自 `decompose_batches.chapter_ids` 的映射;
|
|
39
|
+
* 结果**按该顺序**输出,缺章抛错(runner 捕获后整批重试),批外章条目丢弃。
|
|
40
|
+
* - `knownNames` = 本批之外的累计候选名字(项目数据快照里已出现过的人物 / 设定 / 地点名);
|
|
41
|
+
* 关系端点必须落在「本批 ∪ 累计」集合内,否则丢弃(§6 第 1 层:防模型幻觉出不存在的人物)。
|
|
42
|
+
*/
|
|
43
|
+
export declare function normalizeExtraction(raw: unknown, expectedChapterIndexes: readonly number[], knownNames?: readonly string[]): ExtractionNormalization;
|
|
44
|
+
//# sourceMappingURL=extract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/decompose/extract.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,oBAAoB,EAOrB,MAAM,iCAAiC,CAAC;AAIzC,qEAAqE;AACrE,eAAO,MAAM,mCAAmC,MAAM,CAAC;AACvD,4BAA4B;AAC5B,eAAO,MAAM,+BAA+B,MAAM,CAAC;AACnD,2BAA2B;AAC3B,eAAO,MAAM,8BAA8B,MAAM,CAAC;AAClD,4BAA4B;AAC5B,eAAO,MAAM,+BAA+B,IAAI,CAAC;AACjD,eAAe;AACf,eAAO,MAAM,gCAAgC,KAAK,CAAC;AACnD,eAAe;AACf,eAAO,MAAM,8BAA8B,IAAI,CAAC;AAChD,eAAe;AACf,eAAO,MAAM,+BAA+B,IAAI,CAAC;AACjD,eAAe;AACf,eAAO,MAAM,+BAA+B,KAAK,CAAC;AAElD;;;;;;;;;GASG;AACH,eAAO,MAAM,wBAAwB,0FASO,CAAC;AAC7C,MAAM,MAAM,qBAAqB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9E,qCAAqC;AACrC,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,oBAAoB,CAAC;IAC7B,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,OAAO,EACZ,sBAAsB,EAAE,SAAS,MAAM,EAAE,EACzC,UAAU,GAAE,SAAS,MAAM,EAAO,GACjC,uBAAuB,CAoCzB"}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
// 拆解 S2:批抽取结果的校验与归一(纯函数、无 IO、不碰 db)。
|
|
2
|
+
//
|
|
3
|
+
// 契约:docs/design/60-decompose.md §5(抽取 schema 口径表)与 §4(逐章对齐护栏)。
|
|
4
|
+
// 分工:模型原始 JSON(`unknown`,不信任)进 → 干净结果出。**唯一整批失败条件是缺章**
|
|
5
|
+
// (runner 捕获后整批重试:重试代价 = 一批 token,而缺章的产出本来就不完整);
|
|
6
|
+
// 其余问题(超条数 / 白名单外关系 / 端点不存在 / 字段超长)一律就地截断或丢弃,记入 `discarded`
|
|
7
|
+
// 供调用方写日志——纯函数不做 IO,也不因坏字段整批失败。
|
|
8
|
+
//
|
|
9
|
+
// 上限、白名单与归一规则单一定义在本模块并导出;散文与注释只引用常量名,不复述数字。
|
|
10
|
+
import { normalizeRelationType } from "@whispering233/ai-editor-shared";
|
|
11
|
+
import { normalizeEntityName } from "./merge.js";
|
|
12
|
+
/** 章摘要长度上限(写入 outline 节点 `summary`,会被聚焦章注入使用——见 20-context.md §2) */
|
|
13
|
+
export const DECOMPOSE_CHAPTER_SUMMARY_MAX_CHARS = 200;
|
|
14
|
+
/** 实体 `description` 长度上限 */
|
|
15
|
+
export const DECOMPOSE_DESCRIPTION_MAX_CHARS = 300;
|
|
16
|
+
/** 人物 `motivation` 长度上限 */
|
|
17
|
+
export const DECOMPOSE_MOTIVATION_MAX_CHARS = 200;
|
|
18
|
+
/** 人物 `personality` 条数上限 */
|
|
19
|
+
export const DECOMPOSE_PERSONALITY_MAX_ITEMS = 6;
|
|
20
|
+
/** 每章人物条数上限 */
|
|
21
|
+
export const DECOMPOSE_CHAPTER_MAX_CHARACTERS = 12;
|
|
22
|
+
/** 每章设定条数上限 */
|
|
23
|
+
export const DECOMPOSE_CHAPTER_MAX_SETTINGS = 8;
|
|
24
|
+
/** 每章地点条数上限 */
|
|
25
|
+
export const DECOMPOSE_CHAPTER_MAX_LOCATIONS = 8;
|
|
26
|
+
/** 每章关系条数上限 */
|
|
27
|
+
export const DECOMPOSE_CHAPTER_MAX_RELATIONS = 12;
|
|
28
|
+
/**
|
|
29
|
+
* 关系类型白名单 = 「AI 可产出」的 shared `RELATION_TYPES` 子集(docs/design/60-decompose.md §5)。
|
|
30
|
+
* **不给全量**:`plants` / `advances` / `resolves` 锚定伏笔、`appears_in` / `occurs_at` / `occurs_in`
|
|
31
|
+
* 锚定大纲节点与时间轴、`depends_on` / `involves` / `plot_edge` 属伏笔与画布——这些都是**创作期**由用户
|
|
32
|
+
* 决定的语义,从正文里猜必然错位(模型会把「提到了地点」写成 `occurs_at`)。剩下的结构关系
|
|
33
|
+
* (`belongs_to` / `owns` / `masters`)与人物关系(含 `kills`)才是正文能可靠支撑的。
|
|
34
|
+
* 白名单外一律丢弃:不猜测、不映射到「近似类型」。
|
|
35
|
+
* `satisfies readonly RelationType[]`:类型写错字(不在 shared `RELATION_TYPES`)编译期报红,
|
|
36
|
+
* 否则白名单里的错字会让该关系被静默丢弃。
|
|
37
|
+
*/
|
|
38
|
+
export const DECOMPOSE_RELATION_TYPES = [
|
|
39
|
+
"ally",
|
|
40
|
+
"rival",
|
|
41
|
+
"mentor",
|
|
42
|
+
"family",
|
|
43
|
+
"kills",
|
|
44
|
+
"belongs_to",
|
|
45
|
+
"owns",
|
|
46
|
+
"masters",
|
|
47
|
+
];
|
|
48
|
+
/**
|
|
49
|
+
* 校验与归一一批抽取结果。
|
|
50
|
+
*
|
|
51
|
+
* - `expectedChapterIndexes` = 本批应覆盖的章序(1-based 文件位置序),来自 `decompose_batches.chapter_ids` 的映射;
|
|
52
|
+
* 结果**按该顺序**输出,缺章抛错(runner 捕获后整批重试),批外章条目丢弃。
|
|
53
|
+
* - `knownNames` = 本批之外的累计候选名字(项目数据快照里已出现过的人物 / 设定 / 地点名);
|
|
54
|
+
* 关系端点必须落在「本批 ∪ 累计」集合内,否则丢弃(§6 第 1 层:防模型幻觉出不存在的人物)。
|
|
55
|
+
*/
|
|
56
|
+
export function normalizeExtraction(raw, expectedChapterIndexes, knownNames = []) {
|
|
57
|
+
const discarded = [];
|
|
58
|
+
const chaptersByIndex = new Map();
|
|
59
|
+
for (const item of asArray(asRecord(raw)?.chapters)) {
|
|
60
|
+
const chapter = asRecord(item);
|
|
61
|
+
const chapterIndex = chapter === null ? null : asChapterIndex(chapter.chapterIndex);
|
|
62
|
+
if (chapter === null || chapterIndex === null) {
|
|
63
|
+
discarded.push("丢弃无法解析的章条目(缺 chapterIndex)");
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (chaptersByIndex.has(chapterIndex)) {
|
|
67
|
+
discarded.push(`第${chapterIndex}章在批结果里重复出现,只取首条`);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
chaptersByIndex.set(chapterIndex, chapter);
|
|
71
|
+
}
|
|
72
|
+
const missing = expectedChapterIndexes.filter((chapterIndex) => !chaptersByIndex.has(chapterIndex));
|
|
73
|
+
if (missing.length > 0) {
|
|
74
|
+
throw new Error(`拆解批结果缺章:${missing.join("、")}(整批重试)`);
|
|
75
|
+
}
|
|
76
|
+
const expected = new Set(expectedChapterIndexes);
|
|
77
|
+
for (const chapterIndex of chaptersByIndex.keys()) {
|
|
78
|
+
if (!expected.has(chapterIndex))
|
|
79
|
+
discarded.push(`第${chapterIndex}章不在本批范围内,已丢弃`);
|
|
80
|
+
}
|
|
81
|
+
// 关系端点的存在性判据:本批全部章的名字 ∪ 累计候选集合(同口径归一化后再比较)
|
|
82
|
+
const known = new Set([...knownNames.map(normalizeEntityName)]);
|
|
83
|
+
for (const chapter of chaptersByIndex.values()) {
|
|
84
|
+
for (const name of entityNamesOf(chapter))
|
|
85
|
+
known.add(name);
|
|
86
|
+
}
|
|
87
|
+
const chapters = expectedChapterIndexes.map((chapterIndex) => normalizeChapter(chaptersByIndex.get(chapterIndex), chapterIndex, known, discarded));
|
|
88
|
+
return { result: { chapters }, discarded };
|
|
89
|
+
}
|
|
90
|
+
/** 单章归一:条数上限截断 + 字段收窄;丢弃项(含原因)追加进 `discarded` */
|
|
91
|
+
function normalizeChapter(raw, chapterIndex, known, discarded) {
|
|
92
|
+
const label = `第${chapterIndex}章`;
|
|
93
|
+
const summary = asText(raw.summary) ?? "";
|
|
94
|
+
const characters = cap(asArray(raw.characters).map(normalizeCharacter).filter(isPresent), DECOMPOSE_CHAPTER_MAX_CHARACTERS, `${label}:人物超 DECOMPOSE_CHAPTER_MAX_CHARACTERS,已截断`, discarded);
|
|
95
|
+
const settings = cap(asArray(raw.settings).map(normalizeSetting).filter(isPresent), DECOMPOSE_CHAPTER_MAX_SETTINGS, `${label}:设定超 DECOMPOSE_CHAPTER_MAX_SETTINGS,已截断`, discarded);
|
|
96
|
+
const locations = cap(asArray(raw.locations).map(normalizeLocation).filter(isPresent), DECOMPOSE_CHAPTER_MAX_LOCATIONS, `${label}:地点超 DECOMPOSE_CHAPTER_MAX_LOCATIONS,已截断`, discarded);
|
|
97
|
+
const relations = [];
|
|
98
|
+
for (const item of asArray(raw.relations)) {
|
|
99
|
+
const { relation, reason } = filterRelation(item, known);
|
|
100
|
+
if (relation === null) {
|
|
101
|
+
discarded.push(`${label}:${reason}`);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
relations.push(relation);
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
chapterIndex,
|
|
108
|
+
// 标题取**模型回声**(缺则用章序兜底)——只为批结果可读(进度页展开行 / 日志);
|
|
109
|
+
// 章标题的权威来源 = S1 写的大纲节点标题(切分清洗后的标题),两源并存是有意的:
|
|
110
|
+
// S3 回写章摘要时只写 `summary`,不得用本字段覆盖标题(见 merge-write.ts)
|
|
111
|
+
chapterTitle: asText(raw.chapterTitle) ?? `第${chapterIndex}章`,
|
|
112
|
+
summary: clip(summary, DECOMPOSE_CHAPTER_SUMMARY_MAX_CHARS),
|
|
113
|
+
characters,
|
|
114
|
+
settings,
|
|
115
|
+
locations,
|
|
116
|
+
relations: cap(relations, DECOMPOSE_CHAPTER_MAX_RELATIONS, `${label}:关系超 DECOMPOSE_CHAPTER_MAX_RELATIONS,已截断`, discarded),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* 人物归一:`name` 缺失即丢弃;`description` / `motivation` 截断、`personality` 截条数。
|
|
121
|
+
* `ability_panel` / `custom_fields` 契约禁止填(§5:能力面板是用户自定义字段树,AI 建树会污染结构)
|
|
122
|
+
* ——输出是**显式取字段**,禁止填的字段根本没有落点(不是「过滤掉」而是「不读」)。
|
|
123
|
+
*/
|
|
124
|
+
function normalizeCharacter(value) {
|
|
125
|
+
const raw = asRecord(value);
|
|
126
|
+
const name = asText(raw?.name);
|
|
127
|
+
if (raw === null || name === null)
|
|
128
|
+
return null;
|
|
129
|
+
const character = { name };
|
|
130
|
+
assign(character, "role", asText(raw.role));
|
|
131
|
+
assign(character, "description", clip(asText(raw.description) ?? "", DECOMPOSE_DESCRIPTION_MAX_CHARS) || undefined);
|
|
132
|
+
assign(character, "alias", asText(raw.alias));
|
|
133
|
+
assign(character, "gender", asText(raw.gender));
|
|
134
|
+
assign(character, "age", asAge(raw.age));
|
|
135
|
+
assign(character, "race", asText(raw.race));
|
|
136
|
+
const personality = asArray(raw.personality)
|
|
137
|
+
.map(asText)
|
|
138
|
+
.filter(isPresent)
|
|
139
|
+
.slice(0, DECOMPOSE_PERSONALITY_MAX_ITEMS);
|
|
140
|
+
if (personality.length > 0)
|
|
141
|
+
character.personality = personality;
|
|
142
|
+
assign(character, "motivation", clip(asText(raw.motivation) ?? "", DECOMPOSE_MOTIVATION_MAX_CHARS) || undefined);
|
|
143
|
+
return character;
|
|
144
|
+
}
|
|
145
|
+
/** 设定归一:`rules` / `tags` 只留非空字符串(UI 把 rules 渲染成 tags 控件,长文本放进去会难看) */
|
|
146
|
+
function normalizeSetting(value) {
|
|
147
|
+
const raw = asRecord(value);
|
|
148
|
+
const name = asText(raw?.name);
|
|
149
|
+
if (raw === null || name === null)
|
|
150
|
+
return null;
|
|
151
|
+
const setting = { name };
|
|
152
|
+
assign(setting, "description", clip(asText(raw.description) ?? "", DECOMPOSE_DESCRIPTION_MAX_CHARS) || undefined);
|
|
153
|
+
const tags = textList(raw.tags);
|
|
154
|
+
if (tags.length > 0)
|
|
155
|
+
setting.tags = tags;
|
|
156
|
+
const rules = textList(raw.rules);
|
|
157
|
+
if (rules.length > 0)
|
|
158
|
+
setting.rules = rules;
|
|
159
|
+
return setting;
|
|
160
|
+
}
|
|
161
|
+
/** 地点归一:`type` 自由文本;`parent_id` 契约禁止填(不做地点层级,§5)——同人物,不读即不落 */
|
|
162
|
+
function normalizeLocation(value) {
|
|
163
|
+
const raw = asRecord(value);
|
|
164
|
+
const name = asText(raw?.name);
|
|
165
|
+
if (raw === null || name === null)
|
|
166
|
+
return null;
|
|
167
|
+
const location = { name };
|
|
168
|
+
assign(location, "type", asText(raw.type));
|
|
169
|
+
assign(location, "description", clip(asText(raw.description) ?? "", DECOMPOSE_DESCRIPTION_MAX_CHARS) || undefined);
|
|
170
|
+
return location;
|
|
171
|
+
}
|
|
172
|
+
/** 关系过滤:白名单外 / 端点不在候选集合 / 缺字段 → 丢弃并给原因(`relation === null` ⇔ `reason !== null`) */
|
|
173
|
+
function filterRelation(value, known) {
|
|
174
|
+
const raw = asRecord(value);
|
|
175
|
+
const source = asText(raw?.source);
|
|
176
|
+
const target = asText(raw?.target);
|
|
177
|
+
const type = normalizeRelationType(asText(raw?.type) ?? "");
|
|
178
|
+
if (source === null || target === null || type === "") {
|
|
179
|
+
return { relation: null, reason: "丢弃缺 source/target/type 的关系" };
|
|
180
|
+
}
|
|
181
|
+
if (!DECOMPOSE_RELATION_TYPES.includes(type)) {
|
|
182
|
+
return { relation: null, reason: `关系「${source}→${target}(${type})」的类型不在 DECOMPOSE_RELATION_TYPES,已丢弃` };
|
|
183
|
+
}
|
|
184
|
+
if (!known.has(normalizeEntityName(source)) || !known.has(normalizeEntityName(target))) {
|
|
185
|
+
return { relation: null, reason: `关系「${source}→${target}(${type})」的端点不在候选集合,已丢弃` };
|
|
186
|
+
}
|
|
187
|
+
const relation = { source, target, type };
|
|
188
|
+
assign(relation, "evidence", asText(raw?.evidence));
|
|
189
|
+
return { relation, reason: null };
|
|
190
|
+
}
|
|
191
|
+
/** 本批某章里出现过的实体名(归一化;关系端点存在性判据的「本批」一半) */
|
|
192
|
+
function entityNamesOf(chapter) {
|
|
193
|
+
const names = [];
|
|
194
|
+
for (const key of ["characters", "settings", "locations"]) {
|
|
195
|
+
for (const item of asArray(chapter[key])) {
|
|
196
|
+
const name = asText(asRecord(item)?.name);
|
|
197
|
+
if (name !== null)
|
|
198
|
+
names.push(normalizeEntityName(name));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return names;
|
|
202
|
+
}
|
|
203
|
+
function asRecord(value) {
|
|
204
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
205
|
+
}
|
|
206
|
+
function asArray(value) {
|
|
207
|
+
return Array.isArray(value) ? value : [];
|
|
208
|
+
}
|
|
209
|
+
/** 非空字符串(trim 后非空)→ 原值;其余(null / 数字 / 对象 / 空串)一律当缺字段 */
|
|
210
|
+
function asText(value) {
|
|
211
|
+
if (typeof value !== "string")
|
|
212
|
+
return null;
|
|
213
|
+
return value.trim() === "" ? null : value;
|
|
214
|
+
}
|
|
215
|
+
function asChapterIndex(value) {
|
|
216
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 1 ? value : null;
|
|
217
|
+
}
|
|
218
|
+
/** age 允许文本或数字(与 shared `characterDataSchema` 同口径) */
|
|
219
|
+
function asAge(value) {
|
|
220
|
+
return typeof value === "string" || typeof value === "number" ? value : undefined;
|
|
221
|
+
}
|
|
222
|
+
/** 字符串数组字段(非字符串项丢弃;空数组视同未填) */
|
|
223
|
+
function textList(value) {
|
|
224
|
+
return asArray(value).map(asText).filter(isPresent);
|
|
225
|
+
}
|
|
226
|
+
/** 超长截断(先 trim:模型爱加首尾空白) */
|
|
227
|
+
function clip(value, maxChars) {
|
|
228
|
+
const text = value.trim();
|
|
229
|
+
return text.length <= maxChars ? text : text.slice(0, maxChars);
|
|
230
|
+
}
|
|
231
|
+
function isPresent(value) {
|
|
232
|
+
return value !== null;
|
|
233
|
+
}
|
|
234
|
+
/** 可选字段只在有值时赋值(避免 `undefined` / `null` 键进 JSON) */
|
|
235
|
+
function assign(target, key, value) {
|
|
236
|
+
if (value !== undefined && value !== null)
|
|
237
|
+
target[key] = value;
|
|
238
|
+
}
|
|
239
|
+
/** 条数上限截断:截断时记一条 discarded(note 文案引用常量名,不复述数字) */
|
|
240
|
+
function cap(items, maxItems, note, discarded) {
|
|
241
|
+
if (items.length <= maxItems)
|
|
242
|
+
return [...items];
|
|
243
|
+
discarded.push(note);
|
|
244
|
+
return items.slice(0, maxItems);
|
|
245
|
+
}
|
|
246
|
+
//# sourceMappingURL=extract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/decompose/extract.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { DecomposeBatchResult, DecomposeJobRes } from "@whispering233/ai-editor-shared";
|
|
2
|
+
import { type Db, type DecomposeJobRow } from "@whispering233/ai-editor-db";
|
|
3
|
+
import type { SplitChapter, SplitWithSlices } from "./split.js";
|
|
4
|
+
import type { ProjectContext } from "../middleware/project.js";
|
|
5
|
+
/** S1 建档入参:项目已建已开(`db` 是活动连接)、切分结果 + 范围(`scopedChapters` = 范围过滤后的章) */
|
|
6
|
+
export interface IngestDecomposeProjectInput {
|
|
7
|
+
project: ProjectContext;
|
|
8
|
+
split: SplitWithSlices;
|
|
9
|
+
/** 范围过滤后的章(= 批规划输入;正文导入仍用 `split` 的全量切片) */
|
|
10
|
+
scopedChapters: readonly SplitChapter[];
|
|
11
|
+
scopeStart: number;
|
|
12
|
+
scopeEnd: number;
|
|
13
|
+
/** 本次使用的模型(`provider/id`,审计用);未配置 → null */
|
|
14
|
+
model: string | null;
|
|
15
|
+
now: string;
|
|
16
|
+
}
|
|
17
|
+
/** S1 建档产物:job id 与批数(start 响应字段) */
|
|
18
|
+
export interface IngestDecomposeProjectResult {
|
|
19
|
+
jobId: string;
|
|
20
|
+
batchCount: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* 纯文本 → 段落块数组(块数组最小形态:每行一个 paragraph,空行 = 空段落——
|
|
24
|
+
* 与参考资料执行器 `paragraphBlocksOf` 同形态,保原文的段落/空行结构)。
|
|
25
|
+
* 共用面:S1 的逐章正文导入 + S4 的拆解报告正文(服务端不解析块语义)。
|
|
26
|
+
*/
|
|
27
|
+
export declare function paragraphBlocksOf(text: string): unknown[];
|
|
28
|
+
/**
|
|
29
|
+
* S1 建档(同步、不调 LLM):建大纲 → 导入正文 → 落 job 与批规划行 → job 置 `running`
|
|
30
|
+
*(契约:S1 完成后才返回,返回时 job 已进入 `running`;批执行归 S2 runner)。
|
|
31
|
+
*
|
|
32
|
+
* 批规划 = `planBatches(scopedChapters)`(与 analyze 预估同一实现,确定性);批行 `chapter_ids`
|
|
33
|
+
* 按章序映射为章节点 id。
|
|
34
|
+
*/
|
|
35
|
+
export declare function ingestDecomposeProject(input: IngestDecomposeProjectInput): IngestDecomposeProjectResult;
|
|
36
|
+
/** 续拆启动入参(S1':不建大纲、不导正文、不吃源文件) */
|
|
37
|
+
export interface ContinueDecomposeInput {
|
|
38
|
+
project: ProjectContext;
|
|
39
|
+
/** 范围过滤后的章(= 批规划输入;章序必须落在库内章序上) */
|
|
40
|
+
scopedChapters: readonly SplitChapter[];
|
|
41
|
+
scopeStart: number;
|
|
42
|
+
scopeEnd: number;
|
|
43
|
+
/** 本次使用的模型(`provider/id`,审计用);未配置 → null */
|
|
44
|
+
model: string | null;
|
|
45
|
+
now: string;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* S1'(续拆):**只**落 job 行 + 批规划行——不建大纲、不导正文、不动 `outline.json` / `document_records`
|
|
49
|
+
*(正文是 S1 全量导入的一次性产物,设计 §7.1);随后 job 置 `running`,批执行归 S2 runner(与 start 同款)。
|
|
50
|
+
*/
|
|
51
|
+
export declare function ingestDecomposeContinue(input: ContinueDecomposeInput): IngestDecomposeProjectResult;
|
|
52
|
+
/** 续拆后的章条目(章序 = `deriveChapterOrder` 的文件位置序;`charCount` = 正文投影长度) */
|
|
53
|
+
export interface DecomposeChapterEntry {
|
|
54
|
+
index: number;
|
|
55
|
+
title: string;
|
|
56
|
+
charCount: number;
|
|
57
|
+
volumeIndex: number;
|
|
58
|
+
decomposed: boolean;
|
|
59
|
+
}
|
|
60
|
+
/** 续拆预览的库内事实:全书章(含已拆标记)+ 未拆章最小覆盖区间 */
|
|
61
|
+
export interface DecomposeProjectPlan {
|
|
62
|
+
chapters: DecomposeChapterEntry[];
|
|
63
|
+
/** 未拆章总数(全书口径) */
|
|
64
|
+
remainingCount: number;
|
|
65
|
+
/** 未拆章最小覆盖区间;无未拆章 → 0 / 0 */
|
|
66
|
+
defaultScopeStart: number;
|
|
67
|
+
defaultScopeEnd: number;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 库内章清单(顺序 = `deriveChapterOrder`:root → 卷 → 章先序遍历)+ 已拆标记 + 缺省范围。
|
|
71
|
+
* plan 与 continue **共用同一读取面**(各扫一遍必然漂移:预览说要拆的章与实际落的批不一致)。
|
|
72
|
+
* `volumeIndex` = root 下的卷序号(卷序号从 0 起、单卷与存量直挂 root 的章均为 0——与切分的口径同形)。
|
|
73
|
+
*/
|
|
74
|
+
export declare function readDecomposeProjectPlan(project: ProjectContext): DecomposeProjectPlan;
|
|
75
|
+
/**
|
|
76
|
+
* 已完成批的抽取结果(续拆重建本轮累积、S3 归并都读它)。
|
|
77
|
+
* db 层不校验 `result` 形状(`[1,2]` 这类值原样透出)⇒ 此处按契约 schema 守卫。
|
|
78
|
+
*/
|
|
79
|
+
export declare function doneBatchResults(db: Db, jobId: string, doneSeqs: readonly number[]): DecomposeBatchResult[];
|
|
80
|
+
/**
|
|
81
|
+
* job 进度投影(GET /decompose/job):**不含批结果正文**(数百批 × 每条千级 token 会撑爆响应,
|
|
82
|
+
* 展开某批另取 `GET /job/batches/:seq`)。
|
|
83
|
+
*
|
|
84
|
+
* 批行的 `chapterIndexes` / `chapterTitles` 从章节点 id 反查(章序 = 文件位置序 = `deriveChapterOrder`;
|
|
85
|
+
* 标题取大纲节点 title,与大纲页同源);`charCount` = 该批各章正文投影长度和(与章列表 `textLength`
|
|
86
|
+
* 同口径,不存快照)。
|
|
87
|
+
*
|
|
88
|
+
* `report` 从归并清单投影(S4 落盘后非 null):报告实体 id 记在清单的 `reference` 条目上。
|
|
89
|
+
*/
|
|
90
|
+
export declare function buildJobResponse(project: ProjectContext, job: DecomposeJobRow): DecomposeJobRes;
|
|
91
|
+
//# sourceMappingURL=job.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"job.d.ts","sourceRoot":"","sources":["../../src/decompose/job.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,oBAAoB,EAAE,eAAe,EAAyC,MAAM,iCAAiC,CAAC;AAGpI,OAAO,EAaL,KAAK,EAAE,EAEP,KAAK,eAAe,EACrB,MAAM,6BAA6B,CAAC;AAGrC,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE/D,uEAAuE;AACvE,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,cAAc,CAAC;IACxB,KAAK,EAAE,eAAe,CAAC;IACvB,4CAA4C;IAC5C,cAAc,EAAE,SAAS,YAAY,EAAE,CAAC;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,qCAAqC;AACrC,MAAM,WAAW,4BAA4B;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE,CAKzD;AAsDD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,2BAA2B,GAAG,4BAA4B,CAWvG;AAED,kCAAkC;AAClC,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,cAAc,CAAC;IACxB,mCAAmC;IACnC,cAAc,EAAE,SAAS,YAAY,EAAE,CAAC;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,sBAAsB,GAAG,4BAA4B,CAWnG;AA6CD,qEAAqE;AACrE,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,sCAAsC;AACtC,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,qBAAqB,EAAE,CAAC;IAClC,kBAAkB;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,6BAA6B;IAC7B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;CACzB;AAiBD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,cAAc,GAAG,oBAAoB,CA6BtF;AAOD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,oBAAoB,EAAE,CAO3G;AAcD;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,EAAE,eAAe,GAAG,eAAe,CA2C/F"}
|