@customize-agent/knowledge 4.0.17 → 4.0.18

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.
@@ -60,6 +60,8 @@ export declare class ContentExtractor {
60
60
  private cleanOcrText;
61
61
  /** 加载图片像素数据(依赖 sharp) */
62
62
  private loadImagePixels;
63
+ private readImageDimensions;
64
+ private isTooSmallForOcr;
63
65
  private extractPdfText;
64
66
  private normalizedTextLength;
65
67
  private toPdfTextItem;
@@ -918,6 +918,12 @@ export class ContentExtractor {
918
918
  let imageData;
919
919
  try {
920
920
  imageData = await this.loadImagePixels(file.absolutePath);
921
+ if (this.isTooSmallForOcr(imageData.width, imageData.height)) {
922
+ metadata.contentCoverage = 'image_too_small_for_ocr';
923
+ metadata.imageWidth = imageData.width;
924
+ metadata.imageHeight = imageData.height;
925
+ return { text: this.metadataOnlyText(file), metadata, warnings: [`图片尺寸过小(${imageData.width}x${imageData.height}),已跳过 OCR 并仅索引元数据`] };
926
+ }
921
927
  }
922
928
  catch (e) {
923
929
  metadata.contentCoverage = 'image_decode_failed';
@@ -1094,10 +1100,16 @@ export class ContentExtractor {
1094
1100
  for (let i = 0; i < pageImages.length; i++) {
1095
1101
  const imgPath = pageImages[i];
1096
1102
  try {
1103
+ const dimensions = await this.readImageDimensions(imgPath);
1104
+ if (dimensions && this.isTooSmallForOcr(dimensions.width, dimensions.height)) {
1105
+ failedPages.push({ page: i + 1, reason: `image_too_small_for_ocr_${dimensions.width}x${dimensions.height}` });
1106
+ warnings.push(`PDF 第 ${i + 1} 页渲染图片尺寸过小(${dimensions.width}x${dimensions.height}),已跳过 OCR`);
1107
+ continue;
1108
+ }
1097
1109
  const provider = await getOcrProvider();
1098
1110
  const ocrResult = await provider.recognize({
1099
1111
  data: new Uint8Array(0),
1100
- width: 0, height: 0, channels: 0,
1112
+ width: dimensions?.width ?? 0, height: dimensions?.height ?? 0, channels: 0,
1101
1113
  filePath: imgPath,
1102
1114
  });
1103
1115
  const ocrText = this.cleanOcrText(ocrResult.text);
@@ -1219,6 +1231,22 @@ export class ContentExtractor {
1219
1231
  const { data, info } = await sharpFn(filePath).raw().toBuffer({ resolveWithObject: true });
1220
1232
  return { data: new Uint8Array(data), width: info.width, height: info.height };
1221
1233
  }
1234
+ async readImageDimensions(filePath) {
1235
+ try {
1236
+ const sharpMod = await resolveAndImport('sharp');
1237
+ const sharpFn = sharpMod.default ?? sharpMod;
1238
+ const metadata = await sharpFn(filePath).metadata();
1239
+ const width = Number(metadata.width ?? 0);
1240
+ const height = Number(metadata.height ?? 0);
1241
+ return width > 0 && height > 0 ? { width, height } : undefined;
1242
+ }
1243
+ catch {
1244
+ return undefined;
1245
+ }
1246
+ }
1247
+ isTooSmallForOcr(width, height) {
1248
+ return width < 8 || height < 8 || width * height < 128;
1249
+ }
1222
1250
  async extractPdfText(buffer) {
1223
1251
  let pdfjsText = '';
1224
1252
  // 第一层:pdfjs-dist 文本提取(处理压缩内容流、CJK 字体、现代 PDF)
@@ -48,6 +48,8 @@ export declare class TesseractJsProvider implements OcrProvider {
48
48
  filePath?: string;
49
49
  }): Promise<OcrResult>;
50
50
  getWarnings(): string[];
51
+ private readImageDimensions;
52
+ private isTooSmallForOcr;
51
53
  private getWorker;
52
54
  private createReusableWorker;
53
55
  dispose(): Promise<void>;
@@ -44,9 +44,14 @@ export class TesseractJsProvider {
44
44
  async recognize(input) {
45
45
  let pngPath;
46
46
  let tmpDir = null;
47
+ let width = input.width;
48
+ let height = input.height;
47
49
  // 如果传了 filePath,直接使用;否则 raw pixels → PNG
48
50
  if (input.filePath && fs.existsSync(input.filePath)) {
49
51
  pngPath = input.filePath;
52
+ const dimensions = await this.readImageDimensions(pngPath);
53
+ width = dimensions?.width ?? width;
54
+ height = dimensions?.height ?? height;
50
55
  }
51
56
  else {
52
57
  const sharpMod = await resolveAndImport('sharp');
@@ -61,6 +66,9 @@ export class TesseractJsProvider {
61
66
  .withMetadata({ density: 288 })
62
67
  .png().toFile(pngPath);
63
68
  }
69
+ if (this.isTooSmallForOcr(width, height)) {
70
+ return { text: '', confidence: 0, regions: [], warnings: [`image too small for OCR: ${width}x${height}`] };
71
+ }
64
72
  try {
65
73
  const worker = await this.getWorker();
66
74
  const result = await worker.recognize(pngPath);
@@ -88,6 +96,22 @@ export class TesseractJsProvider {
88
96
  getWarnings() {
89
97
  return [...new Set(this.warnings)].slice(-20);
90
98
  }
99
+ async readImageDimensions(filePath) {
100
+ try {
101
+ const sharpMod = await resolveAndImport('sharp');
102
+ const sharpFn = sharpMod.default ?? sharpMod;
103
+ const metadata = await sharpFn(filePath).metadata();
104
+ const width = Number(metadata.width ?? 0);
105
+ const height = Number(metadata.height ?? 0);
106
+ return width > 0 && height > 0 ? { width, height } : undefined;
107
+ }
108
+ catch {
109
+ return undefined;
110
+ }
111
+ }
112
+ isTooSmallForOcr(width, height) {
113
+ return width < 8 || height < 8 || width * height < 128;
114
+ }
91
115
  async getWorker() {
92
116
  if (this.worker)
93
117
  return this.worker;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@customize-agent/knowledge",
3
- "version": "4.0.17",
3
+ "version": "4.0.18",
4
4
  "description": "Local knowledge base infrastructure for customize-agent",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",