@customize-agent/knowledge 4.0.40 → 4.0.41
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/dist/core/knowledge-base-manager.d.ts +9 -0
- package/dist/core/knowledge-base-manager.js +97 -14
- package/dist/core/multi-project-manager.d.ts +1 -0
- package/dist/core/multi-project-manager.js +4 -4
- package/dist/extraction/content-extractor.d.ts +1 -0
- package/dist/extraction/content-extractor.js +60 -14
- package/dist/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -75,6 +75,7 @@ export declare class KnowledgeBaseManager {
|
|
|
75
75
|
collections?: string[];
|
|
76
76
|
weights?: RetrievalWeights;
|
|
77
77
|
generationMode?: boolean;
|
|
78
|
+
disableReranker?: boolean;
|
|
78
79
|
}): Promise<FederatedResult>;
|
|
79
80
|
semanticSearch(query: string, options?: {
|
|
80
81
|
limit?: number;
|
|
@@ -83,6 +84,10 @@ export declare class KnowledgeBaseManager {
|
|
|
83
84
|
}): Promise<FederatedResult>;
|
|
84
85
|
listRelationships(filePath?: string): FileRelationship[];
|
|
85
86
|
listFiles(): IndexStateRecord[];
|
|
87
|
+
listChunks(options?: {
|
|
88
|
+
relativePath?: string;
|
|
89
|
+
limit?: number;
|
|
90
|
+
}): import("./index-state-store.js").StoredChunk[];
|
|
86
91
|
getFileDetail(relativePath: string, options?: {
|
|
87
92
|
maxChunkContentChars?: number;
|
|
88
93
|
}): {
|
|
@@ -164,6 +169,10 @@ export declare class KnowledgeBaseManager {
|
|
|
164
169
|
private llmExpandQueries;
|
|
165
170
|
private retrievalWeights;
|
|
166
171
|
private heuristicRerank;
|
|
172
|
+
private normalizeSearchText;
|
|
173
|
+
private isLowQualityCadText;
|
|
174
|
+
private queryTerms;
|
|
175
|
+
private queryFactLabels;
|
|
167
176
|
private hydrateVectorResultsFromSqlite;
|
|
168
177
|
private toFederatedItem;
|
|
169
178
|
private mergeHybridRankedLists;
|
|
@@ -403,7 +403,11 @@ export class KnowledgeBaseManager {
|
|
|
403
403
|
// 2. 对这些子块进行交叉编码器重排(Cross-Encoder Rerank)
|
|
404
404
|
let reranked = mergedChildChunks;
|
|
405
405
|
let rerankerName = 'local-heuristic-fallback';
|
|
406
|
-
if (
|
|
406
|
+
if (options.disableReranker) {
|
|
407
|
+
reranked = this.heuristicRerank(query, mergedChildChunks);
|
|
408
|
+
rerankerName = 'local-heuristic-disabled-reranker';
|
|
409
|
+
}
|
|
410
|
+
else if (mergedChildChunks.length > 0) {
|
|
407
411
|
const rerankLimit = requestedLimit ? Math.min(30, mergeLimit) : mergedChildChunks.length;
|
|
408
412
|
const candidates = mergedChildChunks.slice(0, rerankLimit);
|
|
409
413
|
// 这里使用的是子块自身内容,通常在 500 tokens 左右,不仅相关性判断最准,而且不会超出 Reranker 的 max_length
|
|
@@ -470,6 +474,9 @@ export class KnowledgeBaseManager {
|
|
|
470
474
|
listFiles() {
|
|
471
475
|
return this.store.listRecords();
|
|
472
476
|
}
|
|
477
|
+
listChunks(options = {}) {
|
|
478
|
+
return this.store.listChunks(options);
|
|
479
|
+
}
|
|
473
480
|
getFileDetail(relativePath, options = {}) {
|
|
474
481
|
const normalized = this.normalizeRelativePath(relativePath);
|
|
475
482
|
const file = this.store.listRecords().find(record => record.relativePath === normalized);
|
|
@@ -746,28 +753,63 @@ export class KnowledgeBaseManager {
|
|
|
746
753
|
};
|
|
747
754
|
}
|
|
748
755
|
heuristicRerank(query, items) {
|
|
749
|
-
const terms =
|
|
756
|
+
const terms = this.queryTerms(query);
|
|
750
757
|
const phrase = query.toLowerCase().trim();
|
|
758
|
+
const normalizedPhrase = this.normalizeSearchText(query);
|
|
759
|
+
const factLabels = this.queryFactLabels(query);
|
|
760
|
+
const wantsTable = /表|行|列|金额|数量|报价|评分|清单|明细|统计|数据/u.test(query);
|
|
761
|
+
const wantsDrawing = /图纸|图层|轴网|标注|块|实体|cad|dwg|dxf|step|iges|模型/u.test(query);
|
|
762
|
+
const wantsData = /json|xml|yaml|字段|配置|数据|路径|price|id|name/u.test(query);
|
|
751
763
|
return items.map(item => {
|
|
752
|
-
const
|
|
764
|
+
const rawContent = `${item.filePath}\n${item.titlePath ?? ''}\n${item.sectionTitle ?? ''}\n${item.chunkKind ?? ''}\n${item.content}`;
|
|
765
|
+
const content = rawContent.toLowerCase();
|
|
766
|
+
const normalizedContent = this.normalizeSearchText(rawContent);
|
|
753
767
|
let rerankBoost = 0;
|
|
754
768
|
if (phrase && content.includes(phrase))
|
|
755
|
-
rerankBoost +=
|
|
769
|
+
rerankBoost += 160;
|
|
770
|
+
if (normalizedPhrase.length >= 4 && normalizedContent.includes(normalizedPhrase))
|
|
771
|
+
rerankBoost += 220;
|
|
756
772
|
const titleText = `${item.titlePath ?? ''}\n${item.sectionTitle ?? ''}`.toLowerCase();
|
|
773
|
+
const normalizedTitle = this.normalizeSearchText(titleText);
|
|
774
|
+
let matchedTermCount = 0;
|
|
757
775
|
for (const term of terms) {
|
|
758
776
|
if (!term)
|
|
759
777
|
continue;
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
778
|
+
const normalizedTerm = this.normalizeSearchText(term);
|
|
779
|
+
const matchedContent = content.includes(term) || normalizedContent.includes(normalizedTerm);
|
|
780
|
+
const matchedTitle = titleText.includes(term) || normalizedTitle.includes(normalizedTerm);
|
|
781
|
+
if (matchedContent) {
|
|
782
|
+
matchedTermCount += 1;
|
|
783
|
+
rerankBoost += 12;
|
|
784
|
+
}
|
|
785
|
+
if (matchedTitle)
|
|
786
|
+
rerankBoost += 22;
|
|
787
|
+
}
|
|
788
|
+
if (matchedTermCount >= 2)
|
|
789
|
+
rerankBoost += matchedTermCount * 18;
|
|
790
|
+
for (const label of factLabels) {
|
|
791
|
+
const normalizedLabel = this.normalizeSearchText(label);
|
|
792
|
+
if (normalizedContent.includes(normalizedLabel))
|
|
793
|
+
rerankBoost += 80;
|
|
794
|
+
if (normalizedTitle.includes(normalizedLabel))
|
|
795
|
+
rerankBoost += 120;
|
|
764
796
|
}
|
|
765
|
-
if (item.chunkKind === 'table'
|
|
766
|
-
rerankBoost +=
|
|
767
|
-
if (item.chunkKind === 'metadata'
|
|
768
|
-
rerankBoost += 60;
|
|
769
|
-
if (item.chunkKind === 'data'
|
|
770
|
-
rerankBoost += 30;
|
|
797
|
+
if (item.chunkKind === 'table')
|
|
798
|
+
rerankBoost += wantsTable ? 25 : -80;
|
|
799
|
+
if (item.chunkKind === 'metadata')
|
|
800
|
+
rerankBoost += wantsDrawing ? 60 : -100;
|
|
801
|
+
if (item.chunkKind === 'data')
|
|
802
|
+
rerankBoost += wantsData ? 30 : -12;
|
|
803
|
+
if (/\.(?:dwg|dxf)(?:$|[?#])/iu.test(item.filePath)) {
|
|
804
|
+
rerankBoost += wantsDrawing ? 120 : -60;
|
|
805
|
+
if (this.isLowQualityCadText(item.content))
|
|
806
|
+
rerankBoost -= wantsDrawing ? 60 : 160;
|
|
807
|
+
}
|
|
808
|
+
if (/工作表:|COL\d+|专业工程暂估价计价表|分部分项工程量清单计价表|材料(工程设备)暂估单价一览表/u.test(item.content)) {
|
|
809
|
+
rerankBoost -= wantsTable ? 35 : 140;
|
|
810
|
+
}
|
|
811
|
+
if (/第\s*\d+\s*页\s*共\s*\d+\s*页|PDF\s*第\s*\d+\s*页/iu.test(item.content) && factLabels.length > 0)
|
|
812
|
+
rerankBoost -= 12;
|
|
771
813
|
const score = item.score + rerankBoost;
|
|
772
814
|
return {
|
|
773
815
|
...item,
|
|
@@ -780,6 +822,47 @@ export class KnowledgeBaseManager {
|
|
|
780
822
|
};
|
|
781
823
|
}).sort((a, b) => b.score - a.score);
|
|
782
824
|
}
|
|
825
|
+
normalizeSearchText(value) {
|
|
826
|
+
return value.toLowerCase().replace(/\s+/gu, '');
|
|
827
|
+
}
|
|
828
|
+
isLowQualityCadText(value) {
|
|
829
|
+
const compact = value.replace(/\s+/gu, '');
|
|
830
|
+
if (compact.length === 0)
|
|
831
|
+
return true;
|
|
832
|
+
const readable = compact.match(/[\u4e00-\u9fa5A-Za-z0-9()()【】《》、,。;;::,.\-/㎡%]/gu)?.length || 0;
|
|
833
|
+
return readable / compact.length < 0.55;
|
|
834
|
+
}
|
|
835
|
+
queryTerms(query) {
|
|
836
|
+
const base = query.toLowerCase().split(/[\s,,。;;::、]+/u).filter(Boolean);
|
|
837
|
+
const labels = this.queryFactLabels(query).map(label => label.toLowerCase());
|
|
838
|
+
return [...new Set([...base, ...labels].filter(term => term.length > 0))];
|
|
839
|
+
}
|
|
840
|
+
queryFactLabels(query) {
|
|
841
|
+
const labels = [];
|
|
842
|
+
if (/建设地点|工程地点|项目地点|地点|在哪里|位于/u.test(query))
|
|
843
|
+
labels.push('建设地点', '工程地点', '项目地点', '项目位于', '位于');
|
|
844
|
+
if (/出资比例|资金比例|资金来源|出资/u.test(query))
|
|
845
|
+
labels.push('项目出资比例', '出资比例', '资金来源', '资金落实情况');
|
|
846
|
+
if (/项目名称|招标项目名称|工程名称/u.test(query))
|
|
847
|
+
labels.push('招标项目名称', '工程名称', '项目名称');
|
|
848
|
+
if (/项目编号|招标编号/u.test(query))
|
|
849
|
+
labels.push('招标项目编号', '项目编号');
|
|
850
|
+
if (/工期|日历天|计划开工|计划竣工/u.test(query))
|
|
851
|
+
labels.push('计划工期', '总工期', '工期', '计划开工日期', '计划竣工日期');
|
|
852
|
+
if (/质量标准|质量要求|合格/u.test(query))
|
|
853
|
+
labels.push('质量标准', '质量要求');
|
|
854
|
+
if (/招标范围|工程范围|承包范围|施工范围/u.test(query))
|
|
855
|
+
labels.push('招标范围', '工程承包范围', '施工范围');
|
|
856
|
+
if (/建设单位|招标人|项目业主/u.test(query))
|
|
857
|
+
labels.push('招标人', '项目业主', '建设单位');
|
|
858
|
+
if (/临水|临电|临时水电|水电接引|接驳点|挂表计量|施工水电/u.test(query))
|
|
859
|
+
labels.push('临水临电', '临时水电接引', '施工水电接引费', '接驳点挂表计量', '挂表计量');
|
|
860
|
+
if (/场地限制|材料堆场|办公区|生活区|加工区/u.test(query))
|
|
861
|
+
labels.push('场地限制', '不具备材料堆场', '搭设加工区', '搭设办公区', '搭设生活区');
|
|
862
|
+
if (/拆除|修补|破损处|改造维修/u.test(query))
|
|
863
|
+
labels.push('改造维修项目', '拆除内容比较多', '破损处进行修补');
|
|
864
|
+
return [...new Set(labels)];
|
|
865
|
+
}
|
|
783
866
|
hydrateVectorResultsFromSqlite(items) {
|
|
784
867
|
return items.map(item => {
|
|
785
868
|
if (!item.rowid)
|
|
@@ -27,6 +27,7 @@ export declare class MultiProjectManager {
|
|
|
27
27
|
filters?: SearchFilters;
|
|
28
28
|
weights?: RetrievalWeights;
|
|
29
29
|
generationMode?: boolean;
|
|
30
|
+
disableReranker?: boolean;
|
|
30
31
|
}): Promise<FederatedResult>;
|
|
31
32
|
semanticSearch(projectRoot: string, query: string, options?: {
|
|
32
33
|
limit?: number;
|
|
@@ -63,16 +63,16 @@ export class MultiProjectManager {
|
|
|
63
63
|
const scope = options.scope ?? 'project';
|
|
64
64
|
const project = await this.getProject(projectRoot);
|
|
65
65
|
if (scope === 'project')
|
|
66
|
-
return project.hybridSearch(query, { limit, filters: options.filters, weights: options.weights, generationMode: options.generationMode });
|
|
66
|
+
return project.hybridSearch(query, { limit, filters: options.filters, weights: options.weights, generationMode: options.generationMode, disableReranker: options.disableReranker });
|
|
67
67
|
const projectResults = scope === 'all'
|
|
68
|
-
? await project.hybridSearch(query, { limit, filters: options.filters, weights: options.weights, generationMode: options.generationMode })
|
|
68
|
+
? await project.hybridSearch(query, { limit, filters: options.filters, weights: options.weights, generationMode: options.generationMode, disableReranker: options.disableReranker })
|
|
69
69
|
: { results: [], scopesSearched: [], queryTimeMs: 0 };
|
|
70
70
|
if (scope === 'global') {
|
|
71
71
|
const global = await this.getGlobalKB();
|
|
72
|
-
return global.hybridSearch(query, { limit, filters: options.filters, weights: options.weights, generationMode: options.generationMode });
|
|
72
|
+
return global.hybridSearch(query, { limit, filters: options.filters, weights: options.weights, generationMode: options.generationMode, disableReranker: options.disableReranker });
|
|
73
73
|
}
|
|
74
74
|
const global = await this.getGlobalKB();
|
|
75
|
-
const globalResults = await global.hybridSearch(query, { limit, filters: options.filters, weights: options.weights, generationMode: options.generationMode });
|
|
75
|
+
const globalResults = await global.hybridSearch(query, { limit, filters: options.filters, weights: options.weights, generationMode: options.generationMode, disableReranker: options.disableReranker });
|
|
76
76
|
const mergeLimit = limit ?? (projectResults.results.length + globalResults.results.length);
|
|
77
77
|
const merged = new FederationSearch().merge([...projectResults.results, ...globalResults.results], mergeLimit, 'all');
|
|
78
78
|
return {
|
|
@@ -7,6 +7,7 @@ import { resolveAndImport, resolvePackage } from './module-resolver.js';
|
|
|
7
7
|
import { createOcrProvider } from './ocr-providers.js';
|
|
8
8
|
const CAD_INTERNAL_TOKEN_RE = /\b(?:TDbPipe|TDbPipeValve|TDbPipeFitting|TDbWellh|AcDb\w+|Dwg\w+|ObjectId|Handle|ByLayer|Continuous|Model|Layout\d*)\b/giu;
|
|
9
9
|
const CAD_INTERNAL_LINE_RE = /^(?:TDb\w+|AcDb\w+|[A-F0-9]{8,}|\d+|Model|Layout\d*|ByLayer|Continuous)$/iu;
|
|
10
|
+
const CAD_DOMAIN_SIGNAL_RE = /工程|项目|施工|建筑|结构|装饰|电气|给排水|消防|暖通|平面|立面|剖面|节点|详图|材料|尺寸|标高|轴线|图层|门窗|墙|地面|顶面|照明|配电|弱电|空调|卫生间|楼梯|屋面|基础|柱|梁|板|图号|设计|说明/u;
|
|
10
11
|
const OCR_NATIVE_NOISE_PATTERNS = [/^Image too small to scale!!/u, /^Line cannot be recognized!!$/u];
|
|
11
12
|
/** 文件内容提取器,支持文档、表格、图片、CAD 等多种文件格式的内容抽取 */
|
|
12
13
|
export class ContentExtractor {
|
|
@@ -146,9 +147,34 @@ export class ContentExtractor {
|
|
|
146
147
|
.replace(/\s+/gu, ' ')
|
|
147
148
|
.trim();
|
|
148
149
|
}
|
|
150
|
+
isLikelyGarbledCadText(value) {
|
|
151
|
+
const compact = value.replace(/\s+/gu, '');
|
|
152
|
+
if (!compact)
|
|
153
|
+
return true;
|
|
154
|
+
const chars = [...compact];
|
|
155
|
+
const readable = chars.filter(char => /[\p{Script=Han}\p{Script=Latin}\d()()【】《》、,。;;::,.\-/㎡%]/u.test(char)).length;
|
|
156
|
+
const cjk = chars.filter(char => /[\p{Script=Han}]/u.test(char)).length;
|
|
157
|
+
const latin = chars.filter(char => /[\p{Script=Latin}]/u.test(char)).length;
|
|
158
|
+
const digits = chars.filter(char => /\d/u.test(char)).length;
|
|
159
|
+
const symbols = chars.length - readable;
|
|
160
|
+
const readableRatio = readable / chars.length;
|
|
161
|
+
const symbolRatio = symbols / chars.length;
|
|
162
|
+
const hasDomainSignal = CAD_DOMAIN_SIGNAL_RE.test(compact);
|
|
163
|
+
const hasCommonTextShape = /[,。;:、,.\-/()()]|\d+(?:\.\d+)?\s*(?:mm|cm|m|㎡|%|°)?/iu.test(compact);
|
|
164
|
+
const latinVowelCount = chars.filter(char => /[aAeEiIoOuU]/u.test(char)).length;
|
|
165
|
+
if (readableRatio < 0.6)
|
|
166
|
+
return true;
|
|
167
|
+
if (symbolRatio > 0.35 && !hasDomainSignal)
|
|
168
|
+
return true;
|
|
169
|
+
if (latin >= 12 && latinVowelCount === 0 && !hasDomainSignal)
|
|
170
|
+
return true;
|
|
171
|
+
if (cjk >= 8 && digits === 0 && !hasDomainSignal && !hasCommonTextShape)
|
|
172
|
+
return true;
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
149
175
|
isReadableCadValue(value) {
|
|
150
176
|
const cleaned = this.cleanCadReadableText(value);
|
|
151
|
-
return cleaned.length >= 2 && !CAD_INTERNAL_LINE_RE.test(cleaned) && /[\p{Script=Han}\p{Letter}\d]/u.test(cleaned);
|
|
177
|
+
return cleaned.length >= 2 && !CAD_INTERNAL_LINE_RE.test(cleaned) && /[\p{Script=Han}\p{Letter}\d]/u.test(cleaned) && !this.isLikelyGarbledCadText(cleaned);
|
|
152
178
|
}
|
|
153
179
|
cleanExtractedText(value, file) {
|
|
154
180
|
const normalized = [...value]
|
|
@@ -162,7 +188,7 @@ export class ContentExtractor {
|
|
|
162
188
|
return normalized
|
|
163
189
|
.split(/\r?\n/u)
|
|
164
190
|
.map(line => this.cleanCadReadableText(line))
|
|
165
|
-
.filter(line => line && !CAD_INTERNAL_LINE_RE.test(line))
|
|
191
|
+
.filter(line => line && !CAD_INTERNAL_LINE_RE.test(line) && !this.isLikelyGarbledCadText(line))
|
|
166
192
|
.join('\n')
|
|
167
193
|
.replace(/\n{3,}/gu, '\n\n');
|
|
168
194
|
}
|
|
@@ -172,7 +198,7 @@ export class ContentExtractor {
|
|
|
172
198
|
return cjk * 4 + alnum + Math.min(value.length, 200) / 20;
|
|
173
199
|
}
|
|
174
200
|
async extractCad(file) {
|
|
175
|
-
const metadata = { extractionMode: 'builtin_cad_structural', vectorizable: true };
|
|
201
|
+
const metadata = { extractionMode: 'builtin_cad_structural', vectorizable: true, preferredExtractionMode: 'dwg_to_dxf_semantic' };
|
|
176
202
|
const warnings = [];
|
|
177
203
|
const ext = path.extname(file.absolutePath).toLowerCase();
|
|
178
204
|
if (ext === '.dxf')
|
|
@@ -180,7 +206,7 @@ export class ContentExtractor {
|
|
|
180
206
|
if (ext === '.dwg') {
|
|
181
207
|
const converted = await this.tryConvertDwgToDxf(file.absolutePath);
|
|
182
208
|
if (converted?.dxfText) {
|
|
183
|
-
const parsed = await this.extractDxf(file, converted.dxfText, { ...metadata, extractionMode: converted.tool, convertedFrom: 'dwg' });
|
|
209
|
+
const parsed = await this.extractDxf(file, converted.dxfText, { ...metadata, extractionMode: converted.tool, convertedFrom: 'dwg', professionalConversionUsed: true });
|
|
184
210
|
parsed.warnings.push(...converted.warnings);
|
|
185
211
|
return parsed;
|
|
186
212
|
}
|
|
@@ -264,14 +290,20 @@ export class ContentExtractor {
|
|
|
264
290
|
if (result.text.trim())
|
|
265
291
|
return result;
|
|
266
292
|
}
|
|
267
|
-
const
|
|
293
|
+
const binaryFragments = this.extractBinaryReadableFragments(file.absolutePath);
|
|
294
|
+
const readable = binaryFragments.filter(value => this.isReadableCadValue(value)).slice(0, 5000);
|
|
295
|
+
const filteredCount = Math.max(0, binaryFragments.length - readable.length);
|
|
268
296
|
metadata.extractionMode = 'builtin_cad_readable_fragments';
|
|
269
|
-
metadata.
|
|
297
|
+
metadata.professionalConversionUsed = false;
|
|
298
|
+
metadata.contentCoverage = readable.length > 0 ? 'cad_readable_text_fragments_filtered' : 'metadata';
|
|
299
|
+
metadata.contentConfidence = readable.length > 0 ? 'low_fallback_filtered' : 'metadata_only';
|
|
300
|
+
metadata.stringCandidateCount = binaryFragments.length;
|
|
270
301
|
metadata.stringCount = readable.length;
|
|
302
|
+
metadata.filteredGarbledStringCount = filteredCount;
|
|
271
303
|
if (readable.length === 0)
|
|
272
304
|
warnings.push(`${file.format} 内置 CAD 解析器未提取到可用文本,仅记录文件元数据,未生成可检索正文切片`);
|
|
273
305
|
else
|
|
274
|
-
warnings.push(`${file.format}
|
|
306
|
+
warnings.push(`${file.format} 内置 DWG→DXF 转换未成功,已使用低置信度可读标注/标题块兜底抽取并过滤疑似乱码 ${filteredCount} 条;该结果仅作为兜底证据,不应等同于完整图层、块、标注和尺寸语义解析`);
|
|
275
307
|
return {
|
|
276
308
|
text: readable.length > 0 ? [this.metadataOnlyText(file), `CAD 图纸可读标注/标题块/属性:\n${readable.join('\n')}`].join('\n') : this.metadataOnlyText(file),
|
|
277
309
|
metadata,
|
|
@@ -373,15 +405,29 @@ export class ContentExtractor {
|
|
|
373
405
|
const mod = await resolveAndImport('dwgdxf');
|
|
374
406
|
if (!mod.convertDwgToDxf)
|
|
375
407
|
return { tool: 'dwgdxf_wasm', warnings: ['内置 dwgdxf WASM 转换器未导出 convertDwgToDxf'] };
|
|
376
|
-
const
|
|
377
|
-
const
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
408
|
+
const dwgBytes = fs.readFileSync(filePath);
|
|
409
|
+
const attempts = [
|
|
410
|
+
{ label: 'package-default' },
|
|
411
|
+
{ label: 'package-dist-wasm', options: { wasmBase: pathToFileURL(path.join(path.dirname(resolvePackage('dwgdxf')), 'wasm')).href } },
|
|
412
|
+
{ label: 'package-root-dist-wasm', options: { wasmBase: pathToFileURL(path.join(path.dirname(path.dirname(resolvePackage('dwgdxf'))), 'wasm')).href } },
|
|
413
|
+
];
|
|
414
|
+
const failures = [];
|
|
415
|
+
for (const attempt of attempts) {
|
|
416
|
+
try {
|
|
417
|
+
const dxfBytes = await mod.convertDwgToDxf(dwgBytes, attempt.options);
|
|
418
|
+
const dxfText = Buffer.from(dxfBytes).toString('utf8');
|
|
419
|
+
if (dxfText.trim())
|
|
420
|
+
return { dxfText, tool: `dwgdxf_wasm:${attempt.label}`, warnings: [] };
|
|
421
|
+
failures.push(`${attempt.label}: 未输出 DXF 文本`);
|
|
422
|
+
}
|
|
423
|
+
catch (error) {
|
|
424
|
+
failures.push(`${attempt.label}: ${error instanceof Error ? error.message : String(error)}`);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
return { tool: 'dwgdxf_wasm', warnings: [`内置 dwgdxf WASM 转换失败: ${failures.join(';')}`] };
|
|
382
428
|
}
|
|
383
429
|
catch (error) {
|
|
384
|
-
return { tool: 'dwgdxf_wasm', warnings: [`内置 dwgdxf WASM
|
|
430
|
+
return { tool: 'dwgdxf_wasm', warnings: [`内置 dwgdxf WASM 加载失败: ${error instanceof Error ? error.message : String(error)}`] };
|
|
385
431
|
}
|
|
386
432
|
}
|
|
387
433
|
async tryConvertDwgToDxf(filePath) {
|
package/dist/index.d.ts
CHANGED
|
@@ -17,5 +17,5 @@ export { HNSWVectorStore } from './vector/hnsw-vector-store.js';
|
|
|
17
17
|
export { CollectionManager, globalCollectionName, projectCollectionName } from './vector/collection-manager.js';
|
|
18
18
|
export type { CollectionClient, VectorCollectionInfo, VectorDocument, VectorSearchQuery, VectorSearchResult, VectorStoreInterface, VectorWriteOptions } from './vector/types.js';
|
|
19
19
|
export { VectorIndexer, type VectorIndexResult } from './vector/vector-indexer.js';
|
|
20
|
-
export { FederationSearch, type FederatedQuery, type FederatedResult, type FederatedSearchItem, type SearchFilters, type SearchScope } from './search/federation-search.js';
|
|
20
|
+
export { FederationSearch, type FederatedQuery, type FederatedResult, type FederatedSearchItem, type RetrievalWeights, type SearchFilters, type SearchScope } from './search/federation-search.js';
|
|
21
21
|
export type { LLMChatMessage, LLMChatOptions, LLMChatResponse, LLMSearchProvider } from './llm/llm-search-provider.js';
|