@customize-agent/knowledge 4.1.3 → 4.1.4
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.
|
@@ -4,12 +4,15 @@ import type { FileCategory } from '../types.js';
|
|
|
4
4
|
* 使入库的即干净、真实需要的数据——下游检索、证据注入、生成链路全流程受益
|
|
5
5
|
* (上下文更瘦、prefix cache 更稳、事实提取更准),并减少生成链路的重复清洗成本。
|
|
6
6
|
*
|
|
7
|
-
*
|
|
7
|
+
* 清洗范围(三类,按文件类型与内容特征分流):
|
|
8
8
|
* A. 格式噪声(K1):页眉/页脚/图框标题栏高重复行、纯页码行、目录区段、连续空行、
|
|
9
9
|
* 投标文件格式模板段、泛化引用行、补疑零信息回复行、图纸纯坐标行;
|
|
10
10
|
* B. 内容无关数据(K2,章节级):合同通用条款(标准示范文本,不含项目数据)、
|
|
11
11
|
* 招标公告程序段(文件获取/递交/开标方式)、评标办法商务评审细则——
|
|
12
12
|
* 施工组织设计(技术标)生成用不到的商务/程序性内容,不入库、不进检索上下文。
|
|
13
|
+
* C. 图纸/清单专门噪声(K3):图纸图框标题栏信息行(图号/比例/签名行)、CAD 属性行
|
|
14
|
+
* (图层/颜色/线型)、清单纯报价表格段(费汇总/暂估/规费/税金,含金额行证据)、
|
|
15
|
+
* 清单扉页签章段——分部分项清单的名称/特征/工程量是施组核心数据,绝不删。
|
|
13
16
|
*
|
|
14
17
|
* 保守策略(宁多勿丢红线):每条规则都要求「标题模式 + 内容特征/规模」多重证据,
|
|
15
18
|
* 只删高置信噪声;清洗后文本若不足原文 30% 整体回退;KB_TEXT_CLEANING=0 关闭清洗。
|
|
@@ -37,6 +40,14 @@ export interface TextCleanStats {
|
|
|
37
40
|
announcementProcedureLines: number;
|
|
38
41
|
/** 评标商务评审细则段行数(K2 内容无关) */
|
|
39
42
|
businessReviewLines: number;
|
|
43
|
+
/** 图纸:图框标题栏信息行数(图号/比例/签名行,K3) */
|
|
44
|
+
cadTitleBlockLines: number;
|
|
45
|
+
/** 图纸:CAD 属性行数(图层/颜色/线型,K3) */
|
|
46
|
+
cadAttributeLines: number;
|
|
47
|
+
/** 清单:纯报价表格段行数(费汇总/暂估价/规费/税金,K3) */
|
|
48
|
+
billPricingLines: number;
|
|
49
|
+
/** 清单:扉页签章段行数(K3) */
|
|
50
|
+
billTitlePageLines: number;
|
|
40
51
|
}
|
|
41
52
|
export interface TextCleaningResult {
|
|
42
53
|
/** 清洗后的文本(30% 回退保护下可能等于原文) */
|
|
@@ -3,14 +3,17 @@ function zeroStats() {
|
|
|
3
3
|
headerFooterLines: 0, pageNumberLines: 0, tocRegionLines: 0, blankLines: 0,
|
|
4
4
|
tenderFormatLines: 0, tenderGenericLines: 0, clarificationLines: 0, cadNoiseLines: 0,
|
|
5
5
|
contractGeneralClauseLines: 0, announcementProcedureLines: 0, businessReviewLines: 0,
|
|
6
|
+
cadTitleBlockLines: 0, cadAttributeLines: 0, billPricingLines: 0, billTitlePageLines: 0,
|
|
6
7
|
};
|
|
7
8
|
}
|
|
8
|
-
/** 文档类型判定:文件名 + 文首内容双重特征(招标文件 / 补疑答疑 / 其他) */
|
|
9
|
+
/** 文档类型判定:文件名 + 文首内容双重特征(招标文件 / 补疑答疑 / 工程量清单 / 其他) */
|
|
9
10
|
function detectDocKind(fileName, head) {
|
|
10
11
|
if (/(补疑|答疑|澄清|补遗|变更通知|招标答疑)/u.test(fileName) || /答疑纪要|澄清函|补遗文件|招标文件答疑/u.test(head))
|
|
11
12
|
return 'clarification';
|
|
12
13
|
if (/(招标文件|招标公告|招标书|邀请招标)/u.test(fileName) || /投标人须知|招标公告|投标邀请/u.test(head))
|
|
13
14
|
return 'tender';
|
|
15
|
+
if (/(清单|BQ|bill|Bill)/u.test(fileName) || /^.{0,300}工程量清单|分部分项工程量清单/u.test(head))
|
|
16
|
+
return 'bill';
|
|
14
17
|
return 'other';
|
|
15
18
|
}
|
|
16
19
|
/** 页眉/页脚/图框标题栏高重复行:全文出现 ≥3 次 + 长度 4-60 + 非表格行 + 非列表项 + 非表头 */
|
|
@@ -113,6 +116,35 @@ function isCoordinateNoiseLine(trimmed) {
|
|
|
113
116
|
const coordMatches = trimmed.match(/-?\d+(?:\.\d+)?\s*[,,]\s*-?\d+(?:\.\d+)?/gu) ?? [];
|
|
114
117
|
return coordMatches.length >= 2;
|
|
115
118
|
}
|
|
119
|
+
/** 图纸:图框标题栏关键词(图号/比例/日期/签名列) */
|
|
120
|
+
const CAD_TITLE_BLOCK_KEY_RE = /^(图号|图别|比例|日期|阶段|版次|设计|制图|审核|校对|审定|复核)/u;
|
|
121
|
+
/** 图框行负向词:含这些词的行是实质内容(设计说明/设计要求/审核意见等),不是图框信息 */
|
|
122
|
+
const CAD_TITLE_BLOCK_GUARD_RE = /说明|要求|依据|变更|图纸|内容|标准|规范|标高|强度|参数|意见|结论|目录|名称|负责人|设计人|审核人/u;
|
|
123
|
+
/**
|
|
124
|
+
* 图纸:图框标题栏信息行("图号 J-01"、"比例 1:100"、"设计 王某某" 类签名/标注行)。
|
|
125
|
+
* 标题 + 负向词双重判定:短行 + 图框关键词开头 + 不含实质内容词。
|
|
126
|
+
*/
|
|
127
|
+
function isCadTitleBlockLine(trimmed) {
|
|
128
|
+
if (trimmed.length > 30 || trimmed.length < 3)
|
|
129
|
+
return false;
|
|
130
|
+
if (!CAD_TITLE_BLOCK_KEY_RE.test(trimmed))
|
|
131
|
+
return false;
|
|
132
|
+
if (CAD_TITLE_BLOCK_GUARD_RE.test(trimmed))
|
|
133
|
+
return false;
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
/** 图纸:CAD 转换产物的图元属性行(图层/颜色/线型/块名等,与施组编制无关) */
|
|
137
|
+
const CAD_ATTRIBUTE_LINE_RE = /^(图层|颜色|线型|线宽|块名|文字样式|标注样式|打印样式|线型比例)\s*[::=]?\s*\S{0,30}$/u;
|
|
138
|
+
/** 图纸:CAD 属性行判定(属性关键词 + 单行短值;含「说明/图例」的行是图例内容,保留) */
|
|
139
|
+
function isCadAttributeLine(trimmed) {
|
|
140
|
+
if (trimmed.length > 40)
|
|
141
|
+
return false;
|
|
142
|
+
if (!CAD_ATTRIBUTE_LINE_RE.test(trimmed))
|
|
143
|
+
return false;
|
|
144
|
+
if (/说明|图例|表/u.test(trimmed))
|
|
145
|
+
return false;
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
116
148
|
/** 合同通用条款章节标题(GF 系列示范文本的标准通用条款,不含项目数据) */
|
|
117
149
|
const CONTRACT_GENERAL_TITLE_RE = /通用合同条款|合同通用条款/u;
|
|
118
150
|
/** 专用合同条款标题:项目数据所在章节,必须保留,同时作为通用条款章节的边界 */
|
|
@@ -130,6 +162,13 @@ const BUSINESS_REVIEW_TITLE_RE = /商务(标)?(部分)?评审|报价评审|投
|
|
|
130
162
|
const TECH_REVIEW_HINT_RE = /施工组织设计|技术(标)?(部分)?评审|技术部分|技术标/u;
|
|
131
163
|
/** 新「第X部分/编」标题(合同通用条款章节边界;通用条款标题本身不触发) */
|
|
132
164
|
const PART_TITLE_RE = /^第[一二三四五六七八九十百\d]+[部分编]/u;
|
|
165
|
+
/** 清单:纯报价表格段标题(费用汇总/暂估/规费/税金/计日工——纯商务数据;
|
|
166
|
+
* 分部分项工程量清单的名称/特征/工程量是施组核心数据,不在此列,绝不删) */
|
|
167
|
+
const BILL_PURE_PRICING_TITLE_RE = /(单位工程)?费汇总表|其他项目清单(与计价表)?|规费|税金(项目)?|暂估(单)?价(一览表)?|暂列金额|计日工|总价措施项目/u;
|
|
168
|
+
/** 清单:段内金额行证据(单价/合价数字 + 元;≥2 行确认是报价数据区段) */
|
|
169
|
+
const BILL_PRICE_ROW_RE = /\d[\d,]*(?:\.\d+)?\s*元/u;
|
|
170
|
+
/** 清单:扉页签章证据(造价工程师签字/执业印章/编制单位——扉页程序性信息) */
|
|
171
|
+
const BILL_TITLE_PAGE_SIGN_RE = /造价(工程师)?|执业(印章)?|签章|编制单位|审核人|法定代表人/u;
|
|
133
172
|
/**
|
|
134
173
|
* 章节级边界收集(合同通用条款):从标题行向后收集至「专用合同条款」或下一个「第X部分/编」
|
|
135
174
|
* 标题为止,返回区段结束位置与累计字符数(规模证据由调用方判定)。
|
|
@@ -190,27 +229,48 @@ function collectSectionLevelNoise(lines, docKind) {
|
|
|
190
229
|
const region = collectChapterRegion(lines, i);
|
|
191
230
|
if (region.end - i >= CONTRACT_CHAPTER_MIN_LINES || region.chars >= CONTRACT_CHAPTER_MIN_CHARS) {
|
|
192
231
|
drops.set(i, { kind: 'contractGeneralClauseLines', end: region.end });
|
|
193
|
-
|
|
232
|
+
// -1:让循环 ++ 后落在区段末行的下一行,继续检查该行标题(相邻区段不互跳)
|
|
233
|
+
i = region.end - 1;
|
|
194
234
|
continue;
|
|
195
235
|
}
|
|
196
236
|
}
|
|
197
|
-
if (docKind
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
237
|
+
if (docKind === 'tender') {
|
|
238
|
+
// 2. 招标公告程序段
|
|
239
|
+
if (TENDER_PROCEDURE_TITLE_RE.test(trimmed)) {
|
|
240
|
+
const region = collectParagraphRegion(lines, i);
|
|
241
|
+
if (region.end > i + 1 && PROCEDURE_TIME_HINT_RE.test(region.body)) {
|
|
242
|
+
drops.set(i, { kind: 'announcementProcedureLines', end: region.end });
|
|
243
|
+
i = region.end - 1;
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
// 3. 评标商务评审细则段
|
|
248
|
+
if (BUSINESS_REVIEW_TITLE_RE.test(trimmed)) {
|
|
249
|
+
const region = collectParagraphRegion(lines, i);
|
|
250
|
+
if (region.end > i + 1 && !TECH_REVIEW_HINT_RE.test(region.body)) {
|
|
251
|
+
drops.set(i, { kind: 'businessReviewLines', end: region.end });
|
|
252
|
+
i = region.end - 1;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
// 4. 清单纯报价表格段(清单文件或招标文件内的清单章节):
|
|
257
|
+
// 标题 + 段内金额行 ≥2 双重证据(费汇总/暂估/规费/税金是纯商务数据;
|
|
258
|
+
// 分部分项清单的名称/特征/工程量不在标题列,绝不误删)
|
|
259
|
+
if ((docKind === 'bill' || docKind === 'tender') && BILL_PURE_PRICING_TITLE_RE.test(trimmed)) {
|
|
260
|
+
const region = collectParagraphRegion(lines, i, 100);
|
|
261
|
+
const priceRows = region.body.split('\n').filter(line => BILL_PRICE_ROW_RE.test(line)).length;
|
|
262
|
+
if (region.end > i + 1 && priceRows >= 2) {
|
|
263
|
+
drops.set(i, { kind: 'billPricingLines', end: region.end });
|
|
264
|
+
i = region.end - 1;
|
|
205
265
|
continue;
|
|
206
266
|
}
|
|
207
267
|
}
|
|
208
|
-
//
|
|
209
|
-
if (
|
|
210
|
-
const region = collectParagraphRegion(lines, i);
|
|
211
|
-
if (region.end > i + 1 &&
|
|
212
|
-
drops.set(i, { kind: '
|
|
213
|
-
i = region.end;
|
|
268
|
+
// 5. 清单扉页签章段(仅清单文件):工程量清单标题 + 造价签章证据
|
|
269
|
+
if (docKind === 'bill' && /^工程量清单(扉页|封面)?$/u.test(trimmed)) {
|
|
270
|
+
const region = collectParagraphRegion(lines, i, 40);
|
|
271
|
+
if (region.end > i + 1 && BILL_TITLE_PAGE_SIGN_RE.test(region.body)) {
|
|
272
|
+
drops.set(i, { kind: 'billTitlePageLines', end: region.end });
|
|
273
|
+
i = region.end - 1;
|
|
214
274
|
}
|
|
215
275
|
}
|
|
216
276
|
}
|
|
@@ -326,6 +386,18 @@ export function cleanExtractedText(input) {
|
|
|
326
386
|
index += 1;
|
|
327
387
|
continue;
|
|
328
388
|
}
|
|
389
|
+
// 8. 图纸:图框标题栏信息行(图号/比例/日期/签名行)
|
|
390
|
+
if (isCad && isCadTitleBlockLine(trimmed)) {
|
|
391
|
+
drop(line, s => { s.cadTitleBlockLines += 1; });
|
|
392
|
+
index += 1;
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
// 9. 图纸:CAD 属性行(图层/颜色/线型)
|
|
396
|
+
if (isCad && isCadAttributeLine(trimmed)) {
|
|
397
|
+
drop(line, s => { s.cadAttributeLines += 1; });
|
|
398
|
+
index += 1;
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
329
401
|
kept.push(line);
|
|
330
402
|
index += 1;
|
|
331
403
|
}
|
|
@@ -215,6 +215,10 @@ export class KnowledgeBaseManager {
|
|
|
215
215
|
cleaning.stats.contractGeneralClauseLines > 0 ? `合同通用条款 ${cleaning.stats.contractGeneralClauseLines}` : '',
|
|
216
216
|
cleaning.stats.announcementProcedureLines > 0 ? `公告程序段 ${cleaning.stats.announcementProcedureLines}` : '',
|
|
217
217
|
cleaning.stats.businessReviewLines > 0 ? `商务评审细则 ${cleaning.stats.businessReviewLines}` : '',
|
|
218
|
+
cleaning.stats.cadTitleBlockLines > 0 ? `图框信息 ${cleaning.stats.cadTitleBlockLines}` : '',
|
|
219
|
+
cleaning.stats.cadAttributeLines > 0 ? `CAD属性 ${cleaning.stats.cadAttributeLines}` : '',
|
|
220
|
+
cleaning.stats.billPricingLines > 0 ? `清单报价表 ${cleaning.stats.billPricingLines}` : '',
|
|
221
|
+
cleaning.stats.billTitlePageLines > 0 ? `清单扉页 ${cleaning.stats.billTitlePageLines}` : '',
|
|
218
222
|
].filter(Boolean).join('、');
|
|
219
223
|
extraction.warnings.push(`入库清洗移除噪声 ${cleaning.removedLines} 行(${cleaningDetail})`);
|
|
220
224
|
}
|