# task-734.1: PDF 인식 로직 opendataloader-pdf 통합 업그레이드

## 목표
시스템 전체의 PDF 인식을 **opendataloader-pdf** 단일 파서로 통합.
업그레이드 후 docling 직접 호출, pdfplumber, pdf-parse(npm) 등 기존 파서가 코드에 남아있으면 안 됨.
**하나의 PDF 인식 시스템만 존재해야 한다.**

## 외부 레포 분석 (학습 대상)
- GitHub: https://github.com/opendataloader-project/opendataloader-pdf
- Python 설치: `pip install -U opendataloader-pdf`
- Node.js 설치: `npm install @opendataloader/pdf`
- 핵심: Java 엔진 + Python 래퍼, XY-Cut++ reading order, 하이브리드(단순→Java/복잡→Docling AI)
- 벤치마크 1위: 전체 0.90, Reading Order 0.94, 테이블 TEDS 0.93
- API: `opendataloader_pdf.convert(input_path, output_dir, format="json")`
- AI 안전 필터링 기본 내장 (프롬프트 인젝션 방어)
- OCR 80+ 언어, 수식(LaTeX), 차트 AI 설명 지원

## 기존 PDF 처리 코드 전수조사 결과 (15개 파일)

### Python 핵심 (교체 대상)
1. `/home/jay/workspace/libs/doc_parser.py` (326줄) — **docling** 기반 주력 파서. parse_pdf(), parse_document(), _build_pdf_converter(), _extract_tables(), _extract_pages(), clear_cache(). SHA-256 캐시 포함.
2. `/home/jay/projects/InsuRo/server/ai_parser.py` (179줄) — Docling 1차 → **pdfplumber** fallback. extract_text_from_pdf(), _extract_with_pdfplumber(), _table_to_markdown().
3. `/home/jay/projects/InsuRo/server/ingest_fcpa.py` (91줄) — doc_parser.parse_pdf 경유. ingest_fcpa_pdf().
4. `/home/jay/projects/InsuRo/server/main.py` (235줄) — /api/insuro/fcpa/upload 엔드포인트에서 ai_parser 호출.

### Python 테스트 (수정 대상)
5. `/home/jay/workspace/libs/tests/test_doc_parser.py` (288줄) — docling mock 기반 테스트
6. `/home/jay/workspace/libs/tests/test_comparison.py` (602줄) — pdfplumber vs docling 비교 테스트
7. `/home/jay/workspace/libs/tests/test_ai_parser_fallback.py` (205줄) — fallback 로직 테스트
8. `/home/jay/workspace/teams/dev2/tests/test_ai_parser_integration.py` (325줄) — ai_parser 통합 테스트
9. `/home/jay/workspace/teams/dev2/tests/test_docling_comparison.py` (419줄) — docling 비교 테스트
10. `/home/jay/projects/InsuRo/server/tests/test_ai_parser.py` (269줄) — ai_parser 단위 테스트
11. `/home/jay/projects/InsuRo/server/tests/test_ingest_fcpa.py` (342줄) — ingest_fcpa 테스트

### Node.js (교체 대상)
12. `/home/jay/projects/insuwiki/functions/src/pdfIndexing.ts` (977줄) — **pdf-parse** (npm). Cloud Function. extractTextWithPdfParse(), splitIntoChunks(), structureAwareChunk(). Gemini 임베딩 → Firestore 저장.
13. `/home/jay/projects/insuwiki/functions/lib/pdfIndexing.js` — 컴파일 결과물 (ts 수정 후 재빌드)
14. `/home/jay/projects/insuwiki/functions/src/__tests__/appendixDetection.test.ts` (559줄) — pdfIndexing 테스트

### 무관 (변경 불필요)
15. `/home/jay/workspace/scripts/file-cleanup.py` — PDF 파싱 안 함, 확장자 필터링만

## 작업 지시

