@heripo/pdf-parser 0.1.16 → 0.1.17

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/README.ko.md CHANGED
@@ -21,6 +21,11 @@
21
21
  - [설치](#설치)
22
22
  - [사용법](#사용법)
23
23
  - [OCR 전략 시스템](#ocr-전략-시스템)
24
+ - [문서 유형 검증](#문서-유형-검증)
25
+ - [대용량 PDF 청크 변환](#대용량-pdf-청크-변환)
26
+ - [이미지 PDF 폴백](#이미지-pdf-폴백)
27
+ - [AbortSignal 지원](#abortsignal-지원)
28
+ - [서버 크래시 복구](#서버-크래시-복구)
24
29
  - [왜 macOS 전용인가?](#왜-macos-전용인가)
25
30
  - [시스템 의존성 상세](#시스템-의존성-상세)
26
31
  - [API 문서](#api-문서)
@@ -34,7 +39,11 @@
34
39
  - **Apple Silicon 최적화**: M1/M2/M3/M4/M5 칩에서 GPU 가속 지원
35
40
  - **자동 환경 설정**: Python 가상환경 및 docling-serve 자동 설치
36
41
  - **이미지 추출**: PDF 내 이미지 자동 추출 및 저장
37
- - **유연한 설정**: OCR, 포맷, 스레딩 옵션 세부 설정 가능
42
+ - **문서 유형 검증**: LLM 기반 고고학 보고서 여부 검증 (선택)
43
+ - **청크 변환**: 대용량 PDF를 청크로 분할하여 안정적으로 처리
44
+ - **이미지 PDF 폴백**: 변환 실패 시 이미지 기반 PDF로 자동 재시도
45
+ - **AbortSignal 지원**: 진행 중인 파싱 작업 취소
46
+ - **서버 크래시 복구**: ECONNREFUSED 발생 시 docling-serve 자동 재시작
38
47
 
39
48
  ## 사전 요구사항
40
49
 
@@ -60,7 +69,7 @@ npm install -g pnpm
60
69
 
61
70
  #### 3. Python 3.9 - 3.12
62
71
 
63
- ⚠️ **중요**: Python 3.13+는 지원하지 않습니다. Docling SDK의 일부 의존성이 Python 3.13과 호환되지 않습니다.
72
+ > **중요**: Python 3.13+는 지원하지 않습니다. Docling SDK의 일부 의존성이 Python 3.13과 호환되지 않습니다.
64
73
 
65
74
  ```bash
66
75
  # Python 3.11 설치 (권장)
@@ -92,11 +101,19 @@ macOS에 기본적으로 설치되어 있습니다. 확인:
92
101
  which lsof
93
102
  ```
94
103
 
104
+ #### 7. ImageMagick + Ghostscript (선택)
105
+
106
+ 이미지 PDF 폴백 기능(`enableImagePdfFallback` 또는 `forceImagePdf`)을 사용할 때만 필요합니다.
107
+
108
+ ```bash
109
+ brew install imagemagick ghostscript
110
+ ```
111
+
95
112
  ### 최초 실행 설정
96
113
 
97
114
  `@heripo/pdf-parser`를 처음 사용할 때 자동으로:
98
115
 
99
- 1. `~/.heripo/pdf-parser/venv`에 Python 가상환경 생성
116
+ 1. 현재 작업 디렉토리의 `.venv`에 Python 가상환경 생성 (`venvPath`로 설정 가능)
100
117
  2. `docling-serve` 및 의존성 설치
101
118
  3. 로컬 포트에서 docling-serve 프로세스 시작
102
119
 
@@ -125,9 +142,9 @@ import { PDFParser } from '@heripo/pdf-parser';
125
142
 
126
143
  const logger = Logger(...);
127
144
 
128
- // PDFParser 인스턴스 생성
145
+ // PDFParser 인스턴스 생성 (logger는 필수)
129
146
  const pdfParser = new PDFParser({
130
- pythonPath: 'python3.11', // Python 실행 경로
147
+ port: 5001,
131
148
  logger,
132
149
  });
133
150
 
@@ -135,58 +152,68 @@ const pdfParser = new PDFParser({
135
152
  await pdfParser.init();
136
153
 
137
154
  // PDF 파싱
138
- const outputPath = await pdfParser.parse(
139
- 'path/to/report.pdf', // 입력 PDF 파일
140
- 'output-directory', // 출력 디렉토리
141
- (resultPath) => {
155
+ const tokenUsageReport = await pdfParser.parse(
156
+ 'file:///path/to/report.pdf', // PDF URL (file:// 또는 http://)
157
+ 'report-001', // 리포트 ID
158
+ async (outputPath) => {
142
159
  // 변환 완료 콜백
143
- console.log('PDF 변환 완료:', resultPath);
160
+ console.log('PDF 변환 완료:', outputPath);
144
161
  },
162
+ false, // cleanupAfterCallback
163
+ {}, // PDFConvertOptions
145
164
  );
146
165
 
147
- // 결과 사용
148
- console.log('출력 경로:', outputPath);
166
+ // 토큰 사용량 리포트 (LLM 사용이 없으면 null)
167
+ console.log('토큰 사용량:', tokenUsageReport);
149
168
  ```
150
169
 
151
170
  ### 고급 옵션
152
171
 
153
172
  ```typescript
173
+ // 옵션 A: 로컬 서버 (포트 모드)
154
174
  const pdfParser = new PDFParser({
155
- pythonPath: 'python3.11',
156
175
  logger,
176
+ port: 5001, // 사용할 포트 (기본값: 5001)
177
+ timeout: 10000000, // 타임아웃 (밀리초)
178
+ venvPath: '/custom/path/.venv', // 커스텀 venv 경로 (기본값: CWD/.venv)
179
+ killExistingProcess: true, // 포트의 기존 프로세스 종료 (기본값: false)
180
+ enableImagePdfFallback: true, // 이미지 PDF 폴백 활성화 (기본값: false)
181
+ });
157
182
 
158
- // docling-serve 설정
159
- port: 5001, // 사용할 포트 (기본값: 5001)
160
- timeout: 10000000, // 타임아웃 (밀리초)
161
-
162
- // 외부 docling-serve 사용
163
- externalDoclingUrl: 'http://localhost:5000', // 외부 서버 사용 시
183
+ // 옵션 B: 외부 docling-serve 사용
184
+ const pdfParser = new PDFParser({
185
+ logger,
186
+ baseUrl: 'http://localhost:5000', // 외부 서버 URL
164
187
  });
165
188
 
166
- // 변환 옵션 지정
167
- await pdfParser.parse('input.pdf', 'output', (result) => console.log(result), {
168
- // OCR 설정
169
- doOcr: true, // OCR 활성화 (기본값: true)
189
+ // 변환 옵션과 함께 파싱
190
+ const tokenUsageReport = await pdfParser.parse(
191
+ 'file:///path/to/input.pdf',
192
+ 'report-001',
193
+ async (outputPath) => console.log(outputPath),
194
+ false,
195
+ {
196
+ // OCR 전략 옵션
197
+ strategySamplerModel: openai('gpt-5.1'),
198
+ vlmProcessorModel: openai('gpt-5.1'),
199
+ vlmConcurrency: 3,
170
200
 
171
- // 출력 포맷
172
- formats: ['docling_json', 'md'], // 출력 형식 선택
201
+ // 문서 유형 검증
202
+ documentValidationModel: openai('gpt-5.1'),
173
203
 
174
- // 스레드
175
- pdfBackend: 'dlparse_v2', // PDF 백엔드
176
- });
177
- ```
204
+ // 대용량 PDF 청크 변환
205
+ chunkedConversion: true,
206
+ chunkSize: 50,
207
+ chunkMaxRetries: 3,
178
208
 
179
- ### 이미지 추출
209
+ // 이미지 PDF 사전 변환 강제
210
+ forceImagePdf: false,
180
211
 
181
- PDF에서 이미지를 자동으로 추출합니다:
212
+ // 문서 처리 타임아웃 (초)
213
+ document_timeout: 600,
182
214
 
183
- ```typescript
184
- const outputPath = await pdfParser.parse(
185
- 'report.pdf',
186
- 'output',
187
- (resultPath) => {
188
- // 이미지는 output/images/ 디렉토리에 저장됨
189
- console.log('이미지 추출 완료:', resultPath);
215
+ // 토큰 사용량 추적
216
+ onTokenUsage: (report) => console.log('토큰 사용량:', report),
190
217
  },
191
218
  );
192
219
  ```
@@ -196,15 +223,15 @@ const outputPath = await pdfParser.parse(
196
223
  작업 완료 후 리소스를 정리합니다:
197
224
 
198
225
  ```typescript
199
- // docling-serve 프로세스 종료
200
- await pdfParser.shutdown();
226
+ // docling-serve 프로세스 종료 및 리소스 해제
227
+ await pdfParser.dispose();
201
228
  ```
202
229
 
203
230
  ## OCR 전략 시스템
204
231
 
205
232
  ### 왜 이 전략인가?
206
233
 
207
- **ocrmac(Apple Vision Framework)은 매우 우수한 OCR 엔진입니다** 무료이고, GPU 가속을 지원하며, 고품질 결과를 제공합니다. 수천~수백만 권의 고고학 보고서를 처리할 때 이만한 솔루션이 없습니다.
234
+ **ocrmac(Apple Vision Framework)은 매우 우수한 OCR 엔진입니다** -- 무료이고, GPU 가속을 지원하며, 고품질 결과를 제공합니다. 수천~수백만 권의 고고학 보고서를 처리할 때 이만한 솔루션이 없습니다.
208
235
 
209
236
  **그러나 ocrmac은 혼합 문자 체계를 처리하지 못합니다.** 한글·한자 혼용 문서(그리고 잠재적으로 다른 혼합 문자 조합)에서 보조 문자가 깨진 텍스트로 변환됩니다. 전체 파이프라인을 비용이 높은 VLM으로 전환하는 대신, **문제가 있는 페이지만 타겟팅**하여 VLM으로 보정합니다.
210
237
 
@@ -219,16 +246,17 @@ await pdfParser.shutdown();
219
246
 
220
247
  - 각 페이지의 OCR 텍스트 요소와 표 셀을 추출
221
248
  - `pdftotext` 참조 텍스트를 품질 기준으로 활용
222
- - VLM이 치환 기반 보정(find replace)을 반환
249
+ - VLM이 치환 기반 보정(find -> replace)을 반환
223
250
  - 실패한 페이지는 원본 OCR 텍스트를 유지하며 건너뜀
224
251
 
225
252
  ### 전략 옵션
226
253
 
227
254
  ```typescript
228
- const outputPath = await pdfParser.parse(
229
- 'input.pdf',
230
- 'output',
231
- (result) => console.log(result),
255
+ const tokenUsageReport = await pdfParser.parse(
256
+ 'file:///path/to/input.pdf',
257
+ 'report-001',
258
+ async (outputPath) => console.log(outputPath),
259
+ false,
232
260
  {
233
261
  // OCR 전략 샘플링 활성화 (Vision LLM 모델 제공)
234
262
  strategySamplerModel: openai('gpt-5.1'),
@@ -245,6 +273,114 @@ const outputPath = await pdfParser.parse(
245
273
  );
246
274
  ```
247
275
 
276
+ ## 문서 유형 검증
277
+
278
+ LLM 기반으로 PDF가 고고학 발굴조사보고서인지 검증하는 선택적 기능입니다. `documentValidationModel`을 제공하면 파서가 PDF에서 텍스트를 추출하고 LLM을 사용하여 문서 유형을 확인한 후 처리합니다. 검증에 실패하면 `InvalidDocumentTypeError`가 발생합니다.
279
+
280
+ ```typescript
281
+ import { InvalidDocumentTypeError } from '@heripo/pdf-parser';
282
+
283
+ try {
284
+ await pdfParser.parse(
285
+ 'file:///path/to/input.pdf',
286
+ 'report-001',
287
+ async (outputPath) => console.log(outputPath),
288
+ false,
289
+ {
290
+ documentValidationModel: openai('gpt-5.1'),
291
+ },
292
+ );
293
+ } catch (error) {
294
+ if (error instanceof InvalidDocumentTypeError) {
295
+ console.error('고고학 보고서가 아닙니다:', error.message);
296
+ }
297
+ }
298
+ ```
299
+
300
+ ## 대용량 PDF 청크 변환
301
+
302
+ 타임아웃이나 메모리 문제를 일으킬 수 있는 대용량 PDF의 경우, 청크 변환을 활성화하여 PDF를 작은 청크로 분할하고 개별적으로 처리할 수 있습니다. 로컬 파일(`file://` URL)에서만 동작합니다.
303
+
304
+ ```typescript
305
+ const tokenUsageReport = await pdfParser.parse(
306
+ 'file:///path/to/large-report.pdf',
307
+ 'report-001',
308
+ async (outputPath) => console.log(outputPath),
309
+ false,
310
+ {
311
+ chunkedConversion: true,
312
+ chunkSize: 50, // 청크당 페이지 수 (기본값: 상수에서 설정)
313
+ chunkMaxRetries: 3, // 실패한 청크의 최대 재시도 횟수 (기본값: 상수에서 설정)
314
+ },
315
+ );
316
+ ```
317
+
318
+ ## 이미지 PDF 폴백
319
+
320
+ 변환이 실패하면 파서가 PDF를 이미지 기반 PDF로 변환한 후 재시도할 수 있습니다. 복잡하거나 손상된 구조의 PDF에 유용합니다. ImageMagick과 Ghostscript가 필요합니다.
321
+
322
+ ### 자동 폴백 (실패 시)
323
+
324
+ 생성자 옵션으로 활성화합니다. 변환이 실패하면 파서가 자동으로 이미지 기반 PDF로 재시도합니다:
325
+
326
+ ```typescript
327
+ const pdfParser = new PDFParser({
328
+ logger,
329
+ port: 5001,
330
+ enableImagePdfFallback: true, // 자동 폴백 활성화
331
+ });
332
+ ```
333
+
334
+ ### 강제 이미지 PDF (항상)
335
+
336
+ parse 옵션으로 이미지 기반 PDF 사전 변환을 강제합니다:
337
+
338
+ ```typescript
339
+ const tokenUsageReport = await pdfParser.parse(
340
+ 'file:///path/to/input.pdf',
341
+ 'report-001',
342
+ async (outputPath) => console.log(outputPath),
343
+ false,
344
+ {
345
+ forceImagePdf: true, // 항상 이미지 PDF로 먼저 변환
346
+ },
347
+ );
348
+ ```
349
+
350
+ 원본 변환과 폴백 변환 모두 실패하면 두 에러를 모두 포함하는 `ImagePdfFallbackError`가 발생합니다.
351
+
352
+ ## AbortSignal 지원
353
+
354
+ `AbortSignal`을 전달하여 진행 중인 파싱 작업을 취소할 수 있습니다:
355
+
356
+ ```typescript
357
+ const controller = new AbortController();
358
+
359
+ // 5분 후 취소
360
+ setTimeout(() => controller.abort(), 5 * 60 * 1000);
361
+
362
+ try {
363
+ await pdfParser.parse(
364
+ 'file:///path/to/input.pdf',
365
+ 'report-001',
366
+ async (outputPath) => console.log(outputPath),
367
+ false,
368
+ {},
369
+ controller.signal, // AbortSignal
370
+ );
371
+ } catch (error) {
372
+ if (error.name === 'AbortError') {
373
+ console.log('파싱이 취소되었습니다');
374
+ }
375
+ }
376
+ ```
377
+
378
+ ## 서버 크래시 복구
379
+
380
+ 로컬 docling-serve 인스턴스(포트 모드)를 사용할 때, 파서가 서버 크래시(ECONNREFUSED 에러)를 자동으로 감지하고 서버를 재시작합니다. 이 과정은 `parse()` 호출 중에 투명하게 처리되며, 실패한 작업은 서버 재시작 후 재시도됩니다.
381
+
382
+ > **참고**: 서버 크래시 복구는 로컬 서버 모드(`port` 옵션)에서만 사용 가능합니다. 외부 서버(`baseUrl` 옵션)를 사용할 때는 복구를 시도하지 않습니다.
383
+
248
384
  ## 왜 macOS 전용인가?
249
385
 
250
386
  `@heripo/pdf-parser`는 **의도적으로 macOS에 강하게 의존**합니다. 이 결정의 핵심 이유는 **Docling SDK의 로컬 OCR 성능**입니다.
@@ -281,14 +417,16 @@ const outputPath = await pdfParser.parse(
281
417
 
282
418
  `@heripo/pdf-parser`는 다음 시스템 레벨 의존성이 필요합니다:
283
419
 
284
- | 의존성 | 필수 버전 | 설치 방법 | 용도 |
285
- | ------- | ---------- | -------------------------- | -------------------------------------------------------------- |
286
- | Python | 3.9 - 3.12 | `brew install python@3.11` | Docling SDK 실행 환경 |
287
- | poppler | Any | `brew install poppler` | PDF 페이지 수 확인 (pdfinfo) 및 텍스트 레이어 추출 (pdftotext) |
288
- | jq | Any | `brew install jq` | JSON 처리 (변환 결과 파싱) |
289
- | lsof | Any | macOS 기본 설치됨 | docling-serve 포트 관리 |
420
+ | 의존성 | 필수 버전 | 설치 방법 | 용도 |
421
+ | ----------- | ---------- | -------------------------- | -------------------------------------------------------------- |
422
+ | Python | 3.9 - 3.12 | `brew install python@3.11` | Docling SDK 실행 환경 |
423
+ | poppler | Any | `brew install poppler` | PDF 페이지 수 확인 (pdfinfo) 및 텍스트 레이어 추출 (pdftotext) |
424
+ | jq | Any | `brew install jq` | JSON 처리 (변환 결과 파싱) |
425
+ | lsof | Any | macOS 기본 설치됨 | docling-serve 포트 관리 |
426
+ | ImageMagick | Any (선택) | `brew install imagemagick` | 이미지 PDF 폴백 및 페이지 렌더링 |
427
+ | Ghostscript | Any (선택) | `brew install ghostscript` | 이미지 PDF 폴백 (PDF를 이미지로 변환) |
290
428
 
291
- > ⚠️ **Python 3.13+는 지원하지 않습니다.** Docling SDK의 일부 의존성이 Python 3.13과 호환되지 않습니다.
429
+ > **Python 3.13+는 지원하지 않습니다.** Docling SDK의 일부 의존성이 Python 3.13과 호환되지 않습니다.
292
430
 
293
431
  ### Python 버전 확인
294
432
 
@@ -318,13 +456,16 @@ which jq
318
456
  #### 생성자 옵션
319
457
 
320
458
  ```typescript
321
- interface PDFParserOptions {
322
- pythonPath?: string; // Python 실행 경로 (기본값: 'python3')
323
- logger?: Logger; // 로거 인스턴스
324
- port?: number; // docling-serve 포트 (기본값: 5001)
459
+ type Options = {
460
+ logger: LoggerMethods; // 로거 인스턴스 (필수)
325
461
  timeout?: number; // 타임아웃 (밀리초, 기본값: 10000000)
326
- externalDoclingUrl?: string; // 외부 docling-serve URL (선택)
327
- }
462
+ venvPath?: string; // Python venv 경로 (기본값: CWD/.venv)
463
+ killExistingProcess?: boolean; // 포트의 기존 프로세스 종료 (기본값: false)
464
+ enableImagePdfFallback?: boolean; // 이미지 PDF 폴백 활성화 (기본값: false, ImageMagick + Ghostscript 필요)
465
+ } & (
466
+ | { port?: number } // 로컬 서버 모드 (기본 포트: 5001)
467
+ | { baseUrl: string } // 외부 서버 모드
468
+ );
328
469
  ```
329
470
 
330
471
  #### 메서드
@@ -337,70 +478,102 @@ Python 환경을 설정하고 docling-serve를 시작합니다.
337
478
  await pdfParser.init();
338
479
  ```
339
480
 
340
- ##### `parse(inputPath, outputDir, callback, options?): Promise<string>`
481
+ ##### `parse(url, reportId, onComplete, cleanupAfterCallback, options, abortSignal?): Promise<TokenUsageReport | null>`
341
482
 
342
483
  PDF 파일을 파싱합니다.
343
484
 
344
485
  **파라미터:**
345
486
 
346
- - `inputPath` (string): 입력 PDF 파일 경로
347
- - `outputDir` (string): 출력 디렉토리 경로
348
- - `callback` (function): 변환 완료 시 호출될 콜백 함수
349
- - `options` (ConversionOptions, 선택): 변환 옵션
487
+ - `url` (string): PDF URL (로컬 파일은 `file://`, 원격은 `http://`)
488
+ - `reportId` (string): 고유 리포트 식별자 (출력 디렉토리 이름에 사용)
489
+ - `onComplete` (ConversionCompleteCallback): 변환 완료 시 출력 디렉토리 경로와 함께 호출되는 콜백 함수
490
+ - `cleanupAfterCallback` (boolean): 콜백 완료 후 출력 디렉토리 삭제 여부
491
+ - `options` (PDFConvertOptions): 변환 옵션
492
+ - `abortSignal` (AbortSignal, 선택): 작업 취소를 위한 시그널
350
493
 
351
494
  **반환값:**
352
495
 
353
- - `Promise<string>`: 출력 파일 경로
354
-
355
- ##### `shutdown(): Promise<void>`
356
-
357
- docling-serve 프로세스를 종료합니다.
496
+ - `Promise<TokenUsageReport | null>`: LLM 작업의 토큰 사용량 리포트, LLM 사용이 없으면 `null`
358
497
 
359
- ```typescript
360
- await pdfParser.shutdown();
361
- ```
498
+ ##### `dispose(): Promise<void>`
362
499
 
363
- ### ConversionOptions
500
+ 파서 인스턴스를 해제하고, 로컬 docling-serve 프로세스를 종료(시작한 경우)하며, 리소스를 해제합니다.
364
501
 
365
502
  ```typescript
366
- interface ConversionOptions {
367
- doOcr?: boolean; // OCR 활성화 (기본값: true)
368
- formats?: string[]; // 출력 형식 (기본값: ['docling_json'])
369
- pdfBackend?: string; // PDF 백엔드 (기본값: 'dlparse_v2')
370
- }
503
+ await pdfParser.dispose();
371
504
  ```
372
505
 
373
- ### PDFConvertOptions (확장)
506
+ ### PDFConvertOptions
374
507
 
375
508
  ```typescript
376
- interface PDFConvertOptions extends ConversionOptions {
509
+ type PDFConvertOptions = {
510
+ // OCR 전략 옵션
377
511
  strategySamplerModel?: LanguageModel; // OCR 전략 샘플링용 Vision LLM
378
512
  vlmProcessorModel?: LanguageModel; // 텍스트 보정용 Vision LLM
379
513
  vlmConcurrency?: number; // 병렬 페이지 처리 (기본값: 1)
380
514
  skipSampling?: boolean; // 전략 샘플링 건너뛰기
381
515
  forcedMethod?: 'ocrmac' | 'vlm'; // 특정 OCR 방식 강제
516
+
517
+ // 이미지 PDF 옵션
518
+ forceImagePdf?: boolean; // 이미지 기반 PDF 사전 변환 강제
519
+
520
+ // 토큰 사용량 추적
521
+ aggregator?: LLMTokenUsageAggregator; // 토큰 사용량 집계기
522
+ onTokenUsage?: (report: TokenUsageReport) => void; // 토큰 사용량 업데이트 콜백
523
+
524
+ // 문서 처리
525
+ document_timeout?: number; // 문서 처리 타임아웃 (초)
526
+ documentValidationModel?: LanguageModel; // 문서 유형 검증용 LLM
527
+
528
+ // 청크 변환 (대용량 PDF)
529
+ chunkedConversion?: boolean; // 청크 변환 활성화
530
+ chunkSize?: number; // 청크당 페이지 수
531
+ chunkMaxRetries?: number; // 실패한 청크의 최대 재시도 횟수
532
+
533
+ // Docling 변환 옵션 (상속)
534
+ num_threads?: number; // 처리 스레드 수
535
+ ocr_lang?: string[]; // OCR 언어
536
+ // ... 기타 Docling ConversionOptions 필드
537
+ };
538
+ ```
539
+
540
+ ### ConvertWithStrategyResult
541
+
542
+ ```typescript
543
+ interface ConvertWithStrategyResult {
544
+ /** 결정된 OCR 전략 */
545
+ strategy: OcrStrategy;
546
+ /** 샘플링 및/또는 VLM 처리의 토큰 사용량 리포트 (LLM 사용이 없으면 null) */
547
+ tokenUsageReport: TokenUsageReport | null;
382
548
  }
383
549
  ```
384
550
 
385
- ## 문제 해결
551
+ ### ConversionCompleteCallback
386
552
 
387
- ### Python 버전 오류
553
+ ```typescript
554
+ type ConversionCompleteCallback = (outputPath: string) => Promise<void> | void;
555
+ ```
388
556
 
389
- **증상**: `Python version X.Y is not supported`
557
+ ### 에러 타입
390
558
 
391
- **해결**:
559
+ #### `InvalidDocumentTypeError`
392
560
 
393
- ```bash
394
- # Python 3.11 설치
395
- brew install python@3.11
561
+ PDF가 문서 유형 검증에 실패할 때 발생합니다 (즉, 고고학 발굴조사보고서가 아닌 경우).
396
562
 
397
- # PDFParser에 명시적으로 지정
398
- const pdfParser = new PDFParser({
399
- pythonPath: 'python3.11',
400
- logger,
401
- });
563
+ ```typescript
564
+ import { InvalidDocumentTypeError } from '@heripo/pdf-parser';
402
565
  ```
403
566
 
567
+ #### `ImagePdfFallbackError`
568
+
569
+ 원본 변환과 이미지 PDF 폴백 변환이 모두 실패할 때 발생합니다. 두 에러에 대한 참조를 포함합니다.
570
+
571
+ ```typescript
572
+ import { ImagePdfFallbackError } from '@heripo/pdf-parser';
573
+ ```
574
+
575
+ ## 문제 해결
576
+
404
577
  ### jq를 찾을 수 없음
405
578
 
406
579
  **증상**: `Command not found: jq`
@@ -427,13 +600,19 @@ brew install poppler
427
600
 
428
601
  **해결**:
429
602
 
430
- ```bash
431
- # 다른 포트 사용
603
+ ```typescript
604
+ // 다른 포트 사용
432
605
  const pdfParser = new PDFParser({
433
- pythonPath: 'python3.11',
434
606
  port: 5002, // 다른 포트 지정
435
607
  logger,
436
608
  });
609
+
610
+ // 또는 기존 프로세스 종료
611
+ const pdfParser = new PDFParser({
612
+ port: 5001,
613
+ killExistingProcess: true,
614
+ logger,
615
+ });
437
616
  ```
438
617
 
439
618
  ### docling-serve 시작 실패
@@ -443,21 +622,31 @@ const pdfParser = new PDFParser({
443
622
  **해결**:
444
623
 
445
624
  ```bash
446
- # 가상환경 재생성
447
- rm -rf ~/.heripo/pdf-parser/venv
625
+ # 가상환경 재생성 (기본 위치)
626
+ rm -rf .venv
448
627
  # 다시 init() 실행
449
628
  ```
450
629
 
630
+ ### ImageMagick / Ghostscript를 찾을 수 없음
631
+
632
+ **증상**: `ImageMagick is not installed but enableImagePdfFallback is enabled`
633
+
634
+ **해결**:
635
+
636
+ ```bash
637
+ brew install imagemagick ghostscript
638
+ ```
639
+
451
640
  ## Linux 지원 현황
452
641
 
453
642
  현재 **macOS 전용**입니다. Linux 지원은 **완전히 배제한 것은 아니지만**, OCR 성능과 비용 효율성 문제로 **현재는 구체적인 계획이 없습니다**.
454
643
 
455
- | 플랫폼 | 상태 | 비고 |
456
- | --------------------- | ------- | ------------------------------- |
457
- | macOS + Apple Silicon | 지원 | 최적 성능, GPU 가속 |
458
- | macOS + Intel | 지원 | GPU 가속 없음 |
459
- | Linux | 미정 | 성능/비용 문제로 현재 계획 없음 |
460
- | Windows | 미정 | WSL2 통한 Linux 방식 고려 가능 |
644
+ | 플랫폼 | 상태 | 비고 |
645
+ | --------------------- | ---- | ------------------------------- |
646
+ | macOS + Apple Silicon | 지원 | 최적 성능, GPU 가속 |
647
+ | macOS + Intel | 지원 | GPU 가속 없음 |
648
+ | Linux | 미정 | 성능/비용 문제로 현재 계획 없음 |
649
+ | Windows | 미정 | WSL2 통한 Linux 방식 고려 가능 |
461
650
 
462
651
  ### Linux 미지원 사유
463
652