@heripo/pdf-parser 0.1.13 → 0.1.15
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/index.cjs +182 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.js +181 -21
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
package/dist/index.d.cts
CHANGED
|
@@ -33,12 +33,16 @@ type PDFConvertOptions = Omit<ConversionOptions, 'to_formats' | 'image_export_mo
|
|
|
33
33
|
aggregator?: LLMTokenUsageAggregator;
|
|
34
34
|
/** Callback fired after each batch of VLM pages completes, with cumulative token usage */
|
|
35
35
|
onTokenUsage?: (report: TokenUsageReport) => void;
|
|
36
|
+
/** Document processing timeout in seconds for the Docling server (default: server default) */
|
|
37
|
+
document_timeout?: number;
|
|
36
38
|
/** Enable chunked conversion for large PDFs (local files only) */
|
|
37
39
|
chunkedConversion?: boolean;
|
|
38
40
|
/** Pages per chunk (default: CHUNKED_CONVERSION.DEFAULT_CHUNK_SIZE) */
|
|
39
41
|
chunkSize?: number;
|
|
40
42
|
/** Max retry attempts per failed chunk (default: CHUNKED_CONVERSION.DEFAULT_MAX_RETRIES) */
|
|
41
43
|
chunkMaxRetries?: number;
|
|
44
|
+
/** LLM model for document type validation (opt-in: skipped when not set) */
|
|
45
|
+
documentValidationModel?: LanguageModel;
|
|
42
46
|
};
|
|
43
47
|
/** Result of strategy-based conversion */
|
|
44
48
|
interface ConvertWithStrategyResult {
|
|
@@ -177,6 +181,17 @@ declare class ImagePdfFallbackError extends Error {
|
|
|
177
181
|
constructor(originalError: Error, fallbackError: Error);
|
|
178
182
|
}
|
|
179
183
|
|
|
184
|
+
/**
|
|
185
|
+
* Error thrown when the uploaded PDF does not appear to be
|
|
186
|
+
* a Korean archaeological investigation report.
|
|
187
|
+
*/
|
|
188
|
+
declare class InvalidDocumentTypeError extends Error {
|
|
189
|
+
readonly reason: string;
|
|
190
|
+
readonly name = "InvalidDocumentTypeError";
|
|
191
|
+
readonly code = "INVALID_DOCUMENT_TYPE";
|
|
192
|
+
constructor(reason: string);
|
|
193
|
+
}
|
|
194
|
+
|
|
180
195
|
/**
|
|
181
196
|
* Intermediate format produced by VLM page-by-page processing.
|
|
182
197
|
* Intentionally kept simple so VLM prompts stay short and accurate.
|
|
@@ -285,4 +300,4 @@ declare class VlmResponseValidator {
|
|
|
285
300
|
private static detectRepetitivePattern;
|
|
286
301
|
}
|
|
287
302
|
|
|
288
|
-
export { type ConversionCompleteCallback, type ConvertWithStrategyResult, ImagePdfFallbackError, type PDFConvertOptions, PDFParser, type VlmPageQuality, type VlmQualityIssue, type VlmQualityIssueType, VlmResponseValidator, type VlmValidationResult };
|
|
303
|
+
export { type ConversionCompleteCallback, type ConvertWithStrategyResult, ImagePdfFallbackError, InvalidDocumentTypeError, type PDFConvertOptions, PDFParser, type VlmPageQuality, type VlmQualityIssue, type VlmQualityIssueType, VlmResponseValidator, type VlmValidationResult };
|
package/dist/index.d.ts
CHANGED
|
@@ -33,12 +33,16 @@ type PDFConvertOptions = Omit<ConversionOptions, 'to_formats' | 'image_export_mo
|
|
|
33
33
|
aggregator?: LLMTokenUsageAggregator;
|
|
34
34
|
/** Callback fired after each batch of VLM pages completes, with cumulative token usage */
|
|
35
35
|
onTokenUsage?: (report: TokenUsageReport) => void;
|
|
36
|
+
/** Document processing timeout in seconds for the Docling server (default: server default) */
|
|
37
|
+
document_timeout?: number;
|
|
36
38
|
/** Enable chunked conversion for large PDFs (local files only) */
|
|
37
39
|
chunkedConversion?: boolean;
|
|
38
40
|
/** Pages per chunk (default: CHUNKED_CONVERSION.DEFAULT_CHUNK_SIZE) */
|
|
39
41
|
chunkSize?: number;
|
|
40
42
|
/** Max retry attempts per failed chunk (default: CHUNKED_CONVERSION.DEFAULT_MAX_RETRIES) */
|
|
41
43
|
chunkMaxRetries?: number;
|
|
44
|
+
/** LLM model for document type validation (opt-in: skipped when not set) */
|
|
45
|
+
documentValidationModel?: LanguageModel;
|
|
42
46
|
};
|
|
43
47
|
/** Result of strategy-based conversion */
|
|
44
48
|
interface ConvertWithStrategyResult {
|
|
@@ -177,6 +181,17 @@ declare class ImagePdfFallbackError extends Error {
|
|
|
177
181
|
constructor(originalError: Error, fallbackError: Error);
|
|
178
182
|
}
|
|
179
183
|
|
|
184
|
+
/**
|
|
185
|
+
* Error thrown when the uploaded PDF does not appear to be
|
|
186
|
+
* a Korean archaeological investigation report.
|
|
187
|
+
*/
|
|
188
|
+
declare class InvalidDocumentTypeError extends Error {
|
|
189
|
+
readonly reason: string;
|
|
190
|
+
readonly name = "InvalidDocumentTypeError";
|
|
191
|
+
readonly code = "INVALID_DOCUMENT_TYPE";
|
|
192
|
+
constructor(reason: string);
|
|
193
|
+
}
|
|
194
|
+
|
|
180
195
|
/**
|
|
181
196
|
* Intermediate format produced by VLM page-by-page processing.
|
|
182
197
|
* Intentionally kept simple so VLM prompts stay short and accurate.
|
|
@@ -285,4 +300,4 @@ declare class VlmResponseValidator {
|
|
|
285
300
|
private static detectRepetitivePattern;
|
|
286
301
|
}
|
|
287
302
|
|
|
288
|
-
export { type ConversionCompleteCallback, type ConvertWithStrategyResult, ImagePdfFallbackError, type PDFConvertOptions, PDFParser, type VlmPageQuality, type VlmQualityIssue, type VlmQualityIssueType, VlmResponseValidator, type VlmValidationResult };
|
|
303
|
+
export { type ConversionCompleteCallback, type ConvertWithStrategyResult, ImagePdfFallbackError, InvalidDocumentTypeError, type PDFConvertOptions, PDFParser, type VlmPageQuality, type VlmQualityIssue, type VlmQualityIssueType, VlmResponseValidator, type VlmValidationResult };
|
package/dist/index.js
CHANGED
|
@@ -1484,6 +1484,32 @@ var PdfTextExtractor = class {
|
|
|
1484
1484
|
}
|
|
1485
1485
|
return result.stdout;
|
|
1486
1486
|
}
|
|
1487
|
+
/**
|
|
1488
|
+
* Extract text from a range of PDF pages using a single pdftotext invocation.
|
|
1489
|
+
* Returns empty string on failure (logged as warning).
|
|
1490
|
+
*
|
|
1491
|
+
* @param pdfPath - Absolute path to the source PDF file
|
|
1492
|
+
* @param firstPage - First page number (1-based)
|
|
1493
|
+
* @param lastPage - Last page number (1-based, inclusive)
|
|
1494
|
+
*/
|
|
1495
|
+
async extractPageRange(pdfPath, firstPage, lastPage) {
|
|
1496
|
+
const result = await spawnAsync("pdftotext", [
|
|
1497
|
+
"-f",
|
|
1498
|
+
firstPage.toString(),
|
|
1499
|
+
"-l",
|
|
1500
|
+
lastPage.toString(),
|
|
1501
|
+
"-layout",
|
|
1502
|
+
pdfPath,
|
|
1503
|
+
"-"
|
|
1504
|
+
]);
|
|
1505
|
+
if (result.code !== 0) {
|
|
1506
|
+
this.logger.warn(
|
|
1507
|
+
`[PdfTextExtractor] pdftotext failed for pages ${firstPage}-${lastPage}: ${result.stderr || "Unknown error"}`
|
|
1508
|
+
);
|
|
1509
|
+
return "";
|
|
1510
|
+
}
|
|
1511
|
+
return result.stdout;
|
|
1512
|
+
}
|
|
1487
1513
|
/**
|
|
1488
1514
|
* Extract text from a single PDF page using pdftotext.
|
|
1489
1515
|
* Returns empty string on failure (logged as warning).
|
|
@@ -2046,8 +2072,9 @@ Note: Hanja are Chinese characters used in Korean documents, different from mode
|
|
|
2046
2072
|
|
|
2047
2073
|
Answer whether any Hanja characters are present on this page.
|
|
2048
2074
|
|
|
2049
|
-
Also identify all languages present on this page. Return an array of
|
|
2050
|
-
|
|
2075
|
+
Also identify all languages present on this page. Return an array of ocrmac-compatible language tags ordered by prevalence (primary language first).
|
|
2076
|
+
Supported tags: ar-SA, ars-SA, cs-CZ, da-DK, de-DE, en-US, es-ES, fr-FR, id-ID, it-IT, ja-JP, ko-KR, ms-MY, nb-NO, nl-NL, nn-NO, no-NO, pl-PL, pt-BR, ro-RO, ru-RU, sv-SE, th-TH, tr-TR, uk-UA, vi-VT, yue-Hans, yue-Hant, zh-Hans, zh-Hant.
|
|
2077
|
+
Examples: ["ko-KR", "en-US"], ["ja-JP"], ["zh-Hant", "en-US"]`;
|
|
2051
2078
|
var OcrStrategySampler = class {
|
|
2052
2079
|
logger;
|
|
2053
2080
|
pageRenderer;
|
|
@@ -2345,6 +2372,119 @@ var LocalFileServer = class {
|
|
|
2345
2372
|
}
|
|
2346
2373
|
};
|
|
2347
2374
|
|
|
2375
|
+
// src/utils/task-failure-details.ts
|
|
2376
|
+
var MAX_RESULT_RETRIES = 3;
|
|
2377
|
+
var RESULT_RETRY_DELAY_MS = 2e3;
|
|
2378
|
+
async function getTaskFailureDetails(task, logger, logPrefix) {
|
|
2379
|
+
for (let attempt = 0; attempt < MAX_RESULT_RETRIES; attempt++) {
|
|
2380
|
+
try {
|
|
2381
|
+
if (attempt > 0) {
|
|
2382
|
+
await new Promise((r) => setTimeout(r, RESULT_RETRY_DELAY_MS));
|
|
2383
|
+
}
|
|
2384
|
+
const result = await task.getResult();
|
|
2385
|
+
if (result.errors?.length) {
|
|
2386
|
+
return result.errors.map((e) => e.message).join("; ");
|
|
2387
|
+
}
|
|
2388
|
+
return `status: ${result.status ?? "unknown"}`;
|
|
2389
|
+
} catch (err) {
|
|
2390
|
+
if (attempt === MAX_RESULT_RETRIES - 1) {
|
|
2391
|
+
logger.error(
|
|
2392
|
+
`${logPrefix} Failed to retrieve task result after ${MAX_RESULT_RETRIES} attempts:`,
|
|
2393
|
+
err
|
|
2394
|
+
);
|
|
2395
|
+
return "unable to retrieve error details";
|
|
2396
|
+
}
|
|
2397
|
+
logger.warn(
|
|
2398
|
+
`${logPrefix} Result not available yet, retrying (${attempt + 1}/${MAX_RESULT_RETRIES})...`
|
|
2399
|
+
);
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2402
|
+
return "unable to retrieve error details";
|
|
2403
|
+
}
|
|
2404
|
+
|
|
2405
|
+
// src/validators/document-type-validator.ts
|
|
2406
|
+
import { z as z3 } from "zod";
|
|
2407
|
+
|
|
2408
|
+
// src/errors/invalid-document-type-error.ts
|
|
2409
|
+
var InvalidDocumentTypeError = class extends Error {
|
|
2410
|
+
constructor(reason) {
|
|
2411
|
+
super(
|
|
2412
|
+
`The uploaded PDF does not appear to be a Korean archaeological investigation report. Reason: ${reason}`
|
|
2413
|
+
);
|
|
2414
|
+
this.reason = reason;
|
|
2415
|
+
}
|
|
2416
|
+
name = "InvalidDocumentTypeError";
|
|
2417
|
+
code = "INVALID_DOCUMENT_TYPE";
|
|
2418
|
+
};
|
|
2419
|
+
|
|
2420
|
+
// src/validators/document-type-validator.ts
|
|
2421
|
+
var SYSTEM_PROMPT = `You are given text extracted from the first and last pages of a PDF document.
|
|
2422
|
+
Determine if this document is a Korean archaeological investigation report (\uACE0\uACE0\uD559 \uC870\uC0AC \uBCF4\uACE0\uC11C).
|
|
2423
|
+
|
|
2424
|
+
Valid types include:
|
|
2425
|
+
- \uBC1C\uAD74\uC870\uC0AC\uBCF4\uACE0\uC11C (excavation investigation report)
|
|
2426
|
+
- \uC2DC\uAD74\uC870\uC0AC\uBCF4\uACE0\uC11C (trial excavation report)
|
|
2427
|
+
- \uC9C0\uD45C\uC870\uC0AC\uBCF4\uACE0\uC11C (surface survey report)
|
|
2428
|
+
- \uC815\uBC00\uBC1C\uAD74\uC870\uC0AC\uBCF4\uACE0\uC11C (detailed excavation report)
|
|
2429
|
+
- \uC218\uC911\uBC1C\uAD74\uC870\uC0AC\uBCF4\uACE0\uC11C (underwater excavation report)
|
|
2430
|
+
|
|
2431
|
+
NOT valid (these are NOT archaeological investigation reports):
|
|
2432
|
+
- \uC218\uB9AC\uBCF4\uACE0\uC11C (repair/restoration report)
|
|
2433
|
+
- \uB2E8\uC21C \uC2E4\uCE21 \uBCF4\uACE0\uC11C (simple measurement report)
|
|
2434
|
+
- \uAC74\uCD95\uC870\uC0AC\uBCF4\uACE0\uC11C (architectural investigation report)
|
|
2435
|
+
- \uD559\uC220\uC870\uC0AC\uBCF4\uACE0\uC11C (academic research report)
|
|
2436
|
+
- \uD658\uACBD\uC601\uD5A5\uD3C9\uAC00 (environmental impact assessment)
|
|
2437
|
+
- General academic papers or textbooks about archaeology`;
|
|
2438
|
+
var documentTypeSchema = z3.object({
|
|
2439
|
+
isValid: z3.boolean().describe("Whether this is a Korean archaeological investigation report"),
|
|
2440
|
+
reason: z3.string().describe("Brief reason for the decision")
|
|
2441
|
+
});
|
|
2442
|
+
var DocumentTypeValidator = class {
|
|
2443
|
+
textExtractor;
|
|
2444
|
+
constructor(textExtractor) {
|
|
2445
|
+
this.textExtractor = textExtractor;
|
|
2446
|
+
}
|
|
2447
|
+
/**
|
|
2448
|
+
* Validate that the PDF at the given path is an archaeological investigation report.
|
|
2449
|
+
*
|
|
2450
|
+
* @throws {InvalidDocumentTypeError} if the document is not a valid report type
|
|
2451
|
+
*/
|
|
2452
|
+
async validate(pdfPath, model, options) {
|
|
2453
|
+
const totalPages = await this.textExtractor.getPageCount(pdfPath);
|
|
2454
|
+
if (totalPages === 0) return;
|
|
2455
|
+
const frontText = await this.textExtractor.extractPageRange(
|
|
2456
|
+
pdfPath,
|
|
2457
|
+
1,
|
|
2458
|
+
Math.min(10, totalPages)
|
|
2459
|
+
);
|
|
2460
|
+
let backText = "";
|
|
2461
|
+
if (totalPages > 20) {
|
|
2462
|
+
backText = await this.textExtractor.extractPageRange(
|
|
2463
|
+
pdfPath,
|
|
2464
|
+
Math.max(1, totalPages - 9),
|
|
2465
|
+
totalPages
|
|
2466
|
+
);
|
|
2467
|
+
}
|
|
2468
|
+
const combinedText = (frontText + "\n" + backText).trim();
|
|
2469
|
+
if (combinedText.length === 0) return;
|
|
2470
|
+
const result = await LLMCaller.call({
|
|
2471
|
+
schema: documentTypeSchema,
|
|
2472
|
+
systemPrompt: SYSTEM_PROMPT,
|
|
2473
|
+
userPrompt: `--- Document text (first and last pages) ---
|
|
2474
|
+
${combinedText}`,
|
|
2475
|
+
primaryModel: model,
|
|
2476
|
+
maxRetries: 2,
|
|
2477
|
+
temperature: 0,
|
|
2478
|
+
abortSignal: options?.abortSignal,
|
|
2479
|
+
component: "DocumentTypeValidator",
|
|
2480
|
+
phase: "validation"
|
|
2481
|
+
});
|
|
2482
|
+
if (!result.output.isValid) {
|
|
2483
|
+
throw new InvalidDocumentTypeError(result.output.reason);
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2486
|
+
};
|
|
2487
|
+
|
|
2348
2488
|
// src/core/chunked-pdf-converter.ts
|
|
2349
2489
|
import {
|
|
2350
2490
|
copyFileSync,
|
|
@@ -2699,14 +2839,15 @@ var ChunkedPDFConverter = class {
|
|
|
2699
2839
|
const status = await task.poll();
|
|
2700
2840
|
if (status.task_status === "success") return;
|
|
2701
2841
|
if (status.task_status === "failure") {
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2842
|
+
const elapsed = ((Date.now() - startTime) / 1e3).toFixed(1);
|
|
2843
|
+
this.logger.error(
|
|
2844
|
+
`[ChunkedPDFConverter] Task ${task.taskId} failed after ${elapsed}s`
|
|
2845
|
+
);
|
|
2846
|
+
const details = await getTaskFailureDetails(
|
|
2847
|
+
task,
|
|
2848
|
+
this.logger,
|
|
2849
|
+
"[ChunkedPDFConverter]"
|
|
2850
|
+
);
|
|
2710
2851
|
throw new Error(`[ChunkedPDFConverter] Chunk task failed: ${details}`);
|
|
2711
2852
|
}
|
|
2712
2853
|
await new Promise(
|
|
@@ -2971,8 +3112,27 @@ var PDFConverter = class {
|
|
|
2971
3112
|
this.enableImagePdfFallback = enableImagePdfFallback;
|
|
2972
3113
|
this.timeout = timeout;
|
|
2973
3114
|
}
|
|
3115
|
+
documentTypeValidated = false;
|
|
3116
|
+
/**
|
|
3117
|
+
* Validate that the PDF is a Korean archaeological investigation report.
|
|
3118
|
+
* Skipped when no documentValidationModel is configured or for non-local URLs.
|
|
3119
|
+
* Only runs once per converter instance (flag prevents duplicate checks on recursive calls).
|
|
3120
|
+
*/
|
|
3121
|
+
async validateDocumentType(url, options, abortSignal) {
|
|
3122
|
+
if (this.documentTypeValidated) return;
|
|
3123
|
+
this.documentTypeValidated = true;
|
|
3124
|
+
if (!options.documentValidationModel) return;
|
|
3125
|
+
const pdfPath = url.startsWith("file://") ? url.slice(7) : null;
|
|
3126
|
+
if (!pdfPath) return;
|
|
3127
|
+
const textExtractor = new PdfTextExtractor(this.logger);
|
|
3128
|
+
const validator = new DocumentTypeValidator(textExtractor);
|
|
3129
|
+
await validator.validate(pdfPath, options.documentValidationModel, {
|
|
3130
|
+
abortSignal
|
|
3131
|
+
});
|
|
3132
|
+
}
|
|
2974
3133
|
async convert(url, reportId, onComplete, cleanupAfterCallback, options, abortSignal) {
|
|
2975
3134
|
this.logger.info("[PDFConverter] Converting:", url);
|
|
3135
|
+
await this.validateDocumentType(url, options, abortSignal);
|
|
2976
3136
|
if (options.chunkedConversion && url.startsWith("file://")) {
|
|
2977
3137
|
const chunked = new ChunkedPDFConverter(
|
|
2978
3138
|
this.logger,
|
|
@@ -3027,6 +3187,7 @@ var PDFConverter = class {
|
|
|
3027
3187
|
const aggregator = options.aggregator ?? new LLMTokenUsageAggregator();
|
|
3028
3188
|
const trackedOptions = { ...options, aggregator };
|
|
3029
3189
|
const pdfPath = url.startsWith("file://") ? url.slice(7) : null;
|
|
3190
|
+
await this.validateDocumentType(url, trackedOptions, abortSignal);
|
|
3030
3191
|
const strategy = await this.determineStrategy(
|
|
3031
3192
|
pdfPath,
|
|
3032
3193
|
reportId,
|
|
@@ -3343,6 +3504,7 @@ var PDFConverter = class {
|
|
|
3343
3504
|
return {
|
|
3344
3505
|
...omit(options, [
|
|
3345
3506
|
"num_threads",
|
|
3507
|
+
"document_timeout",
|
|
3346
3508
|
"forceImagePdf",
|
|
3347
3509
|
"strategySamplerModel",
|
|
3348
3510
|
"vlmProcessorModel",
|
|
@@ -3352,7 +3514,8 @@ var PDFConverter = class {
|
|
|
3352
3514
|
"onTokenUsage",
|
|
3353
3515
|
"chunkedConversion",
|
|
3354
3516
|
"chunkSize",
|
|
3355
|
-
"chunkMaxRetries"
|
|
3517
|
+
"chunkMaxRetries",
|
|
3518
|
+
"documentValidationModel"
|
|
3356
3519
|
]),
|
|
3357
3520
|
to_formats: ["json", "html"],
|
|
3358
3521
|
image_export_mode: "embedded",
|
|
@@ -3364,6 +3527,8 @@ var PDFConverter = class {
|
|
|
3364
3527
|
framework: "livetext"
|
|
3365
3528
|
},
|
|
3366
3529
|
generate_picture_images: true,
|
|
3530
|
+
do_picture_classification: true,
|
|
3531
|
+
do_picture_description: true,
|
|
3367
3532
|
generate_page_images: false,
|
|
3368
3533
|
// Page images are rendered by PageRenderer (ImageMagick) after conversion
|
|
3369
3534
|
images_scale: 2,
|
|
@@ -3378,6 +3543,9 @@ var PDFConverter = class {
|
|
|
3378
3543
|
accelerator_options: {
|
|
3379
3544
|
device: "mps",
|
|
3380
3545
|
num_threads: options.num_threads
|
|
3546
|
+
},
|
|
3547
|
+
...options.document_timeout !== void 0 && {
|
|
3548
|
+
document_timeout: options.document_timeout
|
|
3381
3549
|
}
|
|
3382
3550
|
};
|
|
3383
3551
|
}
|
|
@@ -3464,16 +3632,7 @@ var PDFConverter = class {
|
|
|
3464
3632
|
* Fetch detailed error information from a failed task result.
|
|
3465
3633
|
*/
|
|
3466
3634
|
async getTaskFailureDetails(task) {
|
|
3467
|
-
|
|
3468
|
-
const result = await task.getResult();
|
|
3469
|
-
if (result.errors?.length) {
|
|
3470
|
-
return result.errors.map((e) => e.message).join("; ");
|
|
3471
|
-
}
|
|
3472
|
-
return `status: ${result.status ?? "unknown"}`;
|
|
3473
|
-
} catch (err) {
|
|
3474
|
-
this.logger.error("[PDFConverter] Failed to retrieve task result:", err);
|
|
3475
|
-
return "unable to retrieve error details";
|
|
3476
|
-
}
|
|
3635
|
+
return getTaskFailureDetails(task, this.logger, "[PDFConverter]");
|
|
3477
3636
|
}
|
|
3478
3637
|
async downloadResult(taskId) {
|
|
3479
3638
|
this.logger.info(
|
|
@@ -4057,6 +4216,7 @@ var VlmResponseValidator = class {
|
|
|
4057
4216
|
};
|
|
4058
4217
|
export {
|
|
4059
4218
|
ImagePdfFallbackError,
|
|
4219
|
+
InvalidDocumentTypeError,
|
|
4060
4220
|
PDFParser,
|
|
4061
4221
|
VlmResponseValidator
|
|
4062
4222
|
};
|