### Phase 1: Python 측 통합
1. **opendataloader-pdf 설치**: `pip install -U opendataloader-pdf` (로컬 모드 우선, hybrid는 선택)
2. **doc_parser.py 교체**: docling 직접 호출 → opendataloader_pdf.convert() 기반으로 교체
   - `parse_pdf(file_bytes)` 인터페이스(ParseResult 반환) 유지 — 하위 호출부 변경 최소화
   - SHA-256 캐시 로직 유지
   - `parse_document()` 확장자 분기 유지 (PDF일 때만 opendataloader 사용)
   - opendataloader 출력 JSON → 기존 ParseResult(text, pages, tables, metadata) 매핑
   - 테이블 추출: opendataloader의 type="table" 요소 활용
   - 페이지별 텍스트: opendataloader의 page number 필드 활용
   - bounding box 정보도 ParseResult에 추가 (선택, 기존 인터페이스 깨지지 않게)
3. **ai_parser.py 정리**: pdfplumber fallback 제거 → doc_parser.parse_pdf() 단일 경로
   - `_extract_with_pdfplumber()` 함수 삭제
   - `import pdfplumber` 제거
   - extract_text_from_pdf()가 doc_parser만 호출하도록 단순화
4. **ingest_fcpa.py, main.py**: doc_parser 인터페이스 유지했으므로 변경 최소 (import 확인만)
5. **테스트 수정**: docling/pdfplumber mock → opendataloader mock으로 교체
   - test_comparison.py: opendataloader vs 이전 결과 비교로 변경 (또는 삭제 검토)
   - test_ai_parser_fallback.py: fallback 없어졌으므로 삭제 또는 단순화
6. **의존성 정리**: requirements.txt 등에서 docling, pdfplumber 제거, opendataloader-pdf 추가

### Phase 2: Node.js 측 통합
1. **@opendataloader/pdf 설치**: insuwiki/functions/ 에서 `npm install @opendataloader/pdf`
2. **pdfIndexing.ts 교체**:
   - `pdf-parse` → `@opendataloader/pdf` 교체
   - `extractTextWithPdfParse()` → opendataloader 기반으로 재구현
   - opendataloader는 헤딩 계층, 테이블, 페이지 구조를 네이티브 제공 → structureAwareChunk 개선 가능
   - 기존 [PAGE N] 마커 방식 유지 또는 opendataloader page number 활용
   - appendix 감지 로직(isAppendixSection, separateAppendixSections 등)은 유지 (비즈니스 로직)
3. **테스트 수정**: appendixDetection.test.ts 등 pdf-parse mock → opendataloader mock
4. **의존성 정리**: package.json에서 pdf-parse 제거, @opendataloader/pdf 추가
5. **TypeScript 빌드**: `npm run build` 확인

### Phase 3: 검증
1. **금소법 PDF 테스트**: `/home/jay/workspace/libs/tests/금융소비자_보호에_관한_법률법률제21065호20260102.pdf` 사용
   - 텍스트 추출 정확도 확인 (조항 번호, 특수문자)
   - 테이블 추출 확인
2. **InsuRo 엔드포인트 테스트**: /api/insuro/fcpa/upload 정상 동작 확인
3. **InsuWiki 빌드 확인**: TypeScript 컴파일 성공
4. **잔여 코드 확인**: 프로젝트 전체에서 `pdfplumber`, `pdf-parse`, `from docling` import가 남아있지 않은지 grep 확인

## 핵심 원칙
- **하나의 시스템**: 업그레이드 후 `opendataloader-pdf`만 존재. docling 직접 호출, pdfplumber, pdf-parse 모두 제거.
- **인터페이스 유지**: doc_parser.py의 ParseResult 구조는 유지하여 하위 호출부 영향 최소화
- **테스트 필수**: 각 Phase 완료 시 해당 테스트 통과 확인
- opendataloader GitHub README와 examples/ 디렉토리 참고하여 최적 사용법 학습

## 참고 자료
- opendataloader-pdf GitHub: https://github.com/opendataloader-project/opendataloader-pdf
- 기존 doc_parser.py: `/home/jay/workspace/libs/doc_parser.py`
- 기존 ai_parser.py: `/home/jay/projects/InsuRo/server/ai_parser.py`
- 기존 pdfIndexing.ts: `/home/jay/projects/insuwiki/functions/src/pdfIndexing.ts`