@customize-agent/knowledge 3.0.3 → 3.0.5
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/classification/classifier.js +1 -1
- package/dist/core/change-tracker.js +5 -2
- package/dist/core/knowledge-base-manager.js +4 -3
- package/dist/embedding/embedding-provider.d.ts +17 -0
- package/dist/embedding/embedding-provider.js +66 -0
- package/dist/extraction/content-extractor.js +108 -85
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +4 -1
|
@@ -53,7 +53,7 @@ export class FileClassifier {
|
|
|
53
53
|
['.txt', 'document', 'plaintext'], ['.textclipping', 'document', 'text_clipping'], ['.rst', 'document', 'plaintext'], ['.asciidoc', 'document', 'plaintext'], ['.tex', 'document', 'plaintext'],
|
|
54
54
|
['.epub', 'document', 'ebook'], ['.mobi', 'document', 'ebook'],
|
|
55
55
|
['.xlsx', 'spreadsheet', 'excel'], ['.xls', 'spreadsheet', 'excel'], ['.xlsm', 'spreadsheet', 'excel'],
|
|
56
|
-
['.csv', 'spreadsheet', 'csv'], ['.tsv', 'spreadsheet', '
|
|
56
|
+
['.csv', 'spreadsheet', 'csv'], ['.tsv', 'spreadsheet', 'tsv'], ['.tab', 'spreadsheet', 'tsv'], ['.ods', 'spreadsheet', 'opendoc'],
|
|
57
57
|
['.png', 'image', 'raster'], ['.jpg', 'image', 'raster'], ['.jpeg', 'image', 'raster'], ['.gif', 'image', 'raster'], ['.bmp', 'image', 'raster'], ['.webp', 'image', 'raster'], ['.tiff', 'image', 'raster'], ['.tif', 'image', 'raster'],
|
|
58
58
|
['.svg', 'image', 'vector'], ['.eps', 'image', 'vector'], ['.raw', 'image', 'raw'], ['.cr2', 'image', 'raw'], ['.nef', 'image', 'raw'], ['.dng', 'image', 'raw'],
|
|
59
59
|
['.dwg', 'cad', 'autocad'], ['.dxf', 'cad', 'autocad'], ['.dwt', 'cad', 'autocad'],
|
|
@@ -30,11 +30,14 @@ export class ChangeTracker {
|
|
|
30
30
|
continue;
|
|
31
31
|
}
|
|
32
32
|
const metadata = this.parseMetadata(indexed.metadataJson);
|
|
33
|
+
const extraction = metadata.extraction && typeof metadata.extraction === 'object' ? metadata.extraction : {};
|
|
34
|
+
const contentCoverage = metadata.contentCoverage ?? extraction.contentCoverage;
|
|
35
|
+
const extractionMode = metadata.extractionMode ?? extraction.extractionMode;
|
|
33
36
|
const needsReindex = indexed.status === 'error'
|
|
34
37
|
|| indexed.chunkCount === 0
|
|
35
38
|
|| (classified.format === 'pdf' && indexed.chunkCount <= 1)
|
|
36
|
-
||
|
|
37
|
-
||
|
|
39
|
+
|| contentCoverage === 'metadata_filename'
|
|
40
|
+
|| extractionMode === 'pdf_metadata_only';
|
|
38
41
|
if (needsReindex) {
|
|
39
42
|
modifiedFiles.push(classified);
|
|
40
43
|
continue;
|
|
@@ -6,7 +6,7 @@ import { FileClassifier } from '../classification/classifier.js';
|
|
|
6
6
|
import { ALL_CATEGORIES, DEFAULT_CATEGORY_DIRS, GLOBAL_KNOWLEDGE_DIR, USER_DATA_DIR } from '../constants.js';
|
|
7
7
|
import { DedupEngine } from '../dedup/dedup-engine.js';
|
|
8
8
|
import { RelationshipDetector } from '../dedup/relationship-detector.js';
|
|
9
|
-
import {
|
|
9
|
+
import { createEmbeddingProviderFromEnvironment } from '../embedding/embedding-provider.js';
|
|
10
10
|
import { ContentExtractor } from '../extraction/content-extractor.js';
|
|
11
11
|
import { FederationSearch } from '../search/federation-search.js';
|
|
12
12
|
import { CollectionManager } from '../vector/collection-manager.js';
|
|
@@ -41,7 +41,7 @@ export class KnowledgeBaseManager {
|
|
|
41
41
|
this.scope = options.scope;
|
|
42
42
|
this.projectRoot = options.projectRoot;
|
|
43
43
|
this.projectId = options.projectId;
|
|
44
|
-
this.embeddingProvider = options.embeddingProvider ??
|
|
44
|
+
this.embeddingProvider = options.embeddingProvider ?? createEmbeddingProviderFromEnvironment();
|
|
45
45
|
this.vectorStores = options.vectorStores ?? new Map();
|
|
46
46
|
this.extractor = new ContentExtractor(options.externalExtractors);
|
|
47
47
|
this.llmProvider = options.llmProvider;
|
|
@@ -200,6 +200,7 @@ export class KnowledgeBaseManager {
|
|
|
200
200
|
status: 'active',
|
|
201
201
|
metadataJson: JSON.stringify({
|
|
202
202
|
mimeType: file.mimeType,
|
|
203
|
+
...extraction.metadata,
|
|
203
204
|
extraction: extraction.metadata,
|
|
204
205
|
warnings: extraction.warnings,
|
|
205
206
|
extractionTimeMs: extraction.extractionTimeMs,
|
|
@@ -705,7 +706,7 @@ ${resultsText}
|
|
|
705
706
|
}
|
|
706
707
|
hasUsableContent(text, metadata) {
|
|
707
708
|
const coverage = String(metadata.contentCoverage ?? '');
|
|
708
|
-
if (
|
|
709
|
+
if (['metadata', 'metadata_filename', 'pdf_metadata_only', 'office_zip_empty_text', 'office_zip_failed'].includes(coverage))
|
|
709
710
|
return false;
|
|
710
711
|
return text.trim().length > 0;
|
|
711
712
|
}
|
|
@@ -14,3 +14,20 @@ export declare class HashEmbeddingProvider implements EmbeddingProvider {
|
|
|
14
14
|
private tokenize;
|
|
15
15
|
private normalize;
|
|
16
16
|
}
|
|
17
|
+
export interface OpenAICompatibleEmbeddingOptions {
|
|
18
|
+
baseUrl: string;
|
|
19
|
+
apiKey?: string;
|
|
20
|
+
model: string;
|
|
21
|
+
dimensions?: number;
|
|
22
|
+
}
|
|
23
|
+
export declare class OpenAICompatibleEmbeddingProvider implements EmbeddingProvider {
|
|
24
|
+
readonly model: string;
|
|
25
|
+
readonly dimensions: number;
|
|
26
|
+
private readonly baseUrl;
|
|
27
|
+
private readonly apiKey?;
|
|
28
|
+
constructor(options: OpenAICompatibleEmbeddingOptions);
|
|
29
|
+
embedDocuments(texts: string[]): Promise<number[][]>;
|
|
30
|
+
embedQuery(text: string): Promise<number[]>;
|
|
31
|
+
private embed;
|
|
32
|
+
}
|
|
33
|
+
export declare function createEmbeddingProviderFromEnvironment(): EmbeddingProvider;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import * as crypto from 'node:crypto';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as os from 'node:os';
|
|
4
|
+
import * as path from 'node:path';
|
|
2
5
|
export class HashEmbeddingProvider {
|
|
3
6
|
dimensions;
|
|
4
7
|
model = 'hash-embedding-local';
|
|
@@ -44,3 +47,66 @@ export class HashEmbeddingProvider {
|
|
|
44
47
|
return vector.map(value => value / norm);
|
|
45
48
|
}
|
|
46
49
|
}
|
|
50
|
+
export class OpenAICompatibleEmbeddingProvider {
|
|
51
|
+
model;
|
|
52
|
+
dimensions;
|
|
53
|
+
baseUrl;
|
|
54
|
+
apiKey;
|
|
55
|
+
constructor(options) {
|
|
56
|
+
this.baseUrl = options.baseUrl.replace(/\/+$/u, '');
|
|
57
|
+
this.apiKey = options.apiKey;
|
|
58
|
+
this.model = options.model;
|
|
59
|
+
this.dimensions = options.dimensions ?? 1024;
|
|
60
|
+
}
|
|
61
|
+
async embedDocuments(texts) {
|
|
62
|
+
return this.embed(texts);
|
|
63
|
+
}
|
|
64
|
+
async embedQuery(text) {
|
|
65
|
+
return (await this.embed([text]))[0] ?? [];
|
|
66
|
+
}
|
|
67
|
+
async embed(input) {
|
|
68
|
+
const response = await fetch(`${this.baseUrl}/embeddings`, {
|
|
69
|
+
method: 'POST',
|
|
70
|
+
headers: {
|
|
71
|
+
'Content-Type': 'application/json',
|
|
72
|
+
...(this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {}),
|
|
73
|
+
},
|
|
74
|
+
body: JSON.stringify({ model: this.model, input }),
|
|
75
|
+
});
|
|
76
|
+
if (!response.ok)
|
|
77
|
+
throw new Error(`Embedding request failed: HTTP ${response.status} ${await response.text()}`);
|
|
78
|
+
const payload = await response.json();
|
|
79
|
+
return (payload.data ?? []).map(item => item.embedding ?? []);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function readStoredEmbeddingConfig() {
|
|
83
|
+
try {
|
|
84
|
+
const configPath = path.join(os.homedir(), '.customize-agent', 'config.json');
|
|
85
|
+
if (!fs.existsSync(configPath))
|
|
86
|
+
return undefined;
|
|
87
|
+
const raw = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
88
|
+
return raw.embedding;
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
export function createEmbeddingProviderFromEnvironment() {
|
|
95
|
+
const stored = readStoredEmbeddingConfig();
|
|
96
|
+
const provider = process.env.CUSTOMIZE_EMBEDDING_PROVIDER ?? process.env.KB_EMBEDDING_PROVIDER ?? stored?.provider;
|
|
97
|
+
if (provider === 'openai-compatible') {
|
|
98
|
+
const baseUrl = process.env.CUSTOMIZE_EMBEDDING_BASE_URL ?? process.env.KB_EMBEDDING_BASE_URL ?? stored?.baseUrl;
|
|
99
|
+
const model = process.env.CUSTOMIZE_EMBEDDING_MODEL ?? process.env.KB_EMBEDDING_MODEL ?? stored?.model;
|
|
100
|
+
if (baseUrl && model) {
|
|
101
|
+
const rawDimensions = process.env.CUSTOMIZE_EMBEDDING_DIMENSIONS ?? process.env.KB_EMBEDDING_DIMENSIONS;
|
|
102
|
+
const dimensions = Number(rawDimensions ?? stored?.dimensions ?? 1024);
|
|
103
|
+
return new OpenAICompatibleEmbeddingProvider({
|
|
104
|
+
baseUrl,
|
|
105
|
+
model,
|
|
106
|
+
apiKey: process.env.CUSTOMIZE_EMBEDDING_API_KEY ?? process.env.KB_EMBEDDING_API_KEY ?? stored?.apiKey,
|
|
107
|
+
dimensions: Number.isFinite(dimensions) ? dimensions : 1024,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return new HashEmbeddingProvider();
|
|
112
|
+
}
|
|
@@ -19,88 +19,91 @@ export class ContentExtractor {
|
|
|
19
19
|
format: file.format,
|
|
20
20
|
};
|
|
21
21
|
const external = this.tryExternalExtractor(file);
|
|
22
|
-
if (external) {
|
|
22
|
+
if (external?.text.trim()) {
|
|
23
23
|
text = external.text;
|
|
24
24
|
Object.assign(metadata, external.metadata);
|
|
25
25
|
warnings.push(...external.warnings);
|
|
26
26
|
}
|
|
27
|
-
else if (file.category === 'cad') {
|
|
28
|
-
const result = await this.extractCad(file);
|
|
29
|
-
text = result.text;
|
|
30
|
-
Object.assign(metadata, result.metadata);
|
|
31
|
-
warnings.push(...result.warnings);
|
|
32
|
-
}
|
|
33
|
-
else if (file.category === 'data') {
|
|
34
|
-
const result = this.extractData(file);
|
|
35
|
-
text = result.text;
|
|
36
|
-
Object.assign(metadata, result.metadata);
|
|
37
|
-
warnings.push(...result.warnings);
|
|
38
|
-
}
|
|
39
|
-
else if (file.category === 'diagram') {
|
|
40
|
-
const result = this.extractDiagram(file);
|
|
41
|
-
text = result.text;
|
|
42
|
-
Object.assign(metadata, result.metadata);
|
|
43
|
-
warnings.push(...result.warnings);
|
|
44
|
-
}
|
|
45
|
-
else if (file.category === 'document' && file.format === 'pdf') {
|
|
46
|
-
const result = await this.extractPdf(file);
|
|
47
|
-
text = result.text;
|
|
48
|
-
Object.assign(metadata, result.metadata);
|
|
49
|
-
warnings.push(...result.warnings);
|
|
50
|
-
}
|
|
51
|
-
else if (file.category === 'document' && ['office', 'presentation'].includes(file.format)) {
|
|
52
|
-
const result = await this.extractOfficeDocument(file);
|
|
53
|
-
text = result.text;
|
|
54
|
-
Object.assign(metadata, result.metadata);
|
|
55
|
-
warnings.push(...result.warnings);
|
|
56
|
-
}
|
|
57
|
-
else if (file.category === 'spreadsheet' && ['csv', 'tsv'].includes(file.format)) {
|
|
58
|
-
const result = this.extractDelimitedText(file);
|
|
59
|
-
text = result.text;
|
|
60
|
-
Object.assign(metadata, result.metadata);
|
|
61
|
-
warnings.push(...result.warnings);
|
|
62
|
-
}
|
|
63
|
-
else if (file.category === 'spreadsheet') {
|
|
64
|
-
const result = await this.extractSpreadsheet(file);
|
|
65
|
-
text = result.text;
|
|
66
|
-
Object.assign(metadata, result.metadata);
|
|
67
|
-
warnings.push(...result.warnings);
|
|
68
|
-
}
|
|
69
|
-
else if (file.category === 'archive') {
|
|
70
|
-
const result = await this.extractArchive(file);
|
|
71
|
-
text = result.text;
|
|
72
|
-
Object.assign(metadata, result.metadata);
|
|
73
|
-
warnings.push(...result.warnings);
|
|
74
|
-
}
|
|
75
|
-
else if (file.category === 'image' && file.format !== 'vector') {
|
|
76
|
-
const result = await this.extractRasterImage(file);
|
|
77
|
-
text = result.text;
|
|
78
|
-
Object.assign(metadata, result.metadata);
|
|
79
|
-
warnings.push(...result.warnings);
|
|
80
|
-
}
|
|
81
|
-
else if (file.category === 'image' && file.format === 'vector') {
|
|
82
|
-
const result = this.extractSvg(file);
|
|
83
|
-
text = result.text;
|
|
84
|
-
Object.assign(metadata, result.metadata);
|
|
85
|
-
warnings.push(...result.warnings);
|
|
86
|
-
}
|
|
87
|
-
else if (file.format === 'text_clipping') {
|
|
88
|
-
const result = this.extractTextClipping(file);
|
|
89
|
-
text = result.text;
|
|
90
|
-
Object.assign(metadata, result.metadata);
|
|
91
|
-
warnings.push(...result.warnings);
|
|
92
|
-
}
|
|
93
|
-
else if (this.isTextReadable(file)) {
|
|
94
|
-
text = fs.readFileSync(file.absolutePath, 'utf8');
|
|
95
|
-
metadata.extractionMode = 'plain_text';
|
|
96
|
-
metadata.vectorizable = true;
|
|
97
|
-
}
|
|
98
27
|
else {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
28
|
+
warnings.push(...(external?.warnings ?? []));
|
|
29
|
+
if (file.category === 'cad') {
|
|
30
|
+
const result = await this.extractCad(file);
|
|
31
|
+
text = result.text;
|
|
32
|
+
Object.assign(metadata, result.metadata);
|
|
33
|
+
warnings.push(...result.warnings);
|
|
34
|
+
}
|
|
35
|
+
else if (file.category === 'data') {
|
|
36
|
+
const result = this.extractData(file);
|
|
37
|
+
text = result.text;
|
|
38
|
+
Object.assign(metadata, result.metadata);
|
|
39
|
+
warnings.push(...result.warnings);
|
|
40
|
+
}
|
|
41
|
+
else if (file.category === 'diagram') {
|
|
42
|
+
const result = this.extractDiagram(file);
|
|
43
|
+
text = result.text;
|
|
44
|
+
Object.assign(metadata, result.metadata);
|
|
45
|
+
warnings.push(...result.warnings);
|
|
46
|
+
}
|
|
47
|
+
else if (file.category === 'document' && file.format === 'pdf') {
|
|
48
|
+
const result = await this.extractPdf(file);
|
|
49
|
+
text = result.text;
|
|
50
|
+
Object.assign(metadata, result.metadata);
|
|
51
|
+
warnings.push(...result.warnings);
|
|
52
|
+
}
|
|
53
|
+
else if (file.category === 'document' && ['office', 'presentation'].includes(file.format)) {
|
|
54
|
+
const result = await this.extractOfficeDocument(file);
|
|
55
|
+
text = result.text;
|
|
56
|
+
Object.assign(metadata, result.metadata);
|
|
57
|
+
warnings.push(...result.warnings);
|
|
58
|
+
}
|
|
59
|
+
else if (file.category === 'spreadsheet' && ['csv', 'tsv'].includes(file.format)) {
|
|
60
|
+
const result = this.extractDelimitedText(file);
|
|
61
|
+
text = result.text;
|
|
62
|
+
Object.assign(metadata, result.metadata);
|
|
63
|
+
warnings.push(...result.warnings);
|
|
64
|
+
}
|
|
65
|
+
else if (file.category === 'spreadsheet') {
|
|
66
|
+
const result = await this.extractSpreadsheet(file);
|
|
67
|
+
text = result.text;
|
|
68
|
+
Object.assign(metadata, result.metadata);
|
|
69
|
+
warnings.push(...result.warnings);
|
|
70
|
+
}
|
|
71
|
+
else if (file.category === 'archive') {
|
|
72
|
+
const result = await this.extractArchive(file);
|
|
73
|
+
text = result.text;
|
|
74
|
+
Object.assign(metadata, result.metadata);
|
|
75
|
+
warnings.push(...result.warnings);
|
|
76
|
+
}
|
|
77
|
+
else if (file.category === 'image' && file.format !== 'vector') {
|
|
78
|
+
const result = await this.extractRasterImage(file);
|
|
79
|
+
text = result.text;
|
|
80
|
+
Object.assign(metadata, result.metadata);
|
|
81
|
+
warnings.push(...result.warnings);
|
|
82
|
+
}
|
|
83
|
+
else if (file.category === 'image' && file.format === 'vector') {
|
|
84
|
+
const result = this.extractSvg(file);
|
|
85
|
+
text = result.text;
|
|
86
|
+
Object.assign(metadata, result.metadata);
|
|
87
|
+
warnings.push(...result.warnings);
|
|
88
|
+
}
|
|
89
|
+
else if (file.format === 'text_clipping') {
|
|
90
|
+
const result = this.extractTextClipping(file);
|
|
91
|
+
text = result.text;
|
|
92
|
+
Object.assign(metadata, result.metadata);
|
|
93
|
+
warnings.push(...result.warnings);
|
|
94
|
+
}
|
|
95
|
+
else if (this.isTextReadable(file)) {
|
|
96
|
+
text = fs.readFileSync(file.absolutePath, 'utf8');
|
|
97
|
+
metadata.extractionMode = 'plain_text';
|
|
98
|
+
metadata.vectorizable = true;
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
text = this.metadataOnlyText(file);
|
|
102
|
+
metadata.extractionMode = 'metadata_only';
|
|
103
|
+
metadata.vectorizable = true;
|
|
104
|
+
metadata.contentCoverage = 'metadata';
|
|
105
|
+
warnings.push(`暂不支持 ${file.category}/${file.format} 内容提取,未解析出正文,未入库`);
|
|
106
|
+
}
|
|
104
107
|
}
|
|
105
108
|
return {
|
|
106
109
|
text: text.trim(),
|
|
@@ -138,7 +141,7 @@ export class ContentExtractor {
|
|
|
138
141
|
warnings.push(`外部解析器 ${extractor.name} 失败: ${error instanceof Error ? error.message : String(error)}`);
|
|
139
142
|
}
|
|
140
143
|
}
|
|
141
|
-
return undefined;
|
|
144
|
+
return warnings.length > 0 ? { text: '', metadata: {}, warnings } : undefined;
|
|
142
145
|
}
|
|
143
146
|
extractTextClipping(file) {
|
|
144
147
|
const buffer = fs.readFileSync(file.absolutePath);
|
|
@@ -282,7 +285,7 @@ export class ContentExtractor {
|
|
|
282
285
|
metadata.contentCoverage = readable.length > 0 ? 'cad_readable_text_fragments' : 'metadata';
|
|
283
286
|
metadata.stringCount = readable.length;
|
|
284
287
|
if (readable.length === 0)
|
|
285
|
-
warnings.push(`${file.format} 内置 CAD
|
|
288
|
+
warnings.push(`${file.format} 内置 CAD 解析器未提取到可用文本,仅记录文件元数据,未生成可检索正文切片`);
|
|
286
289
|
else
|
|
287
290
|
warnings.push(`${file.format} 未检测到专业 DWG 转换器,已使用内置可读标注/标题块抽取;如需完整图纸结构,请安装 ODA File Converter 或 LibreDWG 并配置外部解析器`);
|
|
288
291
|
return {
|
|
@@ -336,18 +339,34 @@ export class ContentExtractor {
|
|
|
336
339
|
try {
|
|
337
340
|
const customCmd = process.env.CUSTOMIZE_DWG_TO_DXF_CMD;
|
|
338
341
|
if (customCmd) {
|
|
339
|
-
|
|
340
|
-
|
|
342
|
+
if (/\s/u.test(customCmd))
|
|
343
|
+
return { tool: 'external_dwg_to_dxf', warnings: ['CUSTOMIZE_DWG_TO_DXF_CMD 只支持可执行文件路径;参数请使用 CUSTOMIZE_DWG_TO_DXF_ARGS JSON 数组配置'] };
|
|
344
|
+
let argTemplate = ['{input}', '{output}'];
|
|
345
|
+
try {
|
|
346
|
+
if (process.env.CUSTOMIZE_DWG_TO_DXF_ARGS)
|
|
347
|
+
argTemplate = JSON.parse(process.env.CUSTOMIZE_DWG_TO_DXF_ARGS);
|
|
348
|
+
}
|
|
349
|
+
catch {
|
|
350
|
+
return { tool: 'external_dwg_to_dxf', warnings: ['CUSTOMIZE_DWG_TO_DXF_ARGS 必须是字符串数组 JSON'] };
|
|
351
|
+
}
|
|
352
|
+
if (!Array.isArray(argTemplate) || !argTemplate.every(arg => typeof arg === 'string'))
|
|
353
|
+
return { tool: 'external_dwg_to_dxf', warnings: ['CUSTOMIZE_DWG_TO_DXF_ARGS 必须是字符串数组 JSON'] };
|
|
354
|
+
const args = argTemplate.map(arg => arg.replace(/\{input\}/gu, filePath).replace(/\{output\}/gu, outputPath));
|
|
355
|
+
const result = spawnSync(customCmd, args, { shell: false, encoding: 'utf8', timeout: 120_000 });
|
|
341
356
|
if (result.status === 0 && fs.existsSync(outputPath))
|
|
342
357
|
return { dxfText: fs.readFileSync(outputPath, 'utf8'), tool: 'external_dwg_to_dxf', warnings: [] };
|
|
343
358
|
return { tool: 'external_dwg_to_dxf', warnings: [`CUSTOMIZE_DWG_TO_DXF_CMD 转换失败: ${result.stderr || result.stdout || result.error?.message || 'unknown error'}`] };
|
|
344
359
|
}
|
|
360
|
+
const failures = [];
|
|
345
361
|
for (const bin of ['dwgread', 'dwg2dxf']) {
|
|
346
362
|
const result = spawnSync(bin, bin === 'dwgread' ? ['-O', 'DXF', '-o', outputPath, filePath] : [filePath, outputPath], { encoding: 'utf8', timeout: 120_000 });
|
|
347
363
|
if (result.status === 0 && fs.existsSync(outputPath))
|
|
348
364
|
return { dxfText: fs.readFileSync(outputPath, 'utf8'), tool: bin, warnings: [] };
|
|
365
|
+
if (result.error && 'code' in result.error && result.error.code === 'ENOENT')
|
|
366
|
+
continue;
|
|
367
|
+
failures.push(`${bin} 转换失败: ${result.stderr || result.stdout || result.error?.message || `exit ${result.status ?? 'unknown'}`}`);
|
|
349
368
|
}
|
|
350
|
-
return { tool: 'builtin_fallback', warnings: ['未检测到可用 DWG→DXF 转换器(dwgread/dwg2dxf/CUSTOMIZE_DWG_TO_DXF_CMD),使用内置图纸可读文本抽取'] };
|
|
369
|
+
return { tool: 'builtin_fallback', warnings: [...failures, failures.length ? 'DWG→DXF 转换失败,使用内置图纸可读文本抽取' : '未检测到可用 DWG→DXF 转换器(dwgread/dwg2dxf/CUSTOMIZE_DWG_TO_DXF_CMD),使用内置图纸可读文本抽取'] };
|
|
351
370
|
}
|
|
352
371
|
finally {
|
|
353
372
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
@@ -559,6 +578,7 @@ export class ContentExtractor {
|
|
|
559
578
|
};
|
|
560
579
|
}
|
|
561
580
|
async extractLegacyWordDocument(file) {
|
|
581
|
+
const warnings = [];
|
|
562
582
|
try {
|
|
563
583
|
const mod = await resolveAndImport('word-extractor');
|
|
564
584
|
const WordExtractor = mod.default ?? mod;
|
|
@@ -571,11 +591,14 @@ export class ContentExtractor {
|
|
|
571
591
|
warnings: [],
|
|
572
592
|
};
|
|
573
593
|
}
|
|
594
|
+
warnings.push('word-extractor 未提取到正文,已降级为二进制可读文本抽取');
|
|
574
595
|
}
|
|
575
|
-
catch {
|
|
576
|
-
|
|
596
|
+
catch (error) {
|
|
597
|
+
warnings.push(`word-extractor 解析失败,已降级为二进制可读文本抽取: ${error instanceof Error ? error.message : String(error)}`);
|
|
577
598
|
}
|
|
578
|
-
|
|
599
|
+
const fallback = this.extractLegacyOfficeBinary(file);
|
|
600
|
+
fallback.warnings.unshift(...warnings);
|
|
601
|
+
return fallback;
|
|
579
602
|
}
|
|
580
603
|
extractLegacyOfficeBinary(file) {
|
|
581
604
|
const strings = this.extractBinaryStrings(file.absolutePath).slice(0, 1_000);
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export { TextChunker, type ChunkConfig, type TextChunk } from './chunking/text-c
|
|
|
2
2
|
export { FileClassifier } from './classification/classifier.js';
|
|
3
3
|
export { DedupEngine, type MinHashSignature, type SimilarityMatch } from './dedup/dedup-engine.js';
|
|
4
4
|
export { RelationshipDetector } from './dedup/relationship-detector.js';
|
|
5
|
-
export { HashEmbeddingProvider, type EmbeddingProvider } from './embedding/embedding-provider.js';
|
|
5
|
+
export { HashEmbeddingProvider, OpenAICompatibleEmbeddingProvider, createEmbeddingProviderFromEnvironment, type EmbeddingProvider, type OpenAICompatibleEmbeddingOptions } from './embedding/embedding-provider.js';
|
|
6
6
|
export { ContentExtractor, type ExtractionResult } from './extraction/content-extractor.js';
|
|
7
7
|
export { CommandExternalExtractor, ExternalExtractorRegistry, type CommandExternalExtractorOptions, type ExternalExtractionResult, type ExternalExtractor, type ExternalExtractorCapability } from './extraction/external-extractor.js';
|
|
8
8
|
export { ChangeTracker } from './core/change-tracker.js';
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ export { TextChunker } from './chunking/text-chunker.js';
|
|
|
4
4
|
export { FileClassifier } from './classification/classifier.js';
|
|
5
5
|
export { DedupEngine } from './dedup/dedup-engine.js';
|
|
6
6
|
export { RelationshipDetector } from './dedup/relationship-detector.js';
|
|
7
|
-
export { HashEmbeddingProvider } from './embedding/embedding-provider.js';
|
|
7
|
+
export { HashEmbeddingProvider, OpenAICompatibleEmbeddingProvider, createEmbeddingProviderFromEnvironment } from './embedding/embedding-provider.js';
|
|
8
8
|
export { ContentExtractor } from './extraction/content-extractor.js';
|
|
9
9
|
export { CommandExternalExtractor, ExternalExtractorRegistry } from './extraction/external-extractor.js';
|
|
10
10
|
export { ChangeTracker } from './core/change-tracker.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@customize-agent/knowledge",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.5",
|
|
4
4
|
"description": "Local knowledge base infrastructure for customize-agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"license": "MIT",
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=22.13.0"
|
|
18
|
+
},
|
|
16
19
|
"author": "Pan-jijian",
|
|
17
20
|
"repository": {
|
|
18
21
|
"type": "git",
|